Skip to content

Commit

Permalink
git: allow http auth via dulwich
Browse files Browse the repository at this point in the history
This change makes use of existing repository authentication mechanisms
to enable http authentication for git dependencies.
  • Loading branch information
abn committed May 8, 2022
1 parent 4838c9f commit 1c1cb92
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ jobs:
run: poetry run mypy

- name: Run pytest (integration suite)
env:
POETRY_TEST_INTEGRATION_GIT_USERNAME: ${GITHUB_ACTOR}
POETRY_TEST_INTEGRATION_GIT_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
run: poetry run python -m pytest -p no:sugar -q --integration tests/integration

- name: Get Plugin Version (poetry-plugin-export)
Expand Down
4 changes: 2 additions & 2 deletions src/poetry/repositories/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from poetry.core.packages.utils.link import Link
from poetry.core.version.markers import parse_marker

from poetry.config.config import Config
from poetry.repositories.cached import CachedRepository
from poetry.repositories.exceptions import PackageNotFound
from poetry.repositories.exceptions import RepositoryError
Expand All @@ -29,6 +28,7 @@


if TYPE_CHECKING:
from poetry.config.config import Config
from poetry.inspection.info import PackageInfo


Expand All @@ -43,7 +43,7 @@ def __init__(
super().__init__(name, disable_cache)
self._url = url
self._authenticator = Authenticator(
config=config or Config(use_environment=True),
config=config,
cache_id=name,
disable_cache=disable_cache,
)
Expand Down
19 changes: 15 additions & 4 deletions src/poetry/utils/authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from cachecontrol import CacheControl
from cachecontrol.caches import FileCache

from poetry.config.config import Config
from poetry.exceptions import PoetryException
from poetry.locations import REPOSITORY_CACHE_DIR
from poetry.utils.helpers import get_cert
Expand All @@ -31,8 +32,6 @@

from cleo.io.io import IO

from poetry.config.config import Config


logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -84,12 +83,12 @@ def get_http_credentials(
class Authenticator:
def __init__(
self,
config: Config,
config: Config | None = None,
io: IO | None = None,
cache_id: str | None = None,
disable_cache: bool = False,
) -> None:
self._config = config
self._config = config or Config(use_environment=True)
self._io = io
self._sessions_for_netloc: dict[str, requests.Session] = {}
self._credentials: dict[str, HTTPAuthCredential] = {}
Expand Down Expand Up @@ -371,3 +370,15 @@ def _get_certs_for_url(self, url: str) -> dict[str, Path | None]:
if selected:
return selected.certs(config=self._config)
return {"cert": None, "verify": None}


_authenticator: Authenticator | None = None


def get_default_authenticator() -> Authenticator:
global _authenticator

if _authenticator is None:
_authenticator = Authenticator()

return _authenticator
7 changes: 6 additions & 1 deletion src/poetry/vcs/git/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from dulwich.repo import Repo

from poetry.console.exceptions import PoetrySimpleConsoleException
from poetry.utils.authenticator import get_default_authenticator
from poetry.utils.helpers import remove_directory


Expand Down Expand Up @@ -181,7 +182,11 @@ def _fetch_remote_refs(cls, url: str, local: Repo) -> FetchPackResult:
"""
client: GitClient
path: str
client, path = get_transport_and_path(url)

credentials = get_default_authenticator().get_credentials_for_url(url=url)
client, path = get_transport_and_path(
url, username=credentials.username, password=credentials.password
)

with local:
return client.fetch(
Expand Down
49 changes: 49 additions & 0 deletions tests/integration/test_utils_vcs_git.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import os
import uuid

from copy import deepcopy
Expand All @@ -15,6 +16,7 @@
from poetry.core.pyproject.toml import PyProjectTOML

from poetry.console.exceptions import PoetrySimpleConsoleException
from poetry.utils.authenticator import Authenticator
from poetry.vcs.git import Git
from poetry.vcs.git.backend import GitRefSpec

Expand Down Expand Up @@ -249,6 +251,53 @@ def test_system_git_fallback_on_http_401(
spy.assert_called_once()


GIT_USERNAME = os.environ.get("POETRY_TEST_INTEGRATION_GIT_USERNAME")
GIT_PASSWORD = os.environ.get("POETRY_TEST_INTEGRATION_GIT_PASSWORD")
HTTP_AUTH_CREDENTIALS_AVAILABLE = not (GIT_USERNAME and GIT_PASSWORD)


@pytest.mark.skipif(
HTTP_AUTH_CREDENTIALS_AVAILABLE,
reason="HTTP authentication credentials not available",
)
def test_configured_repository_http_auth(
mocker: MockerFixture, source_url: str, config: Config
) -> None:
from poetry.vcs.git import backend

spy_clone_legacy = mocker.spy(Git, "_clone_legacy")
spy_get_transport_and_path = mocker.spy(backend, "get_transport_and_path")

config.merge(
{
"repositories": {"git-repo": {"url": source_url}},
"http-basic": {
"git-repo": {
"username": GIT_USERNAME,
"password": GIT_PASSWORD,
}
},
}
)

mocker.patch(
"poetry.vcs.git.backend.get_default_authenticator",
return_value=Authenticator(config=config),
)

with Git.clone(url=source_url, branch="0.1") as repo:
assert_version(repo, BRANCH_TO_REVISION_MAP["0.1"])

spy_clone_legacy.assert_not_called()

spy_get_transport_and_path.assert_called_with(
location=source_url,
username=GIT_USERNAME,
password=GIT_PASSWORD,
)
spy_get_transport_and_path.assert_called_once()


def test_system_git_called_when_configured(
mocker: MockerFixture, source_url: str, use_system_git_client: None
) -> None:
Expand Down

0 comments on commit 1c1cb92

Please sign in to comment.