Skip to content

ci(release): sign binaries with cosign, attest SLSA L3 provenance - #270

Merged
getappz merged 3 commits into
masterfrom
feat/release-cosign-slsa-provenance
Jul 19, 2026
Merged

ci(release): sign binaries with cosign, attest SLSA L3 provenance#270
getappz merged 3 commits into
masterfrom
feat/release-cosign-slsa-provenance

Conversation

@getappz

@getappz getappz commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • release job now signs every release binary with cosign keyless signing (GitHub OIDC → Fulcio cert bound to this repo's release.yml, no long-lived key) and ships a .cosign.bundle per artifact.
  • New provenance job attests SLSA L3 build provenance via the reusable slsa-framework/slsa-github-generator@v2.1.0 workflow, uploading a signed <tag>.intoto.jsonl to the release.
  • README gets a new "Verifying release binaries" section documenting both, plus the attack-coverage table, modeled on taniwhaai/arai's reference implementation (verified real in their ci.yml, not just documented).
  • Corrected the Windows/Scoop install note, which called the binary "unsigned" — it's now cosign-signed; the note points at the new section and is precise about what cosign does/doesn't cover (still not Authenticode-signed, so SmartScreen can still flag it).

Tracked as agentflare item #222. lean-ctx's own release.yml is 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

  • YAML parses; job graph verified (build → release → provenance, release.outputs.hashesprovenance.with.base64-subjects)
  • Real signing/provenance can only be verified end-to-end on an actual tag push (cosign + the SLSA generator both require live GitHub OIDC) — watch the next tagged release
  • zizmor.yml's own security lint runs on this PR

Summary by CodeRabbit

  • New Features
    • Release artifacts are now signed using keyless Cosign signatures, with downloadable signature bundles.
    • Releases now include SLSA v3 provenance attestations to strengthen supply-chain verification.
  • Documentation
    • Updated Windows installation guidance to flag potential Defender/SmartScreen warnings.
    • Added a “Verifying release binaries” section covering Cosign verification and SLSA provenance checks, including a comparison of checksum vs signature vs provenance protections.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The 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.

Changes

Release verification

Layer / File(s) Summary
Release signing and provenance generation
.github/workflows/release.yml
The release job enables OIDC signing, creates cosign bundles for archives, exports base64 SHA256 hashes, and passes them to a new SLSA provenance job.
Binary verification guidance
README.md
Windows installation guidance and a new verification section document cosign signature checks, SLSA L3 provenance checks, failure handling, and checksum security coverage.

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
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: release signing and SLSA provenance attestation.
Description check ✅ Passed It includes the required Summary and Test plan sections and gives useful rationale; the Notes for reviewers section is missing.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/release-cosign-slsa-provenance

Comment @coderabbitai help to get the list of available commands.

zizmor unpinned-uses (high severity) flagged the tag ref; pin to
v2.1.0's resolved commit.

@coderabbitai coderabbitai 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.

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 win

Upload the Cosign bundles after signing.

This step creates dist/*.cosign.bundle after 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

📥 Commits

Reviewing files that changed from the base of the PR and between 150e2c6 and 4f2e856.

📒 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 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.yml

Repository: 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:


🏁 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
PY

Repository: 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)
PY

Repository: 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:


🏁 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
PY

Repository: 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:


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.

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]
🤖 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.

@getappz
getappz enabled auto-merge (squash) July 19, 2026 19:22
@getappz
getappz merged commit ab76c2b into master Jul 19, 2026
15 checks passed
@getappz
getappz deleted the feat/release-cosign-slsa-provenance branch July 19, 2026 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant