diff --git a/src/poetry/utils/authenticator.py b/src/poetry/utils/authenticator.py index 22703be8977..070e503acd8 100644 --- a/src/poetry/utils/authenticator.py +++ b/src/poetry/utils/authenticator.py @@ -245,8 +245,10 @@ def _get_credentials_for_repository( return self._credentials[key] - def _get_credentials_for_url(self, url: str) -> HTTPAuthCredential: - repository = self.get_repository_config_for_url(url) + def _get_credentials_for_url( + self, url: str, exact_match: bool = False + ) -> HTTPAuthCredential: + repository = self.get_repository_config_for_url(url, exact_match) credential = ( self._get_credentials_for_repository(repository=repository) @@ -267,6 +269,14 @@ def _get_credentials_for_url(self, url: str) -> HTTPAuthCredential: return credential + def get_credentials_for_git_url(self, url: str) -> HTTPAuthCredential: + key = f"git+{url}" + + if key not in self._credentials: + self._credentials[key] = self._get_credentials_for_url(url, True) + + return self._credentials[key] + def get_credentials_for_url(self, url: str) -> HTTPAuthCredential: parsed_url = urllib.parse.urlsplit(url) netloc = parsed_url.netloc @@ -338,13 +348,17 @@ def get_certs_for_url(self, url: str) -> dict[str, Path | None]: @functools.lru_cache(maxsize=None) def get_repository_config_for_url( - self, url: str + self, url: str, exact_match: bool = False ) -> AuthenticatorRepositoryConfig | None: parsed_url = urllib.parse.urlsplit(url) candidates_netloc_only = [] candidates_path_match = [] for repository in self.configured_repositories.values(): + if exact_match: + if parsed_url.path == repository.path: + return repository + continue if repository.netloc == parsed_url.netloc: if parsed_url.path.startswith(repository.path) or commonprefix( diff --git a/src/poetry/vcs/git/backend.py b/src/poetry/vcs/git/backend.py index c43493febdb..a1b34436b41 100644 --- a/src/poetry/vcs/git/backend.py +++ b/src/poetry/vcs/git/backend.py @@ -186,7 +186,7 @@ def _fetch_remote_refs(cls, url: str, local: Repo) -> FetchPackResult: client: GitClient path: str - credentials = get_default_authenticator().get_credentials_for_url(url=url) + credentials = get_default_authenticator().get_credentials_for_git_url(url=url) client, path = get_transport_and_path( # type: ignore[no-untyped-call] url, username=credentials.username, password=credentials.password ) diff --git a/tests/utils/test_authenticator.py b/tests/utils/test_authenticator.py index dd1666036ab..7b0c858fc42 100644 --- a/tests/utils/test_authenticator.py +++ b/tests/utils/test_authenticator.py @@ -560,3 +560,38 @@ def test_authenticator_add_repository( basic_auth = base64.b64encode(b"foo:bar").decode() assert request.headers["Authorization"] == f"Basic {basic_auth}" + + +def test_authenticator_git_repositories( + config: Config, + mock_remote: None, + http: type[httpretty.httpretty], + with_simple_keyring: None, + dummy_keyring: DummyBackend, +): + config.merge( + { + "repositories": { + "one": {"url": "https://foo.bar/org/one.git"}, + "two": {"url": "https://foo.bar/org/two.git"}, + }, + "http-basic": { + "one": {"username": "foo", "password": "bar"}, + "two": {"username": "baz", "password": "qux"}, + }, + } + ) + + authenticator = Authenticator(config, NullIO()) + + one = authenticator.get_credentials_for_git_url("https://foo.bar/org/one.git") + assert one.username == "foo" + assert one.password == "bar" + + two = authenticator.get_credentials_for_git_url("https://foo.bar/org/two.git") + assert two.username == "baz" + assert two.password == "qux" + + three = authenticator.get_credentials_for_git_url("https://foo.bar/org/three.git") + assert not three.username + assert not three.password