Skip to content

ci: switch from SLSA provenance to actions/attest with subject-path#106

Merged
keelerm84 merged 10 commits into
mainfrom
devin/1774991594-immutable-releases
Apr 2, 2026
Merged

ci: switch from SLSA provenance to actions/attest with subject-path#106
keelerm84 merged 10 commits into
mainfrom
devin/1774991594-immutable-releases

Conversation

@keelerm84

@keelerm84 keelerm84 commented Mar 31, 2026

Copy link
Copy Markdown
Member

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 changes, no application code or tests modified.

Related issues

Supports the org-wide migration to immutable GitHub releases. Once a release is published, it can no longer be modified, which breaks workflows that upload artifacts after release-please publishes the release.

Describe the solution you've provided

Since this repo only uses attestation (no binary/artifact uploads to the release), draft releases are not needed. actions/attest@v4 stores attestations via GitHub's attestation API rather than as release assets, so the release can be published directly by release-please without a draft→publish flow.

This PR makes the following changes:

  1. SLSA → actions/attest@v4 with subject-path (both workflows): Replaced the separate release-provenance job (using slsa-framework/slsa-github-generator with upload-assets: true) with inline actions/attest@v4 steps. Attestation now uses subject-path: '${{ steps.ci.outputs.dist-dir }}/*tar.gz' to reference the built distribution tarballs directly on disk, eliminating the old base64-encoded hash round-trip entirely. Added attestations: write permission.

  2. CI action output changed (.github/actions/ci/action.yml): Replaced the package-hashes output (base64-encoded sha256 checksums) with a dist-dir output that exposes the stack dist directory path. Removed the "Hash build files for provenance" step. The "Setup dist directory" step now sets both the STACK_DIR env var (used by downstream steps in the composite action) and the dist-dir output (used by workflows for attestation).

  3. Removed orphaned declarations: Cleaned up dead code left behind after the release-provenance job was removed:

    • Removed release-created, upload-tag-name, and package-hashes outputs from the release-package job in release-please.yml (their sole consumer was the deleted release-provenance job).
  4. Dry run safety: The actions/attest step in manual-publish.yml is gated on format('{0}', inputs.dry_run) == 'false'. The format() call coerces both real booleans (from workflow_call) and strings (from workflow_dispatch) to a string before comparison, ensuring the guard works correctly for both trigger sources.

  5. PROVENANCE.md: Updated from slsa-verifier instructions to gh attestation verify instructions and sample output, reflecting the switch to GitHub artifact attestations.

No changes to release-please-config.jsondraft and force-tag-creation are intentionally not set since this attestation-only repo does not need them.

Updates since last revision

  • Reverted the split release-please pattern (two-pass skip-github-pull-request / skip-github-release with inline tag creation) that was briefly added. This pattern is only needed for repos that upload artifacts to releases (which require draft releases). Since this repo is attestation-only, the standard single-pass release-please is correct.
  • Fixed the dry_run condition from !inputs.dry_run to format('{0}', inputs.dry_run) == 'false' — ensures correct evaluation whether the input is a boolean (from workflow_call) or a string (from workflow_dispatch).

Key points for review:

  • manual-publish.yml has contents: read while release-please.yml has contents: write. Verify actions/attest@v4 does not require contents: write — if it does, the manual workflow's attestation step will silently fail.
  • The subject-path glob *tar.gz (no dot prefix) matches the original hash step's glob pattern. Verify this correctly matches only .tar.gz files produced by stack sdist and doesn't inadvertently match unexpected files.
  • The dist-dir output is dynamic (resolved at runtime by stack path --dist-dir). If the CI step were skipped or failed, the attest step would receive an empty path. In release-please.yml, the attest step is gated on releases_created == 'true', and the CI step has the same guard, so this should be safe. In manual-publish.yml, both steps run unconditionally (except the attest dry_run guard), so verify the CI step always succeeds before attest runs.
  • Confirm no downstream consumers depend on the old .intoto.jsonl provenance file that was previously uploaded as a release asset.
  • Confirm no external workflows or reusable workflow callers depended on the removed release-created / upload-tag-name outputs.

Describe alternatives you've considered

  • subject-checksums with base64 round-trip: An earlier revision decoded the CI action's base64-encoded hashes into a checksums file for actions/attest. This worked but was unnecessarily complex — the tarballs are already on disk in the same job, so subject-path is more direct.
  • Draft release pattern: An earlier revision used draft releases with a publish-release job to un-draft after all uploads completed. This was simplified since this repo only uses attestation (not artifact uploads), making draft releases unnecessary.
  • Split release-please pattern: An earlier revision ran release-please in two passes (releases first, then PRs) with inline tag creation. This is needed for repos with artifact uploads that require draft releases, but is unnecessary overhead for attestation-only repos like this one.
  • Keep SLSA generator: Could keep it as a separate reusable workflow, but actions/attest@v4 is the org-standard replacement and simplifies the workflow by running attestation inline.

Additional context

Follows the canonical pattern from launchdarkly/ld-relay (branch v8). Repos that upload actual binaries (e.g. ld-relay, cpp-sdks, roku-client-sdk) use the draft release pattern; attestation-only repos like this one do not need it.

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

@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

@devin-ai-integration devin-ai-integration Bot added the devin-pr PRs created by Devin AI label Mar 31, 2026
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: switch to actions/attest and add force-tag-creation 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.
@devin-ai-integration devin-ai-integration Bot changed the title ci: switch to actions/attest and add force-tag-creation ci: switch from SLSA provenance to actions/attest Mar 31, 2026
The attest step was already guarded, but the checksums file generation
was not. Now both steps are skipped during dry runs.
@devin-ai-integration devin-ai-integration Bot changed the title ci: switch from SLSA provenance to actions/attest ci: switch from SLSA provenance to actions/attest with subject-path Mar 31, 2026
@kinyoklion kinyoklion marked this pull request as ready for review April 1, 2026 17:58
@kinyoklion kinyoklion requested a review from a team as a code owner April 1, 2026 17:58

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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.

Comment thread .github/workflows/manual-publish.yml
@keelerm84 keelerm84 merged commit 77e2e85 into main Apr 2, 2026
13 checks passed
@keelerm84 keelerm84 deleted the devin/1774991594-immutable-releases branch April 2, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devin-pr PRs created by Devin AI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants