Skip to content

fix(notify): recover immutable staged SBOM#121

Merged
psimaker merged 1 commit into
mainfrom
agent/helper-publication-sbom-recovery
Jul 14, 2026
Merged

fix(notify): recover immutable staged SBOM#121
psimaker merged 1 commit into
mainfrom
agent/helper-publication-sbom-recovery

Conversation

@psimaker

@psimaker psimaker commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • normalize SPDX creation and annotation timestamps so fresh helper SBOMs are byte-deterministic;
  • in an exact publication recovery, resolve the existing release through GraphQL and download its staged SBOM through one validated numeric REST asset ID;
  • require the server SHA-256 and the canonical SPDX content to match a fresh Trivy 0.70.0 scan before using the already-staged immutable bytes locally to rebuild the release manifest;
  • verify the manifest bindings to both SBOM.spdx.json and IMAGE-DIGESTS before any rollout.

Failure evidence

Recovery publication run 29344240756 was bound to main@589de9d92dd7eaddfb264765edbdf7c49ce7f8f6. Policy, notify, owner, immutable image, binary-attestation, and binary-build gates succeeded. Stage Release Binaries failed while comparing the freshly generated SBOM to private draft 353712477.

All five binaries and SHA256SUMS remained byte-identical. Trivy 0.70.0 had embedded its invocation time in every package annotation even though creationInfo.created was normalized. After normalizing only those runtime annotation timestamps, the fresh and staged SPDX documents matched exactly. The draft remains private and unchanged with exactly nine pre-rollout assets. No helper container, upgrade, downgrade, forward recovery, rollout evidence, finalization, or public release occurred.

Security and compatibility

  • workflow permissions, owner/ref/predecessor gates, immutable release tag, image digest, binary set, and publication sequencing are unchanged;
  • the recovery path requires exact tag/title/prerelease metadata, one positive numeric release and asset ID, one canonical server SHA-256, a locally rehashed byte stream, exact SPDX namespace and Trivy identity, and canonical whole-document equality;
  • the staged asset is never deleted, overwritten, re-uploaded, edited, or republished; only its verified bytes replace the newly generated runner-local copy before manifest creation;
  • the rollout gate now verifies that the downloaded manifest binds the downloaded SBOM and image-digest asset;
  • no helper runtime, image, tag, binary, attestation, wire format, pairing, namespace, Decision 024, relay, app, or existing-user behavior changes;
  • upload, download, and roundtrip product evidence remain unset, and cleanup remains evidence-orthogonal.

Verification

  • Ruby syntax and notify publication safety policy: pass, including 11 negative gates
  • Actionlint 1.7.12 with ShellCheck 0.10.0: pass
  • Notify Go tests: pass
  • installer shell checks and hermetic dry-run suite: pass
  • two Trivy 0.70.0 scans separated in time become byte-identical after the new normalization: pass
  • live read-only recovery proof against draft 353712477: adopted SBOM digest 20c6306e17149302f34f1a6ed849b3700f8ef0ae6cc3c6032113dc4d29ceb953 and rebuilt manifest digest f6c215f3e62ea5e2c52e080fb9da5064053267165da85e1390ce0848f8bd6f2d both match the unchanged draft; manifest cross-links pass
  • signed SPDX-v2.3 attestation: exact tag, source SHA, signer workflow, and five binary subjects verified; its canonical predicate matches the release SBOM
  • Trivy 0.70.0 filesystem vulnerability and secret scan: no HIGH/CRITICAL vulnerabilities or secret findings
  • Zizmor 1.26.1 at medium severity: no findings; eight pre-existing low documentation findings are unchanged
  • git diff --check: pass

Release truth

Helper publication remains NO-GO. The release is still a private draft, and the real published-image upgrade, rollback, forward-recovery, finalization, and public verification gates must all still succeed.

Normalize every SPDX annotation timestamp so fresh helper SBOMs are deterministic.

During release recovery, fetch the existing draft SBOM by validated asset ID, verify its API digest and canonical content against a fresh scan, then use those immutable bytes locally when rebuilding the release manifest. Cross-check manifest SBOM and image-digest bindings before rollout.
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The release workflow now normalizes additional SBOM metadata, verifies and adopts immutable staged SBOMs only after digest and content checks, improves asset mismatch diagnostics, and validates binary SBOM and image-digest hashes in rollout manifests. Publish-safety assertions enforce these recovery requirements.

Changes

Release integrity validation

Layer / File(s) Summary
Deterministic SBOM normalization and recovery adoption
.github/workflows/docker.yml
SBOM timestamps are canonicalized, and recovery verifies staged SBOM digests and content before replacing the generated file.
Asset and rollout manifest digest validation
.github/workflows/docker.yml
Asset digest mismatches report expected and found values; rollout verification checks binary SBOM and image-digest hashes.
Publish-safety policy enforcement
.github/scripts/notify-publish-safety.rb
Recovery assertions require deterministic SBOM handling, strict staged adoption checks, prohibited release mutations, and additional rollout evidence.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: dependabot[bot]

Poem

SBOM fields align in time,
Digests guard the release line.
Staged files pass the careful gate,
Manifests confirm their matching state.
Recovery moves with proofs in hand.

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
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.
No Private Note Leakage ✅ Passed The changes only add SBOM/release-asset digest checks and fixed-path temp-file handling; no Obsidian contents, vault paths, or keys are logged or sent.
Bounded Ios Background Work ✅ Passed PR only changes a Ruby policy script and GitHub workflow; no Swift/iOS background-execution code is touched, so this check is not applicable.
Bridge Contract Compatibility ✅ Passed PR only changes .github workflow/safety script; no Go bridge or Swift bridge-service files/tests changed, so the documented bridge contract is untouched.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise, conventional-commit style, and accurately reflects the recovery-focused SBOM changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/helper-publication-sbom-recovery

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.

@psimaker psimaker marked this pull request as ready for review July 14, 2026 15:41
@psimaker

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@psimaker

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🧹 Nitpick comments (1)
.github/workflows/docker.yml (1)

912-926: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Third copy of the resolve_release GraphQL+REST lookup logic.

This inline block duplicates the resolve_release() function already defined at Lines 1068-1089 and 1180-1197. Adding a third copy increases the chance that a future fix (e.g., an added validation check) lands in one copy but not the others.

Consider extracting this into a shared script (e.g., .github/scripts/resolve-release.sh) sourced by all three steps.

🤖 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/docker.yml around lines 912 - 926, Extract the duplicated
GraphQL-and-REST release lookup into a shared
`.github/scripts/resolve-release.sh` helper, preserving the existing validation
and release ID resolution behavior. Update the inline block and both existing
`resolve_release()` implementations to source or invoke this shared helper,
ensuring all three workflow steps use the same logic.
🤖 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.

Nitpick comments:
In @.github/workflows/docker.yml:
- Around line 912-926: Extract the duplicated GraphQL-and-REST release lookup
into a shared `.github/scripts/resolve-release.sh` helper, preserving the
existing validation and release ID resolution behavior. Update the inline block
and both existing `resolve_release()` implementations to source or invoke this
shared helper, ensuring all three workflow steps use the same logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5051ec2a-bbbb-4020-887c-140a9e3377a5

📥 Commits

Reviewing files that changed from the base of the PR and between 589de9d and ebea13d.

📒 Files selected for processing (2)
  • .github/scripts/notify-publish-safety.rb
  • .github/workflows/docker.yml
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
.github/workflows/**/*.yml

⚙️ CodeRabbit configuration file

.github/workflows/**/*.yml: Review CI for correct Go test tags, Xcode/iOS simulator assumptions, secret scoping,
dependency integrity, permissions, Docker publishing safety, and unnecessary privilege escalation.

Files:

  • .github/workflows/docker.yml
🔇 Additional comments (7)
.github/workflows/docker.yml (5)

693-701: LGTM!

Also applies to: 892-901


1124-1130: LGTM!


1223-1232: LGTM!


632-635: LGTM!

Also applies to: 830-831, 1162-1164


944-955: 🎯 Functional Correctness

No issue: trivy-action v0.36.0 already defaults to Trivy v0.70.0, so the Tool: trivy-0.70.0 check matches the SBOM generator.

			> Likely an incorrect or invalid review comment.
.github/scripts/notify-publish-safety.rb (2)

386-419: LGTM!


570-571: LGTM!

@psimaker

Copy link
Copy Markdown
Owner Author

Review resolution: the suggested shared release-resolver script is intentionally not introduced in this recovery PR. Every source-bound publication job checks out immutable release commit 664a896, where a new main-only helper would not exist; fetching one from main would mix control code into the release checkout. The inline read-only lookups therefore remain explicit and are statically guarded by the publish-safety policy.

@psimaker psimaker merged commit 8a72ae8 into main Jul 14, 2026
33 checks passed
@psimaker psimaker deleted the agent/helper-publication-sbom-recovery branch July 14, 2026 15:56
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