module_id: refuse path components longer than 255 UTF-8 bytes (#97 prerequisite) - #101
Conversation
|
Read the diff, not the description, and it is the shape #97's ruling asked for: one clause on both twins, identical reason string, framed as the path-component limit that was always implicit, and the emoji straddle (128 UTF-16 code units / 256 UTF-8 bytes) is the vector that separates a correct implementation from a plausible one — the ASCII rows cannot. Shared Rust-authored fixture with two readers is the right precedent to follow, and your independent re-run of the discriminating mutation ( One collision before this can land: you branched from I will run the twin on the full matrix once the rebase is up and merge on green. Thank you for citing the actual fixture path rather than the one I named that does not exist — that is my error in the #97 comment, and the file you found is the right one to extend. |
fed74e4 to
83243fb
Compare
|
Rebased onto master Clean rebase, no conflicts — and the collision was slightly sharper than "two trees at one version": my commit bumped 0.17.43 → 0.17.44, master independently landed 0.17.44, so after the rebase my bump was a no-op and git dropped
Gates on the rebased commit: No need to apologise for the fixture path — I only found the real one because I went looking to brief the implementation accurately, and finding that Ready for the twin whenever you are. The |
…fusal does not refuse the tests c1cac9a (0.17.44) made parse_doc refuse a relative storage data home. Three existing tests then failed on the Windows leg: /data, /forced/data/home and /abs/home are RELATIVE on Windows (no drive letter), so the refusal was firing on the tests' own fixtures rather than on anything the tests meant to assert. Master has been red on Windows since that commit; the push runs in between were cancelled by my own docs-only pushes (cancel-in-progress), and the first run to complete was d8355fc's. Both iceteaSA twins (#101, #102) inherited the red. Fix is in the tests, not the guard: an abs() helper that yields C:\... on Windows and the POSIX path elsewhere, with the reason at its definition. The guard is correct; the fixtures assumed POSIX absoluteness. subc-core 0.17.45 (the wire check counts every non-comment line, test or not). #101 and #102 will need one more bump each on rebase; that cost is mine.
|
The Windows red on your twin was mine, not yours — read from the job log rather than assumed: the three failing tests ( Fixed at |
CONSUMER-IMPACT: ids longer than 255 UTF-8 bytes are now refused at config/HELLO instead of failing later at store-path derivation.
83243fb to
1701768
Compare
|
Rebased onto Gates: workspace tests zero failures · clippy No cost owed on your side — reading the job log rather than assuming the red was mine is the same move I'd want from a reviewer, and #102 is rebased to 0.17.47 alongside, |
|
Landing this myself rather than asking for a fourth rebase. While you were rebasing I took 0.17.46 for a forwarding-test drain-budget fix ( Merged locally onto master as a stack: #101 → 0.17.47 ( |
|
Published: |
Option 2 from #97, split out on its own because placement is blocked behind the
forbid(unsafe_code)question I raised on the issue — and because this stands alone: it fixes a latent store-path failure whether or not placement ever ships.What
module_id_path_hazard(registry.rs) and its TypeScript twinassertPathSafeModuleId(clients/store/src/derivation.ts) both gain one clause: refuse an id longer than 255 UTF-8 bytes, reasonis longer than 255 bytes, identical string on both sides.Framed as a path-component limit, per your ruling, not a cgroup limit. The comments say why it is not a new restriction:
module_idis already one literal component in the store-path derivation, so a 256-byte id fails to get a store directory today on any platform withNAME_MAX255. This states the clause that was always implicit.Bytes, not characters — and the test that can tell
NAME_MAXcounts bytes. Ruststr::len()is bytes; JavaScriptString.lengthis UTF-16 code units. A naivemoduleId.length <= 255in TS accepts an id thatmkdirrejects, and an ASCII-only test suite cannot see the difference — both implementations agree on every ASCII vector while disagreeing on real input.So the fixture carries a straddle case: 64 emoji = 128 UTF-16 code units, 256 UTF-8 bytes. It must be refused. That single vector is what separates a correct implementation from a plausible one.
Fixture
Your comment named
crates/subc-core/tests/fixtures/store_paths_golden.json; that file does not exist. What exists isclients/store/tests/golden/storage_vectors.json— TS-side, positive vectors only, no refusal cases anywhere — and the Rust-authoreddata_home_resolution.jsonthat the TS suite already reads by relative require. The refusal predicate had nothing binding the two languages.Rather than invent a scheme, this follows that existing precedent: a new Rust-authored
crates/subc-core/tests/golden/module_id_path_component_refusals.json, read by Rust viainclude_str!and by TS via the same relative require. One file, two readers — so the two implementations cannot drift apart silently. Vectors: ASCII 255 accepted, ASCII 256 refused, and the emoji straddle.Verification
Mutation-proved in both languages, each reddening by name:
I ran the discriminating one independently rather than take it on report — swapping the TS bound from
TextEncoder().encode(id).lengthtomoduleId.lengthfails exactly one test, the emoji vector, and leaves the other ten green. That is the check doing its job: the ASCII vectors cannot distinguish the two implementations, and the straddle case can.Gates:
cargo test --workspace --locked,cargo clippy --workspace --all-targets --locked -D warnings,cargo fmt --all --check,clients/storebun test11 pass / 66 assertions, wire-version check 6 crates examined none unbumped.subc-core0.17.44,@cortexkit/store0.1.2,Cargo.lockcommitted.CONSUMER-IMPACT:ids longer than 255 UTF-8 bytes are now refused at config parse and HELLO instead of failing later at store-path derivation. No id that ever worked is affected.Still open on #97
The placement half needs your call on the
forbid(unsafe_code)question —tokio::process::Command::pre_execisunsafe,forbidcannot be locally allowed, and the four options with my lean are on the issue. Post-spawn placement is the one I'd argue against: it leaves exactly the window that #97 exists to close.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Rejects
module_idvalues longer than 255 UTF-8 bytes during config parsing and HELLO instead of letting store-path derivation fail later. Existing working IDs, including 255-byte IDs, remain valid.subc-coreto 0.17.46 and@cortexkit/storeto 0.1.2.Written for commit 1701768. Summary will update on new commits.