ci(release): sign binaries with cosign, attest SLSA L3 provenance - #270
Conversation
📝 WalkthroughWalkthroughThe release workflow now keylessly signs archives, computes provenance subject hashes, and attaches SLSA attestations. The README documents cosign and SLSA verification, including Windows Authenticode limitations and verification failure handling. ChangesRelease verification
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ReleaseJob
participant Cosign
participant SLSAGenerator
ReleaseJob->>Cosign: Sign release archives with OIDC keyless signing
Cosign-->>ReleaseJob: Create .cosign.bundle files
ReleaseJob->>SLSAGenerator: Pass base64 SHA256 hashes
SLSAGenerator-->>ReleaseJob: Attach SLSA provenance to the release
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
zizmor unpinned-uses (high severity) flagged the tag ref; pin to v2.1.0's resolved commit.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/release.yml (1)
107-120: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winUpload the Cosign bundles after signing.
This step creates
dist/*.cosign.bundleafter the existing release-upload step, so the bundles are not attached to the GitHub release. README verification will therefore fail because users cannot download the required bundle. Move signing before the release upload or add a follow-up upload for the generated bundles.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release.yml around lines 107 - 120, Ensure the generated .cosign.bundle files are attached to the GitHub release by moving the “Sign binaries with cosign (keyless)” step before the existing release-upload step, or by adding a subsequent upload step that includes dist/*.cosign.bundle. Preserve signing for all matching .tar.gz and .zip artifacts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Line 143: Update the reusable workflow reference in the release workflow from
the commit SHA to the full v2.1.0 tag, and add a targeted zizmor ignore for
unpinned uses on that reference. Preserve the existing
generator_generic_slsa3.yml workflow.
---
Outside diff comments:
In @.github/workflows/release.yml:
- Around line 107-120: Ensure the generated .cosign.bundle files are attached to
the GitHub release by moving the “Sign binaries with cosign (keyless)” step
before the existing release-upload step, or by adding a subsequent upload step
that includes dist/*.cosign.bundle. Preserve signing for all matching .tar.gz
and .zip artifacts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 6de96a9f-1f33-4684-9965-7621ae373226
📒 Files selected for processing (1)
.github/workflows/release.yml
| actions: read # generator reads the workflow run for provenance | ||
| id-token: write # OIDC keyless signing (same trust model as cosign) | ||
| contents: write # attach the attestation to the release | ||
| uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a # v2.1.0 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
curl -fsSL https://raw.githubusercontent.com/slsa-framework/slsa-github-generator/main/README.md |
grep -n -A4 'MUST be referenced by tag'Repository: getappz/agentflare
Length of output: 156
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## release workflow context\n'
sed -n '120,160p' .github/workflows/release.yml
printf '\n## repo references to slsa-github-generator\n'
rg -n "slsa-github-generator|zizmor: ignore\\[unpinned-uses\\]|slsa-verifier" -S .Repository: getappz/agentflare
Length of output: 1788
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## README around SLSA verification\n'
sed -n '180,210p' README.md
printf '\n## exact workflow pin in release.yml\n'
grep -n "slsa-framework/slsa-github-generator" -n .github/workflows/release.ymlRepository: getappz/agentflare
Length of output: 1795
🌐 Web query:
slsa-github-generator reusable workflow reference by tag slsa-verifier trusted builder commit SHA release.yml
💡 Result:
When using slsa-github-generator, you must reference reusable workflows by a specific semantic version tag (e.g., @vX.Y.Z) rather than by commit SHA or shorter tags (like @vX or @vX.Y) [1][2][3]. This requirement is intentional and necessary for slsa-verifier to successfully verify the reference of the trusted builder or generator [1][4]. While this approach deviates from general GitHub Actions best practices—which typically recommend pinning by commit SHA—it is a mandatory constraint due to current technical limitations in GitHub Actions [1][4][5]. Regarding verification, slsa-verifier works by verifying the cryptographic signatures on the generated provenance to confirm it was created by the expected builder [6][7]. It also validates properties such as the builder ID and the source code repository [6][7]. When you need to verify a specific commit SHA, you should use the --print-provenance flag with slsa-verifier to inspect the commit SHA of the config source or materials, rather than specifying the commit SHA directly as an input to the verification flags [6][7]. Summary of Key Practices: - Always reference slsa-github-generator reusable workflows using the full semantic version tag (@vX.Y.Z) [1][8]. - Do not use commit SHAs or short tags for these specific reusable workflow references [2][4][3]. - Use slsa-verifier to check the generated provenance against your expected builder identity and source [6][9]. - For commit SHA validation, inspect the output of slsa-verifier --print-provenance [6][7].
Citations:
- 1: https://github.com/slsa-framework/slsa-github-generator
- 2: https://github.com/slsa-framework/slsa-github-generator/blob/v1.8.0/internal/builders/generic/README.md
- 3: https://github.com/slsa-framework/slsa-github-generator/tree/e64a21260779eaa7823fa8d393d78171e267de64
- 4: https://github.com/slsa-framework/slsa-github-generator/blob/v1.8.0/README.md
- 5: https://github.com/slsa-framework/slsa-github-generator/blob/cdeb3a916610bc00af5dee83d1acdd3c7079923a/BYOB.md
- 6: https://github.com/slsa-framework/slsa-verifier
- 7: https://pkg.go.dev/github.com/slsa-framework/slsa-verifier/v2
- 8: https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md
- 9: https://slsa.dev/spec/v1.2/verifying-artifacts
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import urllib.request, re
url='https://raw.githubusercontent.com/slsa-framework/slsa-github-generator/main/README.md'
text=urllib.request.urlopen(url, timeout=20).read().decode()
for pat in ['MUST be referenced by tag', 'slsa-verifier', 'trusted builder', 'reusable workflow']:
print(f'## {pat}')
for m in re.finditer(pat, text, re.I):
start=max(0,m.start()-180); end=min(len(text), m.end()+260)
print(text[start:end].replace('\n',' '))
print('---')
break
PYRepository: getappz/agentflare
Length of output: 2750
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## README around SLSA verification section\n'
sed -n '186,205p' README.md
printf '\n## upstream generator README mentions of tag/SHA guidance\n'
python3 - <<'PY'
import urllib.request, re
url='https://raw.githubusercontent.com/slsa-framework/slsa-github-generator/main/README.md'
text=urllib.request.urlopen(url, timeout=20).read().decode()
for needle in ['tag', 'commit', 'reusable workflow', 'generator_generic_slsa3.yml', 'unpinned']:
print(f'\n## {needle}')
for line in text.splitlines():
if needle.lower() in line.lower():
print(line)
PYRepository: getappz/agentflare
Length of output: 3720
🌐 Web query:
site:github.com/slsa-framework/slsa-github-generator README reusable workflow tag commit SHA slsa-verifier verify-artifact
💡 Result:
When using slsa-verifier to verify artifacts generated by slsa-github-generator reusable workflows, you must reference the reusable workflow using a semantic version tag (e.g., @vX.Y.Z) rather than a commit SHA or a shorter tag (e.g., @vX or @vX.Y) [1][2][3]. This requirement is intentional and necessary for slsa-verifier to successfully perform verification [4][5]. Specifically, slsa-verifier needs to confirm the identity of the trusted builder or generator used to create the provenance [1][6]. Because GitHub Actions does not provide information about the associated branch or tag when a workflow is called by its commit SHA, slsa-verifier cannot distinguish between commits on a trusted branch (like main) and commits from untrusted sources (such as forks or PRs) [7]. Consequently, referencing by tag is currently the only supported method to ensure the provenance is verifiable [1][4]. While referencing third-party actions by digest is generally considered a best practice in GitHub Actions for security hardening, this specific requirement for slsa-github-generator workflows is a known limitation due to how GitHub Actions handles metadata for reusable workflows [4][5]. The technical community tracks this issue (e.g., issue #12 in the slsa-verifier repository) as a point of ongoing development [1][4].
Citations:
- 1: https://github.com/slsa-framework/slsa-github-generator/blob/refs/tags/v2.1.0/README.md
- 2: https://github.com/slsa-framework/slsa-github-generator/blob/cdeb3a916610bc00af5dee83d1acdd3c7079923a/internal/builders/bazel/README.md
- 3: https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md
- 4: https://github.com/slsa-framework/slsa-github-generator
- 5: https://github.com/slsa-framework/slsa-github-generator/blob/cabe6bc825b741b031e12d0391ae70efe3076b30/README.md
- 6: https://github.com/slsa-framework/slsa-github-generator/blob/main/SPECIFICATIONS.md
- 7: Actions must be pinned to a full-length commit SHA slsa-framework/slsa-github-generator#4440
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import urllib.request, re
url='https://raw.githubusercontent.com/slsa-framework/slsa-github-generator/main/README.md'
text=urllib.request.urlopen(url, timeout=20).read().decode()
patterns = [
r'reusable workflow',
r'generator_generic_slsa3\.yml',
r'release tag',
r'commit SHA',
r'full .*tag',
r'`@v2`\.1\.0',
r'`@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a`',
]
for pat in patterns:
print(f'\n## {pat}')
for m in re.finditer(pat, text, re.I):
start=max(0,m.start()-220); end=min(len(text), m.end()+320)
print(text[start:end].replace('\n',' '))
print('---')
break
PYRepository: getappz/agentflare
Length of output: 2750
🌐 Web query:
"slsa-github-generator" reusable workflow tag commit SHA slsa-verifier README "full release tag"
💡 Result:
When using slsa-github-generator, you must reference the reusable workflow by a full version tag (e.g., @v2.1.0) rather than a commit SHA or a short tag (e.g., @v2) [1][2]. This is a security requirement that allows slsa-verifier to cryptographically verify that the provenance was generated by a trusted, specific version of the generator workflow [3][2]. Referencing by commit SHA is not supported for these reusable workflows because it prevents the verifier from distinguishing between trusted commits and untrusted commits (such as those from pull requests or forks) [3]. Regarding verification with slsa-verifier: 1. Tag Verification: You should not specify a tag in the --source-uri flag [4][5][6]. Instead, if you need to perform source versioning validation, use the --source-tag flag to verify the specific release tag [4][5][6]. 2. Commit SHA Verification: The slsa-verifier does not have a direct flag for commit SHA validation in the same way it does for tags [5][6]. To verify a specific commit SHA, you should use the --print-provenance flag to output the provenance details and then inspect the commit SHA of the config source or materials within that output [4][5][6]. In summary, the generator requires explicit tagging to ensure trust, and the verifier expects you to use specialized flags (--source-tag) for tags or manual inspection (--print-provenance) for commit SHAs [4][2][6].
Citations:
- 1: https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md
- 2: https://github.com/slsa-framework/slsa-github-generator
- 3: Actions must be pinned to a full-length commit SHA slsa-framework/slsa-github-generator#4440
- 4: https://github.com/slsa-framework/slsa-verifier?tab=readme-ov-file
- 5: https://github.com/slsa-framework/slsa-verifier/blob/main/README.md
- 6: https://github.com/slsa-framework/slsa-verifier/blob/refs/tags/v2.7.1/README.md
Use the v2.1.0 tag here
slsa-github-generator reusable workflows need a full release tag so slsa-verifier can validate provenance; the SHA pin breaks that. Switch to @v2.1.0 and add a targeted zizmor: ignore[unpinned-uses].
Suggested change
- uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a # v2.1.0
+ uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 # zizmor: ignore[unpinned-uses]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a # v2.1.0 | |
| uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 # zizmor: ignore[unpinned-uses] |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml at line 143, Update the reusable workflow
reference in the release workflow from the commit SHA to the full v2.1.0 tag,
and add a targeted zizmor ignore for unpinned uses on that reference. Preserve
the existing generator_generic_slsa3.yml workflow.
Summary
releasejob now signs every release binary with cosign keyless signing (GitHub OIDC → Fulcio cert bound to this repo'srelease.yml, no long-lived key) and ships a.cosign.bundleper artifact.provenancejob attests SLSA L3 build provenance via the reusableslsa-framework/slsa-github-generator@v2.1.0workflow, uploading a signed<tag>.intoto.jsonlto the release.ci.yml, not just documented).Tracked as agentflare item #222. lean-ctx's own
release.ymlis intentionally untouched — out of scope for this PR.Why
Today the release pipeline stops at
sha256sum * > SHA256SUMS, which per arai's own threat-model catches a corrupted download but not a substituted release binary or a stolen release-pipeline secret. cosign + SLSA L3 is a well-established pattern (same reusable generator used by Flask/Click/Jinja, urllib3, Argo CD, Flux2, SOPS, OpenSSF Scorecard, and others) and Rust/GitHub-Actions specific to our stack requires no deviation from arai's implementation.Test plan
build → release → provenance,release.outputs.hashes→provenance.with.base64-subjects)zizmor.yml's own security lint runs on this PRSummary by CodeRabbit