Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14380099
D15325.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D15325.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -4079,7 +4079,7 @@
'AlmanacNamespaceListController' => 'AlmanacNamespaceController',
'AlmanacNamespaceNameNgrams' => 'PhabricatorSearchNgrams',
'AlmanacNamespacePHIDType' => 'PhabricatorPHIDType',
- 'AlmanacNamespaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'AlmanacNamespaceQuery' => 'AlmanacQuery',
'AlmanacNamespaceSearchEngine' => 'PhabricatorApplicationSearchEngine',
'AlmanacNamespaceTransaction' => 'PhabricatorApplicationTransaction',
'AlmanacNamespaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
diff --git a/src/applications/almanac/editor/AlmanacDeviceEditor.php b/src/applications/almanac/editor/AlmanacDeviceEditor.php
--- a/src/applications/almanac/editor/AlmanacDeviceEditor.php
+++ b/src/applications/almanac/editor/AlmanacDeviceEditor.php
@@ -148,22 +148,42 @@
$message,
$xaction);
$errors[] = $error;
+ continue;
}
- }
- }
- if ($xactions) {
- $duplicate = id(new AlmanacDeviceQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withNames(array(last($xactions)->getNewValue()))
- ->executeOne();
- if ($duplicate && ($duplicate->getID() != $object->getID())) {
- $error = new PhabricatorApplicationTransactionValidationError(
- $type,
- pht('Not Unique'),
- pht('Almanac devices must have unique names.'),
- last($xactions));
- $errors[] = $error;
+ $other = id(new AlmanacDeviceQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withNames(array($name))
+ ->executeOne();
+ if ($other && ($other->getID() != $object->getID())) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Not Unique'),
+ pht('Almanac devices must have unique names.'),
+ $xaction);
+ $errors[] = $error;
+ continue;
+ }
+
+ if ($name === $object->getName()) {
+ continue;
+ }
+
+ $namespace = AlmanacNamespace::loadRestrictedNamespace(
+ $this->getActor(),
+ $name);
+ if ($namespace) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Restricted'),
+ pht(
+ 'You do not have permission to create Almanac devices '.
+ 'within the "%s" namespace.',
+ $namespace->getName()),
+ $xaction);
+ $errors[] = $error;
+ continue;
+ }
}
}
diff --git a/src/applications/almanac/editor/AlmanacNamespaceEditor.php b/src/applications/almanac/editor/AlmanacNamespaceEditor.php
--- a/src/applications/almanac/editor/AlmanacNamespaceEditor.php
+++ b/src/applications/almanac/editor/AlmanacNamespaceEditor.php
@@ -123,7 +123,7 @@
if ($other && ($other->getID() != $object->getID())) {
$error = new PhabricatorApplicationTransactionValidationError(
$type,
- pht('Invalid'),
+ pht('Not Unique'),
pht(
'The namespace name "%s" is already in use by another '.
'namespace. Each namespace must have a unique name.',
@@ -132,6 +132,26 @@
$errors[] = $error;
continue;
}
+
+ if ($name === $object->getName()) {
+ continue;
+ }
+
+ $namespace = AlmanacNamespace::loadRestrictedNamespace(
+ $this->getActor(),
+ $name);
+ if ($namespace) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Restricted'),
+ pht(
+ 'You do not have permission to create Almanac namespaces '.
+ 'within the "%s" namespace.',
+ $namespace->getName()),
+ $xaction);
+ $errors[] = $error;
+ continue;
+ }
}
}
diff --git a/src/applications/almanac/editor/AlmanacServiceEditor.php b/src/applications/almanac/editor/AlmanacServiceEditor.php
--- a/src/applications/almanac/editor/AlmanacServiceEditor.php
+++ b/src/applications/almanac/editor/AlmanacServiceEditor.php
@@ -140,22 +140,42 @@
$message,
$xaction);
$errors[] = $error;
+ continue;
+ }
+
+ $other = id(new AlmanacServiceQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withNames(array($name))
+ ->executeOne();
+ if ($other && ($other->getID() != $object->getID())) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Not Unique'),
+ pht('Almanac services must have unique names.'),
+ last($xactions));
+ $errors[] = $error;
+ continue;
}
- }
- }
- if ($xactions) {
- $duplicate = id(new AlmanacServiceQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withNames(array(last($xactions)->getNewValue()))
- ->executeOne();
- if ($duplicate && ($duplicate->getID() != $object->getID())) {
- $error = new PhabricatorApplicationTransactionValidationError(
- $type,
- pht('Not Unique'),
- pht('Almanac services must have unique names.'),
- last($xactions));
- $errors[] = $error;
+ if ($name === $object->getName()) {
+ continue;
+ }
+
+ $namespace = AlmanacNamespace::loadRestrictedNamespace(
+ $this->getActor(),
+ $name);
+ if ($namespace) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Restricted'),
+ pht(
+ 'You do not have permission to create Almanac services '.
+ 'within the "%s" namespace.',
+ $namespace->getName()),
+ $xaction);
+ $errors[] = $error;
+ continue;
+ }
}
}
diff --git a/src/applications/almanac/query/AlmanacNamespaceQuery.php b/src/applications/almanac/query/AlmanacNamespaceQuery.php
--- a/src/applications/almanac/query/AlmanacNamespaceQuery.php
+++ b/src/applications/almanac/query/AlmanacNamespaceQuery.php
@@ -1,7 +1,7 @@
<?php
final class AlmanacNamespaceQuery
- extends PhabricatorCursorPagedPolicyAwareQuery {
+ extends AlmanacQuery {
private $ids;
private $phids;
diff --git a/src/applications/almanac/storage/AlmanacNamespace.php b/src/applications/almanac/storage/AlmanacNamespace.php
--- a/src/applications/almanac/storage/AlmanacNamespace.php
+++ b/src/applications/almanac/storage/AlmanacNamespace.php
@@ -68,6 +68,51 @@
return '/almanac/namespace/view/'.$this->getName().'/';
}
+ public function getNameLength() {
+ return strlen($this->getName());
+ }
+
+ /**
+ * Load the namespace which prevents use of an Almanac name, if one exists.
+ */
+ public static function loadRestrictedNamespace(
+ PhabricatorUser $viewer,
+ $name) {
+
+ // For a name like "x.y.z", produce a list of controlling namespaces like
+ // ("z", "y.x", "x.y.z").
+ $names = array();
+ $parts = explode('.', $name);
+ for ($ii = 0; $ii < count($parts); $ii++) {
+ $names[] = implode('.', array_slice($parts, -($ii + 1)));
+ }
+
+ // Load all the possible controlling namespaces.
+ $namespaces = id(new AlmanacNamespaceQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withNames($names)
+ ->execute();
+ if (!$namespaces) {
+ return null;
+ }
+
+ // Find the "nearest" (longest) namespace that exists. If both
+ // "sub.domain.com" and "domain.com" exist, we only care about the policy
+ // on the former.
+ $namespaces = msort($namespaces, 'getNameLength');
+ $namespace = last($namespaces);
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $namespace,
+ PhabricatorPolicyCapability::CAN_EDIT);
+ if ($can_edit) {
+ return null;
+ }
+
+ return $namespace;
+ }
+
/* -( AlmanacPropertyInterface )------------------------------------------- */
diff --git a/src/docs/user/userguide/almanac.diviner b/src/docs/user/userguide/almanac.diviner
--- a/src/docs/user/userguide/almanac.diviner
+++ b/src/docs/user/userguide/almanac.diviner
@@ -133,6 +133,52 @@
`b.mycompany.com`.
+Namespaces
+==========
+
+Almanac namespaces allow you to control who can create services and devices
+with certain names.
+
+If you keep a list of cattle as devices with names like
+`cow001.herd.myranch.com`, `cow002.herd.myranch.moo`, you might have some
+applications which query for all devices in `*.herd.myranch.moo`, and thus
+want to limit who can create devices there in order to prevent mistakes.
+
+If a namespace like `herd.myranch.moo` exists, users must have permission to
+edit the namespace in order to create new services, devices, or namespaces
+within it. For example, a user can not create `cow003.herd.myranch.moo` if
+they do not have edit permission on the `herd.myranch.moo` namespace.
+
+When you try to create a `cow003.herd.myranch.moo` service (or rename an
+existing service to have that name), Almanac looks for these namespaces, then
+checks the policy of the first one it finds:
+
+| Namespace |
+|----|-----
+| `cow003.herd.ranch.moo` | //"Nearest" namespace, considered first.//
+| `herd.ranch.moo` | |
+| `ranch.moo` | |
+| `moo` | //"Farthest" namespace, considered last.//
+
+Note that namespaces treat names as lists of domain parts, not as strict
+substrings, so the namespace `herd.myranch.moo` does not prevent
+someone from creating `goatherd.myranch.moo` or `goat001.goatherd.myranch.moo`.
+The name `goatherd.myranch.moo` is not part of the `herd.myranch.moo` namespace
+because the initial subdomain differs.
+
+If a name belongs to multiple namespaces, the policy of the nearest namespace
+is controlling. For example, if `myranch.moo` has a very restrictive edit
+policy but `shed.myranch.moo` has a more open one, users can create devices and
+services like `rake.shed.myranch.moo` as long as they can pass the policy check
+for `shed.myranch.moo`, even if they do not have permission under the policy
+for `myranch.moo`.
+
+Users can edit services and devices within a namespace if they have edit
+permission on the service or device itself, as long as they don't try to rename
+the service or device to move it into a namespace they don't have permission
+to access.
+
+
Locking and Unlocking Services
==============================
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 22, 3:33 AM (21 h, 40 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6917308
Default Alt Text
D15325.diff (11 KB)
Attached To
Mode
D15325: Apply namespace locking rules in Almanac
Attached
Detach File
Event Timeline
Log In to Comment