mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 08:12:40 +01:00
Add an "Authority" control to Packages to support "Watcher" packages
Summary: See T13657. An install has "watcher" packages which should not allow owners to "Force Accept" other packages. Test Plan: - Created package A, which I own, on "/", with "Weak" authority. - Created package B, which I do not own, on "/src". - Created a revision which touches "/src" and added package B as a reviewer. - Attempted to accept the revision... - Before patch: permitted to "Force Accept" for package B. - After patch: not allowed to "Force Accept" for package B. - Verified that setting package "A" back to "Strong" authority allows a force-accept for package B. Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Differential Revision: https://secure.phabricator.com/D21674
This commit is contained in:
parent
bf889c1c08
commit
a641ec82a3
9 changed files with 148 additions and 0 deletions
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||
ADD authorityMode VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,3 @@
|
|||
UPDATE {$NAMESPACE}_owners.owners_package
|
||||
SET authorityMode = 'strong'
|
||||
WHERE authorityMode = '';
|
|
@ -3966,6 +3966,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php',
|
||||
'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php',
|
||||
'PhabricatorOwnersPackageAuditingTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAuditingTransaction.php',
|
||||
'PhabricatorOwnersPackageAuthorityTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAuthorityTransaction.php',
|
||||
'PhabricatorOwnersPackageAutoreviewTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageAutoreviewTransaction.php',
|
||||
'PhabricatorOwnersPackageContextFreeGrammar' => 'applications/owners/lipsum/PhabricatorOwnersPackageContextFreeGrammar.php',
|
||||
'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php',
|
||||
|
@ -10582,6 +10583,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorNgramsInterface',
|
||||
),
|
||||
'PhabricatorOwnersPackageAuditingTransaction' => 'PhabricatorOwnersPackageTransactionType',
|
||||
'PhabricatorOwnersPackageAuthorityTransaction' => 'PhabricatorOwnersPackageTransactionType',
|
||||
'PhabricatorOwnersPackageAutoreviewTransaction' => 'PhabricatorOwnersPackageTransactionType',
|
||||
'PhabricatorOwnersPackageContextFreeGrammar' => 'PhutilContextFreeGrammar',
|
||||
'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
|
|
|
@ -311,9 +311,17 @@ final class DifferentialRevision extends DifferentialDAO
|
|||
// which the actor may be able to use their authority over to gain the
|
||||
// ability to force-accept for other packages. This query doesn't apply
|
||||
// dominion rules yet, and we'll bypass those rules later on.
|
||||
|
||||
// See T13657. We ignore "watcher" packages which don't grant their owners
|
||||
// permission to force accept anything.
|
||||
|
||||
$authority_query = id(new PhabricatorOwnersPackageQuery())
|
||||
->setViewer($viewer)
|
||||
->withStatuses(array(PhabricatorOwnersPackage::STATUS_ACTIVE))
|
||||
->withAuthorityModes(
|
||||
array(
|
||||
PhabricatorOwnersPackage::AUTHORITY_STRONG,
|
||||
))
|
||||
->withAuthorityPHIDs(array($viewer->getPHID()))
|
||||
->withControl($repository_phid, $paths);
|
||||
$authority_packages = $authority_query->execute();
|
||||
|
|
|
@ -197,6 +197,12 @@ final class PhabricatorOwnersDetailController
|
|||
$name = idx($spec, 'short', $dominion);
|
||||
$view->addProperty(pht('Dominion'), $name);
|
||||
|
||||
$authority_mode = $package->getAuthorityMode();
|
||||
$authority_map = PhabricatorOwnersPackage::getAuthorityOptionsMap();
|
||||
$spec = idx($authority_map, $authority_mode, array());
|
||||
$name = idx($spec, 'short', $authority_mode);
|
||||
$view->addProperty(pht('Authority'), $name);
|
||||
|
||||
$auto = $package->getAutoReview();
|
||||
$autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap();
|
||||
$spec = idx($autoreview_map, $auto, array());
|
||||
|
|
|
@ -90,6 +90,9 @@ EOTEXT
|
|||
$dominion_map = PhabricatorOwnersPackage::getDominionOptionsMap();
|
||||
$dominion_map = ipull($dominion_map, 'name');
|
||||
|
||||
$authority_map = PhabricatorOwnersPackage::getAuthorityOptionsMap();
|
||||
$authority_map = ipull($authority_map, 'name');
|
||||
|
||||
return array(
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('name')
|
||||
|
@ -118,6 +121,16 @@ EOTEXT
|
|||
->setIsCopyable(true)
|
||||
->setValue($object->getDominion())
|
||||
->setOptions($dominion_map),
|
||||
id(new PhabricatorSelectEditField())
|
||||
->setKey('authority')
|
||||
->setLabel(pht('Authority'))
|
||||
->setDescription(
|
||||
pht('Change package authority rules.'))
|
||||
->setTransactionType(
|
||||
PhabricatorOwnersPackageAuthorityTransaction::TRANSACTIONTYPE)
|
||||
->setIsCopyable(true)
|
||||
->setValue($object->getAuthorityMode())
|
||||
->setOptions($authority_map),
|
||||
id(new PhabricatorSelectEditField())
|
||||
->setKey('autoReview')
|
||||
->setLabel(pht('Auto Review'))
|
||||
|
|
|
@ -10,6 +10,7 @@ final class PhabricatorOwnersPackageQuery
|
|||
private $repositoryPHIDs;
|
||||
private $paths;
|
||||
private $statuses;
|
||||
private $authorityModes;
|
||||
|
||||
private $controlMap = array();
|
||||
private $controlResults;
|
||||
|
@ -77,6 +78,11 @@ final class PhabricatorOwnersPackageQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withAuthorityModes(array $modes) {
|
||||
$this->authorityModes = $modes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withNameNgrams($ngrams) {
|
||||
return $this->withNgramsConstraint(
|
||||
new PhabricatorOwnersPackageNameNgrams(),
|
||||
|
@ -231,6 +237,13 @@ final class PhabricatorOwnersPackageQuery
|
|||
$where[] = qsprintf($conn, '%LO', $clauses);
|
||||
}
|
||||
|
||||
if ($this->authorityModes !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'authorityMode IN (%Ls)',
|
||||
$this->authorityModes);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ final class PhabricatorOwnersPackage
|
|||
protected $dominion;
|
||||
protected $properties = array();
|
||||
protected $auditingState;
|
||||
protected $authorityMode;
|
||||
|
||||
private $paths = self::ATTACHABLE;
|
||||
private $owners = self::ATTACHABLE;
|
||||
|
@ -41,6 +42,9 @@ final class PhabricatorOwnersPackage
|
|||
const DOMINION_STRONG = 'strong';
|
||||
const DOMINION_WEAK = 'weak';
|
||||
|
||||
const AUTHORITY_STRONG = 'strong';
|
||||
const AUTHORITY_WEAK = 'weak';
|
||||
|
||||
const PROPERTY_IGNORED = 'ignored';
|
||||
|
||||
public static function initializeNewPackage(PhabricatorUser $actor) {
|
||||
|
@ -58,6 +62,7 @@ final class PhabricatorOwnersPackage
|
|||
->setAuditingState(PhabricatorOwnersAuditRule::AUDITING_NONE)
|
||||
->setAutoReview(self::AUTOREVIEW_NONE)
|
||||
->setDominion(self::DOMINION_STRONG)
|
||||
->setAuthorityMode(self::AUTHORITY_STRONG)
|
||||
->setViewPolicy($view_policy)
|
||||
->setEditPolicy($edit_policy)
|
||||
->attachPaths(array())
|
||||
|
@ -115,6 +120,19 @@ final class PhabricatorOwnersPackage
|
|||
);
|
||||
}
|
||||
|
||||
public static function getAuthorityOptionsMap() {
|
||||
return array(
|
||||
self::AUTHORITY_STRONG => array(
|
||||
'name' => pht('Strong (Package Owns Paths)'),
|
||||
'short' => pht('Strong'),
|
||||
),
|
||||
self::AUTHORITY_WEAK => array(
|
||||
'name' => pht('Weak (Package Watches Paths)'),
|
||||
'short' => pht('Weak'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
// This information is better available from the history table.
|
||||
|
@ -130,6 +148,7 @@ final class PhabricatorOwnersPackage
|
|||
'status' => 'text32',
|
||||
'autoReview' => 'text32',
|
||||
'dominion' => 'text32',
|
||||
'authorityMode' => 'text32',
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
@ -568,6 +587,10 @@ final class PhabricatorOwnersPackage
|
|||
return PhabricatorOwnersAuditRule::newFromState($this->getAuditingState());
|
||||
}
|
||||
|
||||
public function getHasStrongAuthority() {
|
||||
return ($this->getAuthorityMode() === self::AUTHORITY_STRONG);
|
||||
}
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
||||
|
@ -696,6 +719,10 @@ final class PhabricatorOwnersPackage
|
|||
->setKey('dominion')
|
||||
->setType('map<string, wild>')
|
||||
->setDescription(pht('Dominion setting information.')),
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('authority')
|
||||
->setType('map<string, wild>')
|
||||
->setDescription(pht('Authority setting information.')),
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('ignored')
|
||||
->setType('map<string, wild>')
|
||||
|
@ -747,6 +774,23 @@ final class PhabricatorOwnersPackage
|
|||
'short' => $dominion_short,
|
||||
);
|
||||
|
||||
|
||||
$authority_value = $this->getAuthorityMode();
|
||||
$authority_map = self::getAuthorityOptionsMap();
|
||||
if (isset($authority_map[$authority_value])) {
|
||||
$authority_label = $authority_map[$authority_value]['name'];
|
||||
$authority_short = $authority_map[$authority_value]['short'];
|
||||
} else {
|
||||
$authority_label = pht('Unknown ("%s")', $authority_value);
|
||||
$authority_short = pht('Unknown ("%s")', $authority_value);
|
||||
}
|
||||
|
||||
$authority = array(
|
||||
'value' => $authority_value,
|
||||
'label' => $authority_label,
|
||||
'short' => $authority_short,
|
||||
);
|
||||
|
||||
// Force this to always emit as a JSON object even if empty, never as
|
||||
// a JSON list.
|
||||
$ignored = $this->getIgnoredPathAttributes();
|
||||
|
@ -762,6 +806,7 @@ final class PhabricatorOwnersPackage
|
|||
'review' => $review,
|
||||
'audit' => $audit,
|
||||
'dominion' => $dominion,
|
||||
'authority' => $authority,
|
||||
'ignored' => $ignored,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOwnersPackageAuthorityTransaction
|
||||
extends PhabricatorOwnersPackageTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'owners.authority';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getAuthorityMode();
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
$errors = array();
|
||||
|
||||
$map = PhabricatorOwnersPackage::getAuthorityOptionsMap();
|
||||
foreach ($xactions as $xaction) {
|
||||
$new = $xaction->getNewValue();
|
||||
|
||||
if (empty($map[$new])) {
|
||||
$valid = array_keys($map);
|
||||
|
||||
$errors[] = $this->newInvalidError(
|
||||
pht(
|
||||
'Authority setting "%s" is not valid. '.
|
||||
'Valid settings are: %s.',
|
||||
$new,
|
||||
implode(', ', $valid)),
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setAuthorityMode($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$map = PhabricatorOwnersPackage::getAuthorityOptionsMap();
|
||||
$map = ipull($map, 'short');
|
||||
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
$old = idx($map, $old, $old);
|
||||
$new = idx($map, $new, $new);
|
||||
|
||||
return pht(
|
||||
'%s adjusted package authority rules from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderValue($old),
|
||||
$this->renderValue($new));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue