tests/packages/ruby/extractor.wasm is reproducible from exactly one directory on earth, and we publish it as reproducible #132

Closed
opened 2026-09-04 22:35:40 +02:00 by buildagent · 0 comments
Member

Found while fixing the example guest's reproducibility (commit a5f91c2). Measured, not inferred. Deliberately not fixed there, for a reason given below.

The measurement

Same source, two absolute paths, one rustc:

/tmp/locA                  0fb12e629b7adc8aec9f8f7c9ceb850ee737ad146b73200cc0cdc3f5fedf644a
/tmp/locBBBBBBBBBBBBBBBB   ce4d0f32421a4ee35dcede99efa8976989af420a9a5f2ed48b0b470208df6a19

29 551 bytes each, 547 differing bytes, every one inside [23876, 29321) — the name custom section.

Same cause as the example guest: crates/guest/ruby takes a path dependency on crates/guest, cargo derives -C metadata from the package's absolute path, rustc hashes it into the crate disambiguator, and the disambiguator is spelled into every mangled name.

The checked-in tests/packages/ruby/extractor.wasm still carries CskmEPAwE88Sg_16code_index_guest — one particular machine's disambiguator.

Why this is worse than the example-guest instance

The example guest is a test fixture. This is a shipped, operator-installed, digest-pinned package component.

WASM_ARTIFACTS records the claim "reproducible IN THIS REPOSITORY: crates/guest/ruby/build.sh". That statement is true from exactly one directory on earth. Anyone who clones this repository and runs the script gets different bytes and therefore a different package_digest — and the digest is package identity, the thing plugin install --sha256 and every signature check are keyed on.

So the provenance claim a third party would rely on to verify what they installed is one they cannot reproduce. That is a supply-chain honesty defect, not a build annoyance.

CI is not red for it, and that is the trap

ruby_package_e2e::the_shipped_package_is_the_artifact_that_was_recorded re-packs the checked-in bytes and compares digests. Nothing rebuilds the wasm. So the gate passes, permanently, while the reproducibility claim beside it is false — the same shape as a green check over an untrue property that this project has hit repeatedly today.

Why it was not fixed in a5f91c2

Applying --strip-name-section to the Ruby guest moves package_digest and extraction_identity. Per tests/packages/ruby.digest's own discipline that is a package version bump, a re-record, and release notes — not a build-script edit, and not something to leave sitting uncommitted in a tree whose purpose that hour was unblocking a red CI.

Doing it badly would have been worse than leaving it measured and named.

What closing it needs

  1. --strip-name-section in crates/guest/ruby/build.sh, matching what crates/guest/example/build.sh now does — one implementation, already in plugin-host.
  2. Rebuild extractor.wasm; bump the package version (0.2.0 → 0.3.0) because the identity moves.
  3. Re-record tests/packages/ruby.digest and the WASM_ARTIFACTS row.
  4. Re-run the #84 parity axes — the digest is an input to axis A's ClaimTable and to the e2e's install-by-digest path.
  5. Prove it the way the example guest's was proven: two independent absolute paths, byte-identical, both digests quoted.
  6. Then, and only then, the "reproducible in this repository" claim is true and can stay.

The general form, worth considering

Any guest built from crates/guest inherits this, because the cause is the path dependency, not the language. A third-party author following our own SDK will ship an irreproducible artifact unless the strip step is part of the documented build. That belongs in _prdoc/guides/80-package-authoring.md as a requirement, not a footnote — the SDK is the authoring path the whole "every language ships as a plugin" direction rests on.

a5f91c2 (the example guest, fixed and proven from three locations). #84 (which required, and got, exactly this property of tree-sitter-ruby.wasm — "two independent build dirs must produce byte-identical output" — so the standard already exists in this epic and the guest simply did not meet it).

Found while fixing the example guest's reproducibility (commit `a5f91c2`). **Measured, not inferred.** Deliberately not fixed there, for a reason given below. ## The measurement Same source, two absolute paths, one rustc: ``` /tmp/locA 0fb12e629b7adc8aec9f8f7c9ceb850ee737ad146b73200cc0cdc3f5fedf644a /tmp/locBBBBBBBBBBBBBBBB ce4d0f32421a4ee35dcede99efa8976989af420a9a5f2ed48b0b470208df6a19 ``` 29 551 bytes each, **547 differing bytes, every one inside `[23876, 29321)` — the `name` custom section.** Same cause as the example guest: `crates/guest/ruby` takes a path dependency on `crates/guest`, cargo derives `-C metadata` from the package's absolute path, rustc hashes it into the crate disambiguator, and the disambiguator is spelled into every mangled name. The checked-in `tests/packages/ruby/extractor.wasm` still carries `CskmEPAwE88Sg_16code_index_guest` — **one particular machine's disambiguator**. ## Why this is worse than the example-guest instance The example guest is a test fixture. This is a **shipped, operator-installed, digest-pinned package component**. `WASM_ARTIFACTS` records the claim *"reproducible IN THIS REPOSITORY: `crates/guest/ruby/build.sh`"*. That statement is true from exactly one directory on earth. Anyone who clones this repository and runs the script gets different bytes and therefore a different `package_digest` — and the digest is package **identity**, the thing `plugin install --sha256` and every signature check are keyed on. So the provenance claim a third party would rely on to verify what they installed is one they cannot reproduce. That is a supply-chain honesty defect, not a build annoyance. ## CI is not red for it, and that is the trap `ruby_package_e2e::the_shipped_package_is_the_artifact_that_was_recorded` **re-packs the checked-in bytes** and compares digests. Nothing rebuilds the wasm. So the gate passes, permanently, while the reproducibility claim beside it is false — the same shape as a green check over an untrue property that this project has hit repeatedly today. ## Why it was not fixed in `a5f91c2` Applying `--strip-name-section` to the Ruby guest moves `package_digest` **and** `extraction_identity`. Per `tests/packages/ruby.digest`'s own discipline that is a package **version bump**, a re-record, and release notes — not a build-script edit, and not something to leave sitting uncommitted in a tree whose purpose that hour was unblocking a red CI. Doing it badly would have been worse than leaving it measured and named. ## What closing it needs 1. `--strip-name-section` in `crates/guest/ruby/build.sh`, matching what `crates/guest/example/build.sh` now does — one implementation, already in `plugin-host`. 2. Rebuild `extractor.wasm`; **bump the package version** (0.2.0 → 0.3.0) because the identity moves. 3. Re-record `tests/packages/ruby.digest` and the `WASM_ARTIFACTS` row. 4. Re-run the #84 parity axes — the digest is an input to axis A's `ClaimTable` and to the e2e's install-by-digest path. 5. **Prove it the way the example guest's was proven**: two independent absolute paths, byte-identical, both digests quoted. 6. Then, and only then, the "reproducible in this repository" claim is true and can stay. ## The general form, worth considering **Any** guest built from `crates/guest` inherits this, because the cause is the path dependency, not the language. A third-party author following our own SDK will ship an irreproducible artifact unless the strip step is part of the documented build. That belongs in `_prdoc/guides/80-package-authoring.md` as a requirement, not a footnote — the SDK is the authoring path the whole "every language ships as a plugin" direction rests on. ## Related `a5f91c2` (the example guest, fixed and proven from three locations). #84 (which required, and got, exactly this property of `tree-sitter-ruby.wasm` — *"two independent build dirs must produce byte-identical output"* — so the standard already exists in this epic and the guest simply did not meet it).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
h-dv/code-index#132
No description provided.