Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

We’re excited to announce that Immutable Releases are now available in public preview and will be gradually rolled out to all organizations and repositories!

Immutable Releases add a new layer of supply chain security to GitHub Releases by preventing changes to release assets and their associated tags after publication. This helps ensure that the software you publish (and your users consume) remains secure and trustworthy. With Immutable Releases, release assets can no longer be added, modified, or deleted after publishing, and tags are protected from being moved or deleted.

We’d love for you to try out Immutable Releases and share your feedback! Your input will help us polish the experience as we work toward general availability.

Let us know your questions, thoughts, and feedback in the discussion below. Thanks for helping us make GitHub Releases even more secure and reliable for everyone!

You must be logged in to vote

Replies: 13 comments · 19 replies

Comment options

Sounds great. Huge work guys! Much love to the GitHub team, especially the great devs!

You must be logged in to vote
0 replies
Comment options

Hi @tinaheidinger,

This is a fantastic addition! Immutable Releases will greatly enhance the security and trustworthiness of software delivery by ensuring release artifacts remain exactly as published. This kind of supply chain protection is critical, especially as software supply chain attacks continue to rise.

I’m excited to test this feature and provide feedback as it rolls out. Kudos to the team for prioritizing security and improving the release workflow.

Thanks for sharing and looking forward to seeing Immutable Releases become generally available!

Best,
KaloudasDev

You must be logged in to vote
0 replies
Comment options

Will there be an API to manage this at the repository level?

Additionally, how does this work with uploading release assets?

The docs are clear that assets can't be altered, but what about adding new ones?

Is there a certain window where release assets must be added after creating an immutable release or can devs add assets to an immutable release in perpetuity.

So you can't add/remove assets after creating an immutable release. So I might ask - how exactly does this work with publication workflows where there is a delta between release creation via API and asset addition (as they are different API calls).

I just tested with a really simple workflow: https://github.com/AdnaneKhan/TestImmutable/actions/runs/17275237419/job/49030192026#step:5:17

Does this mean that projects that use Actions to create releases and attach assets need to make sure that the workflow:

  • First creates a draft release
  • Adds release assets
  • Publishes the draft

GitHub should add a warning about this interaction as this will lead to a lot of projects release workflows failing to upload assets if they enable the feature and their CI doesn't create a draft first.

You must be logged in to vote
2 replies
@bdehamer
Comment options

Will there be an API to manage this at the repository level?

Yes, we haven't yet published the APIs, but there will be endpoints for enabling/disabling immutable releases at the repository level as well as enforcing this setting at the org level.

So you can't add/remove assets after creating an immutable release

Correct. As you noted, the recommended workflow for publishing an immutable release will be to initially create the release as a draft, attach any associated assets, and then publish the draft.

We'll be sure to make this clear in the documentation. Thanks!

@woodruffw
Comment options

Hi @bdehamer (good to see you here!)

I did a quick scan through the docs again, but couldn't find a reference to the drafting behavior. Do you know if those docs changes are still planned?

(This caused some confusion on one of my projects, and I want to make sure I can rely on drafts being mutable before rolling out immutability on releases again!)

xref zizmorcore/zizmor#1165 (comment)

Comment options

After enabling immutable releases, I am still able to delete the release and the tag later.

You must be logged in to vote
8 replies
@AdnaneKhan
Comment options

I tested that and it doesn’t allow you to.

Let’s say I make an immutable release for tag v1.0.1. Then I go and delete the release and the tag.

Now, due to the rules GitHub applies under the hood with immutable releases, if I try to create v1.0.1 it will block me.

@haya14busa
Comment options

Thanks @AdnaneKhan for confirming it.
That's awesome 💯

@andreaso
Comment options

On the topic of GitHub Actions...

Should be noted that even it's impossible to recreate that deleted v1.0.1 release tag that won't stop someone from instead replacing it with a v1.0.1 branch, which equally well with satisfy uses: org/repo@v1.0.1.

Hence, if we are going to trust immutable releases in a GitHub Actions context it feels like we'll need to verify release attestation on each run?

@hfhbd
Comment options

@andreaso Regarding Github Actions: according to the roadmap, immutable actions will finally available this month: github/roadmap#1103 🎉 If you not want/able to use immutable actions, use the full commit hash. You can/should even enforce it: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/

@haya14busa
Comment options

that won't stop someone from instead replacing it with a v1.0.1 branch, which equally well with satisfy uses: org/repo@v1.0.1.

Oh, that's good point.
It would be great if GitHub also blocks branch with the same immutable tag name.

Comment options

Awesome, nice work! 😺🖖❤️

You must be logged in to vote
0 replies
Comment options

Thank you for the great feature!
I have a feature request.
It would be great if we can enable this feature in all repositories of users by user settings same as organizations.
If users have a lot of repositories, it's hard to enable this feature by repository.

You must be logged in to vote
0 replies
Comment options

In general I think this is a good setting, however I would like it to be more flexible.
To be concrete, I would like to ignore the immutable release enforcement for some specific patterns.

https://github.com/miljodir/workflow-templates/tags

If for instance the tag ends with /v1 or /v2 it should be mutable. Other tags e.g. 1.0.0 and 1.0.1 should be immutable

You must be logged in to vote
3 replies
@suzuki-shunsuke
Comment options

In my understanding, tags are mutable unless you create releases associated with those tags.
I'm not sure your usecases, but you can create immutable releases for tags x.y.z while keeping tags /v1 or /v2 mutable.

@audunsolemdal
Comment options

I just tested this and it seems that you are correct in that tags without a release are still mutable.

@tinaheidinger
Comment options

That's correct - plain git tags aren't affected by this setting, it is scoped to releases and their associated tags

Comment options

Just scanned through my org. Only a single repo out of 300+ repos, where 35 of them use releases, only one of the repos has a mutable Github release.
Ideally I want to activate the immutable releases setting at the org level with "all repositories" with the possibility of adding exclusions.

I know it is possible to use "selected repositories", but the UX for this is bad if needing to select hundreds of repositories, and won't auto add new repositories when created. As minimum there should be a "select all" button in the "select repositories" context before I unselect specific repos so I don't have to click through hundreds of repos.
image

Would you consider improving the flexibility for repository targeting to be similar to repository rulesets? For instance including and excluding by repository name patterns and/or repository properties:

image
You must be logged in to vote
0 replies
Comment options

Noticed a small bug.

Description

I am pushing a new tag to a repository.

And I get

Repository rule violations found for refs/tags/android-v11.13.4.

When I click the "Review all repository rules at ..." link, I see that no repository rules exist for this repository.

This happens because an immutable release that has since been deleted existed for that tag. The error message is wrong.

Reproduction Steps

  1. Create an immutable release
  2. Delete the immutable release
  3. Try to push a tag with the same as the previous immutable release

It will fail with the (wrong) error message.

Expected behavior

The error message should read:

Cannot create tag android-v11.13.4 due to a previous immutable release with this tag.

Or similar.

You must be logged in to vote
1 reply
@juhoinkinen
Comment options

I see this wrong error message too.

Comment options

Can this be applied to Docker image releases via ghrc (and Docker Hub) as well? So an image with the 1.0.1 tag is fixed to a specific image hash and once an immutable release is created that tag can not be uses on an image with a different image hash.

You must be logged in to vote
1 reply
@bdehamer
Comment options

This feature does not extend to GHCR image tags. Many container registries support immutable tags, but this is not yet available in GHCR. I'm not sure if Docker Hub supports tag immutability.

Comment options

I introduce the convenient tool that makes all past GitHub Releases immutable.

https://github.com/suzuki-shunsuke/ghir

One of problems of Immutable Releases is that even if Immutable Releases is enabled, GitHub Releases created before it's enabled are still mutable.
This CLI solves the problem by making all releases immutable.

Requirements

GitHub Access Token with the contents:write permission

How To Use

  1. Install ghir
  2. Enable Immutable Releases
  3. Run ghir
ghir <repository fullname>

e.g.

ghir aquaproj/aqua

Example

I ran ghir against suzuki-shunsuke/tfcmt.

ghir suzuki-shunsuke/tfcmt

Please see the releases: https://github.com/suzuki-shunsuke/tfcmt/releases

Not only the latest release, very old releases also became immutable.

e.g. v0.1.0 Jan 5, 2021 https://github.com/suzuki-shunsuke/tfcmt/releases/tag/v0.1.0

You must be logged in to vote
2 replies
@louwers
Comment options

How does it work?

@suzuki-shunsuke
Comment options

https://github.com/suzuki-shunsuke/ghir#how-it-works

  1. Get GitHub Releases by GitHub API
  2. Exclude draft releases and immutable releases
  3. Update releases without any parameters by GitHub API to make all releases immutable
Comment options

I have a feature request.

Releases created before Immutable Releases is enabled become immutable when they are updated, but I found the release attestation isn't created.
For example, please see the release.
This release became immutable, but it doesn't have the release attestation.

$ gh release view --json isImmutable -R suzuki-shunsuke/tfcmt v0.1.0
{
  "isImmutable": true
}
$ gh release verify -R suzuki-shunsuke/tfcmt v0.1.0
no attestations for tag v0.1.0 (sha1:96c9cf89c9af49c37119c978f5ef6ee0ef47b80c)

It would be great if the release attestation is created when the release is updated.

You must be logged in to vote
2 replies
@bdehamer
Comment options

The reason an attestation may not be generated for an old release is if we are missing digest information for the assets attached to the release.

Starting back in April 2025 we began collecting/persisting the SHA256 digest of every release asset as it was uploaded. This information is then used when we generate the attestation. For older releases for which we have missing/incomplete asset digest information we do not generate an attestation.

Backfilling ALL of the legacy release asset digest information was determined to be too expensive -- however, if we see sufficient demand for this feature we could explore some sort of on-demand backfill on a release-by-release basis.

@AdnaneKhan
Comment options

An on-demand feature would be very valuable - ideally with it calculated at the same time a non-immutable release is converted to an immutable one. I would wager that the number of people converting non-immutable releases to immutable is relatively small and it should not add too much overhead for GitHub. Do tell me if your metrics say I'm wrong, because that would be a pleasant surprise :)

Driving adoption of attestation verification at scale as challenging enough because we (as in people who are trying to drive security changes at companies we work at) have to work with developers to make code changes to add verification. If developers need to add hack-y checks like skipping attestation verification if the release is older than April 2025, then it becomes harder to convince developers to adopt this powerful feature.

Comment options

As we prepare to move the immutable release feature to General Availability, we're making a bug fix to the predicate statement in the release attestation that is generated at the time the immutable release is published. The release attestation uses a format specified in the in-toto release predicate specification.

There is an error in our current implementation where we are populating the releaseId field with the unique identifier for the tagged release. The spec indicates that the releaseId field should actually be the stable ID for the repository and should "remain unchanged between release versions".

Going forward, all new release attestations will contain the correct value for the releaseId field.

This should not impact anyone using the gh release verify or gh release verify-asset commands to verify their release attestations. Anyone using custom tooling for verifying release attestations should be aware of the change.

Currently, a generated release predicate might look something like this:

"predicate": {
    "ownerId": "398027",
    "purl": "pkg:github/foo/bar@v1.0.1",
    "releaseId": "254145143",
    "repository": "foo/bar",
    "repositoryId": "905988044",
    "tag": "v1.0.1"
  }

After our fix is deployed, the same predicate would be defined as follows:

"predicate": {
    "databaseId": "254145143",
    "ownerId": "398027",
    "purl": "pkg:github/foo/bar@v1.0.1",
    "releaseId": "905988044",
    "repository": "foo/bar",
    "repositoryId": "905988044",
    "tag": "v1.0.1"
  }

In the new version, the releaseId correctly identifies the stable identifier for the repository itself (note that it has the same value as the repositoryId field). The stable identifier for the specific release is present in the new databaseId field.

We recognize that the field naming is not particularly intuitive and are proposing an update to the release predicate spec which will clarify the naming of the fields. If this proposal is accepted, we'll likely start using the v0.2 version of of the release predicate at some point in the future.

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Repositories The core of version-controlled code storage Show & Tell Discussions where community members share their projects, experiments, or accomplishments
Morty Proxy This is a proxified and sanitized view of the page, visit original site.