Skip to content

feat(release): SOC2-03 signed release tags + per-release evidence procedure (#218)#241

Merged
Knapp-Kevin merged 4 commits into
devfrom
218-soc2-03-signed-tags-and-evidence
May 7, 2026
Merged

feat(release): SOC2-03 signed release tags + per-release evidence procedure (#218)#241
Knapp-Kevin merged 4 commits into
devfrom
218-soc2-03-signed-tags-and-evidence

Conversation

@Knapp-Kevin

Copy link
Copy Markdown
Collaborator

Summary

Closes #218 sub-task SOC2-03. Extends #237's cosign-keyless pipeline with one new step (sign-blob the release tag's commit SHA) and ships the operator-readable per-release evidence procedure + helper.

Plan / Audit

What ships

Surface Change
.github/workflows/publish.yml New step: cosign keyless sign-blob the release tag's commit SHA; output triple (txt + sig + crt) attached to GitHub Release. PyPI strip step updated to enumerate new artifacts
release/evidence_collect.py (new, 200 LOC) gh-CLI evidence-collection helper. Subprocess discipline list-form argv with shell=False (OWASP A03). Failure propagation to caller (no silent empty-evidence). Renderer split into 4 helpers (each <40 LOC)
docs/RELEASE_EVIDENCE_PROCEDURE.md (new) Operator-readable workflow: pre-release checklist, tag creation, post-release verification, evidence-collection invocation, narrative-attestation template, retention policy, auditor-side verification commands
tests/test_release_evidence_collect.py (new, 6 functional tests) PR table rendering, CI table rendering, reviewer attribution, A03 list-form-argv lock, subprocess-failure propagation, empty-window explicit-note discipline
docs/research-brief-compliance-audit-2026-05-06.md SOC2-03 entry marked closed (matches Plan D bidirectional pattern)

Test plan

  • 6 new functional tests pass (tests/test_release_evidence_collect.py)
  • ruff check + ruff format --check clean
  • mypy release/evidence_collect.py clean
  • Razor: render_markdown originally 58 LOC, refactored into 3 section helpers + orchestrator (each <40 LOC)
  • No new pip dependencies

Inheritance from #237

This PR extends the cosign-keyless trust root that #237 bootstrapped:

  • Same Sigstore Fulcio + Rekor identity (BicameralAI/bicameral-mcp)
  • Same OIDC issuer (token.actions.githubusercontent.com)
  • Same operator-side cosign verify-blob verification command shape

Closes

Epic #218 progress

3 of 6 sub-tasks closed:

3 remain: OWASP-03 (lockfile), OWASP-05 (RECOMMENDED_VERSION URL signing), LLM-06/#214 (skills/MANIFEST.toml).

🤖 Generated with Claude Code

Knapp-Kevin and others added 4 commits May 6, 2026 20:12
…218 sub-task)

Plan for SOC2-03: extend #237's cosign-keyless pipeline with one new
step (sign-blob the release tag's commit SHA), ship a per-release
evidence-collection helper (`release/evidence_collect.py`), and author
the operator-readable workflow doc (`docs/RELEASE_EVIDENCE_PROCEDURE.md`).

Audit: round 1 PASS (L1, mechanical extension of locked substrate).

Three substrate observations folded into implementation:
- Wait for #237 merge before implementing (NOW SATISFIED)
- Add SOC2-03 closure pointer to research brief (matches Plan D pattern)
- Update publish.yml strip step for new tag-commit artifacts

Closes #218 sub-task SOC2-03 (3rd of 6 epic items, after LLM-11 + OWASP-01).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`release/evidence_collect.py` — small CLI that runs gh CLI subprocess
calls to gather per-release evidence (merged PRs, CI runs, reviewer
attribution) and renders a markdown scaffold. Operators run the script
post-release via:

  python -m release.evidence_collect \
    --from-tag v0.13.7 --to-tag v0.13.8 \
    --output dist/release-evidence-v0.13.8.md

Subprocess discipline (OWASP A03): every subprocess.run invocation
uses list-form argv with shell=False (the default). 6 functional tests
including a stub that captures cmd + kwargs to assert the contract.

Failure propagation (OWASP A04): subprocess.CalledProcessError raises
through `collect_evidence`; no silent empty-evidence fallback. Empty PR
list / empty CI list emit explicit "No PRs in window" notes — never
silent omission, which would be misleading evidence.

Razor: render_markdown originally 58 LOC, split into 3 section
helpers (_render_pr_section, _render_ci_section, _render_reviews_section)
each <20 LOC, with the orchestrator coming in at ~20 LOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extend the publish.yml build job with one new step: cosign sign-blob
the SHA the release tag points at. Output triple
(release-tag-commit.txt + .sig + .crt) attaches to the GitHub Release
alongside the existing artifacts (wheel, hooks-manifest, SBOM).

PyPI strip-step updated to enumerate the new tag-commit artifacts
(they sit at dist/ root, not under dist/share/, so the existing
dist/share strip wouldn't catch them and they'd incorrectly land on
PyPI alongside the wheel).

Operators verify the tag-commit signature via:

  cosign verify-blob \
    --certificate-identity-regexp "^https://github.com/BicameralAI/bicameral-mcp/" \
    --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
    --signature release-tag-commit.txt.sig \
    --certificate release-tag-commit.txt.crt \
    release-tag-commit.txt

Successful verification proves the workflow signed this exact commit
SHA at release-publish time — the SOC 2 CC8.1 change-control evidence.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…218 SOC2-03)

`docs/RELEASE_EVIDENCE_PROCEDURE.md` — operator-readable per-release
evidence workflow:
- Pre-release checklist (PR review status, CI green, no force-pushes)
- Release-tag creation steps (git tag -a, gh release create)
- Post-release verification (workflow succeeded, expected artifacts attached)
- Evidence-collection invocation (`python -m release.evidence_collect ...`)
- Operator narrative section (rationale, exceptions, attestation statement)
- Retention policy (>=7 years SOC 2 audit window; storage operator-chosen)
- Verification commands for auditor-side independent verification
  (cosign verify-blob for tag-commit + hooks-manifest;
  cosign verify-attestation for SBOM)

`docs/research-brief-compliance-audit-2026-05-06.md` SOC2-03 entry
gets the closure pointer matching the bidirectional pattern Plan D
established for MCP-01, NIST-RMF-01, AI-ACT-02, SOC2-02.

Closes #218 sub-task SOC2-03. Three of six epic items closed
(LLM-11 + OWASP-01 from #237; SOC2-03 from this PR). Three remain:
OWASP-03 (lockfile), OWASP-05 (RECOMMENDED_VERSION URL signing),
LLM-06/#214 (skills/MANIFEST.toml).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f68aa4db-3263-400f-9eca-89a99f0561a5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 218-soc2-03-signed-tags-and-evidence

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@Knapp-Kevin Knapp-Kevin merged commit 9da8b4e into dev May 7, 2026
6 checks passed
@Knapp-Kevin Knapp-Kevin deleted the 218-soc2-03-signed-tags-and-evidence branch May 7, 2026 00:27
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