Subtask of #169 (worth doing later, ranked 6).
otel.rs's wire module hand-rolls protobuf varints and length prefixes. A
wrong length prefix does not throw — the collector silently drops the record,
and the audit-adjacent export goes dark with nothing in the stream to say so.
That failure mode is the argument: everything else in the audit path fails loudly
or not at all, and this one can fail quietly at the far end of a network hop.
Suggested direction
prost and proptest as dev-dependencies; round-trip-decode what wire emits
and assert it matches what was encoded. An afternoon, no CI infrastructure — the
tests run in the existing suite.
Assessed and rejected: full fuzzing
Not worth it here. The byte-level parse surfaces are operator-supplied (config)
or Bugzilla-supplied (responses), and the one attacker-facing parser is small and
heavily tested. The gap is in what we emit, not what we accept.
Corrected direction (2026-09-02)
proptest is not being added. The encoder's input space is narrow and varint
widths are enumerable, so a targeted table is exhaustive where it matters and
deterministic; proptest would pull in rand, rusty-fork, wait-timeout and
unarray for less. prost alone, as a dev-dependency — no protoc, no
.proto, no build.rs, because the messages are hand-transcribed derives,
which is also what makes them an independent oracle rather than generated code
sharing the encoder's assumptions.
The gap is not where this issue says. The existing hand-written extractor
already decodes the emitted bytes, and it catches all three failure modes named
above (bad length prefix, dropped continuation byte, swapped field number). What
it misses:
- Wire types.
fields() normalizes a decoded varint to to_le_bytes(),
byte-identical to a fixed64 payload — so a fixed64 field emitted as a
varint passes. A real collector rejects it.
- Anything unexpected.
only() takes the first match by field number and
nothing asserts the buffer holds no more, so a duplicated field, an undeclared
field, or a non-canonical varint encoding are all invisible.
Mutation matrix, reproduced independently: length prefix, continuation byte and
field-number mutations are caught by both old and new; fixed64→varint,
duplicated field, undeclared field and non-canonical varint are caught only by
the new tests.
Subtask of #169 (worth doing later, ranked 6).
otel.rs'swiremodule hand-rolls protobuf varints and length prefixes. Awrong length prefix does not throw — the collector silently drops the record,
and the audit-adjacent export goes dark with nothing in the stream to say so.
That failure mode is the argument: everything else in the audit path fails loudly
or not at all, and this one can fail quietly at the far end of a network hop.
Suggested direction
prostandproptestas dev-dependencies; round-trip-decode whatwireemitsand assert it matches what was encoded. An afternoon, no CI infrastructure — the
tests run in the existing suite.
Assessed and rejected: full fuzzing
Not worth it here. The byte-level parse surfaces are operator-supplied (config)
or Bugzilla-supplied (responses), and the one attacker-facing parser is small and
heavily tested. The gap is in what we emit, not what we accept.
Corrected direction (2026-09-02)
proptest is not being added. The encoder's input space is narrow and varint
widths are enumerable, so a targeted table is exhaustive where it matters and
deterministic; proptest would pull in
rand,rusty-fork,wait-timeoutandunarrayfor less.prostalone, as a dev-dependency — noprotoc, no.proto, nobuild.rs, because the messages are hand-transcribed derives,which is also what makes them an independent oracle rather than generated code
sharing the encoder's assumptions.
The gap is not where this issue says. The existing hand-written extractor
already decodes the emitted bytes, and it catches all three failure modes named
above (bad length prefix, dropped continuation byte, swapped field number). What
it misses:
fields()normalizes a decoded varint toto_le_bytes(),byte-identical to a
fixed64payload — so afixed64field emitted as avarint passes. A real collector rejects it.
only()takes the first match by field number andnothing asserts the buffer holds no more, so a duplicated field, an undeclared
field, or a non-canonical varint encoding are all invisible.
Mutation matrix, reproduced independently: length prefix, continuation byte and
field-number mutations are caught by both old and new; fixed64→varint,
duplicated field, undeclared field and non-canonical varint are caught only by
the new tests.