Skip to content

Immutable releases are now generally available on GitHub

Summary

GitHub announced the general availability of immutable releases on 2025-10-28 (surfaced here on 2025-10-31). Once a release is published with immutability enabled, the repository enforces three layered guarantees: (1) release assets are locked — not addable, modifiable, or deletable; (2) the underlying Git tag is protected against deletion or re-pointing; (3) GitHub issues a signed release attestation in Sigstore bundle format that lets any consumer verify asset authenticity and integrity, on or off GitHub. The feature is opt-in at the repository or organization level and applies to new releases only — existing releases remain mutable until republished. Disabling the setting is non-retroactive: releases created while it was on stay immutable forever. Verification is available via gh CLI or any Sigstore-compatible tooling, so CI/CD pipelines can mechanically enforce "only consume attested GitHub releases" policies.

Key takeaways

  • Immutability is a publish-time one-way door, not a retention policy. Once published-as-immutable, the release's asset list and tag pointer are frozen for the life of the release. Turning the org/repo setting off later does not unfreeze earlier immutable releases. This makes the immutability decision a publish-time commit — the same one-way-door shape as object-lock / immutable-object storage in S3, but applied to a higher-level aggregate (tag + asset bundle + attestation) rather than to a single blob. (Source: sources/2025-10-31-github-immutable-releases-ga)

  • Three layered guarantees, not one. The feature bundles three orthogonal protections: asset immutability (nobody — not even the release owner — can swap a .tar.gz), tag protection (the Git tag naming this release can't be deleted or moved to a different commit), and release attestation (a signed Sigstore bundle vouches for the contents). Each blocks a different supply-chain attack: asset-swap-after-publish, tag-hijack-to-different-commit, and downstream-unverified-artifact. Only the attestation is useful outside GitHub — the first two are GitHub-enforced invariants; the third is a portable cryptographic artifact. (Source: sources/2025-10-31-github-immutable-releases-ga)

  • Sigstore bundle format is the interoperability choice. GitHub chose the Sigstore bundle format for attestations rather than a GitHub-proprietary signature envelope. This means verification doesn't require GitHub-specific tooling: any Sigstore-compatible verifier (cosign, the gh attestation verify sub-command, language-SDK verifiers, policy engines like Kyverno or OPA with Sigstore plugins) can confirm authenticity. The architectural implication: GitHub is electing to produce a signed output in an ecosystem-standard format, pushing verification policy into the consumer's environment rather than gating it on GitHub API calls. (Source: sources/2025-10-31-github-immutable-releases-ga)

  • Enforcement is a repo/org setting — not a per-release flag. "You can enable immutable releases at the repository or organization level in your settings. Once enabled, all new releases are immutable." This is a control-plane policy lever, not a per-release checkbox. Organizations can enforce "every new release published here is immutable" across thousands of repos with one setting, without per-release release-author action. (Source: sources/2025-10-31-github-immutable-releases-ga)

  • Backward compatibility is preserved by scope-to-new-releases. Existing releases remain mutable unless explicitly republished. This is the standard concepts/backward-compatibility dodge for a semantic-breaking policy change: apply the new rule only to objects created under it. No migration of the back catalogue, no surprise lock-in for old releases that might legitimately need a post-hoc asset re-upload. (Source: sources/2025-10-31-github-immutable-releases-ga)

  • Attestation is off-platform-verifiable — the portable half. The immutability enforcement on assets and tags is only meaningful inside GitHub's control. A consumer who mirrors the release to their own artifact store or a downstream CDN needs cryptographic proof of origin-and-unchangedness that travels with the bytes. The Sigstore attestation fills that role: verification works in "external environments" — any CI system, any air-gapped enterprise, any Sigstore-aware policy engine — without re-contacting GitHub at verify time. This is the key difference between an enforcement-based supply-chain control and an attestation-based one; immutable releases ships both. (Source: sources/2025-10-31-github-immutable-releases-ga)

Systems, concepts, patterns extracted

Systems - systems/github-releases — GitHub's tagged-artifact distribution surface on top of Git tags. Composed of: a Git tag (stored in the repo), a release note (metadata), N release assets (object blobs typically stored in blob storage behind the GitHub UI). Pre-2025, all three were mutable post-publish. Immutable releases is the feature that adds publish-time-lock semantics. - systems/sigstore — open-source software-signing ecosystem (Sigstore project, CNCF). Defines the bundle format GitHub emits for release attestations; provides the verifier-side tooling (cosign, policy-controller, language SDKs) that consumers use. - systems/github — the SaaS platform that enforces asset/tag immutability and issues the attestation. - systems/git — the underlying VCS whose tag is the root reference in a release; tag-protection is a Git-level invariant enforced by GitHub's ref-update path.

Concepts - concepts/publish-time-immutability — locking a composite artifact (tag + assets + metadata) at publish time so later modification is impossible even by the original publisher; distinguished from retention policies (time-based) and from object-lock (blob-level). The disable-is-non-retroactive property is definitional. - concepts/release-attestation — a signed cryptographic statement that a specific release (tag + asset hashes + metadata) was published by a specific identity through a specific build/publish pipeline, portable outside the platform that produced it. - concepts/tag-protection — Git-server-side invariant that a named tag, once published, cannot be deleted or re-pointed to a different commit; prevents tag-hijack supply-chain attacks where a malicious maintainer re-targets a published tag to a compromised commit.

Patterns - patterns/sigstore-bundle-attestation — the reusable shape: produce a signed bundle in Sigstore format as the release artifact's attestation, so verification is possible with any Sigstore-compatible tool without requiring a callback to the issuing platform; pushes policy enforcement into the consumer's CI/CD.

Operational numbers

Explicitly disclosed in the post: - GA date: 2025-10-28. - Opt-in granularity: repository-level or organization-level setting. - Scope: new releases only; existing releases remain mutable unless republished. - Attestation format: Sigstore bundle format. - Client tooling: GitHub CLI (gh attestation verify) or any Sigstore-compatible tooling.

Not disclosed: - Share of releases expected to adopt immutability in the first 90 days. - Storage / metadata overhead per immutable release (the attestation bundle itself is small — hundreds of bytes — but the referenced Rekor/transparency-log entries are external). - Back-compat with release-API PATCH/DELETE operations (does the API reject modifications on immutable releases with a specific error code?). - Enforcement path for the "existing releases mutable" carve-out (is it a per-release flag, or a date check?). - Whether the attestation references asset SHA-256 digests, the Git commit SHA, both, or additional pipeline provenance.

Caveats / open items

  • Changelog-tier post — architectural depth is shallow. This is a product GA announcement on github.blog/changelog, not an engineering deep-dive. It names the feature's guarantees but does not disclose the enforcement mechanism on the server, the attestation's cryptographic payload structure (identity binding, pipeline provenance vs plain asset hash), or the failure modes (what happens to immutable releases in a cross-repo transfer, for instance). A future engineering post — or the linked docs — would be the next ingestion target if/when they surface.

  • Only new releases. The non-retroactive enforcement is the pragmatic choice but leaves the entire pre-GA back catalogue unprotected. Consumers who rely on release-author-reputation for old releases still have to trust the author didn't modify the asset post-hoc. Policy engines enforcing "only immutable releases" will reject old releases by definition.

  • Tag protection is only for new immutable releases. The post scopes tag protection to "tags for new immutable releases" — i.e., tags created by the immutable-release publish action are protected. Tags created outside the release flow (manual git push --tags) or for non-immutable releases are not automatically protected. Repos that already have a tag-protection-rule policy are presumably orthogonal.

  • Attestation identity model is not described. The post says attestations are "signed" and use the Sigstore bundle format but does not say what identity signs them — GitHub's own keyless OIDC identity (Fulcio issued), a per-repo identity, a per-publisher identity, or a workflow-identity that encodes the publishing GitHub Actions run. The signer identity determines what the attestation actually binds to (platform-level vs workflow-level provenance).

  • HN discussion (153 points) is the signal of substance. The changelog post itself is three paragraphs; community ranking reflects the ecosystem weight of the feature (closes a long-standing supply-chain gap) rather than the depth of the announcement.

Raw

Last updated · 200 distilled / 1,178 read