ci: use draft releases to support immutable GitHub releases#516
ci: use draft releases to support immutable GitHub releases#516
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| fi | ||
| shell: bash | ||
| - name: Attest build provenance | ||
| uses: actions/attest@v4 |
There was a problem hiding this comment.
Attest action unpinned unlike all other actions
Medium Severity
All 8 instances of actions/attest@v4 are referenced by a mutable major-version tag, while every other action in both workflows (actions/checkout, googleapis/release-please-action) is pinned to a specific commit SHA. A compromised or force-pushed v4 tag could inject malicious code into the release pipeline, which runs with contents: write, attestations: write, and id-token: write permissions.
Additional Locations (1)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.


Summary
Migrates the release workflow to support GitHub's immutable releases feature. Once a release is published it can no longer be modified, so we now create releases in draft state, upload all artifacts, and only then publish.
Changes across three files:
release-please-config.json— Added top-level"draft": trueso release-please creates draft releases for all packages. Added"force-tag-creation": trueto every package (not yet supported by release-please, but included for forward compatibility).release-please.yml— Split release-please pattern — release-please is now invoked twice within the same job:skip-github-pull-request: true— only creates releases (no PRs).skip-github-release: true— only creates/updates PRs, and only runs if no releases were created. This ordering ensures tags exist before release-please checks whether a release PR is still needed.release-client,release-server, etc.) now depend only onrelease-please(the former separatecreate-tagsjob has been removed).googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38(v4.4.0).actions/attest@v4— Removed all 7 SLSA provenance jobs (release-{client,server,server-redis}-provenance,release-{client,server,server-redis}-mac-arm64-provenance, plus 2 in the manual workflow). Replaced with inlineactions/attest@v4steps in each build job that decode the base64 hashes into a checksums file and attest in-place.publish-release-*jobs — Three new jobs (publish-release-client,publish-release-server,publish-release-server-redis) that un-draft their respective release only after all artifact jobs complete.manual-sdk-release-artifacts.yml—publish_releaseinput — Added apublish_releaseboolean input (default:true) and apublish-releasejob gated on it, so operators can optionally keep the release in draft after manual artifact uploads.Review & Testing Checklist for Human
ifcondition on the second call correctly uses!= 'true'with&&across all 4 packages.needsarrays inpublish-release-*jobs: Verify each publish job waits on ALL artifact-uploading jobs for that package before un-drafting. A missing dependency means the release gets published before all artifacts are uploaded — the exact problem we're solving. For example,publish-release-clientneeds bothrelease-client(3-OS matrix) andrelease-client-mac-arm64.release-pleasecreates a tag for server-otel if released, and"draft": truemeans release-please creates a draft release, but there is nopublish-release-server-oteljob to un-draft it. If server-otel has no artifact uploads this is fine — but confirm the draft release won't stay stuck.actions/attest@v4(unpinned): The attest action is referenced by major version tag, not a pinned SHA. Verify this aligns with the repo's policy on action pinning (other actions like checkout are SHA-pinned).publish_release: falseto verify the release stays in draft.Notes
ld-relay(commit 1581de9). The key insight is that release-please depends on the tag existing when determining if a release PR is still needed — so tags must be created between the release step and the PR step.${{ github.repository }}expression appears inrun:blocks (tag creation and publish-release jobs). This value is GitHub-controlled (not user input) so script injection risk is negligible, but worth noting since tag names are deliberately routed through env vars.force-tag-creationhas no effect with the current release-please version — it is a forward-compatibility placeholder that will take effect once release-please supports it, at which point the inline tag creation steps can be removed.manual-sdk-release-artifacts.yml'spublish_releasedefaults totrueforworkflow_dispatch, matching the expectation that manual runs typically want to finalize the release.Link to Devin session: https://app.devin.ai/sessions/7d5bda4d9dbe4ae0b950b30a50485e60
Requested by: @keelerm84
Note
Medium Risk
Touches the release automation pipeline (draft/publish flow, manual tag creation, and provenance generation), so misconfiguration could block releases or publish them prematurely.
Overview
Updates the GitHub release automation to support immutable releases by having
release-pleasecreate draft releases and then explicitly creating/pushing tags in-workflow before any release PR updates.Replaces the previous SLSA generator provenance workflows with per-build
actions/attest@v4provenance attestations (via decoded checksum files), and adds publish steps/jobs that un-draft releases only after all artifacts are uploaded (including apublish_releasetoggle for the manual artifacts workflow).Reviewed by Cursor Bugbot for commit d509dbb. Bugbot is set up for automated code reviews on this repo. Configure here.