Skip to content

release: v1.3.0 — speak the industry's language - #18

Merged
ryanjmichie-git merged 11 commits into
mainfrom
release/v1.3.0
Sep 5, 2026
Merged

ryanjmichie-git merged 11 commits into
mainfrom
release/v1.3.0

Conversation

@ryanjmichie-git

Copy link
Copy Markdown
Owner

release: v1.3.0 — speak the industry's language

Every bundle now also carries a standards-conformant attestation: an in-toto Statement v1 with a SLSA Provenance v1 predicate, DSSE-signed inside a Sigstore bundle by the same ephemeral Ed25519 key that signs the chain, verifiable with plain cosign and no ForgeProof code present. Still pure stdlib; cosign is consumer-side only. Full notes: CHANGELOG.md §1.3.0. Plan: PLAN_v1.3.0.md.

Bundle format bumped additively to 1.1.0. Every prior .rpack still verifies with zero errors and zero warnings, strict mode included, enforced by three frozen fixtures (v1.0.1, v1.1.0, v1.2.2 engines). A v1.1.0 bundle read by a pre-v1.3 verifier is green with exactly one benign version warning.

Merge instructions

  • Merge with a merge commit. Do not squash. The companion Action pins engine commit ac9da9b in verifier/UPSTREAM; a squash orphans that SHA and turns the Action's sync-check permanently red. Repo settings already allow merge commits only.
  • After merging, before tagging: git merge-base --is-ancestor ac9da9b origin/main must succeed.
  • Note: this PR's own verify-provenance check is skipped by the head-branch filter (release branches carry no bundle). Expected and acceptable; the draft-PR matrix below covered the Action.

Evidence

Check Result
CI matrix (ubuntu / macos / windows / windows git-bash+cmd / debian python3-only / plugin validate) green on e61a7d8; run on ccadf13 linked in the checks tab
cosign-interop (v2.6.5 and v3.1.3, pinned binaries) green; both negatives fail with the real cosign errors (claim check, signature threshold)
Stress suite 292 passed locally on Windows; CI Stress green
Unit tests 290 passed
Draft-PR matrix #15 / #16 / #17 (closed) (a) new bundle × new Action green, tamper red; (b) frozen v101+v110 × new Action green, zero warnings, tamper red; (c) new bundle × old Action v1.0.2 green with exactly one version warning, tamper red
UAT (scratch-marketplace install of this tree) gate blocks without bundle and allows with one; full lifecycle with approval sealed at HEAD (chain, rpack, sigstore.json, pub.pem); lint hook fired; /forgeproof:verify renders the attestation section; tamper red, restore green; cosign v2.6.5 Verified OK outside ForgeProof, tampered artifact rejected
Companion Action forgeproof-verify v1.1.0 released, v1 moved; all three plugin pins on 6101dd7, zero stale

After merge

  1. Tag v1.3.0 (annotated) on the merge commit; push the tag.
  2. GitHub Release from the CHANGELOG 1.3.0 section.
  3. Re-pin forgeproof-verify verifier/UPSTREAM from SHA ac9da9b to tag v1.3.0 (one Action commit + tag, owed post-release).
  4. T+1–2 days: community marketplace pin advances to the merge SHA; dogfood check green on a fresh PR; Action v1 resolves to v1.1.0.

🤖 Generated with Claude Code

ryanjmichie-git and others added 11 commits August 15, 2026 11:14
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t ahead of attestation work

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dentifier, Phase-2 version bump, transactional finalize, non-vacuous cosign negatives, honest SLSA wording

Second cosign spike (both pinned binaries, 2026-08-15) plus source review of
sigstore_bundle.proto, cosign verify_blob_attestation.go and SLSA v1.2:
- DSSE signature stays keyid-free AND verificationMaterial.publicKey becomes {}
  (a populated hint beside an absent keyid is ambiguous under the proto's
  hint-equality MUST; the empty identifier is unambiguous and Verified OK on
  v2.6.5 and v3.1.3)
- cosign artifact-tamper cases must pass the artifact path (or recompute the
  digest from disk): with --digest alone cosign never reads the artifact
- plugin.json + PLUGIN_VERSION bump moves to Phase 2 so the engine is final
  after Phase 3 (no post-vendor delta; UAT bundles self-report 1.3.0)
- cmd_finalize gains a chain-file rollback guard + failure-injection tests
- compliance doc claims fields-required-at-L1 emission, not L1 attainment
- Phase 1 tests gain fixed hostile-encoding vectors; small-order blocklist and
  Ed25519ph KAT deliberately skipped with rationale

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oding primitives

Phase 1 of PLAN_v1.3.0.md (amendment v2 layout). Nothing lifecycle-wired yet.

- RFC 8032 Ed25519 (sign/verify/public-from-seed), KAT-locked to the RFC 7.1
  vectors; verify hardened for hostile input: s >= L, y >= p, non-square x,
  x=0-with-sign-bit and wrong-length encodings all return False, never raise
- openssh_ed25519_seed parses the unencrypted openssh-key-v1 container and
  dies actionably on encrypted/foreign/truncated keys; asserts the derived
  public key equals the embedded blob (wrong-key signing is impossible)
- ssh_ed25519_pubkey_bytes, RFC 8410 SPKI PEM (golden-string tested)
- DSSE PAE (spec KAT), envelope + Sigstore v0.3 bundle builders: one
  signature, sig-only signature object, verificationMaterial {"publicKey": {}}
- EphemeralEd25519Signer: the three-member v1.4 signer seam
- 35 new tests incl. fixed hostile-encoding vectors and a hand-built
  openssh-key-v1 container helper written independently from the format spec

Test evidence: 241 passed (was 206), banned-literal grep green, only new
import is base64.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y bundle

Phase 2 of PLAN_v1.3.0.md (amendment v2 layout, empty publicKey identifier).

- approval chain action (gate/decision/note; engine fills approver from git
  config, degrading to "" — never blocks); _RECORD_DATA_FLAGS extended so the
  silent-drop guard sees the new flags; explicit fallthrough dies loudly
- builder identity in the finalize block with per-field provenance labels:
  model self-reported (--model), Claude Code version measured via
  shutil.which-only probe, plugin version engine-constant
- in-toto Statement v1 + SLSA Provenance v1 predicate: subjects = deduped
  artifacts (single chain descriptor for zero-artifact runs), approvals
  labeled agent-recorded, chain byproduct reuses the sealed chain_hash
  (LF-normalized text — never a byte re-hash), invocationId = genesis hash
- DSSE-signed via the ephemeral key's parsed seed, bound to the published
  public key BEFORE any chain mutation; embedded under bundle.attestation
  before root_digest so the SSHSIG covers it; sidecars issue-N.sigstore.json
  (byte-identical canonical JSON, zero newline bytes) + issue-N.pub.pem
- rollback guard: any failure after save_chain restores the chain file
  byte-for-byte and removes partial outputs; key deleted only after success
- format version 1.1.0 + KNOWN_RPACK_VERSIONS membership check (three verify
  sites changed together, folded from Phase 3 so v1.0.0 fixtures stay
  warning-free at every commit); detail prints the bundle's version
- reset/init --force/summary know the sidecars; gate and lint hooks
  deliberately unchanged (tested); plugin.json + PLUGIN_VERSION -> 1.3.0
  together (amended sequencing)

Test evidence: 270 passed (was 241). Real CLI e2e produced all three files,
verify green zero warnings; the emitted sidecar verifies Verified OK with
cosign v2.6.5 AND v3.1.3 (no ForgeProof code), artifact tamper exits 1 on both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 3 of PLAN_v1.3.0.md. Read-side only, additive, zero filesystem reads
for attestation purposes.

- three new checks after coverage: attestation (well-formed statement/
  envelope; the payload decode is a new json.loads over attacker bytes,
  guarded with the read_json_file trio incl. RecursionError),
  attestation_signature (DSSE over PAE verified against the bundle's OWN
  ssh-ed25519 key — the one-key binding payoff), attestation_subjects
  (subject set == artifact set or the single chain descriptor; chain
  byproduct digest == the SEALED chain_hash, compared never recomputed)
- absent attestation is SILENT: skipped, zero errors, zero warnings, in
  every mode including --strict; invariants only, never byte re-derivation
- failure classification: four new TAMPER_ERROR_MARKERS entries free of the
  legacy 'hash mismatch'/'prev_hash' fragments; 'Attestation malformed'
  errors deliberately match no marker (FAILED, not TAMPER) and never embed
  attacker-controlled values (substring classification injection)
- additive result key 'attestation' {present, predicate_type, subject_count,
  key_id (verifier-derived), builder, approvals}; markdown gains an
  Attestation section (all bundle content through md_cell) with the exact
  cosign reproduction command
- tests: per-invariant tamper matrix (payload edit, sig flip, foreign DSSE
  key, subject digest edit, chain byproduct edit — each exactly one marker,
  TAMPER DETECTED verdict, root_digest isolated green), malformed matrix
  (wrong types, bad base64, bad JSON, missing keys, two signatures, deep
  nesting with shape fallback + forced RecursionError) all FAILED-not-TAMPER;
  all three frozen fixture classes now assert attestation==skipped,
  warnings==[], format detail names the bundle's version — lenient AND strict

Test evidence: 290 passed (was 270).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rop and compliance mapping

Phase 4 of PLAN_v1.3.0.md (amended wording throughout).

- run skill: record the plan-gate approval right after init (engine fills
  approver), pass --model to finalize (self-reported, stated honestly),
  attestation in the finalize behavior list and the final report; explicit
  note that the seal step already stages the sidecars — do not 'fix' it
- verify skill: the attestation result object + three checks, the new
  failure scenarios (tamper vs signed-malformed), and cosign as an
  alternative view — never a required step
- push skill: PR body notes the attestation + how to verify it
- rpack-format.md: format v1.1.0, membership-based recognition, the
  embedded attestation layout (keyid-free, empty publicKey), sidecar byte
  contracts, the chain_hash LF-normalization caveat, the #slsa-buildtype-v1
  parameter schema and #builder-id trust-base documentation the engine URIs
  resolve to (also fixed the engine constant's path to the real references
  location) — plus the 1.0.0-is-valid-forever statement
- chain-format.md: approval action row; finalize block's builder identity
- docs/cosign-interop.md (new): pinned v2.6.5/v3.1.3 contract, the exact
  command, what each flag proves, and the --digest vacuousness pitfall
- docs/compliance-mapping.md (new): SSDF-as-voluntary framing with the
  2022->2026 mandate window and M-26-05 rescission, CISA form item 3 task
  mapping, CRA Annex VII 2(c)/6 at the manufacturer's discretion, and the
  amended SLSA wording: fields required at Build L1, no level claim
- ROADMAP v1.3.0 narrative corrected (no 'converging regulation', no
  'compliance-ready by default'); PRIVACY.md corrects the live
  username@hostname inaccuracy and adds the approver email + sidecars
- TestSkillContract floor 13 -> 17 (the new invocation count)

Test evidence: 290 passed; claude plugin validate clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n tier

Phase 5 of PLAN_v1.3.0.md (amended: non-vacuous artifact cases).

- cosign-interop CI job, matrixed over BOTH pinned binaries (v2.6.5, v3.1.3;
  installer pinned by commit SHA d58896d6 # v3.9.2): stress/make_bundle.py
  drives the real engine (init -> records -> approval -> finalize --model)
  in RUNNER_TEMP, then one cosign run per artifact passing the artifact PATH
  (cosign hashes each file itself — the attestation's own digest is never
  fed back), one --digest run recomputed from disk with hashlib, and two
  negatives: flipped artifact byte (claim check) and flipped envelope
  payload byte (signature) must fail. cosign appears in this job only.
- stress harness: approval via the real CLI, finalize emits byte-exact
  sidecars (no newline bytes) inside a 60s ceiling, attestation-field tamper
  -> Root digest mismatch, reformatted sidecar does NOT affect verify
  (verify reads no sidecar), reset removes the sidecars
- README: attestation in the intro and bundle contents, cosign as an
  optional interop-only section (not Requirements), test count 168 -> 290
  from a real --collect-only, three frozen fixtures, compat promise widened
  to the v1.0.x/v1.1.x/v1.2.x lines
- CHANGELOG 1.3.0: full section, leading with the additive format bump and
  the benign one-warning behavior on pre-v1.3 verifiers

Evidence: 290 pytest green; stress 292 passed / 0 failed / 0 skipped in
121.5s on Windows; the exact CI command sequence proven locally against both
binaries — 3x Verified OK per binary (path form), --digest form green, and
both negatives failing with the real tamper errors ('provided artifact
digest does not match any digest in statement', 'accepted signatures do not
match threshold, Found: 0, Expected 1').

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…osign v3 line

The v3.1.3 leg of cosign-interop failed inside the installer step itself
(exit 22): cosign v3.x releases replaced the detached cosign-linux-amd64.sig
asset with a cosign-linux-amd64.sigstore.json bundle, and installer v3.9.2's
custom-version path still downloads the .sig (404). Installer v4.1.2 switches
on is_version_ge 3.0.1 to the bundle layout and still handles v2.6.5's .sig
path. The v2.6.5 leg and the entire pytest/validate matrix were green on the
first run — no engine or attestation change here, pin-bump only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All three pin sites move from 0bd8aae # v1.0.2 to the v1.1.0 merge
commit; grep proves zero stale hits outside historical plan documents.
The pinned commit's vendored engine is byte-identical (sha256
f713f3e9...) to this repo's engine-final commit ac9da9b.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ROADMAP: v1.3.0 🧭 → ✅, Last updated 2026-09-05. CHANGELOG 1.3.0 gains the
forgeproof-verify v1.1.0 re-pin entry (done in e61a7d8, not yet recorded).
No engine, manifest, hook, or fixture bytes change: plugin.json and
PLUGIN_VERSION were bumped to 1.3.0 in Phase 2.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ryanjmichie-git
ryanjmichie-git merged commit e6aef5c into main Sep 5, 2026
17 checks passed
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