Release Automation, Tags, GitHub Releases, Packages, and Container Registries: Core Concepts and Mental Model
Model release automation as controlled promotion of one verified source revision and one immutable artifact identity into releases, packages, and registries.
Learning objectives
- Explain why release automation begins with exact source and artifact identity rather than a mutable branch name.
- Distinguish Git tag, GitHub Release, Actions artifact, package version, container tag, container digest and provenance record.
- Trace least-privilege publication from validated source through build-once output to consumer verification.
- Recognize which release records are mutable aliases and which identities should remain immutable.
- Inspect release/package state without changing it before any publication step.
1. The practical problem: publishing is a side effect, not another CI check
CI from Chapter 24 answered whether an exact revision was acceptable to integrate. Release automation adds durable external state: a tag can identify a commit, a GitHub Release can publish assets, a package registry can expose a version, and a container registry can expose both human-friendly tags and content-addressed digests. A green release job is therefore not enough; consumers need to know exactly which source and bytes were published.
The safest default is build once, identify the bytes, then promote those same bytes. Rebuilding separately for a release, staging environment and production creates multiple artifacts that may share a version label without sharing content.
2. Mental model: approved source becomes one verifiable release identity
Read the chain from left to right. An approved source revision is bound to a deliberate version/tag. The release workflow builds and tests once, computes a digest, optionally produces provenance, then publishes that same subject to one or more distribution surfaces. Consumers verify both the chosen version identity and the actual bytes.
flowchart TD A[Approved source SHA] --> B[Version + tag decision] B --> C[Release workflow revision] C --> D[Build/test once] D --> E[Artifact bytes + SHA-256 digest] E --> F[Optional provenance / attestation] E --> G[GitHub Release asset] E --> H[Package / OCI publication] H --> I[Immutable package version or image digest] G --> J[Consumer verification] I --> J F --> J
The arrows are identity-preserving obligations. A tag is not the
artifact bytes. A release ID is not a container digest. A mutable
latest tag may point somewhere new tomorrow, while an
OCI digest identifies content.
3. Define each state before release changes it
| Layer | State to record | Why it matters |
|---|---|---|
| Event/revision | event, ref, exact source SHA, workflow SHA/path, run ID/attempt | Proves which source and automation revision initiated publication. |
| Version/tag | version string, tag name, tag target commit | Version syntax is human policy; tag target is source identity. |
| Build subject | filename/package/image, SHA-256 or OCI digest | The digest is the byte/content identity consumers can verify. |
| GitHub Release | release database ID, draft/prerelease/latest state, tag, assets | A release is GitHub-owned publication metadata around a tag. |
| Package/registry | namespace, package name/version, visibility/access, OCI digest | Registry state can outlive the workflow and may have independent permissions. |
| Token/trust |
contents: write, packages: write,
attestation permissions only where needed
|
Publishing authority belongs only in the publishing job. |
| Provenance | subject digest, signer/workflow identity, attestation ID/result | Provenance binds claims to the exact subject; it does not replace testing. |
| Recovery | deprecate/yank/supersede/delete policy and retained evidence | A bad release should not be “fixed” by silently changing the bytes under the same version. |
4. Read-only inspection comes before mutation
Before creating a release, prove the candidate commit and inspect existing tags/releases so you do not collide with an existing immutable identity.
git status --short
git rev-parse HEAD
git show -s --format='%H %cI %s' HEAD
git tag --points-at HEAD
gh release list --limit 20
gh api "repos/{owner}/{repo}/releases?per_page=20" --jq '.[] | [.id,.tag_name,.draft,.prerelease,.published_at] | @tsv'
For package or GHCR work, inspect the existing package identity and
repository linkage before granting packages: write. A
package can have access control distinct from its source repository,
and a workflow repository must actually have package access.
5. Tags, releases, package versions and digests answer different questions
| Identifier | Answers | Mutability warning |
|---|---|---|
| Git commit SHA | Which source tree revision? | Commit object identity is stable. |
Git tag v1.2.3 |
Which source revision did this release name select? | Ordinary tags can be moved unless protected/locked by policy. |
| GitHub Release ID | Which release record in GitHub? | Metadata can be editable; immutable-release settings protect tag/assets after publish. |
| Package version | Which registry version name? | Registry overwrite/yank rules vary by ecosystem. |
Container tag :latest |
Which image does this alias currently reference? | Mutable by design in many registries. |
OCI digest @sha256:… |
Which image content? | Content-addressed identity; preferred for promotion/verification. |
| Attestation subject digest | Which bytes are covered by a signed claim? | Valid only if verifier also checks expected signer/repository/workflow identity. |
6. Put publishing authority only where publication happens
A build/test job generally needs contents: read or even
permissions: {} when no checkout/API access is needed.
Creating a Git tag or GitHub Release requires repository write
authority; publishing a repository-associated GitHub Package/GHCR
image normally uses GITHUB_TOKEN with
packages: write. Do not give those rights to
pull-request test jobs or every job in the workflow.
Security boundary: an action can access
github.token even when you do not pass the token
explicitly. Keep the job permission set narrow and treat every
executed action/script in a publishing job as code running with
that authority.
7. Immutable releases strengthen the release record
When release immutability is enabled, publishing locks the release-associated tag and assets. GitHub also creates a cryptographically verifiable release attestation covering the release tag, commit SHA and assets. The recommended flow is therefore draft → attach all assets → publish. Draft state remains mutable until publication.
Immutability is not the same as “nothing about the release can ever change.” GitHub still permits selected metadata such as title/release notes and prerelease/latest designation to change. Treat the protected tag and assets—not editable prose—as the integrity boundary.
8. GHCR uses both repository authorization and content identity
GitHub Container Registry supports OCI images. A workflow can use
GITHUB_TOKEN to publish a package associated with its
repository when package access permits it. Public GHCR images can be
pulled anonymously. For promotion and deployment, record the pushed
digest and prefer pulling name@sha256:… instead of
assuming a mutable tag still points to the original image.
A package namespace matching a repository name does not by itself
prove repository linkage. Publishing from a workflow with
GITHUB_TOKEN commonly establishes the association for a
new package, while pre-existing packages may require explicit
Actions repository access.
9. Rollback means selecting known-good immutable content
A rollback should normally promote or redeploy a previously verified digest/version. It should not rebuild old source and call the result “the same release.” For ecosystems that support deprecation or yank semantics, preserve the bad version as historical evidence when policy permits and mark it unsuitable. For container registries, move a mutable deployment alias only after verifying the target digest.
Deleting a release is a destructive administrative action, not a debugging step. Preserve run/attempt, release ID, tag target, asset digest and provenance before cleanup. With immutable releases, deleted tag names cannot be reused, so unique lab versions are essential.
10. Lesson summary
A secure release is a mapping between exact source, exact bytes, explicit version, narrowly authorized publication and independently verifiable distribution state. Human-friendly tags and release pages help discovery; cryptographic digests and provenance establish artifact identity.
Knowledge check
Why is main a poor release identity?
It is a mutable branch reference. A release should record the exact commit SHA and the artifact/content digest produced from it.
Does a GitHub Release asset digest identify the Git tag target?
No. The asset digest identifies bytes; the tag target identifies source. A trustworthy release records and verifies both.
Why should packages: write not be granted to a
normal PR test job?
Package publication is a durable side effect. Untrusted or ordinary validation does not need that authority.
What does image@sha256:… give that
image:latest does not?
A content-addressed immutable image identity instead of a mutable alias.
If immutable releases are enabled, when should assets be attached?
While the release is still a draft, before publishing makes the tag and assets immutable.
Official references and version notes
- About releases — GitHub Releases are based on Git tags and add release metadata/assets around a versioned source point.
- Managing releases — Current release creation, editing and deletion behavior.
- Immutable releases — Current tag/asset immutability and automatic release-attestation behavior.
- GHCR — Current GitHub Container Registry authentication, package linking and digest guidance.
- GitHub Packages permissions — Repository/granular package permissions and GitHub Actions access.
- GITHUB_TOKEN authentication — Least-privilege token use in workflows.
- gh release create — Current CLI release creation, --verify-tag and immutable-release handling.
- gh release verify — Verification of cryptographically signed immutable-release attestations.
- gh release verify-asset — Verify a local asset against the release attestation and digest.
- actions/attest v4.2.2 — Immutable attestation action revision referenced by optional provenance examples.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.