Skip to content

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

Merged
keelerm84 merged 11 commits intomainfrom
devin/1774991561-immutable-releases
Apr 2, 2026
Merged

ci: switch from SLSA provenance to actions/attest with subject-path#116
keelerm84 merged 11 commits intomainfrom
devin/1774991561-immutable-releases

Conversation

@keelerm84
Copy link
Copy Markdown
Member

@keelerm84 keelerm84 commented Mar 31, 2026

Summary

Adapts the release workflow for GitHub's immutable releases feature. 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, not as release assets.

Changes across 5 files:

  1. .github/actions/publish/action.yml — Removed the hashes output and "Hash nuget packages" step that base64-encoded SHA256 checksums. These existed to feed the old SLSA generator's base64-subjects input and are no longer needed since attestation now uses subject-path to reference artifacts directly on disk.

  2. .github/workflows/publish.yml — Replaced the separate provenance job (SLSA generator_generic_slsa3 reusable workflow with upload-assets: true) with an inline actions/attest@v4 step in the publish job using subject-path: 'nupkgs/*'. Added attestations: write permission. Removed the unused tag input from both workflow_dispatch and workflow_call triggers. This eliminates the base64 encode/decode round-trip, the checksums file generation, and the .intoto.jsonl release asset upload entirely.

  3. .github/workflows/release-please.yml — Removed tag: ${{ needs.release-please.outputs.tag_name }} from the publish workflow call and the tag_name output from the release-please job (both are dead code after the tag input removal).

  4. PROVENANCE.md (new) — Added provenance verification guide with gh attestation verify instructions and sample output, using the x-release-please-start-version marker to keep the version in sync with releases.

  5. README.md — Added a "Verifying build provenance with the SLSA framework" section linking to the new PROVENANCE.md.

Why subject-path instead of subject-checksums?

The previous intermediate revision used subject-checksums with a base64 decode step to convert the composite action's hash output into a checksums file. This was redundant — the .nupkg and .snupkg files are already on disk in ./nupkgs/ within the same job, so subject-path: 'nupkgs/*' lets actions/attest@v4 compute checksums directly. This removes all hash-related plumbing from both the composite action and the workflow.

Why no draft releases?

The old SLSA generator uploaded .intoto.jsonl provenance files as release assets (via upload-assets: true), which would fail under immutable releases if the release was already published. The new actions/attest@v4 stores attestations in GitHub's attestation API instead, so the release can be published directly by release-please without needing a draft→publish flow.

Why format('{0}', inputs.dry_run) for the condition?

GitHub Actions workflow_dispatch delivers boolean inputs as strings ('false'), while workflow_call delivers them as actual booleans (false). A plain == 'false' comparison silently fails when receiving a real boolean. Using format('{0}', inputs.dry_run) coerces either type to a string before comparison, ensuring the guard works for both trigger sources.

Review & Testing Checklist for Human

  • Verify the subject-path: 'nupkgs/*' glob matches the output of dotnet pack --output nupkgs in the composite action (should capture both .nupkg and .snupkg files). If the directory is empty or missing at attest time (e.g. during a dry run), confirm the format('{0}', inputs.dry_run) == 'false' guard prevents the attest step from running.
  • Confirm attestations: write permission on the publish job is sufficient for actions/attest@v4 (the old SLSA generator ran as a separate job with actions: read, id-token: write, and contents: write).
  • Validate end-to-end by running a dry-run dispatch of publish.yml (should skip attestation) and then a real release to confirm the attest step succeeds and no .intoto.jsonl asset is expected by downstream consumers.
  • Verify the PROVENANCE.md sample output references the correct workflow path — the attest step runs inside publish.yml (called via release-please.yml); confirm GitHub records the expected workflow in the attestation so the sample output matches reality.
  • Verify the PROVENANCE.md version placeholder (5.3.0) is updated by release-please via the x-release-please-start-version / x-release-please-end markers on the next release.

Notes

  • The format('{0}', inputs.dry_run) == 'false' condition coerces the boolean/string input to a consistent string before comparison, per GitHub Actions expressions docs.
  • release-please.yml still references releases_created (plural) — existing output names are preserved.
  • No changes to release-please-config.json remain in the final diff (the previously-added force-tag-creation was reverted as unnecessary for non-draft repos).
  • The removed provenance job previously generated a named .intoto.jsonl file uploaded as a release asset. Confirm no tooling or verification process depends on that specific asset being present on the GitHub release.
  • The PROVENANCE.md sample output is templated from the real gh attestation verify output format — repo name and workflow references are specific to this repository.

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


Note

Medium Risk
Medium risk because it changes the release/publish GitHub Actions flow for provenance generation and permissions; mistakes could block releases or fail to emit attestations, but it doesn’t affect runtime code.

Overview
Replaces the prior SLSA provenance generation/upload flow with GitHub artifact attestations: the publish workflow now runs actions/attest@v4 (guarded by dry_run) over nupkgs/* and adds attestations: write permissions.

Simplifies the publish composite action and release automation by removing the nuget package hashing output/plumbing and dropping the now-unused tag inputs/outputs from publish.yml and release-please.yml.

Adds PROVENANCE.md with gh attestation verify instructions, links it from README.md, and updates release-please-config.json so the provenance doc is version-bumped with releases.

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

@devin-ai-integration
Copy link
Copy Markdown

🤖 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 PR created by Devin 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
@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:37
@kinyoklion kinyoklion requested a review from a team as a code owner April 1, 2026 17:37
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 2 potential issues.

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.

@keelerm84 keelerm84 merged commit 1aefbcf into main Apr 2, 2026
5 of 6 checks passed
@keelerm84 keelerm84 deleted the devin/1774991561-immutable-releases branch April 2, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devin-pr PR created by Devin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants