Skip to content

ci: implement immutable releases support with actions/attest#413

Open
keelerm84 wants to merge 11 commits intomainfrom
devin/1774991579-immutable-releases
Open

ci: implement immutable releases support with actions/attest#413
keelerm84 wants to merge 11 commits intomainfrom
devin/1774991579-immutable-releases

Conversation

@keelerm84
Copy link
Copy Markdown
Member

@keelerm84 keelerm84 commented Mar 31, 2026

Requirements

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions

N/A — CI-only and documentation changes, no application code or tests affected.

Related issues

Supports the org-wide migration to immutable GitHub releases. Reference implementation: launchdarkly/ld-relay (branch v8).

Describe the solution you've provided

GitHub's immutable releases feature prevents modifying a release after it is published. This repo only uses attestation (no binary/artifact uploads to the release), so actions/attest@v4 — which stores attestations via GitHub's attestation API rather than as release assets — is compatible with immutable releases without needing draft releases.

This PR makes the following changes:

  1. SLSA → actions/attest@v4 (both workflows): Replaced the separate release-provenance job (using slsa-framework/slsa-github-generator reusable workflow with upload-assets: true) with inline actions/attest@v4 steps within the build job. Attestation now uses subject-path: 'dist/*' to reference the built distribution files directly on disk, eliminating the old base64-encoded hash round-trip entirely.

  2. Removed hash outputs from build action: The package-hashes output and "Hash build files for provenance" step were removed from .github/actions/build/action.yml since subject-path reads files directly rather than requiring pre-computed checksums.

  3. attestations: write permission: Added to both workflows to support actions/attest@v4.

  4. Removed orphaned job outputs from release-please.yml: The release-created, upload-tag-name, and package-hashes outputs were only consumed by the now-removed release-provenance job. All three have been removed.

  5. Removed orphaned package-hashes output from manual-publish.yml: Similarly unused after removing the release-provenance job.

  6. Updated PROVENANCE.md and README.md: Replaced all SLSA framework references with GitHub artifact attestation documentation. Verification instructions now use gh attestation verify ... --owner launchdarkly instead of slsa-verifier. Sample output reflects the real gh attestation verify format including policy criteria and attestation details.

  7. dry_run condition fix: Uses format('{0}', inputs.dry_run) == 'false' to safely handle the boolean/string mismatch between workflow_call (boolean) and workflow_dispatch (string) trigger types.

Key things for reviewer to verify:

  • Verify that subject-path: 'dist/*' correctly matches the poetry build output (.tar.gz and .whl files in ./dist/).
  • Confirm no external workflows or systems depend on the removed release-created or upload-tag-name job outputs from release-please.yml. These were only consumed by the release-provenance job within this workflow.
  • The PROVENANCE.md sample output is based on real gh attestation verify output from ld-relay. The repo/workflow names are adapted for this repo but haven't been verified against an actual attested release yet.
  • No draft release configuration or force-tag-creation is needed for this repo since actions/attest@v4 does not upload assets to the GitHub release.

Updates since last revision

  • Updated PROVENANCE.md to use gh attestation verify --owner launchdarkly with the full real output template (policy criteria, attestation details) instead of a simplified placeholder.
  • Updated README.md provenance section heading and description to reference GitHub artifact attestations instead of the SLSA framework.
  • Removed unused tag input from manual-publish.yml (flagged by Cursor Bugbot as dead code).
  • Removed orphaned release-created and upload-tag-name job outputs from release-please.yml.
  • Fixed dry_run conditions to use format('{0}', inputs.dry_run) == 'false' for correct boolean/string handling across trigger types.

Describe alternatives you've considered

An earlier revision used draft releases with a publish-release job to un-draft after completion. This was simplified since this repo only uses attestation (not artifact uploads), so draft releases are unnecessary.

An intermediate revision used subject-checksums with a checksums file (base64 decode of hashes computed in the build action). This was replaced with subject-path since the artifacts are on disk in the same job, making the hash round-trip redundant.

The verify command could use -R launchdarkly/python-server-sdk to scope verification to this specific repo, but --owner launchdarkly was chosen for consistency across all LaunchDarkly SDK repos.

Additional context

No application code or test changes. Only CI workflow files and documentation are modified.

Link to Devin session: https://app.devin.ai/sessions/7d5bda4d9dbe4ae0b950b30a50485e60
Requested by: @keelerm84


Note

Medium Risk
Changes the release/publish CI provenance mechanism and required workflow permissions, which could affect publishing/attestation behavior if misconfigured. No application runtime code changes.

Overview
Migrates build provenance generation from the SLSA reusable workflow (hash-based, release-asset upload) to GitHub artifact attestations via actions/attest@v4 in both manual-publish.yml and release-please.yml, attesting the local dist/* artifacts.

Removes the build action’s package-hashes output and hashing step, deletes the separate release-provenance job/related job outputs, adds attestations: write permissions, and updates PROVENANCE.md to verify with gh attestation verify (plus a small dry_run conditional fix for manual publishing).

Written by Cursor Bugbot for commit 1e7fd43. This will update automatically on new commits. Configure here.

@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Since actions/attest@v4 stores attestations via GitHub's attestation API
(not as release assets), repos that only use attestation don't need draft
releases. Release-please can publish the release directly.

Changes:
- Remove draft:true from release-please-config.json
- Remove create-tag job/steps (force-tag-creation handles this)
- Remove publish-release job (release is published directly)
- Remove publish_release input from manual workflows
@devin-ai-integration devin-ai-integration bot changed the title ci: use draft releases to support immutable GitHub releases ci: implement immutable releases support with actions/attest Mar 31, 2026
force-tag-creation only operates in conjunction with draft releases.
Since this repo does not use draft releases (attestation-only, no
artifact uploads to the release), force-tag-creation is not needed.
@kinyoklion kinyoklion marked this pull request as ready for review April 1, 2026 17:40
@kinyoklion kinyoklion requested a review from a team as a code owner April 1, 2026 17:40
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.


- name: Publish package distributions to PyPI
if: ${{ inputs.dry_run == false }}
if: ${{ format('{0}', inputs.dry_run) == 'false' }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused id: build step identifiers after output removal

Low Severity

The id: build on the build step is now dead code. It previously existed so the workflow could reference steps.build.outputs.package-hashes, but this PR removed that output from the build action. A grep for steps.build across .github/ confirms nothing references it anymore. Since this PR is specifically cleaning up orphaned references (outputs, jobs), this leftover id appears to be an oversight in the same cleanup.

Additional Locations (1)
Fix in Cursor Fix in Web

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants