@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.

Make the new Build Plan "Runnable" behavior work

Summary:
Ref T13258. Fixes T11415. This makes "Runnable" actually do something:

- With "Runnable" set to "If Editable" (default): to manually run, pause, resume, abort, or restart a build, you must normally be able to edit the associated build plan.
- If you toggle "Runnable" to "If Viewable", anyone who can view the build plan may take these actions.

This is pretty straightforward since T9614 already got us pretty close to this ruleset a while ago.

Test Plan:
- Created a Build Plan, set "Can Edit" to just me, toggled "Runnable" to "If Viewable"/"If Editable", tried to take actions as another user.
- With "If Editable", unable to run, pause, resume, abort, or restart as another user.
- With "If Viewable", those actions work.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13258, T11415

Differential Revision: https://secure.phabricator.com/D20229

+115 -18
+3
src/__phutil_library_map__.php
··· 1340 1340 'HarbormasterBuildPlanNameNgrams' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlanNameNgrams.php', 1341 1341 'HarbormasterBuildPlanNameTransaction' => 'applications/harbormaster/xaction/plan/HarbormasterBuildPlanNameTransaction.php', 1342 1342 'HarbormasterBuildPlanPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php', 1343 + 'HarbormasterBuildPlanPolicyCodex' => 'applications/harbormaster/codex/HarbormasterBuildPlanPolicyCodex.php', 1343 1344 'HarbormasterBuildPlanQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanQuery.php', 1344 1345 'HarbormasterBuildPlanSearchAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildPlanSearchAPIMethod.php', 1345 1346 'HarbormasterBuildPlanSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildPlanSearchEngine.php', ··· 6945 6946 'PhabricatorNgramsInterface', 6946 6947 'PhabricatorConduitResultInterface', 6947 6948 'PhabricatorProjectInterface', 6949 + 'PhabricatorPolicyCodexInterface', 6948 6950 ), 6949 6951 'HarbormasterBuildPlanBehavior' => 'Phobject', 6950 6952 'HarbormasterBuildPlanBehaviorOption' => 'Phobject', ··· 6958 6960 'HarbormasterBuildPlanNameNgrams' => 'PhabricatorSearchNgrams', 6959 6961 'HarbormasterBuildPlanNameTransaction' => 'HarbormasterBuildPlanTransactionType', 6960 6962 'HarbormasterBuildPlanPHIDType' => 'PhabricatorPHIDType', 6963 + 'HarbormasterBuildPlanPolicyCodex' => 'PhabricatorPolicyCodex', 6961 6964 'HarbormasterBuildPlanQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 6962 6965 'HarbormasterBuildPlanSearchAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 6963 6966 'HarbormasterBuildPlanSearchEngine' => 'PhabricatorApplicationSearchEngine',
+38
src/applications/harbormaster/codex/HarbormasterBuildPlanPolicyCodex.php
··· 1 + <?php 2 + 3 + final class HarbormasterBuildPlanPolicyCodex 4 + extends PhabricatorPolicyCodex { 5 + 6 + public function getPolicySpecialRuleDescriptions() { 7 + $object = $this->getObject(); 8 + $run_with_view = $object->canRunWithoutEditCapability(); 9 + 10 + $rules = array(); 11 + 12 + $rules[] = $this->newRule() 13 + ->setCapabilities( 14 + array( 15 + PhabricatorPolicyCapability::CAN_EDIT, 16 + )) 17 + ->setIsActive(!$run_with_view) 18 + ->setDescription( 19 + pht( 20 + 'You must have edit permission on this build plan to pause, '. 21 + 'abort, resume, or restart it.')); 22 + 23 + $rules[] = $this->newRule() 24 + ->setCapabilities( 25 + array( 26 + PhabricatorPolicyCapability::CAN_EDIT, 27 + )) 28 + ->setIsActive(!$run_with_view) 29 + ->setDescription( 30 + pht( 31 + 'You must have edit permission on this build plan to run it '. 32 + 'manually.')); 33 + 34 + return $rules; 35 + } 36 + 37 + 38 + }
+2 -5
src/applications/harbormaster/controller/HarbormasterPlanRunController.php
··· 9 9 $plan = id(new HarbormasterBuildPlanQuery()) 10 10 ->setViewer($viewer) 11 11 ->withIDs(array($plan_id)) 12 - ->requireCapabilities( 13 - array( 14 - PhabricatorPolicyCapability::CAN_VIEW, 15 - PhabricatorPolicyCapability::CAN_EDIT, 16 - )) 17 12 ->executeOne(); 18 13 if (!$plan) { 19 14 return new Aphront404Response(); 20 15 } 16 + 17 + $plan->assertHasRunCapability($viewer); 21 18 22 19 $cancel_uri = $this->getApplicationURI("plan/{$plan_id}/"); 23 20
+1 -1
src/applications/harbormaster/controller/HarbormasterPlanViewController.php
··· 266 266 ->setIcon('fa-ban')); 267 267 } 268 268 269 - $can_run = ($can_edit && $plan->canRunManually()); 269 + $can_run = ($plan->hasRunCapability($viewer) && $plan->canRunManually()); 270 270 271 271 $curtain->addAction( 272 272 id(new PhabricatorActionView())
+22 -6
src/applications/harbormaster/plan/HarbormasterBuildPlanBehavior.php
··· 9 9 private $defaultKey; 10 10 private $editInstructions; 11 11 12 + const BEHAVIOR_RUNNABLE = 'runnable'; 13 + const RUNNABLE_IF_VIEWABLE = 'view'; 14 + const RUNNABLE_IF_EDITABLE = 'edit'; 15 + 12 16 public function setKey($key) { 13 17 $this->key = $key; 14 18 return $this; ··· 114 118 return sprintf('behavior.%s', $behavior_key); 115 119 } 116 120 121 + public static function getBehavior($key) { 122 + $behaviors = self::newPlanBehaviors(); 123 + 124 + if (!isset($behaviors[$key])) { 125 + throw new Exception( 126 + pht( 127 + 'No build plan behavior with key "%s" exists.', 128 + $key)); 129 + } 130 + 131 + return $behaviors[$key]; 132 + } 133 + 117 134 public static function newPlanBehaviors() { 118 135 $draft_options = array( 119 136 id(new HarbormasterBuildPlanBehaviorOption()) ··· 224 241 225 242 $run_options = array( 226 243 id(new HarbormasterBuildPlanBehaviorOption()) 227 - ->setKey('edit') 244 + ->setKey(self::RUNNABLE_IF_EDITABLE) 228 245 ->setIcon('fa-pencil green') 229 246 ->setName(pht('If Editable')) 230 247 ->setIsDefault(true) 231 248 ->setDescription( 232 249 pht('Only users who can edit the plan can run it manually.')), 233 250 id(new HarbormasterBuildPlanBehaviorOption()) 234 - ->setKey('view') 251 + ->setKey(self::RUNNABLE_IF_VIEWABLE) 235 252 ->setIcon('fa-exclamation-triangle yellow') 236 253 ->setName(pht('If Viewable')) 237 254 ->setDescription( ··· 315 332 ->setName(pht('Restartable')) 316 333 ->setOptions($restart_options), 317 334 id(new self()) 318 - ->setKey('runnable') 335 + ->setKey(self::BEHAVIOR_RUNNABLE) 319 336 ->setEditInstructions( 320 337 pht( 321 338 'To run a build manually, you normally must have permission to '. ··· 323 340 'can see the build plan be able to run and restart the build, you '. 324 341 'can change the behavior here.'. 325 342 "\n\n". 326 - 'Note that this affects both {nav Run Plan Manually} and '. 327 - '{nav Restart Build}, since the two actions are largely '. 328 - 'equivalent.'. 343 + 'Note that this controls access to all build management actions: '. 344 + '"Run Plan Manually", "Restart", "Abort", "Pause", and "Resume".'. 329 345 "\n\n". 330 346 'WARNING: This may be unsafe, particularly if the build has '. 331 347 'side effects like deployment.'.
+7 -4
src/applications/harbormaster/storage/build/HarbormasterBuild.php
··· 334 334 } 335 335 336 336 public function assertCanIssueCommand(PhabricatorUser $viewer, $command) { 337 - $need_edit = false; 337 + $plan = $this->getBuildPlan(); 338 + 339 + $need_edit = true; 338 340 switch ($command) { 339 341 case HarbormasterBuildCommand::COMMAND_RESTART: 340 - break; 341 342 case HarbormasterBuildCommand::COMMAND_PAUSE: 342 343 case HarbormasterBuildCommand::COMMAND_RESUME: 343 344 case HarbormasterBuildCommand::COMMAND_ABORT: 344 - $need_edit = true; 345 + if ($plan->canRunWithoutEditCapability()) { 346 + $need_edit = false; 347 + } 345 348 break; 346 349 default: 347 350 throw new Exception( ··· 355 358 if ($need_edit) { 356 359 PhabricatorPolicyFilter::requireCapability( 357 360 $viewer, 358 - $this->getBuildPlan(), 361 + $plan, 359 362 PhabricatorPolicyCapability::CAN_EDIT); 360 363 } 361 364 }
+42 -2
src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php
··· 10 10 PhabricatorSubscribableInterface, 11 11 PhabricatorNgramsInterface, 12 12 PhabricatorConduitResultInterface, 13 - PhabricatorProjectInterface { 13 + PhabricatorProjectInterface, 14 + PhabricatorPolicyCodexInterface { 14 15 15 16 protected $name; 16 17 protected $planStatus; ··· 133 134 return true; 134 135 } 135 136 136 - 137 137 public function getName() { 138 138 $autoplan = $this->getAutoplan(); 139 139 if ($autoplan) { ··· 143 143 return parent::getName(); 144 144 } 145 145 146 + public function hasRunCapability(PhabricatorUser $viewer) { 147 + try { 148 + $this->assertHasRunCapability($viewer); 149 + return true; 150 + } catch (PhabricatorPolicyException $ex) { 151 + return false; 152 + } 153 + } 154 + 155 + public function canRunWithoutEditCapability() { 156 + $runnable = HarbormasterBuildPlanBehavior::BEHAVIOR_RUNNABLE; 157 + $if_viewable = HarbormasterBuildPlanBehavior::RUNNABLE_IF_VIEWABLE; 158 + 159 + $option = HarbormasterBuildPlanBehavior::getBehavior($runnable) 160 + ->getPlanOption($this); 161 + 162 + return ($option->getKey() === $if_viewable); 163 + } 164 + 165 + public function assertHasRunCapability(PhabricatorUser $viewer) { 166 + if ($this->canRunWithoutEditCapability()) { 167 + $capability = PhabricatorPolicyCapability::CAN_VIEW; 168 + } else { 169 + $capability = PhabricatorPolicyCapability::CAN_EDIT; 170 + } 171 + 172 + PhabricatorPolicyFilter::requireCapability( 173 + $viewer, 174 + $this, 175 + $capability); 176 + } 177 + 146 178 147 179 /* -( PhabricatorSubscribableInterface )----------------------------------- */ 148 180 ··· 263 295 264 296 public function getConduitSearchAttachments() { 265 297 return array(); 298 + } 299 + 300 + 301 + /* -( PhabricatorPolicyCodexInterface )------------------------------------ */ 302 + 303 + 304 + public function newPolicyCodex() { 305 + return new HarbormasterBuildPlanPolicyCodex(); 266 306 } 267 307 268 308 }