Skip to content

fix(release): standardize on pulseengine cosign + SLSA flow (synth ref)#244

Open
avrabe wants to merge 1 commit into
mainfrom
fix/v0.11.0-release-cosign-slsa
Open

fix(release): standardize on pulseengine cosign + SLSA flow (synth ref)#244
avrabe wants to merge 1 commit into
mainfrom
fix/v0.11.0-release-cosign-slsa

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 24, 2026

Summary

Per the per-tool brief: standardize all six pulseengine release flows
on the synth reference so consumers verify with a single one-liner.
spar already had sums + an SBOM but signed neither and used
gh attestation create … || true — which silently swallowed failures.

This PR adopts the synth flow verbatim with the SBOM --manifest-path
adapted to spar's CLI crate (the only documented adaptation per the
brief). No assets are removed — the brief specifies "spar: ... remove
no existing assets".

Step order in create-release (now matches the brief exactly)

# Step Brief item
1 Build binary archives (upstream build-binaries job)
2 CycloneDX SBOM via --manifest-path crates/spar-cli/Cargo.toml --format json --spec-version 1.5 (upstream build-sbom job; version-stamped to spar-<bare>.cdx.json at flatten)
3 cd release-assets && sha256sum ./* > SHA256SUMS.txt
4 actions/attest-build-provenance@v2 with subject-path: release-assets/*.tar.gz AND release-assets/*.zip (spar ships Windows zip)
5 sigstore/cosign-installer@v3 pinned at v2.4.1
6 cosign sign-blob --yes --bundle SHA256SUMS.txt.cosign.bundle --output-signature SHA256SUMS.txt.sig --output-certificate SHA256SUMS.txt.pem SHA256SUMS.txt
7 build-env.txt (rustc / cargo / cosign / runner)
8 gh release create … --generate-notes release-assets/* (idempotent: existing release gets gh release upload --clobber)

Permissions

Workflow-level already had the trio; job-level permissions: block
added on create-release to make the requirement locally explicit.

Removed

  • The old gh attestation create "$file" --bundle-output … || true loop
    that ran after release creation and silently swallowed failures.

Verification (works after the next tag)

cosign verify-blob \
  --certificate-identity-regexp \
    'https://github.com/pulseengine/spar/.github/workflows/release.yml@.*' \
  --certificate-oidc-issuer \
    'https://token.actions.githubusercontent.com' \
  --bundle SHA256SUMS.txt.cosign.bundle SHA256SUMS.txt

gh attestation verify spar-vX.Y.Z-<triple>.tar.gz --repo pulseengine/spar

Artifacts: REQ-RELEASE-ASSETS-STANDARD + TEST-RELEASE-ASSETS-STANDARD.

Test plan

  • python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))" — YAML parses
  • grep checks confirm attest-build-provenance@v2, cosign-installer@v3, v2.4.1, sign-blob, build-env.txt all present
  • Step order in YAML matches the brief 1–8 spec exactly
  • rivet validate — 0 broken cross-refs; totals byte-identical to baseline
  • Will smoke against the next release tag (gh attestation verify + cosign verify-blob one-liners above)

🤖 Generated with Claude Code

The brief: standardize all six pulseengine tools on one release-asset
shape so consumers verify with a single one-liner. spar already had
sums + an SBOM, but signed neither and used `gh attestation create …
|| true` which silently swallowed failures. This PR adopts the synth
reference flow verbatim:

  archive build  →  CycloneDX SBOM  →  sha256sum ./*
                 →  actions/attest-build-provenance@v2  (subject: tar.gz + zip)
                 →  sigstore/cosign-installer@v3 at cosign v2.4.1
                 →  cosign sign-blob --yes  (SHA256SUMS.txt → .sig + .pem + .cosign.bundle)
                 →  build-env.txt
                 →  gh release create/upload  (idempotent)

Per-tag asset set is now: spar-vX.Y.Z-<triple>.{tar.gz,zip},
spar-X.Y.Z.cdx.json, SHA256SUMS.txt + .sig/.pem/.cosign.bundle,
build-env.txt, plus the spar-specific VSIXes and compliance archive
which fold into SHA256SUMS.txt.

The SBOM step is adapted: `cargo cyclonedx --manifest-path
crates/spar-cli/Cargo.toml --format json --spec-version 1.5`. The
version-stamped name `spar-<bare>.cdx.json` is applied at
release-assets flatten time.

Job-level `permissions:` restate the trio (contents: write, id-token:
write, attestations: write) the OIDC/keyless flow needs. The old
`gh attestation create … || true` step is removed.

Verification one-liner consumers will use after the next release:

  cosign verify-blob \\
    --certificate-identity-regexp \\
      'https://github.com/pulseengine/spar/.github/workflows/release.yml@.*' \\
    --certificate-oidc-issuer \\
      'https://token.actions.githubusercontent.com' \\
    --bundle SHA256SUMS.txt.cosign.bundle SHA256SUMS.txt
  gh attestation verify spar-vX.Y.Z-<triple>.tar.gz --repo pulseengine/spar

Artifacts: REQ-RELEASE-ASSETS-STANDARD + TEST-RELEASE-ASSETS-STANDARD.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@avrabe avrabe enabled auto-merge (squash) May 24, 2026 18:59
@github-actions
Copy link
Copy Markdown

Rivet verification gate

20/20 passed

count
Passed 20
Failed 0
Skipped (no steps) 0

Filter: (and (= type "feature") (or (has-tag "v093") (has-tag "v0100")))

Failed artifacts

(none)

Updated automatically by tools/post_verification_comment.py. Source of truth: artifacts/verification.yaml.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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