blaze-host: document capture, sanitization, and what the tests do not cover
This commit is contained in:
@@ -227,3 +227,67 @@ The script says so explicitly, in one of two forms:
|
||||
no remote peer connected — only loopback (or nothing) reached Rust
|
||||
=> a FIFA session did NOT land here
|
||||
```
|
||||
|
||||
## Raw frame capture (opt-in)
|
||||
|
||||
Evidence infrastructure, off unless `OPENFUT_BLAZE_CAPTURE` names a file.
|
||||
|
||||
```bash
|
||||
OPENFUT_BLAZE_CAPTURE=/home/alex/OpenFUT/captures/gate7.ofcap ./sidecar.sh start
|
||||
```
|
||||
|
||||
Two layers, deliberately:
|
||||
|
||||
```
|
||||
live FIFA traffic
|
||||
├── raw capture exact RX/TX bytes, mode 0600, gitignored — NEVER commit
|
||||
└── blaze-sanitize → repository-safe, replayable fixtures
|
||||
```
|
||||
|
||||
The raw file is forensic evidence and does contain session material; that is
|
||||
what makes it worth keeping and why it never leaves the machine unsanitized.
|
||||
|
||||
**Format.** Deterministic, big-endian: a 20-byte file header, then per-frame
|
||||
records with connection id, a global monotonic sequence, timestamp, direction
|
||||
and the exact frame bytes. RX is recorded as received; TX only *after* a
|
||||
successful write, so a record means the bytes were sent, not intended.
|
||||
|
||||
Component, command, msgNum, msgType and payload length are **not** stored beside
|
||||
the frame — they are already in its 16-byte header, and a redundant copy can
|
||||
disagree with the bytes, leaving a reader unable to tell which is true.
|
||||
`Record::header()` derives them.
|
||||
|
||||
### Sanitizing
|
||||
|
||||
```bash
|
||||
./target/debug/blaze-sanitize captures/gate7.ofcap -o gate7.jsonl --report gate7.txt
|
||||
```
|
||||
|
||||
Redacts only the named tags (`KEY`, `AUTH`, `SESS`, `MAIL`, `PML`) and reports
|
||||
every substitution with path, kind and byte length. Replacement is
|
||||
**length-preserving**, so the TDF varint, payload length and Fire2 header are
|
||||
unchanged and the sanitized frame is exactly the size of the captured one —
|
||||
asserted per frame, failing rather than emitting a subtly different
|
||||
conversation. Frames with nothing sensitive keep their exact wire bytes.
|
||||
Payloads that will not decode are passed through *and reported*, so a reader
|
||||
knows they were never inspected rather than assuming they were checked clean.
|
||||
|
||||
Real run: 101 frames in, 9 redacted, 13 redactions; two live session keys
|
||||
present in the raw capture, zero in the sanitized output.
|
||||
|
||||
### What the tests do and do not cover
|
||||
|
||||
Nine cases, all passing: capture off produces no artefact; RX and TX captured
|
||||
exactly; ordering preserved; fragmented input (one byte at a time) reconstructs
|
||||
the same frames as a single write; coalesced input is captured per frame rather
|
||||
than per read; capture does not alter wire output; sanitization removes a real
|
||||
session key from a real captured login; malformed/truncated/wrong-version
|
||||
captures fail clearly; every listed sensitive tag is provably reachable.
|
||||
|
||||
Mutation-tested: dropping TX capture, truncating captured frames to their
|
||||
header, and removing `KEY` from the sensitive list each turn the suite red.
|
||||
|
||||
**One mutation is not caught:** moving the TX capture above the write. It is
|
||||
indistinguishable while writes succeed and diverges only when one fails, where
|
||||
it would record a frame the client never received. That invariant is held by
|
||||
code placement and a comment, not by a test.
|
||||
|
||||
Reference in New Issue
Block a user