Skip to content

feat: make releases immutable after all assets are uploaded#4410

Merged
lpcox merged 5 commits intomainfrom
copilot/make-releases-immutable
Apr 23, 2026
Merged

feat: make releases immutable after all assets are uploaded#4410
lpcox merged 5 commits intomainfrom
copilot/make-releases-immutable

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 23, 2026

GitHub releases can be edited or deleted after publication, which is a supply-chain risk. This adds a make-immutable job that locks down the release once all assets are in place.

Changes

  • New make-immutable job (release.md, release.lock.yml): runs after generate-sbom (ensuring binaries + SBOM are uploaded), calls gh release edit "$RELEASE_TAG" --make-immutable, and runs in parallel with the agent job. conclusion waits for both.

  • Removed update_release safe-output: the agent can no longer mutate the release body (it would conflict with immutability). Agent now prints generated highlights to workflow logs instead.

  • Updated safe-outputs config in release.lock.yml: removed update_release from GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG, Write Safe Outputs Config, and Write Safe Outputs Tools.

Execution order

release
  ├── generate-sbom → make-immutable ─┐
  └── docker                           ├── conclusion
  └── (other standard jobs) → agent  ─┘

Note: release.lock.yml frontmatter hash is set to "pending-recompile" — run gh aw compile before merging to regenerate the correct hash.

Copilot AI linked an issue Apr 23, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix releases to ensure immutability for better security feat: make releases immutable after all assets are uploaded Apr 23, 2026
Copilot AI requested a review from lpcox April 23, 2026 17:50
@lpcox lpcox marked this pull request as ready for review April 23, 2026 17:51
Copilot AI review requested due to automatic review settings April 23, 2026 17:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a post-release hardening step to reduce supply-chain risk by making GitHub Releases immutable once required assets are uploaded, and removes the agent’s ability to mutate release notes via safe-outputs.

Changes:

  • Add a make-immutable job to run gh release edit ... --make-immutable after SBOM upload.
  • Remove the update_release safe-output/tooling and adjust the agent prompt to print highlights to logs instead of editing the release body.
  • Update the compiled lock workflow to reflect the new job and safe-outputs configuration (requires recompilation).
Show a summary per file
File Description
.github/workflows/release.md Adds the make-immutable job and updates the agent instructions to avoid release-body mutation.
.github/workflows/release.lock.yml Updates compiled workflow: removes update_release, adds make-immutable, and updates dependencies/needs; currently marked pending-recompile.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 4

@@ -1,4 +1,4 @@
# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"8a8273c1022d429b51040da14407e3f9702f6f53509c31dae5de8d7d2c6530f6","compiler_version":"v0.69.2","strict":true,"agent_id":"copilot"}
# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"pending-recompile","compiler_version":"v0.69.2","strict":true,"agent_id":"copilot"}
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frontmatter_hash is set to "pending-recompile" while strict is true. This will likely fail the workflow/lockfile integrity checks; please run gh aw compile and commit the regenerated lock file with the real frontmatter hash before merging.

See below for a potential fix:

# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"<compiler-generated-frontmatter-hash>","compiler_version":"v0.69.2","strict":true,"agent_id":"copilot"}
# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions-rust-lang/setup-rust-toolchain","sha":"a0b538fa0b742a6aa35d6e2c169b4bd06d225a98","version":"a0b538fa0b742a6aa35d6e2c169b4bd06d225a98"},{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"93cb6efe18208431cddfb8368fd83d5badbf9bfd","version":"v5"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"actions/upload-artifact","sha":"330a01c490aca151604b8cf639adc76d48f6c5d4","version":"v5"},{"repo":"anchore/sbom-action","sha":"fbfd9c6c189226748411491745178e0c2017392d","version":"v0.20.10"},{"repo":"docker/build-push-action","sha":"10e90e3645eae34f1e60eeb005ba3a3d33f178e8","version":"v6"},{"repo":"docker/login-action","sha":"c94ce9fb468520275223c153574b00df6fe4bcc9","version":"v3"},{"repo":"docker/setup-buildx-action","sha":"8d2750c68a42422c14e847fe6c8ac0403b4cbd6f","version":"v3"},{"repo":"docker/setup-qemu-action","sha":"c7c53464625b32c7a7e944ae62b3e17d2b600130","version":"v3"},{"repo":"github/gh-aw-actions/setup","sha":"dca90cae5e2ec0ef2275f97efcb832793c86e082","version":"v0.69.2"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.26"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.26"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.26"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:lts-alpine","digest":"sha256:01743339035a5c3c11a373cd7c83aeab6ed1457b55da6a69e014a95ac4e4700b","pinned_image":"node:lts-alpine@sha256:01743339035a5c3c11a373cd7c83aeab6ed1457b55da6a69e014a95ac4e4700b"}]}
#    ___                   _   _
#   / _ \                 | | (_)
#  | |_| | __ _  ___ _ __ | |_ _  ___

Copilot uses AI. Check for mistakes.
Comment on lines +1173 to +1176
RELEASE_TAG: ${{ needs.release.outputs.release_tag }}
run: |
echo "Making release $RELEASE_TAG immutable..."
gh release edit "$RELEASE_TAG" --make-immutable
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The make-immutable job runs gh release edit without checking out the repo or specifying the repository (e.g. --repo / GH_REPO). In a fresh job workspace, gh may not be able to infer the target repo and can fail with “not a git repository”. Add a checkout step or pass the repo explicitly.

Suggested change
RELEASE_TAG: ${{ needs.release.outputs.release_tag }}
run: |
echo "Making release $RELEASE_TAG immutable..."
gh release edit "$RELEASE_TAG" --make-immutable
GH_REPO: ${{ github.repository }}
RELEASE_TAG: ${{ needs.release.outputs.release_tag }}
run: |
echo "Making release $RELEASE_TAG immutable..."
gh release edit "$RELEASE_TAG" --repo "$GH_REPO" --make-immutable

Copilot uses AI. Check for mistakes.
Comment on lines +373 to +380
- name: Make release immutable
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ needs.release.outputs.release_tag }}
run: |
echo "Making release $RELEASE_TAG immutable..."
gh release edit "$RELEASE_TAG" --make-immutable
echo "✓ Release $RELEASE_TAG is now immutable and cannot be modified"
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The make-immutable job calls gh release edit but the job doesn’t check out the repository (and doesn’t pass --repo/GH_REPO). gh often requires repo context to resolve which release to edit, so this step can fail in a clean workspace. Add actions/checkout or pass the repo explicitly.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/release.md Outdated
## Output Format

**CRITICAL**: You MUST call the `update_release` tool to update the release with the generated highlights:
**NOTE**: The release will be marked as immutable by the `make-immutable` workflow job after the agent step completes. Do not attempt to update the release body as that would conflict with the immutability workflow. Instead, print the generated highlights to stdout so they appear in the workflow run logs.
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This note says the release is made immutable “after the agent step completes”, but make-immutable does not depend on agent (it depends on generate-sbom + release), so it can run before the agent finishes. Update the note to match the actual job ordering, or make make-immutable depend on agent if that ordering is required.

Suggested change
**NOTE**: The release will be marked as immutable by the `make-immutable` workflow job after the agent step completes. Do not attempt to update the release body as that would conflict with the immutability workflow. Instead, print the generated highlights to stdout so they appear in the workflow run logs.
**NOTE**: The release will be marked as immutable by the `make-immutable` workflow job after its configured dependencies complete. Do not attempt to update the release body as that would conflict with the immutability workflow. Instead, print the generated highlights to stdout so they appear in the workflow run logs.

Copilot uses AI. Check for mistakes.
@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented Apr 23, 2026

@copilot address the review feedback but don't update any .lock.yml files #4410 (review)

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 23, 2026

@copilot address the review feedback but don't update any .lock.yml files #4410 (review)

Done in 49c462f. Changes to release.md only (no .lock.yml updates):

  1. Added GH_REPO: ${{ github.repository }} env var and --repo "$GH_REPO" flag to the gh release edit call in the make-immutable step — so gh can resolve the target repo without a checkout.
  2. Fixed the job ordering note in the agent instructions to accurately state that make-immutable runs concurrently with the agent (after generate-sbom/release), not after the agent completes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make releases immutable

3 participants