SYSTEM Cited by 1 source
GitHub Releases¶
GitHub Releases is GitHub's tagged-artifact distribution surface on top of Git tags. A release is a composite of:
- A Git tag stored in the repo (points to the commit the release was cut from).
- Release metadata — name, body / release notes, draft / prerelease flags, latest-or-not, author.
- N release assets — arbitrary binary blobs (tarballs, installers,
platform binaries,
.whl/.gem/.zip/.msi, SBOMs) stored in GitHub's blob storage, downloadable via stable URLs.
Releases are GitHub's primary distribution surface for:
- Open-source projects shipping versioned binaries outside a package manager (e.g. the latest release tarball on github.com/org/repo/releases).
- CI/CD workflows that build and attach artifacts to a release.
- Enterprise internal releases, tool distribution, and SBOM publishing.
- Homebrew / Scoop / Chocolatey formulae that point at GitHub release asset URLs.
Immutability feature (GA 2025-10-28)¶
Historically, a published release was fully mutable: the owner could add, modify, or delete assets; move the tag to a different commit; or delete the release entirely. This left the distribution surface open to a cluster of supply-chain attacks:
- Asset swap: compromised maintainer replaces
v1.4.2.tar.gzwith a backdoored tarball; consumers who re-download get the backdoor. - Tag hijack: compromised maintainer force-pushes the tag to a different, malicious commit; see concepts/tag-protection.
- Silent withdrawal: release deleted, consumers lose reproducibility.
On 2025-10-28 GitHub shipped immutable releases to GA. When enabled at the repo or organization level, every new release is published with three layered guarantees:
- Asset immutability — assets cannot be added, modified, or deleted after publication. Enforced at GitHub's release-API and UI write paths.
- Tag protection — the Git tag for the release cannot be deleted or moved to a different commit. See concepts/tag-protection.
- Release attestation — a signed Sigstore-bundle attestation
is issued, verifiable with
gh attestation verifyor any Sigstore-compatible tooling. See concepts/release-attestation and patterns/sigstore-bundle-attestation.
(Source: sources/2025-10-31-github-immutable-releases-ga)
Scope + non-retroactive properties¶
- Setting granularity: repo-level or org-level.
- Scope: only new releases are locked; existing releases remain mutable unless explicitly republished.
- Disable is non-retroactive: turning the setting off doesn't unlock already-immutable releases. This is definitional for publish-time immutability — if it could be retroactively unlocked, the integrity guarantee would be worthless.
What's locked vs what's not¶
| Locked (immutable) | Not locked |
|---|---|
| Release asset list (add/delete) | Release notes / body text (pre-GA clarification needed) |
| Individual asset bytes | Latest-tag pointer across releases |
| Tag → commit pointer | New releases can still be published |
| Attestation bundle | The org/repo immutability setting itself |
The post does not disclose whether release metadata fields (title, body, labels) are part of the immutability envelope; that would need to be confirmed against the docs.
Architectural placement¶
Releases sit on top of — but are architecturally distinct from — the underlying Git repository:
Git repo (blob / tree / commit / tag objects in Git object store)
▲
│ release points to a commit via a Git tag
│
Release (metadata + asset references in GitHub's control plane)
▲
│ asset URLs dereference to blob storage
│
Release assets (opaque binaries in GitHub's blob-storage backend)
▲
│ signed by Sigstore
│
Attestation bundle (Sigstore-format, portable)
Immutability is enforced at the release control plane (write-path rejection of modifications) and exposed as a portable receipt at the data plane (the attestation bundle travels with downloads).
Consumption patterns¶
- Direct URL download:
https://github.com/<org>/<repo>/releases/download/<tag>/<asset>— cacheable, stable, CDN-friendly. Pre-immutability, the URL could point to different bytes over time; post-immutability, bytes for a published-immutable release are stable. - GitHub CLI:
gh release download <tag>. - Package-manager formulae: Homebrew / Scoop / Chocolatey / apt repos that reference release-asset URLs.
- CI verification:
gh attestation verify <asset> --repo <org/repo>orcosign verify-blob-attestation.
Related-system comparison¶
- npm: package versions have always been append-only ("you can't overwrite a published version"); similar publish-time-immutability semantics but scoped to a single tarball per version rather than a multi-asset release.
- Docker registries: tags are mutable by default, OCI image digests are content-addressed (immutable); cosign + Sigstore provides the attestation half. GitHub Releases immutability roughly ports the cosign+tag-protection model to Git-tag-rooted releases.
- Crates.io: published crate versions are immutable; no tag-protection analogue because the source-of-truth is the registry, not a Git tag.
Seen in¶
- sources/2025-10-31-github-immutable-releases-ga — GA announcement, 2025-10-28.
Related¶
- systems/github — the SaaS platform.
- systems/git — the underlying VCS; tag-level invariant source.
- systems/sigstore — the attestation format.
- concepts/publish-time-immutability — the policy the feature implements.
- concepts/release-attestation — the portable verification half.
- concepts/tag-protection — the Git-ref clause.
- patterns/sigstore-bundle-attestation — the attestation-emission shape.