From fafa2f1858b2922b04a3a31e772b613190e35e44 Mon Sep 17 00:00:00 2001 From: funman300 Date: Tue, 11 Aug 2026 02:16:11 +0000 Subject: [PATCH] blaze-host: document capture, sanitization, and what the tests do not cover --- openfut-blaze-host/README.md | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/openfut-blaze-host/README.md b/openfut-blaze-host/README.md index 5556613..a5c5214 100644 --- a/openfut-blaze-host/README.md +++ b/openfut-blaze-host/README.md @@ -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.