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

Fix some repository URI handling issues in Git and Mercurial

Summary:
See <https://github.com/facebook/phabricator/issues/467>. @dctrwatson also ran into an issue where we were trying to `setPass()` a GitURI.

- For Git and Mercurial, properly generate credential URIs where relevant.
- Don't try to `setPass()` on Git-style URIs.

This isn't perfect but should clean things up a bit.

Test Plan: Added unit tests. Lots of `grep`.

Reviewers: btrahan

Reviewed By: btrahan

CC: dctrwatson, aran

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

+145 -113
+2 -91
scripts/repository/test_connection.php
··· 1 1 #!/usr/bin/env php 2 2 <?php 3 3 4 - $root = dirname(dirname(dirname(__FILE__))); 5 - require_once $root.'/scripts/__init_script__.php'; 6 - 7 - if (empty($argv[1])) { 8 - echo "usage: test_connection.php <repository_callsign>\n"; 9 - exit(1); 10 - } 11 - 12 - echo phutil_console_wrap( 13 - phutil_console_format( 14 - 'This script will test that you have configured valid credentials for '. 15 - 'access to a repository, so the Phabricator daemons can pull from it. '. 16 - 'You should run this as the **same user you will run the daemons as**, '. 17 - 'from the **same machine they will run from**. Doing this will help '. 18 - 'detect various problems with your configuration, such as SSH issues.')); 19 - 20 - list($whoami) = execx('whoami'); 21 - $whoami = trim($whoami); 22 - 23 - $ok = phutil_console_confirm("Do you want to continue as '{$whoami}'?"); 24 - if (!$ok) { 25 - die(1); 26 - } 27 - 28 - $callsign = $argv[1]; 29 - echo "Loading '{$callsign}' repository...\n"; 30 - $repository = id(new PhabricatorRepository())->loadOneWhere( 31 - 'callsign = %s', 32 - $argv[1]); 33 - if (!$repository) { 34 - throw new Exception("No such repository exists!"); 35 - } 36 - 37 - $vcs = $repository->getVersionControlSystem(); 38 - 39 - PhutilServiceProfiler::installEchoListener(); 40 - 41 - echo phutil_console_format( 42 - "\n". 43 - "**NOTE:** If you are prompted for an SSH password in the next step, the\n". 44 - "daemon won't work because it doesn't have the password and can't respond\n". 45 - "to an interactive prompt. Instead of typing the password, it will hang\n". 46 - "forever when prompted. There are several ways to resolve this:\n\n". 47 - " - Run the daemon inside an ssh-agent session where you have unlocked\n". 48 - " the key (most secure, but most complicated).\n". 49 - " - Generate a new, passwordless certificate for the daemon to use\n". 50 - " (usually quite easy).\n". 51 - " - Remove the passphrase from the key with `ssh-keygen -p`\n". 52 - " (easy, but questionable)."); 53 - 54 - phutil_console_confirm('Did you read all that?', $default_no = false); 55 - 56 - echo "Trying to connect to the remote...\n"; 57 - switch ($vcs) { 58 - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 59 - $err = $repository->passthruRemoteCommand( 60 - '--limit 1 log %s', 61 - $repository->getRemoteURI()); 62 - break; 63 - case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: 64 - // Do an ls-remote on a nonexistent ref, which we expect to just return 65 - // nothing. 66 - $err = $repository->passthruRemoteCommand( 67 - 'ls-remote %s %s', 68 - $repository->getRemoteURI(), 69 - 'just-testing'); 70 - break; 71 - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: 72 - // TODO: 'hg id' doesn't support --insecure so we can't tell it not to 73 - // spew. If 'hg id' eventually supports --insecure, consider using it. 74 - echo "(It is safe to ignore any 'certificate with fingerprint ... not ". 75 - "verified' warnings, although you may want to configure Mercurial ". 76 - "to recognize the server's fingerprint/certificate.)\n"; 77 - $err = $repository->passthruRemoteCommand( 78 - 'id --rev tip %s', 79 - $repository->getRemoteURI()); 80 - break; 81 - default: 82 - throw new Exception("Unsupported repository type."); 83 - } 84 - 85 - if ($err) { 86 - echo phutil_console_format( 87 - "<bg:red>** FAIL **</bg> Connection failed. The credentials for this ". 88 - "repository appear to be incorrectly configured.\n"); 89 - exit(1); 90 - } else { 91 - echo phutil_console_format( 92 - "<bg:green>** OKAY **</bg> Connection successful. The credentials for ". 93 - "this repository appear to be correctly configured.\n"); 94 - } 4 + echo "This script is obsolete. Use `bin/repository` to manage repositories.\n"; 5 + exit(1); 95 6
+2
src/__phutil_library_map__.php
··· 1815 1815 'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php', 1816 1816 'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php', 1817 1817 'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php', 1818 + 'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php', 1818 1819 'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php', 1819 1820 'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php', 1820 1821 'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php', ··· 4380 4381 'PhabricatorRepositoryTestCase' => 'PhabricatorTestCase', 4381 4382 'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction', 4382 4383 'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 4384 + 'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase', 4383 4385 'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO', 4384 4386 'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine', 4385 4387 'PhabricatorSSHLog' => 'Phobject',
+2 -2
src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php
··· 63 63 64 64 $cmd = $host_lease->getInterface('command'); 65 65 $cmd->execx( 66 - 'git clone --origin origin %s %s', 67 - $repository->getRemoteURI(), 66 + 'git clone --origin origin %P %s', 67 + $repository->getRemoteURIEnvelope(), 68 68 $path); 69 69 70 70 $this->log(pht('Complete.'));
+2 -2
src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php
··· 842 842 } 843 843 844 844 $future = $proxy->getRemoteCommandFuture( 845 - 'push --verbose --mirror -- %s', 846 - $proxy->getRemoteURI()); 845 + 'push --verbose --mirror -- %P', 846 + $proxy->getRemoteURIEnvelope()); 847 847 848 848 $future 849 849 ->setCWD($proxy->getLocalPath())
+4 -4
src/applications/repository/engine/PhabricatorRepositoryPullEngine.php
··· 188 188 $path); 189 189 } else { 190 190 $repository->execxRemoteCommand( 191 - 'clone --bare -- %s %s', 192 - $repository->getRemoteURI(), 191 + 'clone --bare -- %P %s', 192 + $repository->getRemoteURIEnvelope(), 193 193 $path); 194 194 } 195 195 } ··· 337 337 $path); 338 338 } else { 339 339 $repository->execxRemoteCommand( 340 - 'clone --noupdate -- %s %s', 341 - $repository->getRemoteURI(), 340 + 'clone --noupdate -- %P %s', 341 + $repository->getRemoteURIEnvelope(), 342 342 $path); 343 343 } 344 344 }
+38 -14
src/applications/repository/storage/PhabricatorRepository.php
··· 81 81 'callsign' => $this->getCallsign(), 82 82 'vcs' => $this->getVersionControlSystem(), 83 83 'uri' => PhabricatorEnv::getProductionURI($this->getURI()), 84 - 'remoteURI' => (string)$this->getPublicRemoteURI(), 84 + 'remoteURI' => (string)$this->getRemoteURI(), 85 85 'tracking' => $this->getDetail('tracking-enabled'), 86 86 'description' => $this->getDetail('description'), 87 87 ); ··· 440 440 return $args; 441 441 } 442 442 443 - public function getSSHLogin() { 444 - return $this->getDetail('ssh-login'); 445 - } 446 - 447 443 public function getURI() { 448 444 return '/diffusion/'.$this->getCallsign().'/'; 449 445 } ··· 569 565 570 566 571 567 /** 568 + * Get the remote URI for this repository, including credentials if they're 569 + * used by this repository. 570 + * 571 + * @return PhutilOpaqueEnvelope URI, possibly including credentials. 572 + * @task uri 573 + */ 574 + public function getRemoteURIEnvelope() { 575 + $uri = $this->getRemoteURIObject(); 576 + 577 + $remote_protocol = $this->getRemoteProtocol(); 578 + if ($remote_protocol == 'http' || $remote_protocol == 'https') { 579 + // For SVN, we use `--username` and `--password` flags separately, so 580 + // don't add any credentials here. 581 + if (!$this->isSVN()) { 582 + $credential_phid = $this->getCredentialPHID(); 583 + if ($credential_phid) { 584 + $key = PassphrasePasswordKey::loadFromPHID( 585 + $credential_phid, 586 + PhabricatorUser::getOmnipotentUser()); 587 + 588 + $uri->setUser($key->getUsernameEnvelope()->openEnvelope()); 589 + $uri->setPass($key->getPasswordEnvelope()->openEnvelope()); 590 + } 591 + } 592 + } 593 + 594 + return new PhutilOpaqueEnvelope((string)$uri); 595 + } 596 + 597 + 598 + /** 572 599 * Get the remote URI for this repository, without authentication information. 573 600 * 574 601 * @return string Repository URI. ··· 584 611 // password. 585 612 if (!$this->shouldUseSSH()) { 586 613 $uri->setUser(null); 587 - $uri->setPass(null); 614 + 615 + // This might be a Git URI or a normal URI. If it's Git, there's no 616 + // password support. 617 + if ($uri instanceof PhutilURI) { 618 + $uri->setPass(null); 619 + } 588 620 } 589 621 590 622 return (string)$uri; ··· 629 661 630 662 $uri = new PhutilURI($raw_uri); 631 663 if ($uri->getProtocol()) { 632 - if ($this->isSSHProtocol($uri->getProtocol())) { 633 - if ($this->getSSHLogin()) { 634 - $uri->setUser($this->getSSHLogin()); 635 - } 636 - } 637 664 return $uri; 638 665 } 639 666 640 667 $uri = new PhutilGitURI($raw_uri); 641 668 if ($uri->getDomain()) { 642 - if ($this->getSSHLogin()) { 643 - $uri->setUser($this->getSSHLogin()); 644 - } 645 669 return $uri; 646 670 } 647 671
+95
src/applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryURITestCase 4 + extends PhabricatorTestCase { 5 + 6 + protected function getPhabricatorTestCaseConfiguration() { 7 + return array( 8 + self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true, 9 + ); 10 + } 11 + 12 + public function testURIGeneration() { 13 + $svn = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN; 14 + $git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT; 15 + $hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL; 16 + 17 + $user = $this->generateNewTestUser(); 18 + 19 + $http_secret = id(new PassphraseSecret())->setSecretData('quack')->save(); 20 + 21 + $http_credential = PassphraseCredential::initializeNewCredential($user) 22 + ->setCredentialType(PassphraseCredentialTypePassword::CREDENTIAL_TYPE) 23 + ->setProvidesType(PassphraseCredentialTypePassword::PROVIDES_TYPE) 24 + ->setUsername('duck') 25 + ->setSecretID($http_secret->getID()) 26 + ->save(); 27 + 28 + $repo = PhabricatorRepository::initializeNewRepository($user) 29 + ->setVersionControlSystem($svn) 30 + ->setName('Test Repo') 31 + ->setCallsign('TESTREPO') 32 + ->setCredentialPHID($http_credential->getPHID()) 33 + ->save(); 34 + 35 + // Test HTTP URIs. 36 + 37 + $repo->setDetail('remote-uri', 'http://example.com/'); 38 + $repo->setVersionControlSystem($svn); 39 + 40 + $this->assertEqual('http://example.com/', $repo->getRemoteURI()); 41 + $this->assertEqual('http://example.com/', $repo->getPublicRemoteURI()); 42 + $this->assertEqual('http://example.com/', 43 + $repo->getRemoteURIEnvelope()->openEnvelope()); 44 + 45 + $repo->setVersionControlSystem($git); 46 + 47 + $this->assertEqual('http://example.com/', $repo->getRemoteURI()); 48 + $this->assertEqual('http://example.com/', $repo->getPublicRemoteURI()); 49 + $this->assertEqual('http://duck:quack@example.com/', 50 + $repo->getRemoteURIEnvelope()->openEnvelope()); 51 + 52 + $repo->setVersionControlSystem($hg); 53 + 54 + $this->assertEqual('http://example.com/', $repo->getRemoteURI()); 55 + $this->assertEqual('http://example.com/', $repo->getPublicRemoteURI()); 56 + $this->assertEqual('http://duck:quack@example.com/', 57 + $repo->getRemoteURIEnvelope()->openEnvelope()); 58 + 59 + // Test SSH URIs. 60 + 61 + $repo->setDetail('remote-uri', 'ssh://example.com/'); 62 + $repo->setVersionControlSystem($svn); 63 + 64 + $this->assertEqual('ssh://example.com/', $repo->getRemoteURI()); 65 + $this->assertEqual('ssh://example.com/', $repo->getPublicRemoteURI()); 66 + $this->assertEqual('ssh://example.com/', 67 + $repo->getRemoteURIEnvelope()->openEnvelope()); 68 + 69 + $repo->setVersionControlSystem($git); 70 + 71 + $this->assertEqual('ssh://example.com/', $repo->getRemoteURI()); 72 + $this->assertEqual('ssh://example.com/', $repo->getPublicRemoteURI()); 73 + $this->assertEqual('ssh://example.com/', 74 + $repo->getRemoteURIEnvelope()->openEnvelope()); 75 + 76 + $repo->setVersionControlSystem($hg); 77 + 78 + $this->assertEqual('ssh://example.com/', $repo->getRemoteURI()); 79 + $this->assertEqual('ssh://example.com/', $repo->getPublicRemoteURI()); 80 + $this->assertEqual('ssh://example.com/', 81 + $repo->getRemoteURIEnvelope()->openEnvelope()); 82 + 83 + // Test Git URIs. 84 + 85 + $repo->setDetail('remote-uri', 'git@example.com:path.git'); 86 + $repo->setVersionControlSystem($git); 87 + 88 + $this->assertEqual('git@example.com:path.git', $repo->getRemoteURI()); 89 + $this->assertEqual('git@example.com:path.git', $repo->getPublicRemoteURI()); 90 + $this->assertEqual('git@example.com:path.git', 91 + $repo->getRemoteURIEnvelope()->openEnvelope()); 92 + 93 + } 94 + 95 + }