mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
test(buzz-media): make the truncation sweep prove it reached the code
The sweep could report "no panic at any prefix" without ever executing the code under test, and did exactly that once already. Add a black-box reachability witness: mutate channels/block_align/bits in a known-good WAV and assert the verdict flips. It needs no source instrumentation and can only pass if those fields are read. Self-tested both directions. Against the unfixed validator the witness passes and the battery fails on the riff-repaired arm alone. With the fmt field checks made inert as a negative control the witness fails with "mutating channels did not change the verdict". A green sweep is evidence only when the witness passes first. Co-authored-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz> Signed-off-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -127,3 +127,20 @@ That is the pattern WAV is missing: it checks a prefix, then indexes the
|
||||
ORIGINAL buffer past it. Fix shape is one whole-body slice —
|
||||
`bytes.get(offset + 8..offset + 24).ok_or(MetadataForbidden)?` — then slice
|
||||
the six fields from it. Removes the class, not the instance.
|
||||
|
||||
### Reachability witness (added after the sweep itself proved untrustworthy)
|
||||
|
||||
The sweep now ships with `fmt_field_checks_are_live`, a black-box witness that
|
||||
needs no source instrumentation: mutate `channels` / `block_align` / `bits` in a
|
||||
known-good WAV and assert the verdict flips Ok -> Err. It can only pass if those
|
||||
bytes are actually read.
|
||||
|
||||
Self-tested both directions, which is the only reason to trust it:
|
||||
- Against the unfixed validator: witness PASSES, battery FAILS on the
|
||||
`riff-repaired` arm at prefix 22 (and only that arm).
|
||||
- With the fmt field checks made inert as a negative control: witness FAILS with
|
||||
"mutating channels did not change the verdict -> field is not read".
|
||||
|
||||
**If the witness fails, every "no panic" line below it is vacuous and must not be
|
||||
reported as a pass.** That ordering is the whole point — this harness has twice
|
||||
produced confident green output while touching nothing.
|
||||
|
||||
+67
-26
@@ -1,10 +1,18 @@
|
||||
//! Truncation battery + black-box reachability witness for the audio validators.
|
||||
//!
|
||||
//! Instrument discipline: a green sweep is worthless unless the sweep provably
|
||||
//! executed the code it claims to cover. `fmt_field_checks_are_live` is that
|
||||
//! witness — it needs no source instrumentation, only the observation that
|
||||
//! mutating a `fmt ` field must flip the verdict. If it fails, every "no panic"
|
||||
//! result below is vacuous and must not be reported as a pass.
|
||||
|
||||
fn cfg() -> buzz_media::config::MediaConfig {
|
||||
buzz_media::config::MediaConfig {
|
||||
s3_endpoint: String::new(), s3_access_key: String::new(),
|
||||
s3_secret_key: String::new(), s3_bucket: String::new(),
|
||||
s3_region: "us-east-1".into(),
|
||||
s3_addressing_style: buzz_media::config::S3AddressingStyle::Path,
|
||||
max_image_bytes: 50*1024*1024, max_gif_bytes: 10*1024*1024,
|
||||
max_image_bytes: 50 * 1024 * 1024, max_gif_bytes: 10 * 1024 * 1024,
|
||||
max_video_bytes: 524_288_000, max_file_bytes: 104_857_600,
|
||||
max_audio_bytes: 26_214_400,
|
||||
public_base_url: "http://localhost:3000/media".into(),
|
||||
@@ -12,41 +20,74 @@ fn cfg() -> buzz_media::config::MediaConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn sweep(name: &str, full: &[u8], repair_riff: bool) -> Option<usize> {
|
||||
fn v(bytes: &[u8]) -> Result<(String, String), buzz_media::error::MediaError> {
|
||||
buzz_media::validation::validate_file_content(bytes, &cfg())
|
||||
}
|
||||
|
||||
fn dir() -> std::path::PathBuf {
|
||||
std::path::PathBuf::from(std::env::var("DAWN_SAN").expect("DAWN_SAN"))
|
||||
}
|
||||
|
||||
/// Rewrite the RIFF declared size to match actual length. Without this a
|
||||
/// truncated WAV dies at `declared + 8 == len` and never reaches the fmt walk.
|
||||
fn repair_riff(b: &mut [u8]) {
|
||||
if b.len() >= 8 {
|
||||
let d = (b.len() - 8) as u32;
|
||||
b[4..8].copy_from_slice(&d.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
/// REACHABILITY WITNESS. Proves the fmt field reads execute, black-box.
|
||||
#[test]
|
||||
fn fmt_field_checks_are_live() {
|
||||
let good = std::fs::read(dir().join("tagged.wav")).unwrap();
|
||||
assert!(v(&good).is_ok(), "baseline WAV must validate; got {:?}", v(&good));
|
||||
|
||||
// fmt body starts at 20: channels@22, sample_rate@24, byte_rate@28,
|
||||
// block_align@32, bits@34. Corrupting any must flip Ok -> Err, which is
|
||||
// only possible if those bytes were actually read.
|
||||
for (name, off, val) in [
|
||||
("channels", 22usize, 0u16),
|
||||
("block_align", 32, 0xffff),
|
||||
("bits", 34, 7),
|
||||
] {
|
||||
let mut bad = good.clone();
|
||||
bad[off..off + 2].copy_from_slice(&val.to_le_bytes());
|
||||
assert!(v(&bad).is_err(), "mutating {name} did not change the verdict -> field is not read");
|
||||
}
|
||||
eprintln!("reachability witness OK: fmt field reads are live");
|
||||
}
|
||||
|
||||
fn sweep(name: &str, full: &[u8], repair: bool) -> Option<usize> {
|
||||
let lens: Vec<usize> = (0..full.len().min(600))
|
||||
.chain((600..full.len()).step_by(97))
|
||||
.collect();
|
||||
let mut first = None;
|
||||
let lens: Vec<usize> = (0..full.len().min(600)).chain((600..full.len()).step_by(97)).collect();
|
||||
for n in lens {
|
||||
let mut slice = full[..n].to_vec();
|
||||
// Keep the RIFF declared size consistent with the truncated length, or
|
||||
// the `declared + 8 == len` gate rejects everything before the fmt walk
|
||||
// and the sweep never reaches the code under test.
|
||||
if repair_riff && slice.len() >= 8 {
|
||||
let d = (slice.len() - 8) as u32;
|
||||
slice[4..8].copy_from_slice(&d.to_le_bytes());
|
||||
}
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
let _ = buzz_media::validation::validate_file_content(&slice, &cfg());
|
||||
});
|
||||
if r.is_err() && first.is_none() { first = Some(n); }
|
||||
if repair { repair_riff(&mut slice); }
|
||||
let hit = std::panic::catch_unwind(|| { let _ = v(&slice); }).is_err();
|
||||
if hit && first.is_none() { first = Some(n); }
|
||||
}
|
||||
match first {
|
||||
None => println!("{name:24} OK (no panic at any prefix)"),
|
||||
Some(n) => println!("{name:24} *** first panic at prefix {n} ***"),
|
||||
None => eprintln!("{name:26} OK (no panic at any prefix)"),
|
||||
Some(n) => eprintln!("{name:26} *** first panic at prefix {n} ***"),
|
||||
}
|
||||
first
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dawn_truncation_sweep_all_containers() {
|
||||
let dir = std::path::PathBuf::from(std::env::var("DAWN_SAN").unwrap());
|
||||
fn truncation_battery_no_panics() {
|
||||
let d = dir();
|
||||
let mut bad = Vec::new();
|
||||
for name in ["tagged.mp3","mpeg2_22k.mp3","mpeg25_11k.mp3","tagged.ogg","bigart.ogg","long.ogg"] {
|
||||
let full = std::fs::read(dir.join(name)).unwrap();
|
||||
if sweep(name, &full, false).is_some() { bad.push(name); }
|
||||
for name in ["tagged.mp3", "mpeg2_22k.mp3", "mpeg25_11k.mp3", "tagged.ogg", "bigart.ogg", "long.ogg"] {
|
||||
let full = std::fs::read(d.join(name)).unwrap();
|
||||
if sweep(name, &full, false).is_some() { bad.push(name.to_string()); }
|
||||
}
|
||||
// WAV twice: naive (declared size left stale) and repaired (reaches fmt walk).
|
||||
let wav = std::fs::read(dir.join("tagged.wav")).unwrap();
|
||||
if sweep("tagged.wav (naive)", &wav, false).is_some() { bad.push("wav-naive"); }
|
||||
if sweep("tagged.wav (riff-repaired)", &wav, true).is_some() { bad.push("wav-repaired"); }
|
||||
assert!(bad.is_empty(), "validator panicked: {bad:?}");
|
||||
// WAV both ways. The naive arm is kept ONLY to keep the contrast visible;
|
||||
// it is not evidence. The repaired arm is the one that reaches the fields.
|
||||
let wav = std::fs::read(d.join("tagged.wav")).unwrap();
|
||||
if sweep("tagged.wav (naive)", &wav, false).is_some() { bad.push("wav-naive".into()); }
|
||||
if sweep("tagged.wav (riff-repaired)", &wav, true).is_some() { bad.push("wav-repaired".into()); }
|
||||
assert!(bad.is_empty(), "validator panicked on truncated input: {bad:?}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user