mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-24 14:30:56 +01:00
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
This commit is contained in:
parent
983cf885e7
commit
ee0ad4703e
7 changed files with 115 additions and 18 deletions
|
@ -1340,6 +1340,7 @@ phutil_register_library_map(array(
|
||||||
'HarbormasterBuildPlanNameNgrams' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlanNameNgrams.php',
|
'HarbormasterBuildPlanNameNgrams' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlanNameNgrams.php',
|
||||||
'HarbormasterBuildPlanNameTransaction' => 'applications/harbormaster/xaction/plan/HarbormasterBuildPlanNameTransaction.php',
|
'HarbormasterBuildPlanNameTransaction' => 'applications/harbormaster/xaction/plan/HarbormasterBuildPlanNameTransaction.php',
|
||||||
'HarbormasterBuildPlanPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php',
|
'HarbormasterBuildPlanPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php',
|
||||||
|
'HarbormasterBuildPlanPolicyCodex' => 'applications/harbormaster/codex/HarbormasterBuildPlanPolicyCodex.php',
|
||||||
'HarbormasterBuildPlanQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanQuery.php',
|
'HarbormasterBuildPlanQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanQuery.php',
|
||||||
'HarbormasterBuildPlanSearchAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildPlanSearchAPIMethod.php',
|
'HarbormasterBuildPlanSearchAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildPlanSearchAPIMethod.php',
|
||||||
'HarbormasterBuildPlanSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildPlanSearchEngine.php',
|
'HarbormasterBuildPlanSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildPlanSearchEngine.php',
|
||||||
|
@ -6945,6 +6946,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorNgramsInterface',
|
'PhabricatorNgramsInterface',
|
||||||
'PhabricatorConduitResultInterface',
|
'PhabricatorConduitResultInterface',
|
||||||
'PhabricatorProjectInterface',
|
'PhabricatorProjectInterface',
|
||||||
|
'PhabricatorPolicyCodexInterface',
|
||||||
),
|
),
|
||||||
'HarbormasterBuildPlanBehavior' => 'Phobject',
|
'HarbormasterBuildPlanBehavior' => 'Phobject',
|
||||||
'HarbormasterBuildPlanBehaviorOption' => 'Phobject',
|
'HarbormasterBuildPlanBehaviorOption' => 'Phobject',
|
||||||
|
@ -6958,6 +6960,7 @@ phutil_register_library_map(array(
|
||||||
'HarbormasterBuildPlanNameNgrams' => 'PhabricatorSearchNgrams',
|
'HarbormasterBuildPlanNameNgrams' => 'PhabricatorSearchNgrams',
|
||||||
'HarbormasterBuildPlanNameTransaction' => 'HarbormasterBuildPlanTransactionType',
|
'HarbormasterBuildPlanNameTransaction' => 'HarbormasterBuildPlanTransactionType',
|
||||||
'HarbormasterBuildPlanPHIDType' => 'PhabricatorPHIDType',
|
'HarbormasterBuildPlanPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'HarbormasterBuildPlanPolicyCodex' => 'PhabricatorPolicyCodex',
|
||||||
'HarbormasterBuildPlanQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'HarbormasterBuildPlanQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'HarbormasterBuildPlanSearchAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
'HarbormasterBuildPlanSearchAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
'HarbormasterBuildPlanSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'HarbormasterBuildPlanSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HarbormasterBuildPlanPolicyCodex
|
||||||
|
extends PhabricatorPolicyCodex {
|
||||||
|
|
||||||
|
public function getPolicySpecialRuleDescriptions() {
|
||||||
|
$object = $this->getObject();
|
||||||
|
$run_with_view = $object->canRunWithoutEditCapability();
|
||||||
|
|
||||||
|
$rules = array();
|
||||||
|
|
||||||
|
$rules[] = $this->newRule()
|
||||||
|
->setCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->setIsActive(!$run_with_view)
|
||||||
|
->setDescription(
|
||||||
|
pht(
|
||||||
|
'You must have edit permission on this build plan to pause, '.
|
||||||
|
'abort, resume, or restart it.'));
|
||||||
|
|
||||||
|
$rules[] = $this->newRule()
|
||||||
|
->setCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->setIsActive(!$run_with_view)
|
||||||
|
->setDescription(
|
||||||
|
pht(
|
||||||
|
'You must have edit permission on this build plan to run it '.
|
||||||
|
'manually.'));
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -9,16 +9,13 @@ final class HarbormasterPlanRunController extends HarbormasterPlanController {
|
||||||
$plan = id(new HarbormasterBuildPlanQuery())
|
$plan = id(new HarbormasterBuildPlanQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIDs(array($plan_id))
|
->withIDs(array($plan_id))
|
||||||
->requireCapabilities(
|
|
||||||
array(
|
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT,
|
|
||||||
))
|
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$plan) {
|
if (!$plan) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$plan->assertHasRunCapability($viewer);
|
||||||
|
|
||||||
$cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
|
$cancel_uri = $this->getApplicationURI("plan/{$plan_id}/");
|
||||||
|
|
||||||
if (!$plan->canRunManually()) {
|
if (!$plan->canRunManually()) {
|
||||||
|
|
|
@ -266,7 +266,7 @@ final class HarbormasterPlanViewController extends HarbormasterPlanController {
|
||||||
->setIcon('fa-ban'));
|
->setIcon('fa-ban'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$can_run = ($can_edit && $plan->canRunManually());
|
$can_run = ($plan->hasRunCapability($viewer) && $plan->canRunManually());
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
|
|
|
@ -9,6 +9,10 @@ final class HarbormasterBuildPlanBehavior
|
||||||
private $defaultKey;
|
private $defaultKey;
|
||||||
private $editInstructions;
|
private $editInstructions;
|
||||||
|
|
||||||
|
const BEHAVIOR_RUNNABLE = 'runnable';
|
||||||
|
const RUNNABLE_IF_VIEWABLE = 'view';
|
||||||
|
const RUNNABLE_IF_EDITABLE = 'edit';
|
||||||
|
|
||||||
public function setKey($key) {
|
public function setKey($key) {
|
||||||
$this->key = $key;
|
$this->key = $key;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -114,6 +118,19 @@ final class HarbormasterBuildPlanBehavior
|
||||||
return sprintf('behavior.%s', $behavior_key);
|
return sprintf('behavior.%s', $behavior_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getBehavior($key) {
|
||||||
|
$behaviors = self::newPlanBehaviors();
|
||||||
|
|
||||||
|
if (!isset($behaviors[$key])) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'No build plan behavior with key "%s" exists.',
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $behaviors[$key];
|
||||||
|
}
|
||||||
|
|
||||||
public static function newPlanBehaviors() {
|
public static function newPlanBehaviors() {
|
||||||
$draft_options = array(
|
$draft_options = array(
|
||||||
id(new HarbormasterBuildPlanBehaviorOption())
|
id(new HarbormasterBuildPlanBehaviorOption())
|
||||||
|
@ -224,14 +241,14 @@ final class HarbormasterBuildPlanBehavior
|
||||||
|
|
||||||
$run_options = array(
|
$run_options = array(
|
||||||
id(new HarbormasterBuildPlanBehaviorOption())
|
id(new HarbormasterBuildPlanBehaviorOption())
|
||||||
->setKey('edit')
|
->setKey(self::RUNNABLE_IF_EDITABLE)
|
||||||
->setIcon('fa-pencil green')
|
->setIcon('fa-pencil green')
|
||||||
->setName(pht('If Editable'))
|
->setName(pht('If Editable'))
|
||||||
->setIsDefault(true)
|
->setIsDefault(true)
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht('Only users who can edit the plan can run it manually.')),
|
pht('Only users who can edit the plan can run it manually.')),
|
||||||
id(new HarbormasterBuildPlanBehaviorOption())
|
id(new HarbormasterBuildPlanBehaviorOption())
|
||||||
->setKey('view')
|
->setKey(self::RUNNABLE_IF_VIEWABLE)
|
||||||
->setIcon('fa-exclamation-triangle yellow')
|
->setIcon('fa-exclamation-triangle yellow')
|
||||||
->setName(pht('If Viewable'))
|
->setName(pht('If Viewable'))
|
||||||
->setDescription(
|
->setDescription(
|
||||||
|
@ -315,7 +332,7 @@ final class HarbormasterBuildPlanBehavior
|
||||||
->setName(pht('Restartable'))
|
->setName(pht('Restartable'))
|
||||||
->setOptions($restart_options),
|
->setOptions($restart_options),
|
||||||
id(new self())
|
id(new self())
|
||||||
->setKey('runnable')
|
->setKey(self::BEHAVIOR_RUNNABLE)
|
||||||
->setEditInstructions(
|
->setEditInstructions(
|
||||||
pht(
|
pht(
|
||||||
'To run a build manually, you normally must have permission to '.
|
'To run a build manually, you normally must have permission to '.
|
||||||
|
@ -323,9 +340,8 @@ final class HarbormasterBuildPlanBehavior
|
||||||
'can see the build plan be able to run and restart the build, you '.
|
'can see the build plan be able to run and restart the build, you '.
|
||||||
'can change the behavior here.'.
|
'can change the behavior here.'.
|
||||||
"\n\n".
|
"\n\n".
|
||||||
'Note that this affects both {nav Run Plan Manually} and '.
|
'Note that this controls access to all build management actions: '.
|
||||||
'{nav Restart Build}, since the two actions are largely '.
|
'"Run Plan Manually", "Restart", "Abort", "Pause", and "Resume".'.
|
||||||
'equivalent.'.
|
|
||||||
"\n\n".
|
"\n\n".
|
||||||
'WARNING: This may be unsafe, particularly if the build has '.
|
'WARNING: This may be unsafe, particularly if the build has '.
|
||||||
'side effects like deployment.'.
|
'side effects like deployment.'.
|
||||||
|
|
|
@ -334,14 +334,17 @@ final class HarbormasterBuild extends HarbormasterDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
public function assertCanIssueCommand(PhabricatorUser $viewer, $command) {
|
public function assertCanIssueCommand(PhabricatorUser $viewer, $command) {
|
||||||
$need_edit = false;
|
$plan = $this->getBuildPlan();
|
||||||
|
|
||||||
|
$need_edit = true;
|
||||||
switch ($command) {
|
switch ($command) {
|
||||||
case HarbormasterBuildCommand::COMMAND_RESTART:
|
case HarbormasterBuildCommand::COMMAND_RESTART:
|
||||||
break;
|
|
||||||
case HarbormasterBuildCommand::COMMAND_PAUSE:
|
case HarbormasterBuildCommand::COMMAND_PAUSE:
|
||||||
case HarbormasterBuildCommand::COMMAND_RESUME:
|
case HarbormasterBuildCommand::COMMAND_RESUME:
|
||||||
case HarbormasterBuildCommand::COMMAND_ABORT:
|
case HarbormasterBuildCommand::COMMAND_ABORT:
|
||||||
$need_edit = true;
|
if ($plan->canRunWithoutEditCapability()) {
|
||||||
|
$need_edit = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
|
@ -355,7 +358,7 @@ final class HarbormasterBuild extends HarbormasterDAO
|
||||||
if ($need_edit) {
|
if ($need_edit) {
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
$viewer,
|
$viewer,
|
||||||
$this->getBuildPlan(),
|
$plan,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
||||||
PhabricatorSubscribableInterface,
|
PhabricatorSubscribableInterface,
|
||||||
PhabricatorNgramsInterface,
|
PhabricatorNgramsInterface,
|
||||||
PhabricatorConduitResultInterface,
|
PhabricatorConduitResultInterface,
|
||||||
PhabricatorProjectInterface {
|
PhabricatorProjectInterface,
|
||||||
|
PhabricatorPolicyCodexInterface {
|
||||||
|
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $planStatus;
|
protected $planStatus;
|
||||||
|
@ -133,7 +134,6 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getName() {
|
public function getName() {
|
||||||
$autoplan = $this->getAutoplan();
|
$autoplan = $this->getAutoplan();
|
||||||
if ($autoplan) {
|
if ($autoplan) {
|
||||||
|
@ -143,6 +143,38 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
||||||
return parent::getName();
|
return parent::getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasRunCapability(PhabricatorUser $viewer) {
|
||||||
|
try {
|
||||||
|
$this->assertHasRunCapability($viewer);
|
||||||
|
return true;
|
||||||
|
} catch (PhabricatorPolicyException $ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canRunWithoutEditCapability() {
|
||||||
|
$runnable = HarbormasterBuildPlanBehavior::BEHAVIOR_RUNNABLE;
|
||||||
|
$if_viewable = HarbormasterBuildPlanBehavior::RUNNABLE_IF_VIEWABLE;
|
||||||
|
|
||||||
|
$option = HarbormasterBuildPlanBehavior::getBehavior($runnable)
|
||||||
|
->getPlanOption($this);
|
||||||
|
|
||||||
|
return ($option->getKey() === $if_viewable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function assertHasRunCapability(PhabricatorUser $viewer) {
|
||||||
|
if ($this->canRunWithoutEditCapability()) {
|
||||||
|
$capability = PhabricatorPolicyCapability::CAN_VIEW;
|
||||||
|
} else {
|
||||||
|
$capability = PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
|
$viewer,
|
||||||
|
$this,
|
||||||
|
$capability);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
||||||
|
|
||||||
|
@ -265,4 +297,12 @@ final class HarbormasterBuildPlan extends HarbormasterDAO
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyCodexInterface )------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
public function newPolicyCodex() {
|
||||||
|
return new HarbormasterBuildPlanPolicyCodex();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue