@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 538 lines 14 kB view raw
1<?php 2 3final class PhabricatorPolicyTestCase extends PhabricatorTestCase { 4 5 /** 6 * Verify that any user can view an object with POLICY_PUBLIC. 7 */ 8 public function testPublicPolicyEnabled() { 9 $env = PhabricatorEnv::beginScopedEnv(); 10 $env->overrideEnvConfig('policy.allow-public', true); 11 12 $this->expectVisibility( 13 $this->buildObject(PhabricatorPolicies::POLICY_PUBLIC), 14 array( 15 'public' => true, 16 'user' => true, 17 'admin' => true, 18 ), 19 pht('Public Policy (Enabled in Config)')); 20 } 21 22 23 /** 24 * Verify that POLICY_PUBLIC is interpreted as POLICY_USER when public 25 * policies are disallowed. 26 */ 27 public function testPublicPolicyDisabled() { 28 $env = PhabricatorEnv::beginScopedEnv(); 29 $env->overrideEnvConfig('policy.allow-public', false); 30 31 $this->expectVisibility( 32 $this->buildObject(PhabricatorPolicies::POLICY_PUBLIC), 33 array( 34 'public' => false, 35 'user' => true, 36 'admin' => true, 37 ), 38 pht('Public Policy (Disabled in Config)')); 39 } 40 41 42 /** 43 * Verify that any logged-in user can view an object with POLICY_USER, but 44 * logged-out users can not. 45 */ 46 public function testUsersPolicy() { 47 $this->expectVisibility( 48 $this->buildObject(PhabricatorPolicies::POLICY_USER), 49 array( 50 'public' => false, 51 'user' => true, 52 'admin' => true, 53 ), 54 pht('User Policy')); 55 } 56 57 58 /** 59 * Verify that only administrators can view an object with POLICY_ADMIN. 60 */ 61 public function testAdminPolicy() { 62 $this->expectVisibility( 63 $this->buildObject(PhabricatorPolicies::POLICY_ADMIN), 64 array( 65 'public' => false, 66 'user' => false, 67 'admin' => true, 68 ), 69 pht('Admin Policy')); 70 } 71 72 73 /** 74 * Verify that no one can view an object with POLICY_NOONE. 75 */ 76 public function testNoOnePolicy() { 77 $this->expectVisibility( 78 $this->buildObject(PhabricatorPolicies::POLICY_NOONE), 79 array( 80 'public' => false, 81 'user' => false, 82 'admin' => false, 83 ), 84 pht('No One Policy')); 85 } 86 87 88 /** 89 * Test offset-based filtering. 90 */ 91 public function testOffsets() { 92 $results = array( 93 $this->buildObject(PhabricatorPolicies::POLICY_NOONE), 94 $this->buildObject(PhabricatorPolicies::POLICY_NOONE), 95 $this->buildObject(PhabricatorPolicies::POLICY_NOONE), 96 $this->buildObject(PhabricatorPolicies::POLICY_USER), 97 $this->buildObject(PhabricatorPolicies::POLICY_USER), 98 $this->buildObject(PhabricatorPolicies::POLICY_USER), 99 ); 100 101 $query = new PhabricatorPolicyAwareTestQuery(); 102 $query->setResults($results); 103 $query->setViewer($this->buildUser('user')); 104 105 $this->assertEqual( 106 3, 107 count($query->setLimit(3)->setOffset(0)->execute()), 108 pht('Invisible objects are ignored.')); 109 110 $this->assertEqual( 111 0, 112 count($query->setLimit(3)->setOffset(3)->execute()), 113 pht('Offset pages through visible objects only.')); 114 115 $this->assertEqual( 116 2, 117 count($query->setLimit(3)->setOffset(1)->execute()), 118 pht('Offsets work correctly.')); 119 120 $this->assertEqual( 121 2, 122 count($query->setLimit(0)->setOffset(1)->execute()), 123 pht('Offset with no limit works.')); 124 } 125 126 127 /** 128 * Test limits. 129 */ 130 public function testLimits() { 131 $results = array( 132 $this->buildObject(PhabricatorPolicies::POLICY_USER), 133 $this->buildObject(PhabricatorPolicies::POLICY_USER), 134 $this->buildObject(PhabricatorPolicies::POLICY_USER), 135 $this->buildObject(PhabricatorPolicies::POLICY_USER), 136 $this->buildObject(PhabricatorPolicies::POLICY_USER), 137 $this->buildObject(PhabricatorPolicies::POLICY_USER), 138 ); 139 140 $query = new PhabricatorPolicyAwareTestQuery(); 141 $query->setResults($results); 142 $query->setViewer($this->buildUser('user')); 143 144 $this->assertEqual( 145 3, 146 count($query->setLimit(3)->setOffset(0)->execute()), 147 pht('Limits work.')); 148 149 $this->assertEqual( 150 2, 151 count($query->setLimit(3)->setOffset(4)->execute()), 152 pht('Limit + offset work.')); 153 } 154 155 156 /** 157 * Test that omnipotent users bypass policies. 158 */ 159 public function testOmnipotence() { 160 $results = array( 161 $this->buildObject(PhabricatorPolicies::POLICY_NOONE), 162 ); 163 164 $query = new PhabricatorPolicyAwareTestQuery(); 165 $query->setResults($results); 166 $query->setViewer(PhabricatorUser::getOmnipotentUser()); 167 168 $this->assertEqual( 169 1, 170 count($query->execute())); 171 } 172 173 174 /** 175 * Test that invalid policies reject viewers of all types. 176 */ 177 public function testRejectInvalidPolicy() { 178 $invalid_policy = 'the duck goes quack'; 179 $object = $this->buildObject($invalid_policy); 180 181 $this->expectVisibility( 182 $object = $this->buildObject($invalid_policy), 183 array( 184 'public' => false, 185 'user' => false, 186 'admin' => false, 187 ), 188 pht('Invalid Policy')); 189 } 190 191 192 /** 193 * Test that extended policies work. 194 */ 195 public function testExtendedPolicies() { 196 $object = $this->buildObject(PhabricatorPolicies::POLICY_USER) 197 ->setPHID('PHID-TEST-1'); 198 199 $this->expectVisibility( 200 $object, 201 array( 202 'public' => false, 203 'user' => true, 204 'admin' => true, 205 ), 206 pht('No Extended Policy')); 207 208 // Add a restrictive extended policy. 209 $extended = $this->buildObject(PhabricatorPolicies::POLICY_ADMIN) 210 ->setPHID('PHID-TEST-2'); 211 $object->setExtendedPolicies( 212 array( 213 PhabricatorPolicyCapability::CAN_VIEW => array( 214 array($extended, PhabricatorPolicyCapability::CAN_VIEW), 215 ), 216 )); 217 218 $this->expectVisibility( 219 $object, 220 array( 221 'public' => false, 222 'user' => false, 223 'admin' => true, 224 ), 225 pht('With Extended Policy')); 226 227 // Depend on a different capability. 228 $object->setExtendedPolicies( 229 array( 230 PhabricatorPolicyCapability::CAN_VIEW => array( 231 array($extended, PhabricatorPolicyCapability::CAN_EDIT), 232 ), 233 )); 234 235 $extended->setCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT)); 236 $extended->setPolicies( 237 array( 238 PhabricatorPolicyCapability::CAN_EDIT => 239 PhabricatorPolicies::POLICY_NOONE, 240 )); 241 242 $this->expectVisibility( 243 $object, 244 array( 245 'public' => false, 246 'user' => false, 247 'admin' => false, 248 ), 249 pht('With Extended Policy + Edit')); 250 } 251 252 253 /** 254 * Test that cyclic extended policies are arrested properly. 255 */ 256 public function testExtendedPolicyCycles() { 257 $object = $this->buildObject(PhabricatorPolicies::POLICY_USER) 258 ->setPHID('PHID-TEST-1'); 259 260 $this->expectVisibility( 261 $object, 262 array( 263 'public' => false, 264 'user' => true, 265 'admin' => true, 266 ), 267 pht('No Extended Policy')); 268 269 // Set a self-referential extended policy on the object. This should 270 // make it fail all policy checks. 271 $object->setExtendedPolicies( 272 array( 273 PhabricatorPolicyCapability::CAN_VIEW => array( 274 array($object, PhabricatorPolicyCapability::CAN_VIEW), 275 ), 276 )); 277 278 $this->expectVisibility( 279 $object, 280 array( 281 'public' => false, 282 'user' => false, 283 'admin' => false, 284 ), 285 pht('Extended Policy with Cycle')); 286 } 287 288 289 /** 290 * Test bulk checks of extended policies. 291 * 292 * This is testing an issue with extended policy filtering which allowed 293 * unusual inputs to slip objects through the filter. See D14993. 294 */ 295 public function testBulkExtendedPolicies() { 296 $object1 = $this->buildObject(PhabricatorPolicies::POLICY_USER) 297 ->setPHID('PHID-TEST-1'); 298 $object2 = $this->buildObject(PhabricatorPolicies::POLICY_USER) 299 ->setPHID('PHID-TEST-2'); 300 $object3 = $this->buildObject(PhabricatorPolicies::POLICY_USER) 301 ->setPHID('PHID-TEST-3'); 302 303 $extended = $this->buildObject(PhabricatorPolicies::POLICY_ADMIN) 304 ->setPHID('PHID-TEST-999'); 305 306 $object1->setExtendedPolicies( 307 array( 308 PhabricatorPolicyCapability::CAN_VIEW => array( 309 array( 310 $extended, 311 array( 312 PhabricatorPolicyCapability::CAN_VIEW, 313 PhabricatorPolicyCapability::CAN_EDIT, 314 ), 315 ), 316 ), 317 )); 318 319 $object2->setExtendedPolicies( 320 array( 321 PhabricatorPolicyCapability::CAN_VIEW => array( 322 array($extended, PhabricatorPolicyCapability::CAN_VIEW), 323 ), 324 )); 325 326 $object3->setExtendedPolicies( 327 array( 328 PhabricatorPolicyCapability::CAN_VIEW => array( 329 array( 330 $extended, 331 array( 332 PhabricatorPolicyCapability::CAN_VIEW, 333 PhabricatorPolicyCapability::CAN_EDIT, 334 ), 335 ), 336 ), 337 )); 338 339 $user = $this->buildUser('user'); 340 341 $visible = id(new PhabricatorPolicyFilter()) 342 ->setViewer($user) 343 ->requireCapabilities( 344 array( 345 PhabricatorPolicyCapability::CAN_VIEW, 346 )) 347 ->apply( 348 array( 349 $object1, 350 $object2, 351 $object3, 352 )); 353 354 $this->assertEqual(array(), $visible); 355 } 356 357 358 /** 359 * An omnipotent user should be able to see even objects with invalid 360 * policies. 361 */ 362 public function testInvalidPolicyVisibleByOmnipotentUser() { 363 $invalid_policy = 'the cow goes moo'; 364 $object = $this->buildObject($invalid_policy); 365 366 $results = array( 367 $object, 368 ); 369 370 $query = new PhabricatorPolicyAwareTestQuery(); 371 $query->setResults($results); 372 $query->setViewer(PhabricatorUser::getOmnipotentUser()); 373 374 $this->assertEqual( 375 1, 376 count($query->execute())); 377 } 378 379 public function testAllQueriesBelongToActualApplications() { 380 $queries = id(new PhutilClassMapQuery()) 381 ->setAncestorClass(PhabricatorPolicyAwareQuery::class) 382 ->execute(); 383 384 foreach ($queries as $qclass => $query) { 385 $class = $query->getQueryApplicationClass(); 386 if (!$class) { 387 continue; 388 } 389 $this->assertTrue( 390 (bool)PhabricatorApplication::getByClass($class), 391 pht( 392 "Application class '%s' for query '%s'.", 393 $class, 394 $qclass)); 395 } 396 } 397 398 public function testMultipleCapabilities() { 399 $object = new PhabricatorPolicyTestObject(); 400 $object->setCapabilities( 401 array( 402 PhabricatorPolicyCapability::CAN_VIEW, 403 PhabricatorPolicyCapability::CAN_EDIT, 404 )); 405 $object->setPolicies( 406 array( 407 PhabricatorPolicyCapability::CAN_VIEW 408 => PhabricatorPolicies::POLICY_USER, 409 PhabricatorPolicyCapability::CAN_EDIT 410 => PhabricatorPolicies::POLICY_NOONE, 411 )); 412 413 $filter = new PhabricatorPolicyFilter(); 414 $filter->requireCapabilities( 415 array( 416 PhabricatorPolicyCapability::CAN_VIEW, 417 PhabricatorPolicyCapability::CAN_EDIT, 418 )); 419 $filter->setViewer($this->buildUser('user')); 420 421 $result = $filter->apply(array($object)); 422 423 $this->assertEqual(array(), $result); 424 } 425 426 public function testPolicyStrength() { 427 $public = PhabricatorPolicyQuery::getGlobalPolicy( 428 PhabricatorPolicies::POLICY_PUBLIC); 429 $user = PhabricatorPolicyQuery::getGlobalPolicy( 430 PhabricatorPolicies::POLICY_USER); 431 $admin = PhabricatorPolicyQuery::getGlobalPolicy( 432 PhabricatorPolicies::POLICY_ADMIN); 433 $noone = PhabricatorPolicyQuery::getGlobalPolicy( 434 PhabricatorPolicies::POLICY_NOONE); 435 436 $this->assertFalse($public->isStrongerThan($public)); 437 $this->assertFalse($public->isStrongerThan($user)); 438 $this->assertFalse($public->isStrongerThan($admin)); 439 $this->assertFalse($public->isStrongerThan($noone)); 440 441 $this->assertTrue($user->isStrongerThan($public)); 442 $this->assertFalse($user->isStrongerThan($user)); 443 $this->assertFalse($user->isStrongerThan($admin)); 444 $this->assertFalse($user->isStrongerThan($noone)); 445 446 $this->assertTrue($admin->isStrongerThan($public)); 447 $this->assertTrue($admin->isStrongerThan($user)); 448 $this->assertFalse($admin->isStrongerThan($admin)); 449 $this->assertFalse($admin->isStrongerThan($noone)); 450 451 $this->assertTrue($noone->isStrongerThan($public)); 452 $this->assertTrue($noone->isStrongerThan($user)); 453 $this->assertTrue($noone->isStrongerThan($admin)); 454 $this->assertFalse($admin->isStrongerThan($noone)); 455 } 456 457 458 /** 459 * Test an object for visibility across multiple user specifications. 460 */ 461 private function expectVisibility( 462 PhabricatorPolicyTestObject $object, 463 array $map, 464 $description) { 465 466 foreach ($map as $spec => $expect) { 467 $viewer = $this->buildUser($spec); 468 469 $query = new PhabricatorPolicyAwareTestQuery(); 470 $query->setResults(array($object)); 471 $query->setViewer($viewer); 472 473 $caught = null; 474 $result = null; 475 try { 476 $result = $query->executeOne(); 477 } catch (PhabricatorPolicyException $ex) { 478 $caught = $ex; 479 } 480 481 if ($expect) { 482 $this->assertEqual( 483 $object, 484 $result, 485 pht('%s with user %s should succeed.', $description, $spec)); 486 } else { 487 $this->assertTrue( 488 $caught instanceof PhabricatorPolicyException, 489 pht('%s with user %s should fail.', $description, $spec)); 490 } 491 } 492 } 493 494 495 /** 496 * Build a test object to spec. 497 */ 498 private function buildObject($policy) { 499 $object = new PhabricatorPolicyTestObject(); 500 $object->setCapabilities( 501 array( 502 PhabricatorPolicyCapability::CAN_VIEW, 503 PhabricatorPolicyCapability::CAN_EDIT, 504 )); 505 $object->setPolicies( 506 array( 507 PhabricatorPolicyCapability::CAN_VIEW => $policy, 508 PhabricatorPolicyCapability::CAN_EDIT => $policy, 509 )); 510 511 return $object; 512 } 513 514 515 /** 516 * Build a test user to spec. 517 */ 518 private function buildUser($spec) { 519 $user = new PhabricatorUser(); 520 521 switch ($spec) { 522 case 'public': 523 break; 524 case 'user': 525 $user->setPHID(1); 526 break; 527 case 'admin': 528 $user->setPHID(1); 529 $user->setIsAdmin(true); 530 break; 531 default: 532 throw new Exception(pht("Unknown user spec '%s'.", $spec)); 533 } 534 535 return $user; 536 } 537 538}