Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions keyrings/codeartifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ def make_codeartifact_client(options):


class CodeArtifactBackend(backend.KeyringBackend):
HOST_REGEX = r"^(.+)-(\d{12})\.d\.codeartifact\.([^\.]+)\.amazonaws\.com$"
# Classic and dualstack (IPv6-capable) repository endpoint hostnames.
HOST_REGEXES = (
r"^(.+)-(\d{12})\.d\.codeartifact\.([^\.]+)\.amazonaws\.com$",
r"^(.+)-(\d{12})\.codeartifact\.([^\.]+)\.on\.aws$",
)
PATH_REGEX = r"^/pypi/([^/]+)/?"

priority = 9.9
Expand Down Expand Up @@ -147,11 +151,17 @@ def get_password(self, service, username):
url = urlparse(service)

# Do a quick check to see if this service URL applies to us.
if url.hostname is None or not url.hostname.endswith(".amazonaws.com"):
if url.hostname is None or not url.hostname.endswith(
(".amazonaws.com", ".on.aws")
):
return

# Split the hostname into its components.
host_match = re.fullmatch(self.HOST_REGEX, url.hostname)
host_match = None
for pattern in self.HOST_REGEXES:
host_match = re.fullmatch(pattern, url.hostname)
if host_match:
break

# If it didn't match the regex, it doesn't apply to us.
if not host_match:
Expand Down
17 changes: 11 additions & 6 deletions tests/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,17 @@ def current_time():
return datetime.now(tz=tzinfo)


def codeartifact_url(domain, owner, region, path):
netloc = f"{domain}-{owner}.d.codeartifact.{region}.amazonaws.com"
CLASSIC_NETLOC = "{domain}-{owner}.d.codeartifact.{region}.amazonaws.com"
DUALSTACK_NETLOC = "{domain}-{owner}.codeartifact.{region}.on.aws"


def codeartifact_url(domain, owner, region, path, netloc_format=CLASSIC_NETLOC):
netloc = netloc_format.format(domain=domain, owner=owner, region=region)
return urlunparse(("https", netloc, path, "", "", ""))


def codeartifact_pypi_url(domain, owner, region, name):
return codeartifact_url(domain, owner, region, f"/pypi/{name}/")
def codeartifact_pypi_url(domain, owner, region, name, netloc_format=CLASSIC_NETLOC):
return codeartifact_url(domain, owner, region, f"/pypi/{name}/", netloc_format)


@contextmanager
Expand All @@ -45,7 +49,8 @@ def config_from_string(content: str):
yield cfg


def test_get_credential_supported_host():
@pytest.mark.parametrize("netloc_format", [CLASSIC_NETLOC, DUALSTACK_NETLOC])
def test_get_credential_supported_host(netloc_format):
def make_client(options):
client = make_codeartifact_client(options)
stubber = Stubber(client)
Expand All @@ -71,7 +76,7 @@ def make_client(options):
config = CodeArtifactKeyringConfig(config_file=StringIO())
backend = CodeArtifactBackend(config=config, make_client=make_client)

url = codeartifact_pypi_url("domain", "000000000000", "region", "name")
url = codeartifact_pypi_url("domain", "000000000000", "region", "name", netloc_format)
credentials = backend.get_credential(url, None)

assert credentials.username == "aws"
Expand Down
7 changes: 7 additions & 0 deletions tests/test_keyring.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ def codeartifact_url(domain, owner, region, path):
return urlunparse(("https", netloc, path, "", "", ""))


def codeartifact_dualstack_url(domain, owner, region, path):
netloc = f"{domain}-{owner}.codeartifact.{region}.on.aws"
return urlunparse(("https", netloc, path, "", "", ""))


def codeartifact_pypi_url(domain, owner, region, name):
return codeartifact_url(domain, owner, region, f"/pypi/{name}/")

Expand Down Expand Up @@ -44,7 +49,9 @@ def test_delete_password_raises(backend):
[
"https://example.com/",
"https://unknown.amazonaws.com/",
"https://unknown.on.aws/",
codeartifact_url("domain", "owner", "region", "/maven/repo/"),
codeartifact_dualstack_url("domain", "owner", "region", "/maven/repo/"),
],
)
def test_get_credential_unsupported_host(backend, service):
Expand Down
Loading