fix(sec): ship Sigstore trust materials (Fulcio root + Rekor key) - #933
fix(sec): ship Sigstore trust materials (Fulcio root + Rekor key)#933hanthor wants to merge 6 commits into
Conversation
…cy.json - Add sigstoreSigned policy entry for ghcr.io/projectbluefin with keyless OIDC verification rules matching Github Actions OIDC workflow signatures. - Add Sigstore public good infrastructure root cert fulcio_v1.crt.pem and rekor.pub key to system_files/shared/usr/lib/pki/containers/. Closes projectbluefin#847
|
This doesn't work with bootc iirc? It just gracefully falls back? |
## Problem The `validate` check has been producing false-negative failures across the open PR backlog. At time of writing, 9 of 19 open PRs (#893, #917, #924, #926, #929, #931, #932, #933, #934) showed a red `validate` check unrelated to their own content: ``` error: docs/skills/index.json is stale. Run scripts/generate_skill_index.py --write ``` ## Root cause `scripts/generate_skill_index.py` stamped `generated_at` with `date.today()` at **script-execution time**, then byte-compared the result against the committed `docs/skills/index.json`. That means the check only passed if CI happened to run on the *same calendar day* the index was last regenerated on `main` — entirely independent of whether any skill doc actually changed. Any PR whose CI ran a day or more after the last regeneration failed. Reproduced locally with zero content edits: `--check` failed purely because days had passed since the last commit to `index.json`. This matters because `validate` is a **required status check** in the merge queue ruleset, so the noise trains reviewers to ignore a gate that is supposed to block merges. ## Fix Only advance `generated_at` when the catalog's actual content (`schema_version` + `skills`) differs from what is committed. `--write` becomes idempotent when nothing changed; `--check` tolerates a stale date as long as the skill data matches. ## Verification Proved in both directions, with a regression test for each: - **No false negative** — backdated the committed index to `2020-01-01` with zero skill content changes; `--check` now passes (previously failed). Covered by `test_generate_skill_index_check_tolerates_stale_generated_at`. - **Real drift still caught** — edited a skill's front matter without regenerating; `--check` still fails with `index.json is stale`. Covered by `test_generate_skill_index_check_still_fails_on_real_drift`. `just check` passes. Skill doc test suite: 8 passed. ## Alternatives rejected - *Compare against the merge result instead of PR head* — doesn't address the cause; the merge tree still gets stamped "today". - *Scope the check to changed files* — would blind it to a PR that edits a skill doc without regenerating the index. - *Stop committing generated files* — far larger blast radius for a date-comparison bug. - *Auto-commit bot step in CI* — added complexity over a small fix. Assisted-by: Claude Sonnet 5 via GitHub Copilot Co-authored-by: Jorge Castro <jorge@projectbluefin.io> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Breaking rewrite of pr-review.md from agent-review checklists (v2.0) to a human-decides, agent-lands backlog review workflow (v3.0). Key changes: - Remove agent-accelerated review lane (lines 31-56 of v2.0) - Encode dossier → verdict → stage → land loop with batch size of 5 - Add per-PR human verdict vocabulary (merge/close/defer/rebase/changes/open/skip) - Add issue triage sweep with issue-specific verdicts - Add blast radius map with system_files/shared/ never-fast-lane rule - Default to merge queue (--auto), --admin requires explicit human instruction - Include worked example using real backlog PRs (#926, #932, #933, #934, #936) - Extract per-type review checklists to See Also links (existing skill docs) - State verified merge queue config (squash-only, ALLGREEN) without restating review count (known doc drift with governance.md, being fixed separately) 296 lines (was 440). Per-type checklists (systemd, shell, dconf, OEM, test, CI) are no longer in this file — the human does that judgment using the linked per-domain skill docs. Assisted-by: Claude Opus 4.6 via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Deferred to the human queue during backlog triage. This is a signature-enforcement change on What it does: adds a Verified so far:
Open questions a reviewer should settle before merging:
Minor: Suggested verification before merge: # Enumerate everything the new scope would govern
gh api /orgs/projectbluefin/packages?package_type=container --jq '.[].name'
# Confirm a real image verifies against the proposed identity
cosign verify ghcr.io/projectbluefin/common:latest \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github\.com/projectbluefin/(bluefin|bluefin-lts|dakota|common|aurora|actions)/\.github/workflows/'No objection to the approach — the gap it closes is real, since |
|
[strategist] CI note for the human reviewer: the 🐝 Hive Agent: |
castrojo
left a comment
There was a problem hiding this comment.
The entry matches the #847 recommendation verbatim and the materials check out: policy.json remains valid JSON, the Fulcio cert is the genuine Sigstore production root (self-signed O=sigstore.dev, CN=sigstore, valid 2021-10-07 → 2031-10-05), and rekor.pub is the standard public-good Rekor key. matchRepository + the GitHub Actions OIDC issuer + workflow-path subjectRegExp is the right shape for our keyless cosign signing.
Two blocking issues:
1. CI is red (pre-commit). end-of-file-fixer fails on system_files/shared/usr/lib/pki/containers/fulcio_v1.crt.pem — missing trailing newline. One-character fix.
2. Namespace-wide scope will break pulls of unsigned/differently-signed images (Breakage gate). The entry covers all of ghcr.io/projectbluefin with sigstoreSigned, which replaces the insecureAcceptAnything catch-all for every image in the namespace — not just bootc OS images. The org publishes many packages that are not signed by the listed workflows, e.g. bluefin-toolbox / ubuntu-toolbox (commonly pulled via distrobox/toolbox on Bluefin itself), finpilot, knuckle, testsuite, brew, lab-runner, bluefin-cache, base/static/skopeo/buildah CI images — and crucially the unsigned bluefin-pr-* PR test images, since "Create and sign multi-arch manifest" is skipped on PR builds. After this lands, bootc switch to a PR test image from a Bluefin machine would be rejected, breaking the factory's own test loop.
Recommend scoping to the signed OS image repos using policy.json's longest-prefix matching, e.g. separate entries for ghcr.io/projectbluefin/bluefin, .../bluefin-lts, .../dakota, .../common (and a deliberate decision on bluefin-pr-*), or first confirming every published package is signed with a matching identity. Minor: aurora in the subjectRegExp is dead weight — projectbluefin/aurora doesn't exist.
Happy to re-approve quickly once the scope is narrowed or an inventory shows full signing coverage.
…cement Splits the enforcement change out of this PR per review on projectbluefin#847. An inventory of ghcr.io/projectbluefin shows the consumer-facing tags of the OS images are not currently cosign-signed (neither the index nor the per-arch child manifests), so *any* sigstoreSigned entry -- namespace-wide or narrowed per-repo -- would reject pulls of images users are on today. This commit therefore lands only the trust materials (Fulcio v1 root and the public-good Rekor key) with no policy change, so the enforcement entry can be added later without a second materials rollout.
|
@castrojo thanks — point 1 fixed, and point 2 turned out to be worse than either of us thought, so I've split the PR. What this PR is now: trust materials only ( Why the policy entry is deferred: I inventoried actual signing coverage in
Two consequences:
The pattern that stands out: within a single repo, the daily/build tags are signed ( So I don't think there's a correct scope to pick here yet — enforcement should follow signing coverage, not lead it. Suggested sequence:
Happy to open issues for (2) if you agree with the read. Also noted re: |
|
Correction / sharpening of my inventory above — I pulled build timestamps from the config blobs, and the pattern isn't the promotion path. It's a date cutoff:
( Every image built on or before ~2026-06-08 is signed; every image built after mid-June 2026 is unsigned, across all repos and both promoted and daily tags. So my earlier read — "the promotion path drops signatures" — was wrong. The signed tags just happen to be the stale ones that predate the break; That makes this a single org-wide signing regression around mid-June 2026, not a per-repo or per-tag issue — one root cause to find rather than a promotion redesign. It also means signing coverage will keep decaying: each rebuild converts a signed tag into an unsigned one, which is why Doesn't change the recommendation — this PR should still land as materials-only and enforcement should follow coverage — but it makes step 2 much more tractable. Worth checking what changed in the cosign/signing step around 2026-06-08; if you want I can open an issue with this table. |
Assessment (agent follow-up on the request-changes review)Both blocking issues from the review are addressed at HEAD (1b523fb):
Independent verification of the signing inventoryI spot-checked ghcr.io/projectbluefin/bluefin directly against the registry (anonymous pull token), and the picture is slightly more nuanced than "nothing is signed":
Two consequences for the future enforcement PR:
Proposed direction
Note: I can't re-review or dismiss the outstanding CHANGES_REQUESTED — that needs a human re-review (cc @castrojo). CI is green and the branch is mergeable pending that. |
|
Root cause found and fixed — deferring the policy entry here was the right call, and the reason is now concrete. cosign 3.x is why nothing is signed. The Renovate bump of Confirmed against this repo's own latest build ( That also corrects my table above: the clean date cutoff isn't the promotion path dropping signatures, it's the cosign upgrade. Anything that still looks signed simply hasn't rebuilt since early June.
Once that lands, consumers bump their pinned actions SHA and rebuild, and signing coverage returns — at which point the |
Summary
sigstoreSignedentry forghcr.io/projectbluefintosystem_files/shared/etc/containers/policy.jsonenforcing keyless OIDC signature verification for container images built/published via GitHub Actions OIDC keyless signing.fulcio_v1.crt.pemandrekor.pubSigstore root assets tosystem_files/shared/usr/lib/pki/containers/.Closes #847