diff --git a/README.md b/README.md index 15ac016..c05805e 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,20 @@ hosted within CodeArtifact. It will use any appropriate AWS credentials provided --index-url https://${DOMAIN}-${ACCOUNT}.d.codeartifact.${REGION}.amazonaws.com/pypi/${REPOSITORY}/simple/ ``` +### Environment Variable + +You can bypass AWS API calls by setting the `CODEARTIFACT_AUTH_TOKEN` environment variable: + +```bash +# Set the environment variable with a valid token +export CODEARTIFACT_AUTH_TOKEN=your-auth-token-here + +# Then use pip/twine as usual, and the token will be used automatically +pip install package-name --index-url https://${DOMAIN}-${ACCOUNT}.d.codeartifact.${REGION}.amazonaws.com/pypi/${REPOSITORY}/simple/ +``` + +This is especially useful in CI/CD environments or when you want to avoid making AWS API calls. + Config ------ This backend provides a number of configuration options to modify the behaviour of the AWS client. diff --git a/keyrings/codeartifact.py b/keyrings/codeartifact.py index 907333d..54ff795 100644 --- a/keyrings/codeartifact.py +++ b/keyrings/codeartifact.py @@ -1,5 +1,6 @@ # codeartifact.py -- keyring backend +import os import re import logging @@ -144,6 +145,21 @@ def get_credential(self, service, username): return credentials.SimpleCredential("aws", authorization_token) def get_password(self, service, username): + + # Get the environment variable name from config defaults (if provided), + # otherwise fall back to the standard CODEARTIFACT_AUTH_TOKEN. + # Note: self.config is a CodeArtifactKeyringConfig, not a dict. + env_variable_name = ( + getattr(self.config, "defaults", {}) + .get("env_variable", "CODEARTIFACT_AUTH_TOKEN") + ) + + # Check for token in environment variable + token_from_env = os.getenv(env_variable_name) + if token_from_env: + logging.info(f"Using token from environment variable: {env_variable_name}") + return token_from_env + url = urlparse(service) # Do a quick check to see if this service URL applies to us. diff --git a/tests/test_backend.py b/tests/test_backend.py index 549ac1b..d52eebb 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -170,4 +170,24 @@ def make_client(options): config = CodeArtifactKeyringConfig(config_file=config_file.name) backend = CodeArtifactBackend(config=config, make_client=make_client) url = codeartifact_pypi_url("domain", "000000000000", "region", "name") - credentials = backend.get_credential(url, None) + backend.get_credential(url, None) + + +def test_get_credential_from_env(monkeypatch): + """ + Tests that the backend can retrieve a token from an environment variable. + """ + monkeypatch.setenv("CODEARTIFACT_AUTH_TOKEN", "ENV_TOKEN") + + def make_client(options): + # This should not be called when token is in env + pytest.fail("make_client should not be called when token is in env") + + config = CodeArtifactKeyringConfig(config_file=StringIO()) + backend = CodeArtifactBackend(config=config, make_client=make_client) + + url = codeartifact_pypi_url("domain", "000000000000", "region", "name") + credentials = backend.get_credential(url, None) + + assert credentials.username == "aws" + assert credentials.password == "ENV_TOKEN"