ORAS Package Push Action
A GitHub Action that packages YAML manifests and pushes them to OCI registries as artifacts with proper annotations and multi-tagging support.
The Problem
While working with GitOps workflows, I needed a way to package and distribute Kubernetes manifests as OCI artifacts. OCI registries like GHCR support arbitrary artifacts, not just container images, making them perfect for storing versioned YAML manifests, Kustomize bases, Crossplane Compositions or any other GitOps artifacts.
The ORAS CLI provides the functionality, but using it in GitHub Actions requires installing the CLI, authenticating to registries, building proper annotation structures, managing multiple tags, and handling glob patterns. Each repository needed custom scripts or workflow steps, leading to inconsistency and maintenance overhead.
The Solution
This action packages files using glob patterns and publishes them to OCI registries with automatic annotation generation and multi-tagging support. You provide the source path, registry, and version. The action handles the rest.
The bigger win is consistency. One action across all projects means standardized artifact publishing. Every project gets proper OCI annotations, version tags, and SHA-based tags without custom scripts.
Quick Example
- name: Publish Artifacts
uses: michielvha/oras-package-push-action@v1
with:
registry: ghcr.io
repository: ${{ github.repository_owner }}/my-artifacts/manifests
source-path: "manifests/**/*.yaml"
version: v1.0.0The action packages files matching the glob pattern, adds OCI annotations, and publishes them to the registry with the specified version tag and additional tags like latest.
Why This Matters
OCI registries can do much more than just store container images. They're powerful artifact distribution mechanisms. GitOps workflows can benefit from storing versioned artifacts in OCI registries when immutability and version control matter.
I started building this action when I needed to distribute Crossplane compositions in a decentralised architecture. In that setup, each cluster runs its own Crossplane instance, and I needed a way to share compositions across clusters without the drawbacks of a centralized Kustomize base.
The problem with a shared Kustomize base is that updating it affects all overlays immediately. If I update a composition in the base, every environment using it gets the change... including production. I needed version control. I wanted to migrate production to a new composition version gradually, without forcing all environments to update at once.
The alternative was duplicating the same composition config across multiple overlays, which defeats the purpose of having shared compositions in the first place.
OCI artifacts solve this. Each composition version becomes an immutable artifact that overlays can reference independently. Production can stay on v1.0.0 while staging tests v1.1.0, and I don't have to maintain duplicate configs. When I'm ready to migrate production, I update the reference to the new version tag.
This action makes it easy to leverage OCI registries for GitOps artifact distribution, reducing the complexity of maintaining separate artifact repositories and simplifying version management.
For detailed usage, configuration options, and examples, see the GitHub repository.
