Skip to content

RUSTSEC-2024-0449: rash build.rs reads binding.yaml with no YAML crate (supersedes serde-saphyr) - #452

Open
noahgift wants to merge 8 commits into
mainfrom
fix/rustsec-2024-0449-saphyr
Open

noahgift wants to merge 8 commits into
mainfrom
fix/rustsec-2024-0449-saphyr

Conversation

@noahgift

@noahgift noahgift commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Refs #453, #450, #449, #426. Remaining advisory paths: #451.

This PR now carries the #453 approach, merged on top of the earlier serde-saphyr commits (no force-push). The resulting tree takes none of serde-saphyr: no new crate.

  • rash/build.rs reads binding.yaml with rash/build_support/binding_yaml.rs, a strict line reader for the one shape it uses: a top-level bindings: block sequence of flat mappings, with four scalar keys. Anything it does not fully read in a key it uses is an error. It never guesses. An unreadable file prints a cargo warning; the old script skipped it silently.
  • rash has no build-dependencies. cargo tree -p bashrs -i unsafe-libyaml -e normal,build is empty. tests/build_deps_no_unsafe_libyaml.rs asserts it through cargo tree, and it fails on main.
  • The build-script output is byte-identical to the old script's. tests/build_binding_yaml.rs holds the 17 directive lines as a golden.
  • There is a differential against serde_yaml_ng in rash/build_support/differential/. It is a separate package with its own empty [workspace], so serde_yaml_ng stays out of bashrs's graph and Cargo.lock. Over provable-contracts 626868c: 41 files, 41 identical, 0 refused. A corpus path that finds no files fails. A mutant that drops function turns 3 of 4 tests red.

Checks at 75d4280 (tree identical to the #453 branch head):

  • cargo fmt --all -- --check passes.
  • cargo test -p bashrs --test build_binding_yaml --test build_deps_no_unsafe_libyaml: 6 passed.
  • cargo test -p bashrs --lib: 15762 passed. The 24 failures are all testing::shellcheck_validation_tests, which need shellcheck; the test host does not have it.

Not fixed here: cargo deny check advisories stays red on RUSTSEC-2024-0449. Two dev-only paths remain: jugar-probar (dev of bashrs) and aprender-contracts via provable-contracts (dev of bashrs-specs), tracked in #451. ci / lint will stay red until then.

Quorum on 75d4280: 3/3 PASS (claude-sonnet-5-5 ×2, claude-haiku-4-5). It is marked degraded: same-family. A planted control (serde_yaml_ng put back under rash [build-dependencies]) drew FAIL from 3/3 lanes, each naming the planted rash/Cargo.toml line.

🤖 Generated with Claude Code

noahgift and others added 6 commits October 12, 2026 21:07
…rde-saphyr, not serde_yaml_ng (unsafe-libyaml)

rash's only YAML read is the provable-contracts binding.yaml in build.rs, and
it pulled serde_yaml_ng -> unsafe-libyaml (unmaintained) into bashrs's
build graph. serde-saphyr =1.3.0 is pure Rust; only `deserialize` is taken.
Options hold it to what serde_yaml_ng accepted: YAML 1.2 booleans only, `<<`
an ordinary key, a duplicate key an error.

build.rs main() was Cognitive 136; it is split into helpers with no
behaviour change (max Cyclomatic 7, Cognitive 18). The old (origin/main,
serde_yaml_ng) and new build scripts, each built standalone and run against
the same binding.yaml, print byte-identical stdout for: the real file
(AllImplemented 16/16), one binding set to `partial` (both panic, UNALLOWED
GAP CONTRACT_PARSER_SOUNDNESS_V1_LEX), and a duplicate top-level key (both
skip the file).

`cargo tree -i unsafe-libyaml -e normal,build -p bashrs` is now empty; it is
non-empty with origin/main's rash/Cargo.toml. Remaining paths are not
bashrs's build or runtime: jugar-probar (dev-dependency of bashrs and
bashrs-wasm), provable-contracts -> aprender-contracts -> serde_yaml (dev of
bashrs-specs), and aprender's build-dependency under bashrs-oracle.

Refs PMAT-450

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…saphyr)

The pre-commit hook regenerated the TDG baseline. All 993 content_hash
entries equal blake3 of the blobs at 59e5704. Besides rash/build.rs,
ten linter files had baseline hashes from before #439/#399 on main and
are refreshed here; their sources are unchanged by this branch.

Refs PMAT-450

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ate, so bashrs no longer pulls unsafe-libyaml

rash's only path to unsafe-libyaml was its serde_yaml_ng build-dependency,
used by build.rs to read provable-contracts/contracts/bashrs/binding.yaml.
Every crate depending on bashrs inherited the advisory through it.

build.rs uses four scalar keys (contract, equation, status, function) of
one shape: a top-level `bindings:` block sequence of flat mappings. It now
reads that shape with rash/build_support/binding_yaml.rs, a strict line
reader shared with its tests through #[path]. Anything it does not fully
read in a key it uses (block or flow collections, block scalars, anchors,
tags, escapes, multi-line values, duplicate keys, a null required value)
is an error, never a guess; keys it does not use are skipped with their
nested lines. rash now has no build-dependencies. An unreadable file
prints a cargo warning; the old script skipped it silently.

Measured:
- tests/build_deps_no_unsafe_libyaml.rs asks `cargo tree -p bashrs -e
  normal,build`: FAILS on fd39a6e (serde_yaml_ng v0.10.0,
  unsafe-libyaml v0.2.11), passes here.
- With binding.yaml present beside the checkout, the build-script output
  file is byte-identical before and after (19 lines). The 17 directive
  lines are committed as a golden (tests/data/binding_yaml/) and
  tests/build_binding_yaml.rs matches it; a reader that keeps the `.yaml`
  suffix turns that test red.
- A one-off differential against serde_yaml_ng over all 41 provable-
  contracts binding.yaml files: 41 identical, 0 different. Of 12 crafted
  edge cases, 10 are identical and 2 (null status, block-scalar status)
  are refused here where serde_yaml_ng read them.

Cargo.lock drops serde_yaml_ng from bashrs's dependency list only; it stays
in the lock through bashrs-oracle -> aprender, which this does not touch.

Refs #453, #426

Pmat-Ticket: PMAT-453
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st, not a one-off

The parent commit's third acceptance criterion (the reader returns exactly
what serde_yaml_ng returned over every provable-contracts binding.yaml) was
backed by a one-off run that no one could repeat from the tree.

tests/build_binding_yaml_differential.rs compares the reader with the old
build script's serde_yaml_ng structs, field for field:
- always: the committed bashrs binding.yaml fixture, the accepted inline
  shapes, and two shapes serde_yaml_ng reads that the reader refuses by
  design (block-scalar status, anchor);
- with BINDING_YAML_CORPUS=<provable-contracts>/contracts: every
  */binding.yaml there, failing if it finds none, so a wrong path cannot
  pass by reading nothing.

serde_yaml_ng comes back as a dev-dependency only. Cargo.lock lists it under
bashrs again (the lock does not separate dev from build edges), and
`cargo tree -p bashrs -e normal,build -i unsafe-libyaml` stays empty;
tests/build_deps_no_unsafe_libyaml.rs still passes.

Measured: over provable-contracts 626868c, 41 files, 41 identical, 0
refused. A mutant that drops `function` (always None) turns three of the
four tests red; restoring it turns them green.

Refs #453, #426

Pmat-Ticket: PMAT-453
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ashrs's graph again

The previous commit put serde_yaml_ng back as a bashrs dev-dependency for the
differential test. cargo deny checks dev edges too, so that added a third
unsafe-libyaml path (RUSTSEC-2024-0449) that would keep advisories red after
the jugar-probar and aprender-contracts paths (#451) are gone.

The differential now lives in rash/build_support/differential/, a package
with its own empty [workspace] table: not a bashrs member, not in Cargo.lock,
not packaged with bashrs (cargo skips nested packages). rash/Cargo.toml and
Cargo.lock are byte-identical to the first commit of this branch again.

    cargo test --manifest-path rash/build_support/differential/Cargo.toml
    BINDING_YAML_CORPUS=<provable-contracts>/contracts \
      cargo test --manifest-path rash/build_support/differential/Cargo.toml

Measured: over provable-contracts 626868c, 41 files, 41 identical, 0
refused; a corpus path with no binding.yaml fails; the `function: None`
mutant turns three of four tests red and green again when restored.
`cargo deny check advisories` lists the same two dev paths as the first
commit (jugar-probar, aprender-contracts), none through bashrs's own
dependencies.

Refs #453, #426, #451

Pmat-Ticket: PMAT-453
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ding serde-saphyr

#452 replaced serde_yaml_ng in rash/build.rs with serde-saphyr, a new
external crate. #453 replaces it with no crate: a strict reader for the one
shape build.rs reads (rash/build_support/binding_yaml.rs), byte-identical
build-script output, and a serde_yaml_ng differential kept in its own
package, 41 of 41 provable-contracts binding.yaml files identical.

This merge takes the #453 tree whole: serde-saphyr, its Cargo.lock entries,
the re-baselined .pmat/baseline.json and the PMAT-450 roadmap row from
#452's two commits are not in the result. The tree is identical to the
#453 branch head; nothing here was force-pushed.

Refs #452, #453, #450, #426

Pmat-Ticket: PMAT-453
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@noahgift noahgift changed the title RUSTSEC-2024-0449: rash build.rs reads binding.yaml with serde-saphyr, not serde_yaml_ng RUSTSEC-2024-0449: rash build.rs reads binding.yaml with no YAML crate (supersedes serde-saphyr) Oct 13, 2026

This branch has not been deployed

No deployments
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