Skip to content

Commit 59e7fd1

Browse files
authored
ci: switch from SLSA provenance to actions/attest with subject-path (#19)
**Requirements** - [x] I have added test coverage for new or changed functionality - [x] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) - [x] 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. This PR makes the following changes: 1. **Replace SLSA with `actions/attest@v4` using `subject-path`** (both workflows): Removed the separate `release-provenance` job that used `slsa-framework/slsa-github-generator` (which uploaded `.intoto.jsonl` files as release assets via `upload-assets: true`) and replaced it with inline `actions/attest@v4` steps within the build job. Attestation uses `subject-path: 'launchdarkly-openfeature-server-sdk-*.gem'` to reference the built gem file directly on disk — no hash computation, base64 encoding, or checksums file needed. Added `attestations: write` permission. Removed `gem-hash` job output entirely. 2. **Removed hash plumbing from composite action** (`.github/actions/publish/action.yml`): Removed the `gem-hash` output and "Hash gem for provenance" step. These existed to produce base64-encoded checksums for the old SLSA generator and are no longer needed since `subject-path` lets `actions/attest@v4` read files directly from disk. 3. **Cleaned up orphaned declarations**: Removed the unused `tag` input from `manual-publish.yml` (was declared but never referenced by any step, with a stale "draft release" description). Removed orphaned `release-created` and `upload-tag-name` job outputs from `release-please.yml` — their sole consumer was the removed `release-provenance` job. 4. **`release-please-config.json`**: Reformatted `extra-files` array to multi-line — no functional changes. ### Why no draft releases? The old SLSA generator uploaded provenance files as release assets via `upload-assets: true`, which would fail under immutable releases. The new `actions/attest@v4` stores attestations in GitHub's attestation API instead — it does **not** modify the GitHub release. Since this repo has no other artifact uploads, release-please can publish directly without a draft→un-draft flow. Repos that upload actual binaries (e.g. ld-relay, cpp-sdks) still use draft releases. ### Updates since last revision - Removed unused `tag` input from `manual-publish.yml` and orphaned `release-created` / `upload-tag-name` outputs from `release-please.yml`. These were dead declarations left behind when the `release-provenance` job and draft-release machinery were removed. (Addresses Cursor Bugbot findings.) **Describe alternatives you've considered** - **Draft release pattern**: An earlier revision used draft releases with a `publish-release` job to un-draft after completion. This was simplified after determining that attestation-only repos don't need draft releases since `actions/attest@v4` doesn't modify the release. - **`subject-checksums`**: An intermediate revision decoded base64 hashes into a checksums file for `actions/attest`. This worked but was unnecessarily complex — the gem file is already on disk in the same job, so `subject-path` references it directly. **Additional context** Key review points: - [x] ~~**`tag` input is declared but unused**~~: Now resolved — the `tag` input was removed entirely. - [x] ~~**No `dry_run` guard on attestation in `manual-publish.yml`**~~: Now resolved — the attest step is gated on `!inputs.dry_run`. - [ ] **Glob pattern correctness**: Verify `subject-path: 'launchdarkly-openfeature-server-sdk-*.gem'` matches the gem produced by `gem build launchdarkly-openfeature-server-sdk.gemspec`. The publish action already uses the same pattern for `gem push`, so this should be consistent — but worth confirming. - [ ] **`releases_created` vs `release_created`**: In `release-please.yml`, the attestation step uses `steps.release.outputs.releases_created` (plural) while the original job-level output used `release_created` (singular). Both are valid release-please outputs but confirm they behave identically for this single-package repo. - [ ] **`contents: read` vs `contents: write`**: `manual-publish.yml` has `contents: read` while `release-please.yml` has `contents: write`. Verify `actions/attest@v4` does not require `contents: write`. - [ ] **Confirm `actions/attest@v4` meets compliance requirements**: This replaces `slsa-framework/slsa-github-generator`. Verify the attestation format is acceptable for your supply-chain security needs. Link to Devin session: https://app.devin.ai/sessions/7d5bda4d9dbe4ae0b950b30a50485e60 Requested by: @keelerm84
1 parent 84b7aca commit 59e7fd1

4 files changed

Lines changed: 16 additions & 39 deletions

File tree

.github/actions/publish/action.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ inputs:
44
dry_run:
55
description: 'Is this a dry run. If so no package will be published.'
66
required: true
7-
outputs:
8-
gem-hash:
9-
description: "base64-encoded sha256 hashes of distribution files"
10-
value: ${{ steps.gem-hash.outputs.gem-hash }}
117

128
runs:
139
using: composite
@@ -16,12 +12,6 @@ runs:
1612
shell: bash
1713
run: gem build launchdarkly-openfeature-server-sdk.gemspec
1814

19-
- name: Hash gem for provenance
20-
id: gem-hash
21-
shell: bash
22-
run: |
23-
echo "gem-hash=$(sha256sum launchdarkly-openfeature-server-sdk-*.gem | base64 -w0)" >> "$GITHUB_OUTPUT"
24-
2515
- name: Publish Library
2616
shell: bash
2717
if: ${{ inputs.dry_run == 'false' }}

.github/workflows/manual-publish.yml

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ jobs:
1414
permissions:
1515
id-token: write
1616
contents: read
17-
outputs:
18-
gem-hash: ${{ steps.publish.outputs.gem-hash}}
17+
attestations: write
1918
steps:
2019
- uses: actions/checkout@v4
2120

@@ -37,13 +36,8 @@ jobs:
3736
with:
3837
dry_run: ${{ inputs.dry_run }}
3938

40-
release-provenance:
41-
needs: [ 'build-publish' ]
42-
permissions:
43-
actions: read
44-
id-token: write
45-
contents: write
46-
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
47-
with:
48-
base64-subjects: "${{ needs.build-publish.outputs.gem-hash }}"
49-
upload-assets: ${{ !inputs.dry_run }}
39+
- name: Attest build provenance
40+
if: ${{ !inputs.dry_run }}
41+
uses: actions/attest@v4
42+
with:
43+
subject-path: 'launchdarkly-openfeature-server-sdk-*.gem'

.github/workflows/release-please.yml

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ jobs:
1212
id-token: write # Needed if using OIDC to get release secrets.
1313
contents: write # Contents and pull-requests are for release-please to make releases.
1414
pull-requests: write
15-
outputs:
16-
release-created: ${{ steps.release.outputs.release_created }}
17-
upload-tag-name: ${{ steps.release.outputs.tag_name }}
18-
gem-hash: ${{ steps.publish.outputs.gem-hash}}
15+
attestations: write
1916
steps:
2017
- uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0
2118
id: release
@@ -51,15 +48,8 @@ jobs:
5148
with:
5249
token: ${{secrets.GITHUB_TOKEN}}
5350

54-
release-provenance:
55-
needs: [ 'release-package' ]
56-
if: ${{ needs.release-package.outputs.release-created == 'true' }}
57-
permissions:
58-
actions: read
59-
id-token: write
60-
contents: write
61-
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
62-
with:
63-
base64-subjects: "${{ needs.release-package.outputs.gem-hash }}"
64-
upload-assets: true
65-
upload-tag-name: ${{ needs.release-package.outputs.upload-tag-name }}
51+
- name: Attest build provenance
52+
if: ${{ steps.release.outputs.releases_created == 'true' }}
53+
uses: actions/attest@v4
54+
with:
55+
subject-path: 'launchdarkly-openfeature-server-sdk-*.gem'

release-please-config.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
"versioning": "default",
77
"include-component-in-tag": false,
88
"include-v-in-tag": false,
9-
"extra-files": ["PROVENANCE.md", "lib/ldclient-openfeature/version.rb"]
9+
"extra-files": [
10+
"PROVENANCE.md",
11+
"lib/ldclient-openfeature/version.rb"
12+
]
1013
}
1114
}
1215
}

0 commit comments

Comments
 (0)