Skip to main content

max / audiofiles

3.7 KB · 92 lines History Blame Raw
1 //! CHRONIC #2 enforcement seal (ultra-fuzz run-6 --deep).
2 //!
3 //! The tombstone filter (`deleted_at IS NULL`) was opt-in per query and drifted
4 //! across runs: a new read of the raw `samples` table that forgot the filter
5 //! leaked deleted samples into tag/collection/mirror views. The `live_samples`
6 //! view centralizes the filter, but a view alone does not *prevent* a new raw
7 //! `FROM samples` listing from drifting back in.
8 //!
9 //! This test makes that drift a build failure: every production read of the raw
10 //! `samples` table must either go through `live_samples` (auto-filtered) or carry
11 //! an explicit `tombstone-ok: <reason>` justification within 3 lines. A new
12 //! unfiltered `FROM samples` listing read fails here until the author routes it
13 //! through the view or marks it, a visible, reviewed decision, not a silent
14 //! regression.
15 //!
16 //! Exemptions, by construction:
17 //! - `DELETE FROM samples` (a write, not a read).
18 //! - The `CREATE VIEW live_samples` definition itself.
19 //! - `#[cfg(test)]` modules (they legitimately assert raw table state). This
20 //! assumes the repo convention of test modules at file end.
21
22 use std::fs;
23 use std::path::{Path, PathBuf};
24
25 /// True if `line` reads from the raw `samples` table (word-bounded), i.e. not
26 /// `live_samples` and not `samples_*` (e.g. `samples_fts`, `sample_features`).
27 fn reads_raw_samples(line: &str) -> bool {
28 const NEEDLE: &str = "FROM samples";
29 let mut idx = 0;
30 while let Some(pos) = line[idx..].find(NEEDLE) {
31 let after = idx + pos + NEEDLE.len();
32 let boundary = line.as_bytes().get(after);
33 let is_word = boundary.is_some_and(|&c| c.is_ascii_alphanumeric() || c == b'_');
34 if !is_word {
35 return true; // exact table `samples`, not `samples_...`
36 }
37 idx = after;
38 }
39 false
40 }
41
42 #[test]
43 fn tombstone_filter_seal() {
44 let src = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
45 let mut stack = vec![src];
46 let mut violations: Vec<String> = Vec::new();
47
48 while let Some(dir) = stack.pop() {
49 for entry in fs::read_dir(&dir).unwrap() {
50 let path: PathBuf = entry.unwrap().path();
51 if path.is_dir() {
52 stack.push(path);
53 continue;
54 }
55 if path.extension().and_then(|e| e.to_str()) != Some("rs") {
56 continue;
57 }
58 let text = fs::read_to_string(&path).unwrap();
59 let lines: Vec<&str> = text.lines().collect();
60 // Test modules (conventionally at file end) legitimately read raw rows.
61 let end = lines
62 .iter()
63 .position(|l| l.contains("#[cfg(test)]"))
64 .unwrap_or(lines.len());
65
66 for (i, line) in lines[..end].iter().enumerate() {
67 if !reads_raw_samples(line) || line.contains("DELETE FROM samples") {
68 continue;
69 }
70 let lo = i.saturating_sub(3);
71 let window = lines[lo..=i].join("\n");
72 if window.contains("tombstone-ok") || window.contains("CREATE VIEW") {
73 continue;
74 }
75 let rel = path
76 .strip_prefix(env!("CARGO_MANIFEST_DIR"))
77 .unwrap_or(&path);
78 violations.push(format!("{}:{} {}", rel.display(), i + 1, line.trim()));
79 }
80 }
81 }
82
83 assert!(
84 violations.is_empty(),
85 "CHRONIC #2 seal: raw `FROM samples` read(s) without `live_samples` or a \
86 `tombstone-ok` justification:\n {}\n\nRoute visible-sample reads through \
87 `FROM live_samples`, or add a `tombstone-ok: <reason>` comment within 3 \
88 lines if the raw access is intentional (point-lookup, tombstone sweep).",
89 violations.join("\n ")
90 );
91 }
92