Skip to main content

oci-push

oci-push copies or retags OCI artifacts between registries or within the same registry. This step supports container images and Helm charts stored in OCI registries, making it useful for promoting artifacts through a pipeline — for example, retagging an image with a release version or copying it to a production registry. Multi-arch image indexes are copied in full. Registry authentication is supported for both source and destination.

Configuration

NameTypeRequiredDescription
srcRefstringYReference to the source OCI artifact. Supports both tag format registry/repository:tag and digest format registry/repository@sha256:digest. For Helm OCI artifacts, the oci:// prefix is supported (e.g., oci://registry/repository:tag) and will use Helm-specific credential lookup.
destRefstringYDestination reference including tag (e.g., registry/repository:tag). For Helm OCI artifacts, the oci:// prefix is supported. For retag-in-place, use the same repository as srcRef with the new tag.
annotationsobjectNAnnotations to set on the destination artifact. Keys may be prefixed with index: or manifest: to scope them to the index or image manifest respectively. Unprefixed keys default to the image manifest. For single images, index:-prefixed keys are ignored. Values support expressions. Existing annotations on the source artifact are preserved; specified annotations are added or overwritten.
insecureSkipTLSVerifybooleanNWhether to skip TLS verification for both source and destination registries. Defaults to false.

Outputs

NameTypeDescription
imagestringFull destination reference with tag (e.g., prod.example.com/myapp:v1.2.3).
digeststringDigest of the pushed artifact (e.g., sha256:abc123...).
tagstringTag that was applied, parsed from destRef.

Limits

The total compressed size of the artifact (config blob and all layers) must not exceed 1 GiB (or as configured by your administrator). For multi-arch image indexes, this includes the sum across all child images. Exceeding this limit causes a terminal (non-retryable) error.

This limit is not enforced when srcRef and destRef refer to the same repository (i.e. retagging within the same registry and path), since no blob transfer occurs in that case.

Examples

Retagging an Image with a Release Version

In this example, a dedicated "release" Stage sits downstream from a testing Stage. When verified Freight is promoted into this Stage, its single step retags the image with a semver release version in the same repository. Because the source and destination are in the same repository, this is a lightweight metadata operation with no blob transfer.

steps:
- uses: oci-push
config:
srcRef: registry.example.com/myapp@${{ imageFrom("registry.example.com/myapp").digest }}
destRef: registry.example.com/myapp:v1.2.3

Copying to a Production Registry

In this example, a verified image is copied from a sandbox registry to a production registry, preserving its original tag. Credentials for each registry are resolved independently.

steps:
- uses: oci-push
config:
srcRef: sandbox.example.com/myapp@${{ imageFrom("sandbox.example.com/myapp").digest }}
destRef: prod.example.com/myapp:${{ imageFrom("sandbox.example.com/myapp").tag }}

Copying to a Per-Stage Repository

In this example, images are copied to stage-specific repositories (e.g., for garbage collection policies that limit images per repository). The step output is then used by kustomize-set-image to update the deployment manifest.

steps:
- uses: oci-push
as: push-to-stage
config:
srcRef: registry.example.com/widget-service@${{ imageFrom("registry.example.com/widget-service").digest }}
destRef: registry.example.com/widget-service/${{ ctx.stage }}:${{ imageFrom("registry.example.com/widget-service").tag }}
- uses: kustomize-set-image
config:
path: ./out
images:
- image: registry.example.com/widget-service
newName: registry.example.com/widget-service/${{ ctx.stage }}
digest: ${{ outputs["push-to-stage"].digest }}

Promoting an OCI Helm Chart

In this example, a Helm chart stored in an OCI registry is copied to a production registry. The oci:// prefix ensures Helm-specific credentials are used for authentication.

steps:
- uses: oci-push
config:
srcRef: oci://registry.example.com/charts/my-app:${{ chartFrom("oci://registry.example.com/charts/my-app").version }}
destRef: oci://prod-registry.example.com/charts/my-app:${{ chartFrom("oci://registry.example.com/charts/my-app").version }}

Adding Annotations

In this example, OCI annotations are stamped onto the destination manifest during the push. This can be used to record provenance metadata such as the source repository or Kargo promotion name.

steps:
- uses: oci-push
config:
srcRef: registry.example.com/myapp@${{ imageFrom("registry.example.com/myapp").digest }}
destRef: registry.example.com/myapp:v1.2.3
annotations:
org.opencontainers.image.source: "https://github.com/example/myapp"
io.kargo.promotion: ${{ ctx.promotion }}

Scoped Annotations for Multi-Arch Images

When pushing image indexes (multi-arch), annotation keys can be prefixed with index: or manifest: to control where they are applied. Unprefixed keys default to the image manifest.

steps:
- uses: oci-push
config:
srcRef: registry.example.com/myapp@${{ imageFrom("registry.example.com/myapp").digest }}
destRef: registry.example.com/myapp:v1.2.3
annotations:
org.opencontainers.image.source: "https://github.com/example/myapp"
index:org.opencontainers.image.revision: ${{ commitFrom("https://github.com/example/myapp").id }}
manifest:org.opencontainers.image.description: "my app image"

Copying with TLS Verification Disabled

In this example, an artifact is copied between registries with self-signed certificates by disabling TLS verification. This should only be used in development or testing environments where the registries are trusted.

steps:
- uses: oci-push
config:
srcRef: internal-registry.local/myapp:latest
destRef: staging-registry.local/myapp:latest
insecureSkipTLSVerify: true