Skip to content

feat: sigstore-sign.yml reusable keyless signer (Noah 17:13Z item 2) - #91

Merged
noahgift merged 9 commits into
mainfrom
feat/sigstore-sign
Oct 22, 2026
Merged

noahgift merged 9 commits into
mainfrom
feat/sigstore-sign

Conversation

@noahgift

Copy link
Copy Markdown
Contributor

#90. Items 2-4 and 6 of the ruling. Signer identity is read from the Fulcio cert (a called workflow signs as ITS ref: paiml/.github/.github/workflows/sigstore-sign.yml@), so callers verify with that exact identity + issuer via scripts/sigstore-verify.sh (item 5). Falsifiers: valid / tampered / other-identity / no-bundle (4 rows, cosign MODELLED; real cosign is first proven on the first tag run), plus a 6-row structural guard of the workflow. Not proven here: a live OIDC signing run (needs a tag build in a caller). Needs quorum (non-author) + 2 seats; not armed.

🤖 Generated with Claude Code

noahgift and others added 7 commits October 21, 2026 19:15
…DC), with verify script and RED->GREEN guards

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1. sign-blob --new-bundle-format with cosign pinned to v2.5.3, so the jq reads of
   .verificationMaterial.* are non-empty.
2. sigstore-verify.sh also pins the caller repo and caller workflow name (and an
   optional ref); a same-SAN/other-repo row refuses.
3. runs-on input is required with no default; no hosted runner can be assumed.
4. Refuse a tag that is not an ancestor of origin/main (full-depth sha-pinned checkout).
5. check-sigstore-sign.sh parses the YAML with yq instead of grepping; 33 mutants
   (guard exit 0 / if false && / commented out / if: false, || true, secrets[...],
   toJSON(secrets), COSIGN_KEY, --key TAB, unwired outputs, unpinned actions) are RED.
6. No COSIGN env override of the verifier; a row proves COSIGN=true does not verify.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- check-sigstore-sign.sh: the parsed workflow must equal scripts/sigstore-sign.golden.json
  (every key of every step pinned), the two guard bodies are RUN against a temp repo
  (tag/branch/empty, on-main/off-main/garbage/missing origin/main), key sets and env sets
  are exact, shell/defaults/container are forbidden, steps == 8, the signing step cannot
  exit 0 early. 54 mutants RED, 21 of them also RED without the golden.
- sigstore-verify.sh: refuse EMPTY arguments (cosign skips an empty pin), model treats
  empty as skipped like cosign, literal issuer in the fixture, wrong-issuer row, more
  env-override names probed.
- sigstore-sign.yml: caller checkout into caller-src/, artifact-name through env (no
  expression in run:), identity output is the bare SAN so it feeds sigstore-verify.sh.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…irs, tag output (Q-GH91c)

- checker pins every run body and every step's non-run keys as literals written in the checker (no regenerable hash),
  plus CODEOWNERS on workflow/checker/golden/verifier
- guard bodies run under env -i with Actions variables, production shell flags, a bare-origin clone, varied
  GITHUB_JOB/REF_NAME/GITHUB_ACTIONS; GITHUB_ENV/PATH/OUTPUT must stay empty; verdicts memoised per body pair
- sign/bundles live in $RUNNER_TEMP/sigstore-sign-<run>-<attempt>; mkdir (not -p) refuses a reused dir
- new `tag` output; verifier refuses unknown flags; yq must be mikefarah v4, jq present; no `|| true` in the pin scan
- 87 mutants (33 new) RED

Refs GH-1397

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…in job env) (Q-GH91c)

actionlint caught `runner.temp` in job-level env. Each step that needs the per-run dir now sets WORK itself; the
checker pins the env sets and forbids job env.

Refs GH-1397

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…el, per-run cosign dir, nested files

- checker refuses any ${{ in a run body (expressions expand inside comments); comment now says independence is the quorum, CODEOWNERS removed
- verify self-test model refuses unknown flags; flag rows are real files / a 7th flag arg so only the refusal can stop them
- cosign-installer install-dir is the per-run dir (nothing under $HOME); mkdir -p for nested artifact paths before signing
- 91 mutants RED

Refs GH-1397

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ly, TUF cache per-run, exact interface key sets

- sigstore-verify self-test runs the unshadowed script against a recording fake cosign and pins the exact argv (with/without ref); flag rows use real files + valid pins; the model refuses unknown flags and a row tests that directly
- sign step refuses nested paths, non-regular files, *.sigstore.json inputs and slash tags BEFORE any sign-blob (attach glob now sees every bundle); mkdir -p and the *.sigstore.json find filter are gone
- TUF_ROOT is the per-run dir; checker pins inputs/outputs/types/job-output key sets as literals
- 102 mutants RED

Refs GH-1397

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@noahgift

Copy link
Copy Markdown
Contributor Author

Planted quorum #91 @ 9c83a76 (author w-tss01/other; lanes Opus 5.5, non-author, run by rm:w-green Sonnet 5.5)

Verdict: 2 PASS, 1 FAIL -> NOT SIGNABLE until CI green.

  • A security: PASS (check 102/102 mutants red, verify self-test 23/23; no fail-open)
  • B bypass: PASS (nothing accepted that must refuse)
  • C ci/ops: FAIL - own CI run 39748581481 validate+gate RED: "yq is not on PATH" (check-sigstore-sign.sh needs mikefarah yq v4; clean-room runner has none). Fix: provision yq as host change, or drop the yq dependency in the check.
    Non-blocking: (a) verifier pins caller workflow name only, caller-ref optional - consumers must pass ref (rmedia install.sh must); (b) >6 args silently ignored; (c) '=' in filename ambiguous rekor receipt line; (d) contents:write needed even when upload-to-release=false.
    Signer: w-cr-saas.

🤖 Generated with Claude Code

Noah Gift and others added 2 commits October 22, 2026 22:47
… clean-room fleet has no yq

Fixes the red validate/gate on #91 (yq is not on PATH). The reader fails closed (exit 2) on YAML outside its subset; self-test 102/102 mutants + reader rows.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…duplicate keys (Opus delta review: a '>' mutant split the tag guard and passed)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@noahgift
noahgift merged commit b66acd1 into main Oct 22, 2026
2 checks passed
@noahgift
noahgift deleted the feat/sigstore-sign branch October 22, 2026 22:22
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