Chainguard Libraries for Python overview
Learn about Chainguard Libraries for Python, providing enhanced security for PyPI packages through automated …
For the complete documentation index, see llms.txt.
Chainguard Libraries for Python provides a curated index of PyPI packages rebuilt from source and verified against Chainguard’s build provenance. Because Chainguard Libraries uses the standard pip simple-index protocol, switching an existing project requires only an index configuration change — no changes to your application code or dependency declarations.
This guide walks through migrating an existing Python project to Chainguard Libraries, covering the two most common setups:
libraries.cgr.dev. This option is faster for initial evaluation and smaller-scale setups.Before you begin, you need:
requirements.txt, poetry.lock, uv.lock, pdm.lock, Pipfile.lock, or pylock.tomlIf you do not have an entitlement to Chainguard Libraries for Python yet, run the following command to create an entitlement and enable upstream fallback:
chainctl libraries entitlements create --ecosystems=PYTHON --policy=CHAINGUARD_AND_UPSTREAMIt can take up to 30 minutes for fallback policy changes to take effect.
For authentication, you need a pull token or the Python keyring provider.
If you plan to use a repository manager, or a non-interactive environment such as CI/CD, you will need a pull token. You must have the owner role or have the libraries.python.pull_token_creator permission to create one.
chainctl auth pull-token create --repository=python --name=my-python-token --ttl=720hTo export environment variables directly:
eval $(chainctl auth pull-token --output env --repository=python --name=my-python-token)Learn more about creating and managing pull tokens in the Libraries Access documentation.
The keyring leverages chainctl to fetch temporary credentials whenever your environment requests packages from Chainguard. Supported environments include local development and CI/CD platforms that can use assumable identities. The keyring provider requires pip 23.1 or later.
Learn how to install this package in the Chainguard Libraries Access documentation.
Note that .netrc takes precedence over the keyring. Verify that you do not have an existing registry entry in .netrc for Chainguard Libraries:
grep -A2 "libraries.cgr.dev" ~/.netrcRemove or correct any stale entry before proceeding.
Note: Do not commit credentials to version control. Store tokens as environment variables or CI secrets, not as literal values in
pip.conf,.netrc, or any file that might be checked into a repository.
How you configure the index depends on your environment. Follow the instructions that match your setup.
The https://libraries.cgr.dev/python/ endpoint is also the Chainguard Repository endpoint for Python. By default, it serves only Chainguard-built artifacts. When upstream fallback is enabled for your organization, the same endpoint can also serve requested versions from PyPI under Chainguard security controls.
First, configure authentication using a pull token or the Python keyring provider.
Setting pull token credentials in .netrc is a common approach for individual work stations. Setting authentication in pip.conf is preferred for CI/CD, where you need credentials isolated per project or per pipeline rather than a single shared home-directory file.
Note:
.netrconly supports one set of credentials per hostname. Since all Chainguard Libraries are served fromlibraries.cgr.dev, configuring.netrcfor Python will override credentials for any other ecosystem.
First, check for an existing registry entry in .netrc:
grep -A2 "libraries.cgr.dev" ~/.netrcRemove or correct any stale entry before proceeding.
Then, configure your pull token credentials in .netrc:
cat >> ~/.netrc << EOF
machine libraries.cgr.dev
login ${CHAINGUARD_PYTHON_IDENTITY_ID}
password ${CHAINGUARD_PYTHON_TOKEN}
EOF
chmod 600 ~/.netrcUnlike .netrc, pip.conf can be scoped per project or per pipeline rather than shared globally across a whole workstation.
First, check whether an index or credentials are already configured
elsewhere, since a global pip.conf or environment variable can silently
override a project-scoped one:
pip config list -v
env | grep -i pipThen create a project-scoped config file rather than editing the global
~/.pip/pip.conf. This example sets the remediated repository first, with
the standard repository as a fallback, and embeds pull token credentials directly in
each URL:
mkdir -p .pip
cat > .pip/pip.conf << EOF
[global]
index-url = https://${CHAINGUARD_PYTHON_IDENTITY_ID}:${CHAINGUARD_PYTHON_TOKEN}@libraries.cgr.dev/python-remediated/simple/
extra-index-url = https://${CHAINGUARD_PYTHON_IDENTITY_ID}:${CHAINGUARD_PYTHON_TOKEN}@libraries.cgr.dev/python/simple/
EOFPoint pip at it with the PIP_CONFIG_FILE environment variable, scoped to
your current shell or CI job:
export PIP_CONFIG_FILE="$(pwd)/.pip/pip.conf"This method sets both the index and its credentials in one step.
Note: Do not commit credentials to version control. Generate
.pip/pip.confat build time from CI secrets, as shown in this section, rather than committing a version with a literal token embedded in the URL. Add.pip/to.gitignoreif you create it locally with real credentials for testing.
The keyrings-chainguard-libraries package supplies short-lived credentials automatically via chainctl, avoiding static tokens on your local workstation.
Follow the instructions to install the keyring package.
Note: After switching to Chainguard, you can reinstall the keyring package to use the Chainguard-built version.
Next, point your build tool at the Chainguard index.
Note that Chainguard publishes both standard and remediated Python indexes. Remediated versions use a +cgr.N local-version suffix, and Python package managers treat those as compatible higher-precedence replacements for the base version. In addition, CUDA-enabled Python libraries use separate CUDA-specific indexes such as https://libraries.cgr.dev/cu128/simple/, and they are not dependency-complete for NVIDIA toolkit components.
If you configured authentication via .netrc or the Python keyring provider, run the following commands to set the remediated repository first, then the simple repository:
pip config set global.index-url https://libraries.cgr.dev/python-remediated/simple/
pip config set global.extra-index-url https://libraries.cgr.dev/python/simple/If you configured authentication via pull token credentials in pip.conf, this step
is already done; the index-url you set in .pip/pip.conf already points
at Chainguard with credentials embedded.
Edit the pyproject.toml for project-level or the ~/.config/uv/uv.toml to make global-level changes, setting the remediated repository first:
[tool.uv]
index-strategy = "unsafe-best-match"
[[tool.uv.index]]
name = "cgr-pr"
url = "https://libraries.cgr.dev/python-remediated/simple"
authenticate = "always"
[[tool.uv.index]]
name = "cgr-p"
url = "https://libraries.cgr.dev/python/simple"
authenticate = "always"When using the remediated index, set index-strategy = "unsafe-best-match" so uv can resolve dependencies that fall back from remediated to non-remediated packages.
If you are using the Python keyring, enable support for it in pyproject.toml:
[tool.uv]
keyring-provider = "subprocess"Configure the Chainguard sources, setting the remediated index as the primary:
poetry source add --priority=primary chainguard-remediated https://libraries.cgr.dev/python-remediated/simple/
poetry source add chainguard https://libraries.cgr.dev/python/simple/If your organization uses a repository manager, configure Chainguard Libraries as an upstream source in that proxy first. Follow the global configuration documentation for your repository manager.
Once configured, point your build tool at your repository manager URL instead of libraries.cgr.dev directly. In this setup, the credentials are your repository manager credentials — not a Chainguard pull token.
pip config set global.index-url https://<your-repo-manager-url>/repository/python-all/simple/Configure ~/.config/uv/uv.toml for a global default across all projects:
[[tool.uv.index]]
name = "chainguard"
url = "https://<your-repo-manager-url>/repository/python-all/simple/"
default = trueFor a per-project configuration, configure the pyproject.toml:
[[tool.uv.index]]
name = "python-all"
url = "https://repo.example.com/repository/python-all/simple/"Run the following command:
poetry config http-basic.python-all REPO_MANAGER_USERNAME REPO_MANAGER_PASSWORD
poetry source add python-all https://repo.example.com/repository/python-all/simple/Example URLs by repository manager:
| Repository manager | URL pattern |
|---|---|
| JFrog Artifactory | https://example.jfrog.io/artifactory/api/pypi/python-all/simple/ |
| Sonatype Nexus | https://repo.example.com:8443/repository/python-all/simple/ |
| Google Artifact Registry | https://<location>-python.pkg.dev/<project>/python-all/simple/ |
| Cloudsmith | https://dl.cloudsmith.io/.../<org>/python-all/python/simple/ |
For authentication details specific to your repository manager, refer to the global configuration documentation.
Your existing lockfile or hash-pinned requirements.txt contains checksums generated against packages downloaded from PyPI or through your repository manager. Because Chainguard rebuilds packages from verified source as well as providing security controls for upstream artifacts, checksums differ even for identical version numbers. If your file uses --hash entries or --require-hashes, installation will fail with a hash mismatch after switching to Chainguard until these are updated.
Use chainctl libraries update-hashes to rewrite only the integrity hashes in your existing lockfile or requirements file to match Chainguard’s artifacts, without re-resolving your dependency graph. Supported formats include requirements.txt, poetry.lock, uv.lock, pdm.lock, Pipfile.lock, and pylock.toml.
Run the following command to auto-detect and update the lockfile in the current project:
chainctl libraries update-hashesOr specify the lockfile when running the command. For example:
chainctl libraries update-hashes requirements.txtWhen using a repo manager, run a command similar to the following:
chainctl libraries update-hashes
--registry-url https://repo.example.com/repository/python-all/
--token "$REPO_TOKEN"By default, Chainguard hashes are appended alongside your existing hashes rather than replacing them. If your installer fails on a dual-hash entry, use the --replace flag.
Regenerating is not recommended as a first approach. Dependency resolvers pick the newest version satisfying your constraints, which may not yet be available from Chainguard, and may also introduce unrelated dependency upgrades. Expand the following section for instructions on regenerating lockfiles.
If you have a specific reason to regenerate - for example, if you are intentionally refreshing your dependency versions - use the following commands:
pip:
pip-compile --generate-hashes --index-url https://libraries.cgr.dev/python/simple/ requirements.inuv:
rm -f uv.lock
uv syncPoetry 1.x:
poetry lock --no-updatePoetry 2.x:
poetry lockReinstalling after switching indexes can silently reuse a cached artifact from your previous index, with no error indicating this happened. To avoid this, clear caches.
pip cache purgeuv cache cleanpoetry cache clear --all pypiAlso invalidate cached packages in any repository manager that previously proxied PyPI, and rebuild containers without cached layers if your Dockerfile installs dependencies during build:
docker build --no-cache .Reinstall dependencies and confirm that the lockfile reflects Chainguard as the source.
pip install --force-reinstall --no-cache-dir -r requirements.txtuv sync --reinstallpoetry env remove --all
poetry installAfter reinstalling, you can use chainctl to verify which dependencies are built by Chainguard. When upstream fallback is enabled, libraries that aren’t built by Chainguard are subject to Chainguard’s security controls.
chainctl libraries verify --detailed ./.venv/Poetry’s virtualenv location depends on your configuration. If virtualenvs.in-project is enabled, it’s .venv in the project directory. Otherwise, find it with:
poetry env info --pathThen:
chainctl libraries verify --detailed $(poetry env info --path)A successful result shows what percentage of your project’s dependencies were built by Chainguard.
For full details on verification options and output, check out Verification: Analyze Python packages.
Commit the updated lockfile and any non-sensitive configuration changes. Apply the same index, cache, and hash-update steps to other developer workstations and build servers as you migrate them, including CI/CD platforms and any infrastructure that builds the application or installs dependencies.
For organization-wide rollout using a repository manager, refer to the global configuration documentation.
Chainguard Libraries covers a large and growing collection of PyPI packages, but not every package or version is available. If a package is missing, your install will fail with a 404 unless you have configured upstream fallback.
With upstream fallback enabled, packages not yet available from Chainguard are proxied from PyPI, subject to Chainguard’s security controls. Confirm your current policy with:
chainctl libraries entitlements listFor repository manager setups, Chainguard recommends using the configurable fallback rather than configuring a separate public registry fallback in your repository manager, to preserve Chainguard’s security controls.
Learn more about upstream fallback configurations in the Libraries Overview.
Check for an old or incorrectly scoped .netrc entry for libraries.cgr.dev, which silently takes priority over keyring authentication. Run with full verbosity to confirm the credential source:
pip install -vvv <package> 2>&1 | grep -B2 -A2 "credentials\|40[13]"chainctl libraries verify
Check your install output for a local wheel build (Building wheel for <package>), which indicates Chainguard has only a source distribution for that specific pinned version.
Last updated: 2026-07-31 18:47