Page MenuHomePhabricator

D20694.diff
No OneTemporary

D20694.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
'names' => array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
- 'core.pkg.css' => 'af983028',
+ 'core.pkg.css' => '5a4a5010',
'core.pkg.js' => '73a06a9f',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '0b037a4f',
@@ -24,7 +24,7 @@
'rsrc/audio/basic/ting.mp3' => 'a6b6540e',
'rsrc/css/aphront/aphront-bars.css' => '4a327b4a',
'rsrc/css/aphront/dark-console.css' => '7f06cda2',
- 'rsrc/css/aphront/dialog-view.css' => 'b70c70df',
+ 'rsrc/css/aphront/dialog-view.css' => '874f5c06',
'rsrc/css/aphront/list-filter-view.css' => 'feb64255',
'rsrc/css/aphront/multi-column.css' => 'fbc00ba3',
'rsrc/css/aphront/notification.css' => '30240bd2',
@@ -530,7 +530,7 @@
'almanac-css' => '2e050f4f',
'aphront-bars' => '4a327b4a',
'aphront-dark-console-css' => '7f06cda2',
- 'aphront-dialog-view-css' => 'b70c70df',
+ 'aphront-dialog-view-css' => '874f5c06',
'aphront-list-filter-view-css' => 'feb64255',
'aphront-multi-column-view-css' => 'fbc00ba3',
'aphront-panel-view-css' => '46923d46',
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php
@@ -17,32 +17,31 @@
->setRepository($repository)
->getPanelURI();
- $dialog = new AphrontDialogView();
- $text_1 = pht(
- 'If you really want to delete the repository, run this command from '.
- 'the command line:');
- $command = csprintf(
- 'phabricator/ $ ./bin/remove destroy %R',
- $repository->getMonogram());
- $text_2 = pht(
- 'Repositories touch many objects and as such deletes are '.
- 'prohibitively expensive to run from the web UI.');
- $body = phutil_tag(
- 'div',
- array(
- 'class' => 'phabricator-remarkup',
- ),
- array(
- phutil_tag('p', array(), $text_1),
- phutil_tag('p', array(),
- phutil_tag('tt', array(), $command)),
- phutil_tag('p', array(), $text_2),
- ));
+ $doc_uri = PhabricatorEnv::getDoclink(
+ 'Permanently Destroying Data');
return $this->newDialog()
- ->setTitle(pht('Really want to delete the repository?'))
- ->appendChild($body)
- ->addCancelButton($panel_uri, pht('Okay'));
+ ->setTitle(pht('Delete Repository'))
+ ->appendParagraph(
+ pht(
+ 'To permanently destroy this repository, run this command from '.
+ 'the command line:'))
+ ->appendCommand(
+ csprintf(
+ 'phabricator/ $ ./bin/remove destroy %R',
+ $repository->getMonogram()))
+ ->appendParagraph(
+ pht(
+ 'Repositories can not be permanently destroyed from the web '.
+ 'interface. See %s in the documentation for more information.',
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => $doc_uri,
+ 'target' => '_blank',
+ ),
+ pht('Permanently Destroying Data'))))
+ ->addCancelButton($panel_uri, pht('Close'));
}
}
diff --git a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php
--- a/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php
+++ b/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php
@@ -155,8 +155,6 @@
->setName(pht('Delete Repository'))
->setHref($delete_uri)
->setIcon('fa-times')
- ->setColor(PhabricatorActionView::RED)
- ->setDisabled(true)
->setWorkflow(true));
return $this->newCurtainView()
diff --git a/src/applications/people/controller/PhabricatorPeopleDeleteController.php b/src/applications/people/controller/PhabricatorPeopleDeleteController.php
--- a/src/applications/people/controller/PhabricatorPeopleDeleteController.php
+++ b/src/applications/people/controller/PhabricatorPeopleDeleteController.php
@@ -17,58 +17,35 @@
$manage_uri = $this->getApplicationURI("manage/{$id}/");
- if ($user->getPHID() == $viewer->getPHID()) {
- return $this->buildDeleteSelfResponse($manage_uri);
- }
-
- $str1 = pht(
- 'Be careful when deleting users! This will permanently and '.
- 'irreversibly destroy this user account.');
-
- $str2 = pht(
- 'If this user interacted with anything, it is generally better to '.
- 'disable them, not delete them. If you delete them, it will no longer '.
- 'be possible to (for example) search for objects they created, and you '.
- 'will lose other information about their history. Disabling them '.
- 'instead will prevent them from logging in, but will not destroy any of '.
- 'their data.');
-
- $str3 = pht(
- 'It is generally safe to delete newly created users (and test users and '.
- 'so on), but less safe to delete established users. If possible, '.
- 'disable them instead.');
-
- $str4 = pht('To permanently destroy this user, run this command:');
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendRemarkupInstructions(
- csprintf(
- " phabricator/ $ ./bin/remove destroy %R\n",
- '@'.$user->getUsername()));
-
- return $this->newDialog()
- ->setWidth(AphrontDialogView::WIDTH_FORM)
- ->setTitle(pht('Permanently Delete User'))
- ->setShortTitle(pht('Delete User'))
- ->appendParagraph($str1)
- ->appendParagraph($str2)
- ->appendParagraph($str3)
- ->appendParagraph($str4)
- ->appendChild($form->buildLayoutView())
- ->addCancelButton($manage_uri, pht('Close'));
- }
+ $doc_uri = PhabricatorEnv::getDoclink(
+ 'Permanently Destroying Data');
- private function buildDeleteSelfResponse($cancel_uri) {
return $this->newDialog()
- ->setTitle(pht('You Shall Journey No Farther'))
+ ->setTitle(pht('Delete User'))
+ ->appendParagraph(
+ pht(
+ 'To permanently destroy this user, run this command from the '.
+ 'command line:'))
+ ->appendCommand(
+ csprintf(
+ 'phabricator/ $ ./bin/remove destroy %R',
+ $user->getMonogram()))
->appendParagraph(
pht(
- 'As you stare into the gaping maw of the abyss, something '.
- 'holds you back.'))
- ->appendParagraph(pht('You can not delete your own account.'))
- ->addCancelButton($cancel_uri, pht('Turn Back'));
+ 'Unless you have a very good reason to delete this user, consider '.
+ 'disabling them instead.'))
+ ->appendParagraph(
+ pht(
+ 'Users can not be permanently destroyed from the web interface. '.
+ 'See %s in the documentation for more information.',
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => $doc_uri,
+ 'target' => '_blank',
+ ),
+ pht('Permanently Destroying Data'))))
+ ->addCancelButton($manage_uri, pht('Close'));
}
-
}
diff --git a/src/docs/user/field/permanently_destroying_data.diviner b/src/docs/user/field/permanently_destroying_data.diviner
new file mode 100644
--- /dev/null
+++ b/src/docs/user/field/permanently_destroying_data.diviner
@@ -0,0 +1,92 @@
+@title Permanently Destroying Data
+@group fieldmanual
+
+How to permanently destroy data and manage leaked secrets.
+
+Overview
+========
+
+Phabricator intentionally makes it difficult to permanently destroy data, but
+provides a command-line tool for destroying objects if you're certain that
+you want to destroy something.
+
+**Disable vs Destroy**: Most kinds of objects can be disabled, deactivated,
+closed, or archived. These operations place them in inactive states and
+preserve their transaction history.
+
+(NOTE) Disabling (rather than destroying) objects is strongly recommended
+unless you have a very good reason to want to permanently destroy an object.
+
+
+Destroying Data
+===============
+
+To permanently destroy an object, run this command from the command line:
+
+```
+phabricator/ $ ./bin/remove destroy <object>
+```
+
+The `<object>` may be an object monogram or PHID. For instance, you can use
+`@alice` to destroy a particular user, or `T123` to destroy a particular task.
+
+(IMPORTANT) This operation is permanent and can not be undone.
+
+
+CLI Access Required
+===================
+
+In almost all cases, Phabricator requires operational access from the CLI to
+permanently destroy data. One major reason for this requirement is that it
+limits the reach of an attacker who compromises a privileged account.
+
+The web UI is generally append-only and actions generally leave an audit
+trail, usually in the transaction log. Thus, an attacker who compromises an
+account but only gains access to the web UI usually can not do much permanent
+damage and usually can not hide their actions or cover their tracks.
+
+Another reason that destroying data is hard is simply that it's permanent and
+can not be undone, so there's no way to recover from mistakes.
+
+
+Leaked Secrets
+==============
+
+Sometimes you may want to destroy an object because it has leaked a secret,
+like an API key or another credential. For example, an engineer might
+accidentally send a change for review which includes a sensitive private key.
+
+No Phabricator command can rewind time, and once data is written to Phabricator
+the cat is often out of the bag: it has often been transmitted to external
+systems which Phabricator can not interact with via email, webhooks, API calls,
+repository mirroring, CDN caching, and so on. You can try to clean up the mess,
+but you're generally already too late.
+
+The `bin/remove destroy` command will make a reasonable attempt to completely
+destroy objects, but this is just an attempt. It can not unsend email or uncall
+the API, and no command can rewind time and undo a leak.
+
+**Revoking Credentials**: If Phabricator credentials were accidentally
+disclosed, you can revoke them so they no longer function. See
+@{article:Revoking Credentials} for more information.
+
+
+Preventing Leaks
+================
+
+Because time can not be rewound, it is best to prevent sensitive data from
+leaking in the first place. Phabricator supports some technical measures that
+can make it more difficult to accidentally disclose secrets:
+
+**Differential Diff Herald Rules**: You can write "Differential Diff" rules
+in Herald that reject diffs before they are written to disk by using the
+"Block diff with message" action.
+
+These rules can reject diffs based on affected file names or file content.
+This is a coarse tool, but rejecting diffs which contain strings like
+`BEGIN RSA PRIVATE KEY` may make it more difficult to accidentally disclose
+certain secrets.
+
+**Commit Content Herald Rules**: For hosted repositories, you can write
+"Commit Hook: Commit Content" rules in Herald which reject pushes that contain
+commit which match certain rules (like file name or file content rules).
diff --git a/src/docs/user/userguide/diffusion_managing.diviner b/src/docs/user/userguide/diffusion_managing.diviner
--- a/src/docs/user/userguide/diffusion_managing.diviner
+++ b/src/docs/user/userguide/diffusion_managing.diviner
@@ -169,8 +169,8 @@
Basics: Delete Repository
=========================
-Repositories can not be deleted from the web UI, so this option is always
-disabled. Clicking it gives you information about how to delete a repository.
+Repositories can not be deleted from the web UI, so this option only gives you
+information about how to delete a repository.
Repositories can only be deleted from the command line, with `bin/remove`:
@@ -178,9 +178,8 @@
$ ./bin/remove destroy <repository>
```
-WARNING: This command will issue you a dire warning about the severity of the
-action you are taking. Heed this warning. You are **strongly discouraged** from
-destroying repositories. Instead, deactivate them.
+This command will permanently destroy the repository. For more information
+about destroying things, see @{article:Permanently Destroying Data}.
Policies
diff --git a/src/view/AphrontDialogView.php b/src/view/AphrontDialogView.php
--- a/src/view/AphrontDialogView.php
+++ b/src/view/AphrontDialogView.php
@@ -161,15 +161,36 @@
}
public function appendParagraph($paragraph) {
- return $this->appendChild(
- phutil_tag(
- 'p',
- array(
- 'class' => 'aphront-dialog-view-paragraph',
- ),
- $paragraph));
+ return $this->appendParagraphTag($paragraph);
}
+ public function appendCommand($command) {
+ $command_tag = phutil_tag('tt', array(), $command);
+ return $this->appendParagraphTag(
+ $command_tag,
+ 'aphront-dialog-view-command');
+ }
+
+ private function appendParagraphTag($content, $classes = null) {
+ if ($classes) {
+ $classes = (array)$classes;
+ } else {
+ $classes = array();
+ }
+
+ array_unshift($classes, 'aphront-dialog-view-paragraph');
+
+ $paragraph_tag = phutil_tag(
+ 'p',
+ array(
+ 'class' => implode(' ', $classes),
+ ),
+ $content);
+
+ return $this->appendChild($paragraph_tag);
+ }
+
+
public function appendList(array $items) {
$listitems = array();
foreach ($items as $item) {
diff --git a/webroot/rsrc/css/aphront/dialog-view.css b/webroot/rsrc/css/aphront/dialog-view.css
--- a/webroot/rsrc/css/aphront/dialog-view.css
+++ b/webroot/rsrc/css/aphront/dialog-view.css
@@ -158,6 +158,11 @@
margin-top: 16px;
}
+.aphront-dialog-view-command {
+ padding: 8px 16px;
+ background: {$greybackground};
+}
+
.device-desktop .aphront-dialog-flush .phui-oi-list-view {
margin: 0;
padding: 0;

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 15, 8:04 AM (1 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7687195
Default Alt Text
D20694.diff (13 KB)

Event Timeline