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

Modernize user and repository "delete" workflows and improve documentation

Summary:
Fixes T8830. Fixes T13364.

- The inability to destroy objects from the web UI is intentional. Make this clear in the messaging, which is somewhat out of date and partly reflects an earlier era when things could be destroyed.
- `bin/remove destroy` can't rewind time. Document expectations around the "put the cat back in the bag" use case.

Test Plan: Read documentation, clicked through both workflows.

Maniphest Tasks: T13364, T8830

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

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