Skip to content

fix(release): make exact artifact handoff acyclic - #1791

Merged
seonghobae merged 8 commits into
mainfrom
fix/exact-artifact-acyclic-receipt-1782
Sep 3, 2026
Merged

fix(release): make exact artifact handoff acyclic#1791
seonghobae merged 8 commits into
mainfrom
fix/exact-artifact-acyclic-receipt-1782

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Problem

Fixes #1782.

The exact-artifact reusable required the post-upload GitHub Actions artifact digest inside source-identity.json, even though that identity file is itself part of the six-file upload whose bytes determine the digest. A normal caller therefore could not construct the handoff deterministically without a cryptographic fixed point.

RED → repair

RED c18d6789f602ed19022a0c21a964b510ce5543a9 adds an explicit contract that the inner identity must be constructible before GitHub returns the upload receipt and that the outer receipt must be verified again before credentialed signing.

The repair then:

  • removes evidence_artifact_digest from the exact inner source-identity.json shape while preserving the reusable workflow input as the outer receipt (cc58723ffc88dd5d3c3173ca2bfd5c092cc3f26a);
  • updates the hostile-input fixture so the sealed identity is unchanged when the post-upload outer digest changes, and verifies that production validation still passes (b56726530a7e54fa37616c0fec3119b2e9c35326);
  • grants only actions: read to the credentialed signer and independently re-fetches artifact ID/name/digest/run/expiry immediately before downloading/signing (2d13615b0c1eb948b58e6b0af5d65890d660dc03);
  • makes the workflow permission contract require that read-only receipt recheck (be107f2e19875147a04a83c4712b9af07dc859cc);
  • updates the canonical doctoring so inner identity, outer transport receipt, exact ${{ github.workflow_sha }} verifier source, recovery, and the two-stage verification sequence match code (fe610c3e5bf8b478fba13b93a89ab1b62b3155b0).

Security boundary preserved

The six-file cardinality, strict JSON, checksum binding, per-subject CycloneDX 1.7 root binding, immutable artifact ID/name/digest verification, source repository/SHA binding, OIDC separation, repeated verification before signing, online attestation verification, and offline evidence export remain fail-closed. The post-upload digest is not weakened or made best-effort; it is moved to the only layer where it can exist without self-reference: GitHub Actions metadata.

No caller-controlled source is executed in either trusted job. No provider/model policy or product-local release behavior is copied into this owner repository.

Keep Draft until exact-head checks and independent review are complete. LineageWeave #925 must consume only a protected immutable SHA after this owner fix merges; it must not pin this branch.

Summary by CodeRabbit

  • 보안 및 검증 개선

    • 업로드된 증거 아티팩트의 이름, 다이제스트, 워크플로 실행 ID, 만료 여부를 다운로드 전에 재검증합니다.
    • 자격 증명 서명 전에 외부 아티팩트 수령 정보와 내부 검증 결과를 확인합니다.
    • 사전 봉인된 소스 식별 정보가 업로드 후 변경되지 않도록 검증 절차를 개선했습니다.
  • 문서

    • 아티팩트 증명, 검증 경계, 복구 절차 및 Sigstore 번들 형식에 대한 설명을 업데이트했습니다.

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 76f67e89-8b57-4201-9bb5-5d34249762b1

📥 Commits

Reviewing files that changed from the base of the PR and between 08d83f7 and 124e85d.

📒 Files selected for processing (6)
  • .github/workflows/exact-artifact-sbom-attestation.yml
  • docs/doctoring/exact-artifact-sbom-attestation.md
  • scripts/ci/verify_exact_artifact_sbom_handoff.py
  • tests/test_exact_artifact_outer_receipt_contract.py
  • tests/test_exact_artifact_sbom_attestation_contract.py
  • tests/test_verify_exact_artifact_sbom_handoff.py

📝 Walkthrough

Walkthrough

Changes

Exact artifact handoff

Layer / File(s) Summary
Inner identity and outer receipt separation
scripts/ci/verify_exact_artifact_sbom_handoff.py, tests/test_verify_exact_artifact_sbom_handoff.py, tests/test_exact_artifact_outer_receipt_contract.py
source-identity.json no longer contains evidence_artifact_digest. Tests verify that the identity remains stable when GitHub returns the digest after upload.
Same-run artifact verification before signing
.github/workflows/exact-artifact-sbom-attestation.yml, tests/test_exact_artifact_outer_receipt_contract.py, tests/test_exact_artifact_sbom_attestation_contract.py
The signer job receives actions: read permission and rechecks artifact repository, source SHA, name, digest, workflow run, and expiration before download and signing.
Lifecycle documentation and contract updates
docs/doctoring/exact-artifact-sbom-attestation.md, tests/test_exact_artifact_sbom_attestation_contract.py
The documentation describes inner identity sealing, outer receipt verification, repeated verification, recovery, and the updated Sigstore reference.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant GitHubActions
  participant Signer
  participant Verifier
  Caller->>Verifier: Seal source identity without artifact digest
  Caller->>GitHubActions: Upload evidence artifact
  GitHubActions-->>Caller: Return artifact ID and digest
  Caller->>Signer: Pass artifact receipt
  Signer->>GitHubActions: Re-fetch same-run artifact metadata
  GitHubActions-->>Signer: Return verified metadata
  Signer->>Verifier: Verify inner evidence files
  Verifier-->>Signer: Return valid handoff
  Signer->>Signer: Sign verified artifact
Loading

Possibly related PRs

  • ContextualWisdomLab/.github#797: 동일한 exact-artifact SBOM attestation workflow와 verifier의 메타데이터 및 digest 검증을 수정한 PR입니다.
✨ 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 fix/exact-artifact-acyclic-receipt-1782

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.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Independent review — approve

Read the full diff directly (all 6 files), not just the description.

Verified the core fix is real and correctly scoped:

  • scripts/ci/verify_exact_artifact_sbom_handoff.py: evidence_artifact_digest removed from the returned inner source-identity.json dict (the self-referential field), while the CLI argument itself is retained and still validated (_ARTIFACT_DIGEST_RE.fullmatch) — the digest is preserved as an outer receipt input, not deleted from the contract. This matches the stated design exactly: the digest cannot exist before upload, so it cannot be inside a file that is itself part of the uploaded bytes.
  • .github/workflows/exact-artifact-sbom-attestation.yml: new Verify immutable same-run artifact metadata step added to the credentialed attest-exact-artifacts job, gated by a newly-added least-privilege actions: read permission. It checks source_repository/source_sha against the live GITHUB_REPOSITORY/GITHUB_SHA, then re-fetches the artifact via gh api /repos/.../actions/artifacts/{id} and verifies .name, .digest, .workflow_run.id == $GITHUB_RUN_ID, and .expired == false — i.e. it re-derives the outer receipt from GitHub's own live metadata rather than trusting the caller's claim. Confirmed exactly 2 occurrences of this step exist in the file (the pre-existing read-only intake check + this new pre-signing recheck), matching the new test's assertion.
  • New test tests/test_exact_artifact_outer_receipt_contract.py genuinely exercises both halves: a source-level check the removed line is gone, and a workflow-level check the re-verification step count/shape is correct.
  • docs/doctoring/exact-artifact-sbom-attestation.md updated coherently — the trust-boundary prose, the two-job responsibilities, the six-file handoff description, the mermaid lifecycle diagram, and the incident-response checklist all consistently describe the new inner/outer split. Also fixed a stale doc bug in the same pass: ${{ job.workflow_repository }}/${{ job.workflow_sha }} (not real GitHub Actions context fields) corrected to the actual ContextualWisdomLab/.github/${{ github.workflow_sha }}.

Verification run myself, not just trusted from the PR's own checkboxes:

  • Targeted tests (test_exact_artifact_outer_receipt_contract.py, test_verify_exact_artifact_sbom_handoff.py, test_exact_artifact_sbom_attestation_contract.py): 50 passed.
  • Full suite: 2709 passed, 1 skipped, 100% coverage (verify_exact_artifact_sbom_handoff.py itself at 100% line+branch), 100% docstrings (interrogate).

Security boundary claims cross-checked against the actual diff, not taken on faith: six-file cardinality, checksum binding, and CycloneDX validation are untouched by this diff (confirmed via the unrelated test count staying the same); the new step only adds a stricter, GitHub-metadata-backed check, it does not weaken or make best-effort any existing check. No caller-controlled source is checked out or executed in either job (confirmed against the existing sparse-checkout/actions/attest steps, unchanged by this diff).

Minor, non-blocking nit: several changed files (the workflow, the doctoring doc, the script) now end without a trailing newline — harmless, but worth a quick sed -i '' -e '$a\' <file> pass if a future touch of these files is convenient.

Given exact-head checks are genuinely queued (chicken-and-egg, not failing) and the requested independent review is now done, marking ready and proceeding with the standing bypass-merge authorization for this pattern.

@seonghobae
seonghobae marked this pull request as ready for review September 3, 2026 10:46

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@seonghobae
seonghobae merged commit bd866a2 into main Sep 3, 2026
9 of 23 checks passed
@seonghobae
seonghobae deleted the fix/exact-artifact-acyclic-receipt-1782 branch September 3, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

fix(release): remove circular GitHub artifact-digest dependency from exact SBOM handoff

1 participant