Skip to content

Release/v1.4.0 - a name of its own - #19

Merged
ryanjmichie-git merged 7 commits into
mainfrom
release/v1.4.0
Sep 22, 2026
Merged

ryanjmichie-git merged 7 commits into
mainfrom
release/v1.4.0

Conversation

@ryanjmichie-git

Copy link
Copy Markdown
Owner

v1.4.0 — A name of its own

No bundle byte changed. The bundle format stays at 1.1.0; no member is added, removed or re-typed; the code that writes, canonicalizes, signs and verifies a bundle is untouched. The engine diff against v1.3.0 is two lines: PLUGIN_VERSION and one docstring.

What this release adds is around the format, not in it:

  • Normative specification — skills/run/references/rpack-format.md gains a stability statement, an exact definition of the canonical serialization behind root_digest, the four attestation checks that bind a verifier, and an emission profile.
  • Published JSON Schema (2020-12) for format 1.x at an immutable tag-pinned $id; permissive on unknown members; validated in CI only — the engine still imports nothing.
  • Detection definitions, shipped but never installed — shared-mime-info XML and a libmagic rule under share/, proven in CI against every fixture and layout, including the documented limits.
  • Media type application/vnd.forgeproof.rpack+json (vendor tree), to be submitted to IANA after the tag. Its status lives in one ledger line in docs/media-type.md; nothing else states a status.
  • Fourth frozen fixture (fixtures/v130/) from the v1.3.0 engine — the first with an attestation.
  • New CI job format identity (schema + detection), now a required check on main.

Tests 290 → 311. forgeproof-verify v1.1.0 remains current — the verifier is unchanged.

Verification

  • All 13 CI + Stress jobs green on b1bcae0 (ubuntu, macOS, windows, debian python3-only).
  • Schema driver: 11 positives, 5 negatives, 0 mismatches. Detection driver: 109 checks, 0 mismatches.
  • Frozen fixtures v101 / v110 / v122 / v130 unchanged, verifying in both lenient and strict mode.

Merge with a merge commit, not a squash — a squash orphans the SHAs the companion forgeproof-verify Action pins.

🤖 Generated with Claude Code

ryanjmichie-git and others added 7 commits September 20, 2026 09:24
…ion); open v1.4.0 on the roadmap

fixtures/v130 (issue 996) is the unmodified v1.3.0 engine's output at
e6aef5c, LF-only, root_digest 931294a2...; it verifies lenient and strict
with zero errors and zero warnings, all three attestation checks ok.
TestV130Compat mirrors TestV122Compat and adds the attestation-ok test and
a fourth tamper case (one byte inside the attestation turns root_digest
red): 290 -> 300 passed. No engine, manifest, hook, or skill bytes change.
ROADMAP gains the v1.4.0 block per PLAN_v1.4.0 Appendix D; keyless moves to
v1.5.0 and attested review to v1.6.0, with the two docs mentions renumbered.
PLAN_format_identity.md lands as PLAN_v1.4.0.md, approved 2026-09-19, with
dated 2026-09-20 corrections to section 3.3 I1/I8, the 3.4 provenance
caveat, the Step 0 roadmap row, and the T0 Files and Acceptance rows (the
artifact is src/example_v130.py; v130 is the first fixture to carry an
approver e-mail).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…y vs emission; media type; verification requirements)

rpack-format.md gains, additively (path and the SLSA buildType heading
untouched; two pre-existing lines change so they read as statements about
the reference producer: the attestation section's opening sentence and the
"Layout contracts" lead-in): a status-and-stability statement, an identity
section (format, version, application/vnd.forgeproof.rpack+json, the .rpack
collision sentence), a normative validity section written from the engine
source (UTF-8 as the one byte-level rule, member table, the exact canonical
serialization behind root_digest, the two-member denylist, the
canonical-SSHSIG rule), "What binds a verifier" for a present attestation
(the four checks the reference verifier performs; extra signature-object
members, mediaType, and verificationMaterial are never by themselves
grounds for rejection, verificationMaterial is opaque to the format, and a
verifier that implements the Sigstore bundle rules may additionally apply
them), the emission-profile clause from PLAN_v1.4.0 Appendix B.0, the
verification requirements, and a format-bump checklist. docs/media-type.md
is new: the single status ledger line (state A: not yet submitted), the
RFC 6838 5.6 template, what a registration does and does not change, the
editor snippet, the extension note, known limits, the Apple UTI note, and
the upstream-submission checklist behind the sign-off gate. Detection
recipes follow with the detection files.
TestFormatIdentity adds seven tests (300 -> 307 passed): spec path and
anchor frozen, canonical form matches the spec (code-point order, compact,
lowercase \uXXXX, surrogate pairs), no floats in the four fixtures, the
format marker within the first 256 bytes for the four fixtures and a fresh
bundle, the forbidden-phrase sweep with the one-ledger-line rule, the
attestation-wrapper tolerances the spec states, and a test pinning a
documented limitation in both modes: verify resolves recorded artifact
paths, and the chain-file name it builds from issue.number, as given.
The template's security text therefore says SHOULD confine, says what the
reference verifier does and what its verdict discloses, and says the
producer's refusal dates from plugin 1.1.0; its cosign sentence states
what cosign checks and what only the format's own verification binds.
ROADMAP schedules the hardening with v1.5.0.
PLAN_v1.4.0 is corrected in place with dated notes: Appendix A is level
with the docs template (zero differing lines; OpenSSH 8.1 or later, since
ssh-keygen -Y sign/verify first shipped in 8.1 per the openssh.com release
notes; the D11 wording rule applied to the template itself; the two
paragraphs above), Appendix C and D8 make the schema match the verifier
(only dsseEnvelope is required of a present attestation), the real heading
level of the buildType anchor, and one release-checklist item: an errata
sweep before the tag, because the spec URL is immutable after it.
No engine, manifest, hook, skill, or fixture bytes change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
schemas/forgeproof-rpack-1.schema.json is new: JSON Schema 2020-12, $id the
v1.4.0 tag-pinned raw URL with a $comment stating the last-changing-release
rule. It is PLAN_v1.4.0 Appendix C with description annotations taken from
the specification's member table and no further constraining keyword (equal
to the Appendix C block modulo descriptions, checked mechanically), less
the four "minimum": 0 keywords Appendix C carried, removed from both: the
member table says "integer" with no sign restriction, and a released engine
(v1.1.0) can emit a negative count in a bundle every verifier passes. It
describes the member table and relaxes only where the specification tells
verifiers to tolerate something: unknown members at every level, and
mediaType / verificationMaterial, which are described but never required or
constrained; a present attestation requires only dsseEnvelope.
stress/validate_schema.py is the CI driver and the only file that imports
jsonschema; the engine and the pytest suite never do. Positives: the four
frozen fixtures, a fresh bundle from stress/make_bundle.py, that bundle with
an unknown top-level member, and that bundle with mediaType and
verificationMaterial removed from its attestation. Negatives: wrong format,
missing signature, version 2.0.0, two DSSE signatures, tests_passed 1.5 --
each must produce exactly one error, at the expected instance path, from the
expected keyword, so none can pass by failing on something unrelated. It
also checks the schema against the 2020-12 metaschema.
.github/jsonschema-requirements.txt pins jsonschema==4.26.0 and its five
transitive dependencies with hashes, generated by uv pip compile
--generate-hashes --universal --python-version 3.11; verified to install
with --require-hashes into a throwaway venv, from which the driver ran
green (7 positives, 5 negatives, 0 mismatches). No workflow is edited here;
the format-identity job arrives with the detection files.
TestFormatIdentity adds test_schema_is_structurally_sane, stdlib only
(307 -> 308 passed): the 2020-12 $schema, an absolute fragment-free $id
ending in the schema's own repo path, format const and version pattern
against the engine constants (2.0.0 excluded), attestation not required, no
additionalProperties or unevaluatedProperties false anywhere, the
attestation sub-schema's required exactly ["dsseEnvelope"], mediaType and
verificationMaterial annotation-only, and neither named in any list. Shown
red on scratch copies for each of those tolerances and for a broken $id.
PLAN_v1.4.0 records, as dated corrections at T3-2 and above Appendix C, the
two decisions made after the plan text: what the schema describes, and the
added acceptance case; that the requirements file is generated with uv; and
the removal of the four minimum keywords from the Appendix C block.
No engine, manifest, hook, skill, workflow, or fixture bytes change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ve them against every fixture

share/mime/packages/forgeproof-rpack.xml and share/magic/forgeproof are
new: PLAN_v1.4.0 Appendix B.1 / B.2, opt-in files that ForgeProof never
installs. One departure from the B.1 draft: its header comment spelled the
xdg-mime one-liner, whose "--mode" is a double hyphen inside an XML comment.
expat rejects that as not well-formed, and update-mime-database 2.1 prints
"Failed to parse" and still exits 0, registering nothing. The comment now
gives the copy + update-mime-database recipe and points to
docs/media-type.md for the one-liner. The magic rule is B.2 verbatim.
stress/check_detection.py is the CI driver, stdlib only. It copies both
files under a temp dir (inside $RUNNER_TEMP when set), compiles them there
(update-mime-database: rc 0, empty output, globs2 and subclasses carry the
type; file -C -m), and runs gio info under an isolated XDG_DATA_HOME and
file(1) over the four frozen fixtures and a fresh stress/make_bundle.py
bundle in six layouts each: as written, CRLF, compact in insertion order,
key-sorted, canonical, BOM-prefixed; named issue-1.rpack and noext. The
limits are asserted: plain file, with or without -m, says application/json;
key-sorted, canonical and BOM copies are text/plain by content and the type
by glob; unrelated JSON and RP6L bytes are not claimed; a control run
without the XML says text/plain. A missing tool is a failure, never a skip.
109 checks green on WSL Ubuntu 22.04 (shared-mime-info 2.1, gio 2.72.4,
file-5.41); each limit shown red on scratch copies when inverted.
ci.yml gains the format-identity job: apt-installs shared-mime-info,
libglib2.0-bin and file with versions printed, pip-installs the hash-pinned
validator, then runs stress/validate_schema.py and
stress/check_detection.py. No other job installs any of them.
docs/media-type.md gains "Detection files" (user-mode install and
uninstall, the no-install recipe, file -e json -m and the built-in JSON
precedence, the asserted results, the upstream test-list line) and two
Known-limits bullets; the ledger line and the registration template are
untouched. PRIVACY.md's "does not" list gains the MIME / .gitattributes /
editor-settings line.
TestFormatIdentity adds test_detection_files_single_sourced and
test_engine_never_mentions_consumer_tools, stdlib only (308 -> 310 passed).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
.gitattributes gains "*.rpack linguist-language=JSON"; the fixtures rule is
untouched, and git check-attr shows both attributes on every fixture bundle
(text: unset, linguist-language: JSON). No linguist-generated.
README gains a "Format identity" section under "The .rpack Bundle" (the
specification, the bare type name with a pointer to the ledger, the schema
and its $id, the optional .gitattributes line with the prescribed sentence,
a pointer to the detection files), one requirement sentence under "Verify a
bundle", four fixtures and the v1.3.0 engine in both places that counted
three, and the measured test count (290 -> 311, pytest --collect-only). It
says the file renders as JSON and says nothing about diffs: that has not
been observed. The two "OpenSSH 8.0" lines are left as they are.
CHANGELOG gains [1.4.0]: the no-bundle-byte-changed sentence, worded to
hold after the release commit (a fresh bundle differs from a v1.3.0 one
only where its attestation records the plugin version); four fixtures; the
type as proposed with its status in docs/media-type.md; forgeproof-verify
v1.1.0 remains current; what the format-identity job asserts, not a result;
the schema proven against the four fixtures and fresh bundles only.
PRIVACY.md's bundle table gains a Timestamps row, written from the v130
fixture: the bundle carries startedOn / finishedOn inside the attestation
payload (v1.3.0+, equal to the first and last chain block times), earlier
bundles carry none, and the per-block times live in the chain file beside
the bundle.
docs/media-type.md gains "GitHub rendering" (the same line and sentence);
the editor snippet and the known limits were already there, and the ledger
line and the registration template are untouched (0 differing lines
against PLAN_v1.4.0 Appendix A).
TestFormatIdentity adds test_skills_never_write_repo_config, stdlib only
(310 -> 311 passed): no SKILL.md names .gitattributes, update-mime-database,
xdg-mime, or files.associations, and the four skills must be found. Shown
red on a scratch copy for each token and for a missing skill.
No engine, manifest, hook, skill, schema, workflow, or fixture bytes change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…emplate, privacy, changelog

Wording findings logged since Phase 1, resolved before the tag freezes
the spec URL and the schema $id. The engine, hooks, skills, manifest and
fixtures are untouched; no JSON Schema constraint keyword changed.

Spec (rpack-format.md): BCP 14 key-word sentence; version form
1.<minor>.<patch> in Identity; LF after the SSHSIG BEGIN marker stated;
producer-list sentence no longer carries a verifier "must"; base64 rule
and the str() comparison stated as the reference verifier does them;
the MAY on verificationMaterial scoped (empty state {"publicKey": {}}
and mediaType outside it; absent, not an object, empty, or populated
all tolerated); the
three check rows vs the four numbered checks disambiguated; bump
checklist names the drivers' fixture-count pin.

Schema: three description annotations made timeless (no "today", no
"the reference producer emits"); constraints byte-for-byte unchanged;
Appendix C mirrors the two wrapper descriptions.

Registration template (docs/media-type.md == plan Appendix A, 0
differing lines): network-share path opened like any other path on
Windows; producer refusal scoped to the producing platform; chain-file
leg discloses element count and a few member values; "never a
substitute for it" agrees with the spec's MAY; sidecar files named once.

docs/media-type.md: recipes use <plugin-dir> / <your-project>
placeholders; XDG_DATA_HOME prefix on the no-install recipe (also in the
XML comment); file(1) read-limit qualifier; "most files"; "a bundle as
written"; "and diffs" (observed on GitHub).

PRIVACY.md: Last Updated, a 1.4.0 row, and the one read outside the
project that verify performs on a bundle's recorded paths.

README: OpenSSH floor 8.1 (two lines); "and diffs". CHANGELOG: bare
type name (no "proposed"), status parenthesis dropped, OpenSSH line, the
two omitted test names, the five single-sourced files, the plugin-version
footprint, the docs renumber, the exact "nothing new is run" form.

Tests (311 collected, count unchanged): tolerance test gains absent
mediaType and empty / non-object verificationMaterial; $id tag segment
pinned; list-form "file" spelling matched; two more repo-config tokens;
schema driver gains four positives (no attestation, version 1.0.0,
non-string mediaType with non-object verificationMaterial, every integer
count negative) — 11 positives, 5 negatives.

Plan errata (dated 2026-09-22): Appendix A note, Appendix C note, B.1
comment defect and "sorted (indented or minified)", section 10 row (a),
T3-2 version-example note.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
plugin.json and PLUGIN_VERSION move to 1.4.0 together (sync test); the
signer-seam docstring at forgeproof.py:530 now names v1.5 (keyless);
ROADMAP flips v1.4.0 from Next to Shipped, Last updated 2026-09-22, and
drops the word "proposed" from the milestone text so the ledger line in
docs/media-type.md stays the only statement of registration status.
Engine diff against tag v1.3.0 is exactly those two lines: no bundle,
manifest, hook, skill, or fixture byte changes beyond the version.
forgeproof-verify v1.1.0 remains current — the verifier is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ryanjmichie-git
ryanjmichie-git merged commit 881e636 into main Sep 22, 2026
23 checks passed
@ryanjmichie-git
ryanjmichie-git deleted the release/v1.4.0 branch September 29, 2026 04:29
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