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

Guarantee repositories have unique local paths

Summary:
Ref T4039. Long ago these were more freely editable and there were some security concerns around creating a repository, then setting its local path to point somewhere it shouldn't.

Local paths are no longer editable so there's no real reason we need to provide a uniqueness guarantee anymore, but you could still make a mistake with `bin/repository move-paths` by accident, and it's a little cleaner to pull them out into their own column with a key.

(We still don't -- and, largely can't -- guarantee that two paths aren't //equivalent// since one might be symlinked to the other, or symlinked only on some hosts, or whatever, but the primary value here is as a sanity check that you aren't goofing things up and pointing a bunch of repositories at the same working copy by mistake.)

Test Plan:
- Ran migrations.
- Grepped for `local-path`.
- Listed and moved paths with `bin/repository`.
- Created a new repository, verified its local path populated correctly.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4039

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

+89 -37
+2
resources/sql/autopatches/20160503.repo.01.lpath.sql
··· 1 + ALTER TABLE {$NAMESPACE}_repository.repository 2 + ADD localPath VARCHAR(128) COLLATE {$COLLATE_TEXT};
+2
resources/sql/autopatches/20160503.repo.02.lpathkey.sql
··· 1 + ALTER TABLE {$NAMESPACE}_repository.repository 2 + ADD UNIQUE KEY `key_local` (localPath);
+57
resources/sql/autopatches/20160503.repo.03.lpathmigrate.php
··· 1 + <?php 2 + 3 + $table = new PhabricatorRepository(); 4 + $conn_w = $table->establishConnection('w'); 5 + 6 + $default_path = PhabricatorEnv::getEnvConfig('repository.default-local-path'); 7 + $default_path = rtrim($default_path, '/'); 8 + 9 + foreach (new LiskMigrationIterator($table) as $repository) { 10 + $local_path = $repository->getLocalPath(); 11 + if (strlen($local_path)) { 12 + // Repository already has a modern, unique local path. 13 + continue; 14 + } 15 + 16 + $local_path = $repository->getDetail('local-path'); 17 + if (!strlen($local_path)) { 18 + // Repository does not have a local path using the older format. 19 + continue; 20 + } 21 + 22 + $random = Filesystem::readRandomCharacters(8); 23 + 24 + // Try the configured path first, then a default path, then a path with some 25 + // random noise. 26 + $paths = array( 27 + $local_path, 28 + $default_path.'/'.$repository->getID().'/', 29 + $default_path.'/'.$repository->getID().'-'.$random.'/', 30 + ); 31 + 32 + foreach ($paths as $path) { 33 + // Set, then get the path to normalize it. 34 + $repository->setLocalPath($path); 35 + $path = $repository->getLocalPath(); 36 + 37 + try { 38 + queryfx( 39 + $conn_w, 40 + 'UPDATE %T SET localPath = %s WHERE id = %d', 41 + $table->getTableName(), 42 + $path, 43 + $repository->getID()); 44 + 45 + echo tsprintf( 46 + "%s\n", 47 + pht( 48 + 'Assigned repository "%s" to local path "%s".', 49 + $repository->getDisplayName(), 50 + $path)); 51 + 52 + break; 53 + } catch (AphrontDuplicateKeyQueryException $ex) { 54 + // Ignore, try the next one. 55 + } 56 + } 57 + }
+1 -3
src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
··· 631 631 pht('Storage Service'), 632 632 $v_service); 633 633 634 - $view->addProperty( 635 - pht('Storage Path'), 636 - $repository->getHumanReadableDetail('local-path')); 634 + $view->addProperty(pht('Storage Path'), $repository->getLocalPath()); 637 635 638 636 return $view; 639 637 }
+2 -6
src/applications/diffusion/controller/DiffusionRepositoryEditStorageController.php
··· 15 15 16 16 $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); 17 17 18 - $v_local = $repository->getHumanReadableDetail('local-path'); 18 + $v_local = $repository->getLocalPath(); 19 19 $errors = array(); 20 20 21 21 $crumbs = $this->buildApplicationCrumbs(); ··· 51 51 ->appendRemarkupInstructions( 52 52 pht( 53 53 "You can not adjust the local path for this repository from the ". 54 - "web interface. To edit it, run this command:\n\n %s", 55 - sprintf( 56 - 'phabricator/ $ ./bin/repository edit %s --as %s --local-path ...', 57 - $repository->getMonogram(), 58 - $viewer->getUsername()))) 54 + 'web interface.')) 59 55 ->appendChild( 60 56 id(new AphrontFormSubmitControl()) 61 57 ->addCancelButton($edit_uri, pht('Done')));
+1 -1
src/applications/diffusion/management/DiffusionRepositoryStorageManagementPanel.php
··· 40 40 ->setViewer($viewer); 41 41 42 42 if ($repository->usesLocalWorkingCopy()) { 43 - $storage_path = $repository->getHumanReadableDetail('local-path'); 43 + $storage_path = $repository->getLocalPath(); 44 44 } else { 45 45 $storage_path = phutil_tag('em', array(), pht('No Local Working Copy')); 46 46 }
+2 -1
src/applications/repository/conduit/RepositoryCreateConduitAPIMethod.php
··· 110 110 'description' => $request->getValue('description'), 111 111 'tracking-enabled' => (bool)$request->getValue('tracking', true), 112 112 'remote-uri' => $remote_uri, 113 - 'local-path' => $local_path, 114 113 'branch-filter' => array_fill_keys( 115 114 $request->getValue('branchFilter', array()), 116 115 true), ··· 127 126 foreach ($details as $key => $value) { 128 127 $repository->setDetail($key, $value); 129 128 } 129 + 130 + $repository->setLocalPath($local_path); 130 131 131 132 try { 132 133 $repository->save();
+4 -4
src/applications/repository/editor/PhabricatorRepositoryEditor.php
··· 86 86 case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI: 87 87 return $object->getDetail('remote-uri'); 88 88 case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH: 89 - return $object->getDetail('local-path'); 89 + return $object->getLocalPath(); 90 90 case PhabricatorRepositoryTransaction::TYPE_HOSTING: 91 91 return $object->isHosted(); 92 92 case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP: ··· 209 209 $object->setDetail('remote-uri', $xaction->getNewValue()); 210 210 break; 211 211 case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH: 212 - $object->setDetail('local-path', $xaction->getNewValue()); 212 + $object->setLocalPath($xaction->getNewValue()); 213 213 break; 214 214 case PhabricatorRepositoryTransaction::TYPE_HOSTING: 215 215 return $object->setHosted($xaction->getNewValue()); ··· 706 706 707 707 // If the repository does not have a local path yet, assign it one based 708 708 // on its ID. We can't do this earlier because we won't have an ID yet. 709 - $local_path = $object->getDetail('local-path'); 709 + $local_path = $object->getLocalPath(); 710 710 if (!strlen($local_path)) { 711 711 $local_key = 'repository.default-local-path'; 712 712 ··· 716 716 $id = $object->getID(); 717 717 $local_path = "{$local_root}/{$id}/"; 718 718 719 - $object->setDetail('local-path', $local_path); 719 + $object->setLocalPath($local_path); 720 720 $object->save(); 721 721 } 722 722
+1 -1
src/applications/repository/engine/__tests__/PhabricatorWorkingCopyTestCase.php
··· 65 65 ->setCallsign($callsign) 66 66 ->setName(pht('Test Repo "%s"', $callsign)) 67 67 ->setVersionControlSystem($vcs_type) 68 - ->setDetail('local-path', dirname($local).'/'.$callsign) 68 + ->setLocalPath(dirname($local).'/'.$callsign) 69 69 ->setDetail('remote-uri', 'file://'.$dir->getPath().'/'); 70 70 71 71 $this->didConstructRepository($repo);
-11
src/applications/repository/management/PhabricatorRepositoryManagementEditWorkflow.php
··· 22 22 'help' => pht('Edit as user.'), 23 23 ), 24 24 array( 25 - 'name' => 'local-path', 26 - 'param' => 'path', 27 - 'help' => pht('Edit the local path.'), 28 - ), 29 - array( 30 25 'name' => 'serve-http', 31 26 'param' => 'string', 32 27 'help' => pht('Edit the http serving policy.'), ··· 83 78 84 79 $xactions = array(); 85 80 86 - $type_local_path = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH; 87 81 $type_protocol_http = 88 82 PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP; 89 83 $type_protocol_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH; ··· 93 87 PhabricatorRepository::SERVE_READWRITE, 94 88 ); 95 89 96 - if ($args->getArg('local-path')) { 97 - $xactions[] = id(new PhabricatorRepositoryTransaction()) 98 - ->setTransactionType($type_local_path) 99 - ->setNewValue($args->getArg('local-path')); 100 - } 101 90 $serve_http = $args->getArg('serve-http'); 102 91 if ($serve_http && in_array($serve_http, $allowed_serve_modes)) { 103 92 $xactions[] = id(new PhabricatorRepositoryTransaction())
+2 -4
src/applications/repository/management/PhabricatorRepositoryManagementMovePathsWorkflow.php
··· 128 128 } 129 129 130 130 $repo = $row['repository']; 131 - $details = $repo->getDetails(); 132 - $details['local-path'] = $row['dst']; 133 131 134 132 queryfx( 135 133 $repo->establishConnection('w'), 136 - 'UPDATE %T SET details = %s WHERE id = %d', 134 + 'UPDATE %T SET localPath = %s WHERE id = %d', 137 135 $repo->getTableName(), 138 - phutil_json_encode($details), 136 + $row['dst'], 139 137 $repo->getID()); 140 138 } 141 139
+13 -4
src/applications/repository/storage/PhabricatorRepository.php
··· 62 62 protected $credentialPHID; 63 63 protected $almanacServicePHID; 64 64 protected $spacePHID; 65 + protected $localPath; 65 66 66 67 private $commitCount = self::ATTACHABLE; 67 68 private $mostRecentCommit = self::ATTACHABLE; ··· 107 108 'pushPolicy' => 'policy', 108 109 'credentialPHID' => 'phid?', 109 110 'almanacServicePHID' => 'phid?', 111 + 'localPath' => 'text128?', 110 112 ), 111 113 self::CONFIG_KEY_SCHEMA => array( 112 114 'callsign' => array( ··· 121 123 ), 122 124 'key_slug' => array( 123 125 'columns' => array('repositorySlug'), 126 + 'unique' => true, 127 + ), 128 + 'key_local' => array( 129 + 'columns' => array('localPath'), 124 130 'unique' => true, 125 131 ), 126 132 ), ··· 216 222 return $monograms; 217 223 } 218 224 225 + public function setLocalPath($path) { 226 + // Convert any extra slashes ("//") in the path to a single slash ("/"). 227 + $path = preg_replace('(//+)', '/', $path); 228 + 229 + return parent::setLocalPath($path); 230 + } 231 + 219 232 public function getDetail($key, $default = null) { 220 233 return idx($this->details, $key, $default); 221 234 } ··· 277 290 'action' => 'browse', 278 291 'line' => $line, 279 292 )); 280 - } 281 - 282 - public function getLocalPath() { 283 - return $this->getDetail('local-path'); 284 293 } 285 294 286 295 public function getSubversionBaseURI($commit = null) {
+2 -2
src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
··· 70 70 71 71 $repo->setDetail('hosting-enabled', true); 72 72 73 - $repo->setDetail('local-path', '/var/repo/SVN'); 73 + $repo->setLocalPath('/var/repo/SVN'); 74 74 $this->assertEqual( 75 75 'file:///var/repo/SVN', 76 76 $repo->getSubversionPathURI()); 77 77 78 - $repo->setDetail('local-path', '/var/repo/SVN/'); 78 + $repo->setLocalPath('/var/repo/SVN/'); 79 79 $this->assertEqual( 80 80 'file:///var/repo/SVN', 81 81 $repo->getSubversionPathURI());