Skip to content

feat(workflows): publish SLSA provenance + SBOM attestations on every release tag (closes #58) - #94

Merged
chrisleekr merged 7 commits into
mainfrom
bot/issue-58-supply-chain-attestations
May 2, 2026
Merged

feat(workflows): publish SLSA provenance + SBOM attestations on every release tag (closes #58)#94
chrisleekr merged 7 commits into
mainfrom
bot/issue-58-supply-chain-attestations

Conversation

@chrisleekr-bot

@chrisleekr-bot chrisleekr-bot Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Wires SLSA v1 build provenance and CycloneDX/SPDX SBOMs into every Docker image the release pipeline publishes, and adds a hard regression gate (gh attestation verify × 2 predicates) that fails the workflow if either attestation is silently dropped by a future refactor of docker-build.yml. All edits are additive YAML + matching docs — no Dockerfile.*, package.json, or src/ change. Closes #58.

Two attestation flavours land per release tag:

  • BuildKit-nativeprovenance: mode=max + sbom: true on the build step overrides docker/build-push-action's default-off-when-push-by-digest behaviour. BuildKit emits per-arch attestation manifests; imagetools create walks each index digest so the descriptors survive the manifest-list assembly without extra CLI plumbing.
  • GitHub-Sigstoreanchore/sbom-action generates a CycloneDX SBOM from the merged image; actions/attest-build-provenance@v4 and actions/attest-sbom@v4 bind Sigstore-signed attestations to the merged manifest digest, surfaced via the GitHub Attestations API and Docker Hub's "Build attestations" badge.

Permissions follow least-privilege: top-level grows only attestations: read (so the scan job can verify), and the merge job overrides locally with id-token: write + attestations: write. Build / scan stay read-only.

Changes

  • Enable BuildKit SLSA v1 provenance + SPDX SBOM emission on the per-arch build step, with comments explaining the push-by-digest interaction. (T1)
  • Preserve attestation descriptors through the manifest-list merge — no CLI plumbing needed since imagetools create walks the per-arch index digests now that BuildKit attaches attestation siblings. (T2)
  • Scope id-token: write + attestations: write to the merge job only; add top-level attestations: read for verification. (T3)
  • Capture the merged manifest digest with regex validation, generate a CycloneDX SBOM via anchore/sbom-action@v0, and publish Sigstore-signed provenance + SBOM via actions/attest-build-provenance@v4 + actions/attest-sbom@v4. (T4)
  • Add a Verify image attestations step in the scan job that calls gh attestation verify once per predicate type (SLSA + CycloneDX) before Trivy. Each call fails the job if its predicate is missing — regression gate. (T5)
  • Document the consumer verification flow (gh attestation verify and docker buildx imagetools inspect) and the registry / Sigstore / GitHub-API storage matrix. (T7, T8)
  • Update CLAUDE.md CI/CD table row for docker-build.yml and add 20260502-supply-chain-attestations to "Recent Changes". (T9)

Files changed

  • .github/workflows/docker-build.yml · primary subject — adds BuildKit attestation flags, scoped permissions, merged-digest capture, SBOM generation + Sigstore-signed attestations, and the gh attestation verify regression gate.
  • docs/operate/deployment.md · new "Verifying image attestations" subsection under Build with consumer commands for both attestation flavours and both image variants.
  • docs/operate/observability.md · new "Supply-chain attestations" section documenting the registry / Sigstore / GitHub-API storage matrix; cross-links deployment.md.
  • CLAUDE.md · CI/CD table row + Recent Changes entry.
  • IMPLEMENT.md · per-task verification report for the bot tracking comment.

Commits

  • a24bc88 · docs(implement): fix CLAUDE.md bullet that prettier flattened into a sub-list
  • 41ea01a · feat(workflows): publish SLSA provenance + SBOM attestations on every release tag

Tests run

  • bun run typecheck · pass (no output, exit 0)
  • bun run lint · pass (0 errors, 289 pre-existing warnings — none new from this change)
  • bun run formatbun run format:fix · pass after re-flowing two doc tables
  • actionlint .github/workflows/*.yml · pass (no output)
  • bun run scripts/check-docs-citations.ts · pass
  • bun run scripts/check-docs-versions.ts · pass
  • mkdocs build --strict · pass (Documentation built in 0.58 seconds)
  • bun test · 519 pass / 153 skip / 194 pre-existing fail (verified baseline by git stash && bun test: same counts — failing suites need Postgres + Valkey from bun run dev:deps, unrelated to this YAML/Markdown change)

Verification

  • T1provenance: mode=max + sbom: true set on docker/build-push-action@v7; inline comment cites the push-by-digest default-off behaviour the issue called out and links the Docker multi-platform guide.
  • T2imagetools create preserved as-is; inline comment in the merge step explains why no CLI plumbing is needed (per-arch index digests now reference both image AND attestation manifests).
  • T3 — Top-level permissions: grew only attestations: read; merge job overrides locally with id-token: write + attestations: write. Build / scan retain only read scopes.
  • T4 — After Create manifest list and push: digest capture (with regex validation), anchore/sbom-action@v0 (CycloneDX), actions/attest-build-provenance@v4, actions/attest-sbom@v4. All four steps target the merged-image digest.
  • T5 — Scan job calls gh attestation verify twice (SLSA, CycloneDX) before Trivy; each fails the job if its predicate is absent.
  • T6 — deviation noted — Plan said SHA-pin in addition to major-version tag, but repo-wide grep for SHA-pinned uses: returned zero matches: every workflow uses tag-only major-version pinning, with Renovate's github-actions group rule handling bumps. Pinned new actions tag-only at major version (@v4, @v0) to match repo posture and avoid Renovate-undo churn. Also bumped attest-* from the plan's @v3 to @v4 since v4.x has been GA since 2026-02-26 and the repo otherwise tracks current majors (checkout@v6, build-push-action@v7, download-artifact@v8).
  • T7-T8docs/operate/deployment.md and docs/operate/observability.md carry consumer commands and storage matrix; mkdocs build --strict clean and the bespoke citation / version checks pass.
  • T9 — CI/CD table row and Recent Changes entry added in CLAUDE.md.
  • T10 — deferred — End-to-end smoke test via gh workflow run docker-build.yml against a dev tag is the maintainer's call (it pushes a real image to Docker Hub and consumes attestations-API quota). All YAML / docs gates that can run locally pass.

Security posture preserved

  • Top-level perms only added attestations: read (least required to verify).
  • Sigstore minting + writing scopes are confined to the merge job.
  • gh attestation verify runs with the default secrets.GITHUB_TOKEN — no PAT.
  • Defense-in-depth env:-first pattern preserved on every new step.

Related Issues

Test plan

  • Tests added/updated where the change introduces new behaviour (N/A — YAML + docs only)
  • bun run typecheck clean
  • bun run lint no new errors
  • Existing tests still pass (or pre-existing failures noted above)

Summary by CodeRabbit

  • New Features

    • Published images now include Sigstore-signed SLSA v1 provenance and CycloneDX SBOM attestations.
    • Attestations can be verified using provided verification commands.
  • Documentation

    • Added guides for verifying image attestations and retrieving attestation details.
    • Added supply-chain attestations documentation describing attestation storage, format, and verification.

chrisleekr-bot[bot] added 2 commits May 2, 2026 06:20
… release tag

Closes #58.

Adds two attestation flavours to docker-build.yml:

  - BuildKit-native: provenance: mode=max + sbom: true on the build step
    overrides build-push-action's default-off-when-push-by-digest behaviour.
    BuildKit emits per-arch attestation manifests; imagetools create walks
    each index digest so descriptors survive the manifest-list assembly.

  - GitHub-Sigstore: anchore/sbom-action generates a CycloneDX SBOM from
    the merged image; actions/attest-build-provenance and actions/attest-sbom
    bind Sigstore-signed attestations to the merged manifest digest, surfaced
    via the GitHub Attestations API and Docker Hub's "Build attestations" badge.

Permissions: top-level grows attestations: read so build/scan can verify;
merge job overrides locally with id-token: write + attestations: write.

The scan job now calls gh attestation verify twice (once per predicate type)
before Trivy - a hard regression gate against silent attestation drops.

Docs (deployment.md + observability.md) document the consumer verification
commands and registry/Sigstore/GitHub-API storage surfaces. CLAUDE.md
CI/CD table and Recent Changes index updated.
…sub-list

The prior commit's lint-staged hook turned `SLSA + SBOM` (with a leading
plus on a continuation line) into a `- SBOM` sub-bullet. Inline the bullet
so the rendered IMPLEMENT.md preserves the intended sentence.
@chrisleekr-bot

chrisleekr-bot Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

bot workflow review — succeeded

🔍 Code review complete — 5 files, +289/-116.

Summary

PR #94 wires SLSA v1 build provenance and CycloneDX/SPDX SBOMs into every Docker image the release pipeline publishes, with a gh attestation verify regression gate that fails the workflow if either attestation is silently dropped. The change is YAML + docs only — no src/, Dockerfile.*, or package.json edits. Technical execution is sound: BuildKit attestation flags correctly override docker/build-push-action's push-by-digest-default-off behaviour, the merge-job permission scoping is least-privilege, the merged-digest capture validates with a sha256 regex, and the scan-job verify step calls gh attestation verify once per predicate type (failing on either miss). One minor finding posted inline; otherwise ready to merge.

What was checked

  • Read .github/workflows/docker-build.yml (368 lines) in full — verified permission scoping (top-level attestations: read, merge-job override id-token: write + attestations: write), confirmed provenance: mode=max + sbom: true on the build step, traced the digest flow through imagetools createimagetools inspect --formatanchore/sbom-actionattest-build-provenanceattest-sbomgh attestation verify.
  • Read docs/operate/deployment.md and docs/operate/observability.md diffs in full — verified consumer commands, predicate types, and storage matrix.
  • Read CLAUDE.md diff — table widening from prettier reflow plus one new "Recent Changes" bullet.
  • Cross-referenced anchore/sbom-action's action.yml to confirm whether it exposes a platform input for multi-arch refs (it does not — Syft scans the runner's default platform).
  • git fetch origin maingit diff origin/main...HEAD to confirm the working tree is up-to-date with the diff under review.
  • No typecheck/lint/test runs done — the PR is YAML + Markdown and the author's tests-run section already records bun run typecheck, bun run lint, actionlint, mkdocs build --strict, and the bespoke citation/version checks all green.

Findings

[minor] .github/workflows/docker-build.yml:277 — Sigstore-attested CycloneDX SBOM only covers the runner's native architecture

anchore/sbom-action has no platform input (confirmed against action.yml). When given a multi-arch manifest reference, Syft scans the runner's native platform — ubuntu-24.04 here, so amd64 only. The resulting CycloneDX SBOM that actions/attest-sbom@v4 binds to the merged manifest digest therefore omits arm64-only packages (alpine arm64 base layers, any arch-specific binaries baked into Dockerfile.daemon's toolchain).

The BuildKit-attached SPDX SBOM on each per-arch leaf manifest still covers both architectures, but docs/operate/deployment.md (the table row that says "A CycloneDX SBOM enumerating every package layered into the merged image") and the PR description ("orchestrator runtime, daemon toolchain, OS libs") overstate what the Sigstore-flavour attestation actually provides. An operator triaging an arm64-only CVE via gh attestation verify --predicate-type https://cyclonedx.org/bom will get a false negative.

Recommended fix: either (a) tighten the doc copy to acknowledge the CycloneDX flavour is amd64-only and direct arm64 audits to the per-arch BuildKit SPDX SBOM, or (b) generate per-arch CycloneDX SBOMs by looping over linux/amd64+linux/arm64, attesting each with subject-digest set to the per-arch image manifest. (b) is closer to the spec the docs advertise.

Reasoning

Things I considered but did NOT flag:

  • Permission scoping — top-level attestations: read is the minimum the scan job needs to call gh attestation verify; merge-job locally adds id-token: write (Sigstore OIDC) + attestations: write (Attestations API). Build/scan keep read-only. Least-privilege is correct.
  • gh attestation verify against a tag rather than a digest — the oci://...:variant_tag reference is resolved at tool runtime, but the merge job is the only writer to that tag and imagetools create is atomic, so the resolved digest is deterministic. Not worth flagging.
  • Double imagetools inspect call in the digest-capture step — one human-readable, one for the --format digest. Two registry round-trips, but the second is cheap and the human-readable inspect is genuinely useful in the log. Not worth flagging.
  • anchore/sbom-action@v0 major-only pin — author's deviation note already addresses this (repo convention is tag-only major-version pinning + Renovate group rule); not actionable here.
  • set -e on the verify step — GitHub Actions runs bash with -eo pipefail by default, so a failed first gh attestation verify short-circuits the second. Behaviour matches the comment's claim that "either failure fails the workflow."
  • actions/attest-sbom@v4 predicate-type detection — the action infers the predicate URI from SBOM content; CycloneDX → https://cyclonedx.org/bom matches the verify-step's --predicate-type. Coherent.
  • Defense-in-depth env:-first pattern — every new run: block reads IMAGE_REF / REPO / IMAGE / TAG / DIGEST from env:, never from ${{ … }} expansion inside the script. Pattern preserved.
  • The change does not touch src/ — no test coverage gap to flag.

The single finding I posted is a documentation accuracy issue, not a correctness or security bug. The implementation is otherwise tight.

cost: $2.1705 · turns: 27 · duration: 299s

Comment thread .github/workflows/docker-build.yml
@chrisleekr-bot

chrisleekr-bot Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

bot workflow resolve — succeeded

🔎 Resolve iteration complete — 0 failing checks, 1 open comment threads (some may already be resolved).

Resolve iteration — PR #94

Iteration date: 2026-05-02

Summary

PR #94 (feat(workflows): publish SLSA provenance + SBOM attestations on every release tag (closes #58)) had 0 failing checks and 1 open review-comment thread entering this resolve. The branch was already up-to-date with main (2 commits ahead, 0 behind), so no rebase was needed. The single review thread was a documentation-accuracy finding from the prior review workflow, classified as Valid and addressed via the doc-tightening option (option a) the reviewer suggested. After the fix commit 0f7fe9e, CI is back to all-green and the review thread is resolved. Ready for maintainer merge.

CI status

No failing checks at the start of this iteration. The follow-up commit 0f7fe9e re-triggered the suite; final post-fix state below.

Check Workflow State on 0f7fe9e
Lint & Test CI pass
build Docs pass (mkdocs --strict exercised the doc edits)
Analyze (actions) CodeQL pass
Analyze (javascript-typescript) CodeQL pass
CodeQL CodeQL pass
Gitleaks (push + PR) Secrets Scan pass
Label PR based on title Generate Labels pass

No fix attempts consumed (start state was already 0 fail; the polling loop simply waited for the re-runs of the post-push suite).

Review comments

Comment ID File:line Classification Action Reply Thread resolved?
3176252148 .github/workflows/docker-build.yml:277 Valid Tightened doc copy in docs/operate/deployment.md (predicate-table row at L77 + the trailing-paragraph hint above the imagetools inspect snippet at L97) and docs/operate/observability.md (storage-matrix Format column at L125) to scope the Sigstore-signed CycloneDX SBOM claim to amd64 and direct arm64 audits to the per-arch BuildKit-attached SPDX SBOM. Took option (a) from the suggested fix — Syft per-platform looping (option b) would restructure the merge job for coverage the BuildKit SPDX SBOM already provides on each per-arch leaf manifest. Workflow file (.github/workflows/docker-build.yml) intentionally not modified because this resolve agent is environment-policy-blocked from editing under .github/workflows/. Commit 0f7fe9e. 3176256894 ✅ Yes (GraphQL resolveReviewThread)

Commits pushed

SHA Subject
0f7fe9e docs(operate): scope CycloneDX SBOM claim to amd64 in attestation docs

Outstanding

Nothing blocks merge from a resolve perspective:

  • Single review thread classified Valid, fixed, replied, and marked resolved.
  • All CI checks green on 0f7fe9e.
  • bun run scripts/check-docs-citations.ts, bun run scripts/check-docs-versions.ts, and bunx prettier --check 'docs/**/*.md' all green locally; mkdocs --strict runs in Docs / build (also green).
  • This bot can post inline replies but cannot submit a formal APPROVE review decision (FR-017). Final approval and gh pr merge remain a human action.

cost: $4.5778 · turns: 3 · duration: 55s

chrisleekr-bot[bot] and others added 3 commits May 2, 2026 06:33
The Sigstore-signed CycloneDX SBOM that `actions/attest-sbom@v4` binds
to the merged manifest digest is generated by `anchore/sbom-action`
(Syft), which scans the runner's native architecture only — so on
`ubuntu-24.04` it covers amd64 packages, not arm64. Tighten the table
copy in `deployment.md` and `observability.md` to acknowledge this and
direct arm64 audits to the per-arch BuildKit-attached SPDX SBOM (which
already covers both arches). Resolves PR #94 inline review.

Co-authored-by: chrisleekr-bot[bot] <chrisleekr-bot[bot]@users.noreply.github.com>
Co-authored-by: chrisleekr-bot[bot] <chrisleekr-bot[bot]@users.noreply.github.com>
Co-authored-by: chrisleekr-bot[bot] <chrisleekr-bot[bot]@users.noreply.github.com>
@chrisleekr-bot

chrisleekr-bot Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

bot workflow review — succeeded

🔍 Code review complete — 6 files, +315/-132.

Review — PR #94 (bot/issue-58-supply-chain-attestations)

Reviewed at HEAD be841df.

Summary

PR #94 adds SLSA v1 build provenance + CycloneDX/SPDX SBOM attestations to every Docker image the release pipeline publishes, plus a gh attestation verify regression gate that fails the workflow if either attestation flavour is silently dropped by a future refactor of docker-build.yml. The diff is YAML + Markdown only — no src/, Dockerfile.*, or package.json edits. Technical execution remains sound: BuildKit attestation flags correctly override docker/build-push-action's push-by-digest-default-off behaviour, the merge-job permission scoping is least-privilege (top-level attestations: read only; id-token: write + attestations: write confined to the merge job), the merged-digest capture validates with a sha256:[0-9a-f]{64} regex, and the scan-job verify step calls gh attestation verify once per predicate type. The prior review iteration's documentation-accuracy finding (CycloneDX SBOM coverage is amd64-only) has been resolved by tightening the doc copy. One new Minor finding posted inline; otherwise ready for human approval and merge.

What was checked

  • Read .github/workflows/docker-build.yml (368 lines) in full — verified permission scoping (attestations: read at top-level vs. id-token: write + attestations: write confined to the merge job), confirmed provenance: mode=max + sbom: true on the build step, traced the digest flow through imagetools createimagetools inspect --formatanchore/sbom-actionattest-build-provenanceattest-sbomgh attestation verify.
  • Read docs/operate/deployment.md and docs/operate/observability.md diffs — verified the consumer commands, the predicate-type table, the storage matrix, and the post-resolve "amd64 packages only" caveat on the Sigstore CycloneDX flavour now consistently appears in deployment.md:77, deployment.md:97, and observability.md:125.
  • Read CLAUDE.md diff — table widening from prettier reflow plus one new "Recent Changes" bullet.
  • Cross-referenced actions/attest-sbom's action.yml@v4 and actions/attest's src/sbom.ts to confirm the CycloneDX predicate-type constant (https://cyclonedx.org/bom) matches the --predicate-type argument on gh attestation verify at .github/workflows/docker-build.yml:343. Note: the same lookup surfaced that actions/attest-sbom@v4 is deprecated upstream — see Findings.
  • Cross-referenced actions/attest-build-provenance@v4's action.yml — confirmed it is not deprecated (no warning step), only the SBOM wrapper is.
  • git fetch origin maingit rev-list --left-right --count main...HEAD → 0 behind / 5 ahead. No rebase needed.
  • No typecheck/lint/test runs done — the PR is YAML + Markdown and the author's tests-run section already records bun run typecheck, bun run lint, actionlint, mkdocs build --strict, and the bespoke citation/version checks all green.

Findings

[minor] .github/workflows/docker-build.yml:293actions/attest-sbom@v4 is deprecated upstream

actions/attest-sbom@v4 is a thin composite shim around actions/attest@v4.1.0. Its first step prints ::warning::actions/attest-sbom has been deprecated, please use actions/attest instead (verified by reading actions/attest-sbom/action.yml@v4). Functionality is preserved — the wrapper auto-detects CycloneDX vs SPDX and synthesises the predicate (CycloneDX → https://cyclonedx.org/bom, confirmed against actions/attest/src/sbom.ts::generateCycloneDXPredicate, which matches the verify-step argument at .github/workflows/docker-build.yml:343). The impact is cosmetic: every release will surface a deprecation warning in the merge job, and Renovate will eventually try to flip this to a successor. actions/attest-build-provenance@v4 (line 286) is not affected.

Recommended fix: Either (a) switch to actions/attest@v4 directly with predicate-path: sbom-${{ matrix.variant }}.cyclonedx.json + predicate-type: https://cyclonedx.org/bom (same Sigstore bundle, same registry push, no warning), or (b) keep the wrapper and accept the warning until upstream removes the shim — both are low-risk.

Reasoning

Things I considered but did NOT flag:

  • Predicate-type mismatch risk — confirmed against actions/attest/src/sbom.ts::generateCycloneDXPredicate that CycloneDX maps to https://cyclonedx.org/bom, which is what the verify step at .github/workflows/docker-build.yml:343 requests. Coherent.
  • The prior CycloneDX-amd64-only finding — resolved by doc tightening in commit 0f7fe9e. Verified the doc copy at docs/operate/deployment.md:77 (predicate-type table), docs/operate/deployment.md:97 (paragraph above imagetools inspect snippet), and docs/operate/observability.md:125 (storage-matrix Format column) all consistently scope the Sigstore CycloneDX SBOM to amd64 and direct arm64 audits to the per-arch BuildKit SPDX SBOM. No regression.
  • Permission scoping — top-level attestations: read is the minimum the scan job needs to call gh attestation verify; merge-job locally adds id-token: write (Sigstore OIDC) + attestations: write (Attestations API). Build/scan keep read-only. Least-privilege is correct.
  • gh attestation verify against a tag rather than a digest — the oci://...:variant_tag reference is resolved at tool runtime, but the merge job is the only writer to that tag and imagetools create is atomic, so the resolved digest is deterministic. Not worth flagging.
  • subject-digest flowimagetools inspect ... --format '{{ .Manifest.Digest }}' returns the merged manifest-list digest, which is what both attest-build-provenance and attest-sbom bind to via subject-digest, and what gh attestation verify oci://...:tag resolves the tag to. End-to-end consistent.
  • Double imagetools inspect call in the digest-capture step — one human-readable, one for the --format digest. Two registry round-trips, but the second is cheap and the human-readable inspect is genuinely useful in the log. Not worth flagging.
  • anchore/sbom-action@v0 major-only pin — author's deviation note already addresses this (repo convention is tag-only major-version pinning + Renovate group rule); not actionable here.
  • Verify-step set -e semantics — GitHub Actions runs bash with -eo pipefail by default, so a failed first gh attestation verify short-circuits the second. The comment's claim that "either failure fails the workflow" is correct.
  • Defense-in-depth env:-first pattern — every new run: block reads IMAGE_REF / REPO / IMAGE / TAG / DIGEST from env:, never from ${{ … }} expansion inside the script. Pattern preserved.
  • Scan job's 4× redundant verify calls — the scan matrix is {amd64, arm64} × {orchestrator, daemon}. Each cell calls gh attestation verify against the same tag, which resolves to the same merged manifest-list digest, so all four cells fetch the same attestation. Not a bug — the scan job is the regression gate, and running it per matrix cell preserves a uniform shape with the Trivy scan that follows. Not worth flagging.
  • The change does not touch src/ — no test coverage gap to flag.

cost: $4.0709 · turns: 56 · duration: 428s

push-to-registry: true

- name: Attest SBOM
uses: actions/attest-sbom@v4

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

💭 Suggestion | 🟡 Minor

actions/attest-sbom@v4 is deprecated upstream — every release run surfaces a workflow warning.

The v4 ref of actions/attest-sbom (latest tag, what @v4 resolves to today) is a thin composite shim around actions/attest@v4.1.0 whose first step prints ::warning::actions/attest-sbom has been deprecated, please use actions/attest instead (see actions/attest-sbom/action.yml@v4). Functionality is preserved — the wrapper auto-detects CycloneDX vs SPDX and synthesises the predicate (CycloneDX → https://cyclonedx.org/bom, which matches the gh attestation verify predicate type at .github/workflows/docker-build.yml:343). But every release tag will silently raise a deprecation warning in the merge job, and Renovate will eventually try to flip this to a successor. actions/attest-build-provenance@v4 (line 286) is not deprecated, so this only affects the Attest SBOM step.

Suggested fix: Switch to actions/attest@v4 directly: pass predicate-path: sbom-${{ matrix.variant }}.cyclonedx.json + predicate-type: https://cyclonedx.org/bom (the constant the wrapper already maps to for CycloneDX). Same Sigstore bundle, same registry push, no deprecation warning. Alternatively keep the wrapper and accept the warning until upstream removes the shim — low-risk either way.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

⚠️ Maintainer action required

Valid finding — actions/attest-sbom@v4 is deprecated upstream and surfaces a ::warning:: in every release run. The recommended swap to actions/attest@v4 is a workflow-only edit; this resolve agent is environment-policy-blocked from modifying files under .github/workflows/, so it has been left for the maintainer to land directly.

Confirmed against actions/attest-sbom/action.yml@v4: the composite shim wraps actions/attest@v4.1.0 and its first step prints ::warning::actions/attest-sbom has been deprecated, please use actions/attest instead. CycloneDX → https://cyclonedx.org/bom mapping is preserved in either path, so the verify step at .github/workflows/docker-build.yml:343 keeps working unchanged. Suggested edit at .github/workflows/docker-build.yml:292-298:

- name: Attest SBOM
  uses: actions/attest@v4
  with:
    subject-name: ${{ env.IMAGE_NAME }}
    subject-digest: ${{ steps.inspect.outputs.digest }}
    predicate-path: "sbom-${{ matrix.variant }}.cyclonedx.json"
    predicate-type: https://cyclonedx.org/bom
    push-to-registry: true

Same Sigstore bundle, same registry push, no deprecation warning. actions/attest-build-provenance@v4 (line 286) is not affected — only the SBOM step.

@chrisleekr

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

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 commented May 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6a6a96e6-a785-4bd8-9eb3-2e85ace8fcd1

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
📝 Walkthrough

Walkthrough

This PR adds SLSA v1 provenance and CycloneDX SBOM attestations to the Docker build pipeline. The workflow now generates attestations during per-arch builds, publishes them to the registry after manifest-list creation via Sigstore, and verifies both attestation types before running Trivy scans.

Changes

Supply-Chain Attestations for Docker Releases

Layer / File(s) Summary
Permissions & Configuration
.github/workflows/docker-build.yml:54–62, 191–202
Workflow-level attestations: read permission added. Merge job timeout extended to 15 minutes with explicit least-privilege scoping: id-token: write, attestations: write, contents: read.
Build-Time Provenance & SBOM Generation
.github/workflows/docker-build.yml:160–169
Docker build/push step enabled BuildKit provenance (provenance: mode=max) and SBOM generation (sbom: true) on per-arch builds to emit attestation descriptors alongside leaf image manifests.
Manifest Merge & Attestation Publishing
.github/workflows/docker-build.yml:249–298
After building manifest list, merge job extracts and validates the merged digest, generates CycloneDX SBOM from the digest, then publishes two Sigstore-signed attestations (SLSA provenance + SBOM) to the registry using the captured digest as the subject.
Attestation Verification Gate
.github/workflows/docker-build.yml:329–344
Scan job verifies published image has both SLSA provenance and CycloneDX BOM attestations via gh attestation verify before proceeding to Trivy scanning, blocking release if either predicate is missing.
Workflow & Release Documentation
CLAUDE.md:95–154
CI/CD pipeline table updated to document attestation responsibilities; new "Recent Changes" entry (20260502-supply-chain-attestations) describes provenance/SBOM publication behavior, verification, and related docs/issue closure.
Implementation Documentation
IMPLEMENT.md:1–148
Updated to document Issue #58: BuildKit configuration for attestation generation, post-merge Sigstore publication, manifest-list descriptor preservation, permission scoping, and scan-time verification gates; includes security posture notes and deviations from standard flow.
Resolution Report
RESOLVE.md:1–44
Updated to PR #94 with post-fix CI status on commit 0f7fe9e and one resolved review thread validating documentation scope (amd64-only CycloneDX SBOM vs. per-arch BuildKit SBOMs).
Deployment & Observability Guides
docs/operate/deployment.md:70–110, docs/operate/observability.md:117–130
New sections document verification workflow for published attestations using gh attestation verify and docker buildx imagetools inspect; attestation storage/format/scope matrix; notes on Docker Hub attestation badge and scan-job gating behavior.

Sequence Diagram

sequenceDiagram
    actor Developer
    participant BuildAction as docker/build-push-action
    participant BuildKit as BuildKit
    participant Registry as Docker Registry
    participant MergeStep as Merge Job
    participant Sigstore as Sigstore
    participant ScanJob as Scan Job

    Developer->>BuildAction: Push multi-arch build (provenance: mode=max, sbom: true)
    BuildAction->>BuildKit: Build per-arch images with attestation enabled
    BuildKit->>BuildKit: Generate SLSA v1 provenance + SPDX SBOM
    BuildKit->>Registry: Push 4 leaf manifests + attestation descriptors
    BuildAction->>MergeStep: Emit per-arch digests & attestation metadata
    
    MergeStep->>Registry: Assemble manifest list from leaf digests
    MergeStep->>Registry: Extract merged digest from manifest list
    MergeStep->>MergeStep: Generate CycloneDX SBOM from merged digest
    MergeStep->>Sigstore: Sign SLSA provenance + CycloneDX SBOM
    Sigstore->>Registry: Publish two Sigstore attestations to image subject
    
    ScanJob->>Registry: Fetch published image
    ScanJob->>ScanJob: gh attestation verify (SLSA predicate)
    ScanJob->>ScanJob: gh attestation verify (CycloneDX predicate)
    alt Both attestations valid
        ScanJob->>ScanJob: Run Trivy scan
        ScanJob->>Registry: Upload SARIF results
    else Missing attestation
        ScanJob-->>Developer: ❌ Release gate fails
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The PR spans workflow configuration with conditional logic, shell script integration for digest extraction and SBOM generation, permission scoping changes, and coordinated documentation updates across five files. The changes are cohesive but require verification of BuildKit attestation propagation through the merge step, permission correctness, and consistency across docs.

Possibly related PRs

  • PR #27: Introduces the multi-platform build/merge/scan architecture that this PR extends by adding provenance and SBOM attestation generation and verification.

Suggested labels

type: ci ⚙️, type: docs 📋

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding SLSA provenance and SBOM attestation publishing to the release workflow.
Linked Issues check ✅ Passed All primary objectives from issue #58 are met: BuildKit provenance/SBOM enabled, attestation descriptors preserved through merge, Sigstore attestations added, regression gate implemented, and documentation updated.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #58 requirements: workflow YAML enhancements, documentation additions, and no modifications to source code, Dockerfiles, or package.json.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@chrisleekr-bot

chrisleekr-bot Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

bot workflow review — succeeded

🔍 Code review complete — 6 files, +315/-132.

Review — PR #94 (bot/issue-58-supply-chain-attestations)

Reviewed at HEAD be841df.

Summary

PR #94 wires SLSA v1 build provenance + CycloneDX/SPDX SBOM attestations into every Docker image the release pipeline publishes, plus a gh attestation verify regression gate that fails the workflow if either Sigstore-signed predicate is silently dropped by a future refactor of docker-build.yml. The diff is YAML + Markdown only — no src/, Dockerfile.*, or package.json edits. Implementation remains sound: BuildKit attestation flags correctly override docker/build-push-action's push-by-digest-default-off behaviour, the merge-job permission scoping is least-privilege (top-level attestations: read only; id-token: write + attestations: write confined to the merge job), the merged-digest capture validates with a sha256:[0-9a-f]{64} regex, and the scan-job verify step calls gh attestation verify once per predicate type. The HEAD has not changed since the previous review iteration; the prior CycloneDX-amd64-only finding was resolved by 0f7fe9e. One new Minor finding posted inline; the prior actions/attest-sbom@v4 deprecation finding (line 293) is still active and unaddressed but not duplicated as a fresh inline. Otherwise ready for human approval and merge.

What was checked

  • Re-read .github/workflows/docker-build.yml (368 lines) end-to-end — verified permission scoping (attestations: read at top-level, id-token: write + attestations: write confined to the merge job), confirmed provenance: mode=max + sbom: true on the build step, traced the digest flow through imagetools createimagetools inspect --formatanchore/sbom-actionattest-build-provenanceattest-sbomgh attestation verify.
  • Re-read docs/operate/deployment.md and docs/operate/observability.md — verified the consumer commands, the predicate-type table, the storage matrix, and the post-resolve "amd64 packages only" caveat on the Sigstore CycloneDX flavour now consistently appears in deployment.md:77, deployment.md:97, and observability.md:125.
  • Re-read CLAUDE.md diff — table widening from prettier reflow plus one new "Recent Changes" bullet.
  • Cross-referenced anchore/sbom-action's action.yml@main (the only ref @v0 floats to) — confirmed there is no platform input, so Syft scans the runner's native architecture (amd64 on ubuntu-24.04) when given a multi-arch manifest reference. Doc copy is now consistent with this constraint.
  • Cross-referenced actions/attest-sbom's action.yml@v4 — confirmed it is a composite shim around actions/attest@v4.1.0 whose first step prints ::warning::actions/attest-sbom has been deprecated, please use actions/attest instead. Same finding the prior review iteration posted at .github/workflows/docker-build.yml:293; still open.
  • Cross-referenced actions/attest-build-provenance's action.yml@v4 — confirmed it is not deprecated (no warning step), still the current path. Both attest-* v4 shims pin to the same actions/attest@v4.1.0 SHA 59d89421af93a897026c735860bf21b6eb4f7b26.
  • git fetch origin main:maingit rev-list --left-right --count main...HEAD → 0 behind / 5 ahead. No rebase needed.
  • git log --oneline main..HEAD confirms HEAD is unchanged from the previous review iteration's be841df. No new commits to review.
  • No typecheck/lint/test runs done — the PR is YAML + Markdown and the author's tests-run section already records bun run typecheck, bun run lint, actionlint, mkdocs build --strict, and the bespoke citation/version checks all green.

Findings

[minor] .github/workflows/docker-build.yml:343 — Regression gate is Sigstore-only; BuildKit per-arch attestations are unprotected

gh attestation verify queries GitHub's Attestations API for the Sigstore-signed bundles emitted by actions/attest-build-provenance + actions/attest-sbom. It does not inspect the BuildKit-attached vnd.docker.reference.type=attestation-manifest siblings on the per-arch leaf manifests — and those siblings are the only source docs/operate/deployment.md:97 directs arm64 supply-chain audits to (the Sigstore CycloneDX flavour is amd64-only after the resolve-iteration doc tightening). A future refactor that drops provenance: mode=max or sbom: true from the build step (.github/workflows/docker-build.yml:168-169) would still leave the Sigstore attestations intact, so gh attestation verify would pass — but every arm64 audit downstream would silently get nothing. The PR description and docs/operate/deployment.md:95 ("any future regression that drops an attestation") over-read the gate's actual scope. Recommended fix: add a sibling check that asserts docker buildx imagetools inspect <ref> --format '{{ json .SBOM }}' and '{{ json .Provenance }}' are non-empty for both linux/amd64 and linux/arm64. Closes the BuildKit half of the gate without depending on Sigstore.

[minor] .github/workflows/docker-build.yml:293actions/attest-sbom@v4 is deprecated upstream (PRIOR FINDING — STILL OPEN)

Already posted by the prior review iteration as inline comment r3176256908 (and triaged by the resolve iteration but not addressed in code). Re-confirmed against https://raw.githubusercontent.com/actions/attest-sbom/v4/action.yml: every release run will surface ::warning::actions/attest-sbom has been deprecated, please use actions/attest instead in the merge job. Functionality is preserved (the shim wraps actions/attest@v4.1.0 and synthesises the https://cyclonedx.org/bom predicate, which matches the verify-step argument at .github/workflows/docker-build.yml:343). Not duplicating as a fresh inline because the existing thread on the same line is still visible — see prior comment for the recommended actions/attest@v4 migration. actions/attest-build-provenance@v4 (line 286) is not affected.

Reasoning

Things I considered but did NOT flag:

  • HEAD unchanged since the previous review iteration. be841df was the same SHA the prior review reviewed. The CycloneDX-amd64-only finding from review iteration 1 was resolved by 0f7fe9e; the deprecation finding from review iteration 2 is still open (re-noted in Findings, not duplicated inline).
  • Predicate-type mismatch risk — confirmed against actions/attest's upstream that CycloneDX maps to https://cyclonedx.org/bom, which is what the verify step at line 343 requests. Coherent.
  • Permission scoping — top-level attestations: read is the minimum the scan job needs to call gh attestation verify; merge-job locally adds id-token: write (Sigstore OIDC) + attestations: write (Attestations API). Build/scan keep read-only. Least-privilege is correct.
  • gh attestation verify against a tag rather than a digest — the oci://...:variant_tag reference is resolved at tool runtime, but the merge job is the only writer to that tag and imagetools create is atomic, so the resolved digest is deterministic. Not worth flagging.
  • subject-digest flowimagetools inspect ... --format '{{ .Manifest.Digest }}' returns the merged manifest-list digest, which is what both attest-build-provenance and attest-sbom bind to via subject-digest, and what gh attestation verify oci://...:tag resolves the tag to. End-to-end consistent.
  • Double imagetools inspect call in the digest-capture step — one human-readable, one for the --format digest. Two registry round-trips, but the second is cheap and the human-readable inspect is genuinely useful in the log. Not worth flagging.
  • anchore/sbom-action@v0 major-only pin — author's deviation note already addresses this (repo convention is tag-only major-version pinning + Renovate group rule); not actionable here.
  • Verify-step set -e semantics — GitHub Actions runs bash with -eo pipefail by default, so a failed first gh attestation verify short-circuits the second. The comment's claim that "either failure fails the workflow" is correct.
  • Defense-in-depth env:-first pattern — every new run: block reads IMAGE_REF / REPO / IMAGE / TAG / DIGEST from env:, never from ${{ … }} expansion inside the script. Pattern preserved.
  • Scan job's 4× redundant verify calls — the scan matrix is {amd64, arm64} × {orchestrator, daemon}. Each cell calls gh attestation verify against the same tag, which resolves to the same merged manifest-list digest, so all four cells fetch the same attestation. Not a bug — the scan job is the regression gate, and running it per matrix cell preserves a uniform shape with the Trivy scan that follows. Not worth flagging.
  • Docker login ordering in the scan jobLogin to Docker Hub (line 314-318) runs before Verify image attestations (line 332), so gh attestation verify's tag→digest resolution against the registry has credentials. ✓
  • Build matrix failure semanticsfail-fast: false on the build matrix lets all cells complete, but if any cell fails the build job overall fails, and needs: build skips merge. Correct.
  • The change does not touch src/ — no test coverage gap to flag.

cost: $3.6923 · turns: 40 · duration: 578s

gh attestation verify "$IMAGE_REF" --repo "$REPO" \
--predicate-type https://slsa.dev/provenance/v1
gh attestation verify "$IMAGE_REF" --repo "$REPO" \
--predicate-type https://cyclonedx.org/bom

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

💭 Suggestion | 🟡 Minor

Regression gate is Sigstore-only — a future drop of provenance: mode=max / sbom: true would silently lose the per-arch BuildKit SBOM that arm64 audits depend on.

gh attestation verify at .github/workflows/docker-build.yml:340-343 queries GitHub's Attestations API for the Sigstore-signed bundles emitted by actions/attest-build-provenance + actions/attest-sbom. It does not inspect the BuildKit-attached vnd.docker.reference.type=attestation-manifest siblings on the per-arch leaf manifests. Those siblings are the only source the docs direct arm64 supply-chain audits to (docs/operate/deployment.md:97: "the only source for arm64 package coverage"), because the Sigstore CycloneDX flavour is amd64-only. A future refactor that drops provenance: mode=max or sbom: true from the build step (.github/workflows/docker-build.yml:168-169) would still leave the Sigstore attestations intact, so this verify step would pass — but every arm64 audit downstream would silently get nothing. The PR description ("any future regression that drops an attestation") and docs/operate/deployment.md:95 over-read what the gate actually protects.

Suggested fix: Add a sibling check that fails the workflow if BuildKit's per-arch attestations aren't published — e.g. assert docker buildx imagetools inspect <ref> --format '{{ json .SBOM }}' and '{{ json .Provenance }}' are non-empty for both linux/amd64 and linux/arm64. That closes the BuildKit half of the gate without depending on Sigstore.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

⚠️ Maintainer action required

Valid finding — gh attestation verify covers Sigstore-signed predicates only and won't catch a regression that drops the BuildKit-attached attestations on per-arch leaf manifests. The recommended imagetools inspect sibling check is a workflow-only edit; this resolve agent is environment-policy-blocked from modifying files under .github/workflows/, so it has been left for the maintainer to land directly.

The asymmetry matters because docs/operate/deployment.md:97 directs arm64 supply-chain audits at the BuildKit-attached SPDX SBOM (the Sigstore CycloneDX flavour is amd64-only after the 0f7fe9e doc tightening). A future refactor that drops provenance: mode=max or sbom: true from .github/workflows/docker-build.yml:168-169 would still leave the Sigstore attestations intact, so the existing verify step at .github/workflows/docker-build.yml:340-343 would pass — but every arm64 audit downstream would silently get nothing. Suggested addition just before the existing Verify image attestations step (or as a new step in merge):

- name: Verify per-arch BuildKit attestations
  env:
    IMAGE_REF: ${{ env.IMAGE_NAME }}:${{ steps.imgtag.outputs.tag }}
  run: |
    set -euo pipefail
    for arch in linux/amd64 linux/arm64; do
      sbom=$(docker buildx imagetools inspect "$IMAGE_REF" \
        --format '{{ json (index .SBOM "'"$arch"'") }}')
      prov=$(docker buildx imagetools inspect "$IMAGE_REF" \
        --format '{{ json (index .Provenance "'"$arch"'") }}')
      if [[ -z "$sbom" || "$sbom" == "null" ]]; then
        echo "ERROR: missing BuildKit SBOM on $arch" >&2; exit 1
      fi
      if [[ -z "$prov" || "$prov" == "null" ]]; then
        echo "ERROR: missing BuildKit provenance on $arch" >&2; exit 1
      fi
    done

That closes the BuildKit half of the gate without depending on Sigstore. Alternatively, if the maintainer prefers to keep the gate Sigstore-only, the docs at deployment.md:95 and the PR description should be tightened to scope the "any future regression that drops an attestation" claim to Sigstore predicates only.

Co-authored-by: chrisleekr-bot[bot] <chrisleekr-bot[bot]@users.noreply.github.com>
@chrisleekr-bot

chrisleekr-bot Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

bot workflow resolve — succeeded

🔎 Resolve iteration complete — 0 failing checks, 3 open comment threads (some may already be resolved).

Resolve iteration — PR #94

Iteration date: 2026-05-02 (second resolve pass, post-review iteration #2)

Summary

PR #94 (feat(workflows): publish SLSA provenance + SBOM attestations on every release tag (closes #58)) entered this resolve with 0 failing checks and 3 review threads (per the trigger header). GraphQL inspection showed only 2 threads were actually open: the line-277 thread was already resolved by the prior resolve iteration in commit 0f7fe9e. Branch was 0 behind / 6 ahead of main, so no rebase was needed. Both open threads are bot-authored review-iteration findings against .github/workflows/docker-build.yml — both classified Valid but environment-policy-blocked (the resolve agent cannot modify files under .github/workflows/, same constraint the prior iteration documented). Replies were posted with the exact maintainer-action diffs and threads left open so the maintainer sees the deferred work. No commits pushed this iteration; CI state is unchanged from d85a748 (all green).

CI status

No failing checks at the start of this iteration. No commits pushed, so CI was not re-triggered — final state is the same all-green ledger from d85a748:

Check Workflow State on d85a748
Lint & Test CI pass
build Docs pass
Analyze (actions) CodeQL pass
Analyze (javascript-typescript) CodeQL pass
CodeQL CodeQL pass
Gitleaks (push + PR) Secrets Scan pass
Label PR based on title Generate Labels pass

Zero fix attempts consumed against the FIX_ATTEMPTS_CAP=3 budget.

Review comments

Comment ID File:line Classification Action Reply Thread resolved?
3176252148 .github/workflows/docker-build.yml:277 Valid (already addressed) Resolved in the prior iteration via doc tightening in commit 0f7fe9e. No action this iteration. n/a (prior iteration: 3176256894) ✅ Yes (resolved by prior iteration)
3176271719 .github/workflows/docker-build.yml:293 Valid — maintainer action required actions/attest-sbom@v4 is upstream-deprecated (composite shim around actions/attest@v4.1.0 that prints ::warning::actions/attest-sbom has been deprecated). Recommended one-step swap to actions/attest@v4 with explicit predicate-type: https://cyclonedx.org/bom. Workflow edit deferred — environment-policy-blocked from editing files under .github/workflows/ (same constraint as prior iteration). Reply contains the exact YAML diff for the maintainer. 3176312123 ❌ No — left open for maintainer follow-up
3176305901 .github/workflows/docker-build.yml:343 Valid — maintainer action required gh attestation verify only covers Sigstore-signed predicates and won't catch a regression that drops BuildKit's provenance: mode=max / sbom: true on the per-arch builds — yet docs/operate/deployment.md:97 directs arm64 audits at exactly those BuildKit-attached SPDX SBOMs. Recommended fix: add a sibling docker buildx imagetools inspect step asserting non-empty .SBOM + .Provenance for both linux/amd64 and linux/arm64. Workflow edit deferred — same env-policy block. Reply contains the exact YAML for the maintainer. 3176312364 ❌ No — left open for maintainer follow-up

Commits pushed

None this iteration. Prior iterations' commits remain in place:

SHA Subject
0f7fe9e docs(operate): scope CycloneDX SBOM claim to amd64 in attestation docs

Outstanding

Two maintainer-action items block "ready to merge" from a strict resolve-clean perspective. Both are valid review findings that this resolve agent classified Valid but couldn't action because they require editing .github/workflows/docker-build.yml, which is outside this agent's edit allowlist:

  1. docker-build.yml:293actions/attest-sbom@v4 deprecation. Swap to actions/attest@v4 with predicate-type: https://cyclonedx.org/bom. Cosmetic in steady state (every release prints a deprecation ::warning::); becomes blocking when upstream removes the shim. See reply 3176312123 for the exact diff.

  2. docker-build.yml:343 — Sigstore-only regression gate. Add a docker buildx imagetools inspect sibling check that asserts BuildKit per-arch attestations are non-empty for both linux/amd64 and linux/arm64. Closes the BuildKit half of the gate without depending on Sigstore. See reply 3176312364 for the exact step YAML.

Other notes:

  • All CI checks green on d85a748. No fix-attempts consumed against the cap.
  • This bot can post inline replies but cannot submit a formal APPROVE review decision (FR-017). Final approval and gh pr merge remain a human action.
  • Both unresolved threads are intentionally left open so the maintainer's PR view surfaces the deferred work.

cost: $3.0063 · turns: 5 · duration: 65s

Two open review threads on `.github/workflows/docker-build.yml`
(`@v4` deprecation + Sigstore-only regression gate) classified Valid
but environment-policy-blocked from this resolve agent's edit allowlist.
Replies posted with exact maintainer-action diffs; threads left open.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@chrisleekr
chrisleekr merged commit 95856bc into main May 2, 2026
9 checks passed
@chrisleekr
chrisleekr deleted the bot/issue-58-supply-chain-attestations branch May 2, 2026 07:29
chrisleekr pushed a commit that referenced this pull request May 3, 2026
# [1.9.0](v1.8.0...v1.9.0) (2026-05-03)

### Bug Fixes

* **checkout:** fetch PR base branch so origin/<baseBranch> resolves (closes [#74](#74)) ([#96](#96)) ([71f83a6](71f83a6))
* **fetcher:** paginate GraphQL connections + MAX_FETCHED_* caps (closes [#66](#66)) ([#95](#95)) ([f728ecd](f728ecd))
* **triage:** accept note-only evidence; raise research max-turns to 200 ([#97](#97)) ([3b6036c](3b6036c))
* **workflow:** fix release.yml ([#98](#98)) ([cb43d69](cb43d69))

### Features

* **workflows:** publish SLSA provenance + SBOM attestations on every release tag (closes [#58](#58)) ([#94](#94)) ([95856bc](95856bc))
@chrisleekr

Copy link
Copy Markdown
Owner

🎉 This PR is included in version 1.9.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security(infrastructure): published Docker images ship without SBOM or SLSA provenance attestations

1 participant