Commit 1c1cb921 by Arun Babu Neelicattu

git: allow http auth via dulwich

This change makes use of existing repository authentication mechanisms
to enable http authentication for git dependencies.
parent 4838c9fe
...@@ -89,6 +89,9 @@ jobs: ...@@ -89,6 +89,9 @@ jobs:
run: poetry run mypy run: poetry run mypy
- name: Run pytest (integration suite) - 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 run: poetry run python -m pytest -p no:sugar -q --integration tests/integration
- name: Get Plugin Version (poetry-plugin-export) - name: Get Plugin Version (poetry-plugin-export)
......
...@@ -17,7 +17,6 @@ from poetry.core.packages.dependency import Dependency ...@@ -17,7 +17,6 @@ from poetry.core.packages.dependency import Dependency
from poetry.core.packages.utils.link import Link from poetry.core.packages.utils.link import Link
from poetry.core.version.markers import parse_marker from poetry.core.version.markers import parse_marker
from poetry.config.config import Config
from poetry.repositories.cached import CachedRepository from poetry.repositories.cached import CachedRepository
from poetry.repositories.exceptions import PackageNotFound from poetry.repositories.exceptions import PackageNotFound
from poetry.repositories.exceptions import RepositoryError from poetry.repositories.exceptions import RepositoryError
...@@ -29,6 +28,7 @@ from poetry.utils.patterns import wheel_file_re ...@@ -29,6 +28,7 @@ from poetry.utils.patterns import wheel_file_re
if TYPE_CHECKING: if TYPE_CHECKING:
from poetry.config.config import Config
from poetry.inspection.info import PackageInfo from poetry.inspection.info import PackageInfo
...@@ -43,7 +43,7 @@ class HTTPRepository(CachedRepository, ABC): ...@@ -43,7 +43,7 @@ class HTTPRepository(CachedRepository, ABC):
super().__init__(name, disable_cache) super().__init__(name, disable_cache)
self._url = url self._url = url
self._authenticator = Authenticator( self._authenticator = Authenticator(
config=config or Config(use_environment=True), config=config,
cache_id=name, cache_id=name,
disable_cache=disable_cache, disable_cache=disable_cache,
) )
......
...@@ -18,6 +18,7 @@ import requests.exceptions ...@@ -18,6 +18,7 @@ import requests.exceptions
from cachecontrol import CacheControl from cachecontrol import CacheControl
from cachecontrol.caches import FileCache from cachecontrol.caches import FileCache
from poetry.config.config import Config
from poetry.exceptions import PoetryException from poetry.exceptions import PoetryException
from poetry.locations import REPOSITORY_CACHE_DIR from poetry.locations import REPOSITORY_CACHE_DIR
from poetry.utils.helpers import get_cert from poetry.utils.helpers import get_cert
...@@ -31,8 +32,6 @@ if TYPE_CHECKING: ...@@ -31,8 +32,6 @@ if TYPE_CHECKING:
from cleo.io.io import IO from cleo.io.io import IO
from poetry.config.config import Config
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -84,12 +83,12 @@ class AuthenticatorRepositoryConfig: ...@@ -84,12 +83,12 @@ class AuthenticatorRepositoryConfig:
class Authenticator: class Authenticator:
def __init__( def __init__(
self, self,
config: Config, config: Config | None = None,
io: IO | None = None, io: IO | None = None,
cache_id: str | None = None, cache_id: str | None = None,
disable_cache: bool = False, disable_cache: bool = False,
) -> None: ) -> None:
self._config = config self._config = config or Config(use_environment=True)
self._io = io self._io = io
self._sessions_for_netloc: dict[str, requests.Session] = {} self._sessions_for_netloc: dict[str, requests.Session] = {}
self._credentials: dict[str, HTTPAuthCredential] = {} self._credentials: dict[str, HTTPAuthCredential] = {}
...@@ -371,3 +370,15 @@ class Authenticator: ...@@ -371,3 +370,15 @@ class Authenticator:
if selected: if selected:
return selected.certs(config=self._config) return selected.certs(config=self._config)
return {"cert": None, "verify": None} return {"cert": None, "verify": None}
_authenticator: Authenticator | None = None
def get_default_authenticator() -> Authenticator:
global _authenticator
if _authenticator is None:
_authenticator = Authenticator()
return _authenticator
...@@ -18,6 +18,7 @@ from dulwich.refs import ANNOTATED_TAG_SUFFIX ...@@ -18,6 +18,7 @@ from dulwich.refs import ANNOTATED_TAG_SUFFIX
from dulwich.repo import Repo from dulwich.repo import Repo
from poetry.console.exceptions import PoetrySimpleConsoleException from poetry.console.exceptions import PoetrySimpleConsoleException
from poetry.utils.authenticator import get_default_authenticator
from poetry.utils.helpers import remove_directory from poetry.utils.helpers import remove_directory
...@@ -181,7 +182,11 @@ class Git: ...@@ -181,7 +182,11 @@ class Git:
""" """
client: GitClient client: GitClient
path: str 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: with local:
return client.fetch( return client.fetch(
......
from __future__ import annotations from __future__ import annotations
import os
import uuid import uuid
from copy import deepcopy from copy import deepcopy
...@@ -15,6 +16,7 @@ from dulwich.repo import Repo ...@@ -15,6 +16,7 @@ from dulwich.repo import Repo
from poetry.core.pyproject.toml import PyProjectTOML from poetry.core.pyproject.toml import PyProjectTOML
from poetry.console.exceptions import PoetrySimpleConsoleException from poetry.console.exceptions import PoetrySimpleConsoleException
from poetry.utils.authenticator import Authenticator
from poetry.vcs.git import Git from poetry.vcs.git import Git
from poetry.vcs.git.backend import GitRefSpec from poetry.vcs.git.backend import GitRefSpec
...@@ -249,6 +251,53 @@ def test_system_git_fallback_on_http_401( ...@@ -249,6 +251,53 @@ def test_system_git_fallback_on_http_401(
spy.assert_called_once() 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( def test_system_git_called_when_configured(
mocker: MockerFixture, source_url: str, use_system_git_client: None mocker: MockerFixture, source_url: str, use_system_git_client: None
) -> None: ) -> None:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment