Skip to main content

oras-pants-plugin

A Pantsbuild plugin that wraps the outputs of package-able targets, such as pex_binary, as OCI artifacts and publishes them to OCI registries with oras. Any registry that stores OCI artifacts works: GitHub Container Registry, Docker Hub, Artifact Registry, ECR, ACR, Harbor, a local registry:2, and so on.

Installation

Add the plugin to pants.toml and enable its backend:

[GLOBAL]
plugins = ["oras-pants-plugin==<version>"]
backend_packages.add = ["pants.backend.python", "oras_pants_plugin"]

[oras.registries.ghcr]
address = "ghcr.io/my-org"
default = true

Wrap the targets to publish in an oci_artifact target, like the builtin archive target does:

# src/app/BUILD
pex_binary(name="app", entry_point="main.py")

oci_artifact(
    name="app-artifact",
    packages=[":app"],
    oci_repository="app",
    oci_tags=["1.2.0", "latest"],
    oci_artifact_type="application/vnd.python.pex.v1",
)

Build it, or build and push it:

pants package src/app:app-artifact   # writes the OCI image layout to dist/src.app/app-artifact/
pants publish src/app:app-artifact   # copies it to ghcr.io/my-org/app:1.2.0 and :latest

Pull it back anywhere with oras pull ghcr.io/my-org/app:1.2.0, which restores src.app/app.pex.

How it works

oras is downloaded as a static binary; nothing is installed into a Pants resolve.

pants package builds every packages target as pants package would, then runs oras push --oci-layout to write one OCI image layout directory to output_path under --distdir. Every file or directory the packages targets produce becomes one layer, titled with its own --distdir-relative path (a packed or loose layout PEX is a directory, pushed as a gzipped tar layer that oras pull unpacks again). The artifact is tagged with every oci_tags entry and the manifest's artifactType is oci_artifact_type.

pants publish packages the target the same way, then runs one oras cp --from-oci-layout per registry, in the foreground so oras can show progress. The copy addresses the layout's manifest by digest, so the published artifact has exactly the digest pants package reported. A target without oci_repository, that resolves to no registry, with skip_oras=True, or run with [oras].skip = true is skipped before it is packaged. Each copy is reported as published, failed or skipped like every other publisher; --publish-output writes the same as JSON, with the registry, repository, tags and digest of each copy.

oci_artifact fields

Field Purpose
packages Addresses of targets pants package can build, e.g. [":app"]. Each output becomes a layer.
output_path Where pants package writes the layout directory, relative to --distdir. Default: <spec path with dots>/<target name>.
oci_tags Tags applied in the layout and in every registry. Default: ["latest"]. [] leaves the artifact untagged, addressable by digest only.
oci_artifact_type The artifactType of the manifest, passed as --artifact-type, e.g. application/vnd.python.pex.v1. Default: oras' application/vnd.unknown.artifact.v1.
oci_registries Registry addresses (ghcr.io/my-org, localhost:5000) or @aliases of [oras].registries entries to publish to. Default: every [oras].registries entry with default = true.
oci_repository The repository within each registry, e.g. team/app; the published reference is <registry>/<oci_repository>:<tag>. Unset skips the target in pants publish.
skip_oras If true, the target is skipped by pants publish.

Configuration

Option Default Purpose
[oras].registries {} Registries by alias: {"alias": {"address": "host[:port][/prefix]", "default": bool}}. An entry aliased default is a default too.
[oras].skip false Skip oras during pants publish.
[oras].args [] Extra arguments for every oras cp, e.g. --to-plain-http or --to-insecure. The registry is the copy's destination, so its flags are the --to-* ones. They follow the plugin's own flags, so a repeated flag overrides it.
[oras].config unset A registry authentication file in the ~/.docker/config.json format, passed as --to-registry-config. Relative paths are resolved from the build root.
[oras].extra_env_vars [] Extra environment variables for oras cp, as NAME=value or NAME to copy from Pants' environment, e.g. HTTPS_PROXY or SSL_CERT_FILE.
[oras].version bundled default oras release to download.
[oras].known_versions bundled default Checksums of downloadable releases; extend to use another version.

Credentials

oras reads the credentials that docker login or oras login store in $DOCKER_CONFIG/config.json or ~/.docker/config.json, and runs the credential helpers configured there. PATH, HOME and DOCKER_CONFIG are always passed to oras cp, so logging in once is enough:

oras login ghcr.io          # or: docker login ghcr.io
pants publish src/app:app-artifact

In CI, pass the token to a login step before pants publish, or point [oras].config at an auth file. Avoid --to-username/--to-password in [oras].args: pants.toml is committed.

Publishing into a directory

oras cp can write to an OCI image layout directory instead of a registry, which is handy for inspecting what would be pushed. With --to-oci-layout, the registry reference becomes a directory path in the sandbox, so combine it with --keep-sandboxes=always to look at the result:

pants --oras-args="['--to-oci-layout']" --keep-sandboxes=always publish src/app:app-artifact

The layout pants package writes to dist/ is the same artifact; oras discover, oras manifest fetch and oras pull all accept it with --oci-layout:

oras manifest fetch --oci-layout dist/src.app/app-artifact:1.2.0 | jq

Using a different oras version

Add the release's checksums and sizes to known_versions and set version:

[oras]
version = "1.3.5"
known_versions.add = [
  "1.3.5|linux_arm64 |<sha256>|<size>",
  "1.3.5|linux_x86_64|<sha256>|<size>",
  "1.3.5|macos_arm64 |<sha256>|<size>",
  "1.3.5|macos_x86_64|<sha256>|<size>",
]

Compute each line with curl -L $URL | tee >(wc -c) >(shasum -a 256) >/dev/null, where $URL is the oras_<version>_<os>_<arch>.tar.gz asset of the GitHub release (linux/darwin, amd64/arm64). The release's oras_<version>_checksums.txt lists the same checksums.

Supported versions

Plugin Pants Python oras
0.x 2.33 3.14 >=1.3,<2

Pants loads plugins into its own interpreter, so the plugin requires the Python version Pants runs on. The packages being wrapped may target any Python version.

Releases

Wheels are published to PyPI. Release notes live in the changelog and on the GitHub releases page.

Contributing, Bug Reports and Feature Requests

This plugin lives in the pants-plugin-depot repo. See its CONTRIBUTING.md, or open an issue.

Metadata

Release files for oras-pants-plugin 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for oras-pants-plugin 0.2.0
File Interpreter ABI Platform
oras_pants_plugin-0.2.0-py3-none-any.whl Python 3 none any Details

Release files / oras_pants_plugin-0.2.0-py3-none-any.whl

Download URL oras_pants_plugin-0.2.0-py3-none-any.whl
Size 23.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1919529644ccc4f9fed7f3266cfdbab68759d7df10ab7c2b90bbac21829d50b7
BLAKE2b-256 checksum
How to use checksums
ae4b240dd52bded072c1b9264a0aad9027ec753cddd0bfddff80c57641c8d8b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Security for oras-pants-plugin 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 1 file in this release has been uploaded with provenance metadata.

Attestation for oras_pants_plugin-0.2.0-py3-none-any.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page