Commit 3a1b45fc by Sébastien Eustace Committed by GitHub

Merge pull request #4086 from Darsstar/pip-style-keyring-fallback

Added pip style keyring password lookup as a fallback.
parents b54f2dc8 6db85a66
...@@ -75,6 +75,21 @@ If a system keyring is available and supported, the password is stored to and re ...@@ -75,6 +75,21 @@ If a system keyring is available and supported, the password is stored to and re
Keyring support is enabled using the [keyring library](https://pypi.org/project/keyring/). For more information on supported backends refer to the [library documentation](https://keyring.readthedocs.io/en/latest/?badge=latest). Keyring support is enabled using the [keyring library](https://pypi.org/project/keyring/). For more information on supported backends refer to the [library documentation](https://keyring.readthedocs.io/en/latest/?badge=latest).
{{% note %}}
Poetry will fallback to Pip style use of keyring so that backends like
Microsoft's [artifacts-keyring](https://pypi.org/project/artifacts-keyring/) get a change to retrieve
valid credentials. It will need to be properly installed into Poetry's virtualenv,
preferrably by installing a plugin.
If you are letting Poetry manage your virtual environments you will want a virtualenv
seeder installed in Poetry's virtualenv that installs the desired keyring backend
during `poetry install`. To again use Azure DevOps as an example: [azure-devops-artifacts-helpers](https://pypi.org/project/azure-devops-artifacts-helpers/)
provides such a seeder. This would of course best achieved by installing a Poetry plugin
if it exists for you use case instead of doing it yourself.
{{% /note %}}
Alternatively, you can use environment variables to provide the credentials: Alternatively, you can use environment variables to provide the credentials:
```bash ```bash
......
...@@ -24,8 +24,8 @@ from poetry.utils.env import EnvCommandError ...@@ -24,8 +24,8 @@ from poetry.utils.env import EnvCommandError
from poetry.utils.helpers import safe_rmtree from poetry.utils.helpers import safe_rmtree
from poetry.utils.pip import pip_editable_install from poetry.utils.pip import pip_editable_install
from ..utils.authenticator import Authenticator
from ..utils.pip import pip_install from ..utils.pip import pip_install
from .authenticator import Authenticator
from .chef import Chef from .chef import Chef
from .chooser import Chooser from .chooser import Chooser
from .operations.install import Install from .operations.install import Install
......
...@@ -6,10 +6,9 @@ from typing import List ...@@ -6,10 +6,9 @@ from typing import List
from typing import Optional from typing import Optional
from typing import Union from typing import Union
from poetry.utils.helpers import get_cert from ..utils.authenticator import Authenticator
from poetry.utils.helpers import get_client_cert from ..utils.helpers import get_cert
from poetry.utils.password_manager import PasswordManager from ..utils.helpers import get_client_cert
from .uploader import Uploader from .uploader import Uploader
...@@ -32,7 +31,7 @@ class Publisher: ...@@ -32,7 +31,7 @@ class Publisher:
self._package = poetry.package self._package = poetry.package
self._io = io self._io = io
self._uploader = Uploader(poetry, io) self._uploader = Uploader(poetry, io)
self._password_manager = PasswordManager(poetry.config) self._authenticator = Authenticator(poetry.config, self._io)
@property @property
def files(self) -> List[Path]: def files(self) -> List[Path]:
...@@ -58,13 +57,13 @@ class Publisher: ...@@ -58,13 +57,13 @@ class Publisher:
if not (username and password): if not (username and password):
# Check if we have a token first # Check if we have a token first
token = self._password_manager.get_pypi_token(repository_name) token = self._authenticator.get_pypi_token(repository_name)
if token: if token:
logger.debug(f"Found an API token for {repository_name}.") logger.debug(f"Found an API token for {repository_name}.")
username = "__token__" username = "__token__"
password = token password = token
else: else:
auth = self._password_manager.get_http_auth(repository_name) auth = self._authenticator.get_http_auth(repository_name)
if auth: if auth:
logger.debug( logger.debug(
"Found authentication information for {}.".format( "Found authentication information for {}.".format(
......
...@@ -34,7 +34,7 @@ from poetry.utils.patterns import wheel_file_re ...@@ -34,7 +34,7 @@ from poetry.utils.patterns import wheel_file_re
from ..config.config import Config from ..config.config import Config
from ..inspection.info import PackageInfo from ..inspection.info import PackageInfo
from ..installation.authenticator import Authenticator from ..utils.authenticator import Authenticator
from .exceptions import PackageNotFound from .exceptions import PackageNotFound
from .exceptions import RepositoryError from .exceptions import RepositoryError
from .pypi_repository import PyPiRepository from .pypi_repository import PyPiRepository
......
...@@ -4,6 +4,7 @@ import urllib.parse ...@@ -4,6 +4,7 @@ import urllib.parse
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
from typing import Dict
from typing import Optional from typing import Optional
from typing import Tuple from typing import Tuple
...@@ -108,7 +109,7 @@ class Authenticator: ...@@ -108,7 +109,7 @@ class Authenticator:
if credentials == (None, None): if credentials == (None, None):
if "@" not in netloc: if "@" not in netloc:
credentials = self._get_credentials_for_netloc_from_config(netloc) credentials = self._get_credentials_for_netloc(netloc)
else: else:
# Split from the right because that's how urllib.parse.urlsplit() # Split from the right because that's how urllib.parse.urlsplit()
# behaves if more than one @ is present (which can be checked using # behaves if more than one @ is present (which can be checked using
...@@ -133,24 +134,42 @@ class Authenticator: ...@@ -133,24 +134,42 @@ class Authenticator:
return credentials[0], credentials[1] return credentials[0], credentials[1]
def _get_credentials_for_netloc_from_config( def get_pypi_token(self, name: str) -> str:
self, netloc: str return self._password_manager.get_pypi_token(name)
) -> Tuple[Optional[str], Optional[str]]:
credentials = (None, None)
for repository_name in self._config.get("repositories", []): def get_http_auth(self, name: str) -> Optional[Dict[str, str]]:
repository_config = self._config.get(f"repositories.{repository_name}") return self._get_http_auth(name, None)
if not repository_config:
continue
url = repository_config.get("url") def _get_http_auth(
self, name: str, netloc: Optional[str]
) -> Optional[Dict[str, str]]:
if name == "pypi":
url = "https://upload.pypi.org/legacy/"
else:
url = self._config.get(f"repositories.{name}.url")
if not url: if not url:
continue return
parsed_url = urllib.parse.urlsplit(url) parsed_url = urllib.parse.urlsplit(url)
if netloc == parsed_url.netloc: if netloc is None or netloc == parsed_url.netloc:
auth = self._password_manager.get_http_auth(repository_name) auth = self._password_manager.get_http_auth(name)
if auth is None or auth["password"] is None:
username = auth["username"] if auth else None
auth = self._get_credentials_for_netloc_from_keyring(
url, parsed_url.netloc, username
)
return auth
def _get_credentials_for_netloc(
self, netloc: str
) -> Tuple[Optional[str], Optional[str]]:
credentials = (None, None)
for repository_name in self._config.get("repositories", []):
auth = self._get_http_auth(repository_name, netloc)
if auth is None: if auth is None:
continue continue
...@@ -158,3 +177,30 @@ class Authenticator: ...@@ -158,3 +177,30 @@ class Authenticator:
return auth["username"], auth["password"] return auth["username"], auth["password"]
return credentials return credentials
def _get_credentials_for_netloc_from_keyring(
self, url: str, netloc: str, username: Optional[str]
) -> Optional[Dict[str, str]]:
import keyring
cred = keyring.get_credential(url, username)
if cred is not None:
return {
"username": cred.username,
"password": cred.password,
}
cred = keyring.get_credential(netloc, username)
if cred is not None:
return {
"username": cred.username,
"password": cred.password,
}
if username:
return {
"username": username,
"password": None,
}
return None
...@@ -12,6 +12,7 @@ import httpretty ...@@ -12,6 +12,7 @@ import httpretty
import pytest import pytest
from cleo.testers.command_tester import CommandTester from cleo.testers.command_tester import CommandTester
from keyring.backend import KeyringBackend
from poetry.config.config import Config as BaseConfig from poetry.config.config import Config as BaseConfig
from poetry.config.dict_config_source import DictConfigSource from poetry.config.dict_config_source import DictConfigSource
...@@ -53,6 +54,61 @@ class Config(BaseConfig): ...@@ -53,6 +54,61 @@ class Config(BaseConfig):
return super(Config, self).all() return super(Config, self).all()
class DummyBackend(KeyringBackend):
def __init__(self):
self._passwords = {}
@classmethod
def priority(cls):
return 42
def set_password(self, service, username, password):
self._passwords[service] = {username: password}
def get_password(self, service, username):
return self._passwords.get(service, {}).get(username)
def get_credential(self, service, username):
return self._passwords.get(service, {}).get(username)
def delete_password(self, service, username):
if service in self._passwords and username in self._passwords[service]:
del self._passwords[service][username]
@pytest.fixture()
def dummy_keyring():
return DummyBackend()
@pytest.fixture()
def with_simple_keyring(dummy_keyring):
import keyring
keyring.set_keyring(dummy_keyring)
@pytest.fixture()
def with_fail_keyring():
import keyring
from keyring.backends.fail import Keyring
keyring.set_keyring(Keyring())
@pytest.fixture()
def with_chained_keyring(mocker):
from keyring.backends.fail import Keyring
mocker.patch("keyring.backend.get_all_keyring", [Keyring()])
import keyring
from keyring.backends.chainer import ChainerBackend
keyring.set_keyring(ChainerBackend())
@pytest.fixture @pytest.fixture
def config_cache_dir(tmp_dir): def config_cache_dir(tmp_dir):
path = Path(tmp_dir) / ".cache" / "pypoetry" path = Path(tmp_dir) / ".cache" / "pypoetry"
......
...@@ -156,13 +156,13 @@ def test_create_poetry_with_multi_constraints_dependency(): ...@@ -156,13 +156,13 @@ def test_create_poetry_with_multi_constraints_dependency():
assert len(package.requires) == 2 assert len(package.requires) == 2
def test_poetry_with_default_source(): def test_poetry_with_default_source(with_simple_keyring):
poetry = Factory().create_poetry(fixtures_dir / "with_default_source") poetry = Factory().create_poetry(fixtures_dir / "with_default_source")
assert 1 == len(poetry.pool.repositories) assert 1 == len(poetry.pool.repositories)
def test_poetry_with_non_default_source(): def test_poetry_with_non_default_source(with_simple_keyring):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_source") poetry = Factory().create_poetry(fixtures_dir / "with_non_default_source")
assert len(poetry.pool.repositories) == 2 assert len(poetry.pool.repositories) == 2
...@@ -176,7 +176,7 @@ def test_poetry_with_non_default_source(): ...@@ -176,7 +176,7 @@ def test_poetry_with_non_default_source():
assert isinstance(poetry.pool.repositories[1], PyPiRepository) assert isinstance(poetry.pool.repositories[1], PyPiRepository)
def test_poetry_with_non_default_secondary_source(): def test_poetry_with_non_default_secondary_source(with_simple_keyring):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_secondary_source") poetry = Factory().create_poetry(fixtures_dir / "with_non_default_secondary_source")
assert len(poetry.pool.repositories) == 2 assert len(poetry.pool.repositories) == 2
...@@ -192,7 +192,7 @@ def test_poetry_with_non_default_secondary_source(): ...@@ -192,7 +192,7 @@ def test_poetry_with_non_default_secondary_source():
assert isinstance(repository, LegacyRepository) assert isinstance(repository, LegacyRepository)
def test_poetry_with_non_default_multiple_secondary_sources(): def test_poetry_with_non_default_multiple_secondary_sources(with_simple_keyring):
poetry = Factory().create_poetry( poetry = Factory().create_poetry(
fixtures_dir / "with_non_default_multiple_secondary_sources" fixtures_dir / "with_non_default_multiple_secondary_sources"
) )
...@@ -214,7 +214,7 @@ def test_poetry_with_non_default_multiple_secondary_sources(): ...@@ -214,7 +214,7 @@ def test_poetry_with_non_default_multiple_secondary_sources():
assert isinstance(repository, LegacyRepository) assert isinstance(repository, LegacyRepository)
def test_poetry_with_non_default_multiple_sources(): def test_poetry_with_non_default_multiple_sources(with_simple_keyring):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_multiple_sources") poetry = Factory().create_poetry(fixtures_dir / "with_non_default_multiple_sources")
assert len(poetry.pool.repositories) == 3 assert len(poetry.pool.repositories) == 3
...@@ -245,7 +245,7 @@ def test_poetry_with_no_default_source(): ...@@ -245,7 +245,7 @@ def test_poetry_with_no_default_source():
assert isinstance(poetry.pool.repositories[0], PyPiRepository) assert isinstance(poetry.pool.repositories[0], PyPiRepository)
def test_poetry_with_two_default_sources(): def test_poetry_with_two_default_sources(with_simple_keyring):
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Factory().create_poetry(fixtures_dir / "with_two_default_sources") Factory().create_poetry(fixtures_dir / "with_two_default_sources")
......
...@@ -7,7 +7,13 @@ import requests ...@@ -7,7 +7,13 @@ import requests
from cleo.io.null_io import NullIO from cleo.io.null_io import NullIO
from poetry.installation.authenticator import Authenticator from poetry.utils.authenticator import Authenticator
class SimpleCredential:
def __init__(self, username, password):
self.username = username
self.password = password
@pytest.fixture() @pytest.fixture()
...@@ -52,7 +58,9 @@ def test_authenticator_uses_credentials_from_config_if_not_provided( ...@@ -52,7 +58,9 @@ def test_authenticator_uses_credentials_from_config_if_not_provided(
assert "Basic YmFyOmJheg==" == request.headers["Authorization"] assert "Basic YmFyOmJheg==" == request.headers["Authorization"]
def test_authenticator_uses_username_only_credentials(config, mock_remote, http): def test_authenticator_uses_username_only_credentials(
config, mock_remote, http, with_simple_keyring
):
config.merge( config.merge(
{ {
"repositories": {"foo": {"url": "https://foo.bar/simple/"}}, "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
...@@ -85,7 +93,7 @@ def test_authenticator_uses_password_only_credentials(config, mock_remote, http) ...@@ -85,7 +93,7 @@ def test_authenticator_uses_password_only_credentials(config, mock_remote, http)
def test_authenticator_uses_empty_strings_as_default_password( def test_authenticator_uses_empty_strings_as_default_password(
config, mock_remote, http config, mock_remote, http, with_simple_keyring
): ):
config.merge( config.merge(
{ {
...@@ -120,6 +128,46 @@ def test_authenticator_uses_empty_strings_as_default_username( ...@@ -120,6 +128,46 @@ def test_authenticator_uses_empty_strings_as_default_username(
assert "Basic OmJhcg==" == request.headers["Authorization"] assert "Basic OmJhcg==" == request.headers["Authorization"]
def test_authenticator_falls_back_to_keyring_url(
config, mock_remote, http, with_simple_keyring, dummy_keyring
):
config.merge(
{
"repositories": {"foo": {"url": "https://foo.bar/simple/"}},
}
)
dummy_keyring.set_password(
"https://foo.bar/simple/", None, SimpleCredential(None, "bar")
)
authenticator = Authenticator(config, NullIO())
authenticator.request("get", "https://foo.bar/files/foo-0.1.0.tar.gz")
request = http.last_request()
assert "Basic OmJhcg==" == request.headers["Authorization"]
def test_authenticator_falls_back_to_keyring_netloc(
config, mock_remote, http, with_simple_keyring, dummy_keyring
):
config.merge(
{
"repositories": {"foo": {"url": "https://foo.bar/simple/"}},
}
)
dummy_keyring.set_password("foo.bar", None, SimpleCredential(None, "bar"))
authenticator = Authenticator(config, NullIO())
authenticator.request("get", "https://foo.bar/files/foo-0.1.0.tar.gz")
request = http.last_request()
assert "Basic OmJhcg==" == request.headers["Authorization"]
def test_authenticator_request_retries_on_exception(mocker, config, http): def test_authenticator_request_retries_on_exception(mocker, config, http):
sleep = mocker.patch("time.sleep") sleep = mocker.patch("time.sleep")
sdist_uri = "https://foo.bar/files/{}/foo-0.1.0.tar.gz".format(str(uuid.uuid4())) sdist_uri = "https://foo.bar/files/{}/foo-0.1.0.tar.gz".format(str(uuid.uuid4()))
......
...@@ -2,80 +2,26 @@ import os ...@@ -2,80 +2,26 @@ import os
import pytest import pytest
from keyring.backend import KeyringBackend
from poetry.utils.password_manager import KeyRing from poetry.utils.password_manager import KeyRing
from poetry.utils.password_manager import KeyRingError from poetry.utils.password_manager import KeyRingError
from poetry.utils.password_manager import PasswordManager from poetry.utils.password_manager import PasswordManager
class DummyBackend(KeyringBackend): def test_set_http_password(config, with_simple_keyring, dummy_keyring):
def __init__(self):
self._passwords = {}
@classmethod
def priority(cls):
return 42
def set_password(self, service, username, password):
self._passwords[service] = {username: password}
def get_password(self, service, username):
return self._passwords.get(service, {}).get(username)
def delete_password(self, service, username):
if service in self._passwords and username in self._passwords[service]:
del self._passwords[service][username]
@pytest.fixture()
def backend():
return DummyBackend()
@pytest.fixture()
def mock_available_backend(backend):
import keyring
keyring.set_keyring(backend)
@pytest.fixture()
def mock_unavailable_backend():
import keyring
from keyring.backends.fail import Keyring
keyring.set_keyring(Keyring())
@pytest.fixture()
def mock_chainer_backend(mocker):
from keyring.backends.fail import Keyring
mocker.patch("keyring.backend.get_all_keyring", [Keyring()])
import keyring
from keyring.backends.chainer import ChainerBackend
keyring.set_keyring(ChainerBackend())
def test_set_http_password(config, mock_available_backend, backend):
manager = PasswordManager(config) manager = PasswordManager(config)
assert manager.keyring.is_available() assert manager.keyring.is_available()
manager.set_http_password("foo", "bar", "baz") manager.set_http_password("foo", "bar", "baz")
assert "baz" == backend.get_password("poetry-repository-foo", "bar") assert "baz" == dummy_keyring.get_password("poetry-repository-foo", "bar")
auth = config.get("http-basic.foo") auth = config.get("http-basic.foo")
assert "bar" == auth["username"] assert "bar" == auth["username"]
assert "password" not in auth assert "password" not in auth
def test_get_http_auth(config, mock_available_backend, backend): def test_get_http_auth(config, with_simple_keyring, dummy_keyring):
backend.set_password("poetry-repository-foo", "bar", "baz") dummy_keyring.set_password("poetry-repository-foo", "bar", "baz")
config.auth_config_source.add_property("http-basic.foo", {"username": "bar"}) config.auth_config_source.add_property("http-basic.foo", {"username": "bar"})
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -86,19 +32,19 @@ def test_get_http_auth(config, mock_available_backend, backend): ...@@ -86,19 +32,19 @@ def test_get_http_auth(config, mock_available_backend, backend):
assert "baz" == auth["password"] assert "baz" == auth["password"]
def test_delete_http_password(config, mock_available_backend, backend): def test_delete_http_password(config, with_simple_keyring, dummy_keyring):
backend.set_password("poetry-repository-foo", "bar", "baz") dummy_keyring.set_password("poetry-repository-foo", "bar", "baz")
config.auth_config_source.add_property("http-basic.foo", {"username": "bar"}) config.auth_config_source.add_property("http-basic.foo", {"username": "bar"})
manager = PasswordManager(config) manager = PasswordManager(config)
assert manager.keyring.is_available() assert manager.keyring.is_available()
manager.delete_http_password("foo") manager.delete_http_password("foo")
assert backend.get_password("poetry-repository-foo", "bar") is None assert dummy_keyring.get_password("poetry-repository-foo", "bar") is None
assert config.get("http-basic.foo") is None assert config.get("http-basic.foo") is None
def test_set_pypi_token(config, mock_available_backend, backend): def test_set_pypi_token(config, with_simple_keyring, dummy_keyring):
manager = PasswordManager(config) manager = PasswordManager(config)
assert manager.keyring.is_available() assert manager.keyring.is_available()
...@@ -106,28 +52,28 @@ def test_set_pypi_token(config, mock_available_backend, backend): ...@@ -106,28 +52,28 @@ def test_set_pypi_token(config, mock_available_backend, backend):
assert config.get("pypi-token.foo") is None assert config.get("pypi-token.foo") is None
assert "baz" == backend.get_password("poetry-repository-foo", "__token__") assert "baz" == dummy_keyring.get_password("poetry-repository-foo", "__token__")
def test_get_pypi_token(config, mock_available_backend, backend): def test_get_pypi_token(config, with_simple_keyring, dummy_keyring):
backend.set_password("poetry-repository-foo", "__token__", "baz") dummy_keyring.set_password("poetry-repository-foo", "__token__", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
assert manager.keyring.is_available() assert manager.keyring.is_available()
assert "baz" == manager.get_pypi_token("foo") assert "baz" == manager.get_pypi_token("foo")
def test_delete_pypi_token(config, mock_available_backend, backend): def test_delete_pypi_token(config, with_simple_keyring, dummy_keyring):
backend.set_password("poetry-repository-foo", "__token__", "baz") dummy_keyring.set_password("poetry-repository-foo", "__token__", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
assert manager.keyring.is_available() assert manager.keyring.is_available()
manager.delete_pypi_token("foo") manager.delete_pypi_token("foo")
assert backend.get_password("poetry-repository-foo", "__token__") is None assert dummy_keyring.get_password("poetry-repository-foo", "__token__") is None
def test_set_http_password_with_unavailable_backend(config, mock_unavailable_backend): def test_set_http_password_with_unavailable_backend(config, with_fail_keyring):
manager = PasswordManager(config) manager = PasswordManager(config)
assert not manager.keyring.is_available() assert not manager.keyring.is_available()
...@@ -138,7 +84,7 @@ def test_set_http_password_with_unavailable_backend(config, mock_unavailable_bac ...@@ -138,7 +84,7 @@ def test_set_http_password_with_unavailable_backend(config, mock_unavailable_bac
assert "baz" == auth["password"] assert "baz" == auth["password"]
def test_get_http_auth_with_unavailable_backend(config, mock_unavailable_backend): def test_get_http_auth_with_unavailable_backend(config, with_fail_keyring):
config.auth_config_source.add_property( config.auth_config_source.add_property(
"http-basic.foo", {"username": "bar", "password": "baz"} "http-basic.foo", {"username": "bar", "password": "baz"}
) )
...@@ -151,9 +97,7 @@ def test_get_http_auth_with_unavailable_backend(config, mock_unavailable_backend ...@@ -151,9 +97,7 @@ def test_get_http_auth_with_unavailable_backend(config, mock_unavailable_backend
assert "baz" == auth["password"] assert "baz" == auth["password"]
def test_delete_http_password_with_unavailable_backend( def test_delete_http_password_with_unavailable_backend(config, with_fail_keyring):
config, mock_unavailable_backend
):
config.auth_config_source.add_property( config.auth_config_source.add_property(
"http-basic.foo", {"username": "bar", "password": "baz"} "http-basic.foo", {"username": "bar", "password": "baz"}
) )
...@@ -165,7 +109,7 @@ def test_delete_http_password_with_unavailable_backend( ...@@ -165,7 +109,7 @@ def test_delete_http_password_with_unavailable_backend(
assert config.get("http-basic.foo") is None assert config.get("http-basic.foo") is None
def test_set_pypi_token_with_unavailable_backend(config, mock_unavailable_backend): def test_set_pypi_token_with_unavailable_backend(config, with_fail_keyring):
manager = PasswordManager(config) manager = PasswordManager(config)
assert not manager.keyring.is_available() assert not manager.keyring.is_available()
...@@ -174,7 +118,7 @@ def test_set_pypi_token_with_unavailable_backend(config, mock_unavailable_backen ...@@ -174,7 +118,7 @@ def test_set_pypi_token_with_unavailable_backend(config, mock_unavailable_backen
assert "baz" == config.get("pypi-token.foo") assert "baz" == config.get("pypi-token.foo")
def test_get_pypi_token_with_unavailable_backend(config, mock_unavailable_backend): def test_get_pypi_token_with_unavailable_backend(config, with_fail_keyring):
config.auth_config_source.add_property("pypi-token.foo", "baz") config.auth_config_source.add_property("pypi-token.foo", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -182,7 +126,7 @@ def test_get_pypi_token_with_unavailable_backend(config, mock_unavailable_backen ...@@ -182,7 +126,7 @@ def test_get_pypi_token_with_unavailable_backend(config, mock_unavailable_backen
assert "baz" == manager.get_pypi_token("foo") assert "baz" == manager.get_pypi_token("foo")
def test_delete_pypi_token_with_unavailable_backend(config, mock_unavailable_backend): def test_delete_pypi_token_with_unavailable_backend(config, with_fail_keyring):
config.auth_config_source.add_property("pypi-token.foo", "baz") config.auth_config_source.add_property("pypi-token.foo", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -192,7 +136,7 @@ def test_delete_pypi_token_with_unavailable_backend(config, mock_unavailable_bac ...@@ -192,7 +136,7 @@ def test_delete_pypi_token_with_unavailable_backend(config, mock_unavailable_bac
assert config.get("pypi-token.foo") is None assert config.get("pypi-token.foo") is None
def test_keyring_raises_errors_on_keyring_errors(mocker, mock_unavailable_backend): def test_keyring_raises_errors_on_keyring_errors(mocker, with_fail_keyring):
mocker.patch("poetry.utils.password_manager.KeyRing._check") mocker.patch("poetry.utils.password_manager.KeyRing._check")
key_ring = KeyRing("poetry") key_ring = KeyRing("poetry")
...@@ -207,16 +151,14 @@ def test_keyring_raises_errors_on_keyring_errors(mocker, mock_unavailable_backen ...@@ -207,16 +151,14 @@ def test_keyring_raises_errors_on_keyring_errors(mocker, mock_unavailable_backen
def test_keyring_with_chainer_backend_and_not_compatible_only_should_be_unavailable( def test_keyring_with_chainer_backend_and_not_compatible_only_should_be_unavailable(
mock_chainer_backend, with_chained_keyring,
): ):
key_ring = KeyRing("poetry") key_ring = KeyRing("poetry")
assert not key_ring.is_available() assert not key_ring.is_available()
def test_get_http_auth_from_environment_variables( def test_get_http_auth_from_environment_variables(environ, config, with_simple_keyring):
environ, config, mock_available_backend
):
os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar" os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar"
os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz" os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz"
......
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