3"""Adversarial fixtures for immutable suppression-debt ceilings."""
5from __future__
import annotations
7from pathlib
import Path
9from selftest_assert
import expect
10from suppression_baseline_scan
import ceiling_snapshot, scan_baseline_repository
11from suppression_model
import Suppression
13TIDY =
".github/tidy-baseline.txt"
14COMPOUND =
".github/mcdc-compound-baseline.txt"
15TREE =
".github/tree-coverage-baseline.txt"
16FREESTANDING =
".github/freestanding-runtime-baseline.json"
18 "# clang-tidy ratchet baseline -- per-file-per-check finding counts.\n"
19 "# Consumed by scripts/checks/tidy_ratchet.py --check (CI gate: tidy).\n"
22 "# MC/DC compound-decision ratchet baseline -- per-file-per-function counts.\n"
23 "# Consumed by scripts/checks/mcdc_compound_ratchet.py --check\n"
24 "# Total at this baseline: 1 uncovered compound decision\n"
27 "# ONE coverage baseline for every first-party translation unit.\n"
28 "# Emitted by `python3 scripts/checks/check_tree_coverage.py --update`.\n"
32def _write_probe(root: Path, rel: str, text: str =
"") ->
None:
33 """Write one ASCII baseline-integrity probe file."""
35 target.parent.mkdir(parents=
True, exist_ok=
True)
36 target.write_text(text, encoding=
"ascii")
40 root: Path, paths: list[str], ledger: dict[str, tuple[str, str]] |
None =
None
41) -> tuple[list[Suppression], set[str]]:
42 """Run the production baseline scanner and return rows plus finding codes."""
43 rows, findings = scan_baseline_repository(
47 ceiling_ledger=ledger,
49 return rows, {item.code
for item
in findings}
52def _assert_key_swaps(root: Path, failures: list[str]) ->
None:
53 """Assert debt cannot move within or between baseline authorities."""
54 original_tidy = TIDY_HEADER +
"libs/a.c\tmisc-a\t1\nlibs/b.c\tmisc-b\t4\n"
55 original_compound = COMPOUND_HEADER +
"libs/c.c\tfn_c\t1\n"
56 _write_probe(root, TIDY, original_tidy)
57 _write_probe(root, COMPOUND, original_compound)
58 rows, original_codes = _scan_probe(root, [TIDY, COMPOUND])
59 ledger = ceiling_snapshot(rows)
60 _rows, frozen_codes = _scan_probe(root, [TIDY, COMPOUND], ledger)
62 not original_codes
and not frozen_codes,
63 "quiet: unchanged canonical per-key ceilings validate",
66 changed = TIDY_HEADER +
"libs/a.c\tmisc-new\t2\nlibs/b.c\tmisc-b\t3\n"
67 _write_probe(root, TIDY, changed)
68 _rows, within_codes = _scan_probe(root, [TIDY, COMPOUND], ledger)
70 "baseline-growth" in within_codes,
71 "must fire: same-total within-baseline bucket swaps cannot absorb debt",
74 changed = TIDY_HEADER +
"libs/c.c\tfn_c\t1\nlibs/b.c\tmisc-b\t4\n"
75 _write_probe(root, TIDY, changed)
76 _write_probe(root, COMPOUND, COMPOUND_HEADER +
"libs/a.c\tmisc-a\t1\n")
77 _rows, swap_codes = _scan_probe(root, [TIDY, COMPOUND], ledger)
79 "baseline-growth" in swap_codes,
80 "must fire: equal-count cross-baseline bucket swaps cannot absorb debt",
85def _assert_path_aliases(root: Path, failures: list[str]) ->
None:
86 """Assert noncanonical spellings cannot mint alternate debt keys."""
87 for alias
in (
"./libs/a.c",
"libs\\a.c",
"."):
88 _write_probe(root, TIDY, TIDY_HEADER + f
"{alias}\tmisc-a\t1\n")
89 _rows, alias_codes = _scan_probe(root, [TIDY])
91 "malformed-baseline-row" in alias_codes,
92 f
"must fire: noncanonical path alias {alias!r} is rejected",
97def _assert_tree_controls(root: Path, failures: list[str]) ->
None:
98 """Assert tree-coverage dimensions and path identity stay independent."""
102 TREE_HEADER +
"# rows: 1\nlibs/a.c\tMEASURED\t90\t100\t70\t80\n",
104 tree_rows, tree_original_codes = _scan_probe(root, [TREE])
105 tree_ledger = ceiling_snapshot(tree_rows)
109 TREE_HEADER +
"# rows: 1\nlibs/a.c\tMEASURED\t89\t100\t71\t80\n",
111 _rows, tree_swap_codes = _scan_probe(root, [TREE], tree_ledger)
113 not tree_original_codes
and "baseline-growth" in tree_swap_codes,
114 "must fire: tree line debt cannot trade against branch burn-down",
122 +
"libs/a.c\tMEASURED\t1\t2\t1\t1\n"
123 +
"libs/a.c\tUNMEASURED\tplatform-cross-only\n",
125 _rows, duplicate_codes = _scan_probe(root, [TREE])
127 "duplicate-baseline-row" in duplicate_codes,
128 "must fire: tree coverage MEASURED/UNMEASURED share one path identity",
133def _assert_authority_controls(root: Path, failures: list[str]) ->
None:
134 """Assert missing provenance and invented authorities fail closed."""
135 _write_probe(root, TIDY,
"# header removed\nlibs/a.c\tmisc-a\t1\n")
136 _write_probe(root,
".github/future-ratchet.txt",
"libs/a.c\tmisc-a\t1\n")
137 _rows, authority_codes = _scan_probe(root, [TIDY,
".github/future-ratchet.txt"])
139 {
"missing-baseline-provenance",
"unknown-baseline-file"} <= authority_codes,
140 "must fire: provenance removal and noncanonical ratchet authorities fail closed",
145def assert_baseline_ceiling_controls(base: Path, failures: list[str]) ->
None:
146 """Assert canonical per-key ceilings reject swaps, aliases, and authority drift."""
147 root = base /
"baseline-ceiling-probe"
149 "scripts/checks/tidy_ratchet.py",
150 "scripts/checks/mcdc_compound_ratchet.py",
151 "scripts/checks/check_tree_coverage.py",
156 _write_probe(root, rel)
157 _assert_key_swaps(root, failures)
158 _assert_path_aliases(root, failures)
159 _assert_tree_controls(root, failures)
160 _assert_authority_controls(root, failures)
161 _assert_freestanding_controls(root, failures)
164def _assert_freestanding_controls(root: Path, failures: list[str]) ->
None:
165 """Assert the freestanding runtime baseline ratchets shrink-only."""
166 _write_probe(root,
"scripts/checks/check_freestanding_runtime.py")
168 '{"apps": {"probe_app": {"forbidden_symbols": [], "forbidden_archives": {},'
169 ' "sbrk_provider": "none", "end_symbol": false}}, "linker_script_exceptions": []}'
171 _write_probe(root, FREESTANDING, clean)
172 rows, quiet_codes = _scan_probe(root, [FREESTANDING])
173 ledger = ceiling_snapshot(rows)
174 _rows, frozen_codes = _scan_probe(root, [FREESTANDING], ledger)
176 not quiet_codes
and not frozen_codes,
177 "quiet: registered freestanding baseline validates",
180 grown = clean.replace(
'"forbidden_symbols": []',
'"forbidden_symbols": ["malloc"]')
181 _write_probe(root, FREESTANDING, grown)
182 _rows, grown_codes = _scan_probe(root, [FREESTANDING], ledger)
184 "baseline-growth" in grown_codes,
185 "must fire: freestanding debt growth cannot exceed its ceiling",
188 _write_probe(root, FREESTANDING,
'{"apps": {}}')
189 _rows, malformed_codes = _scan_probe(root, [FREESTANDING])
191 "malformed-baseline-row" in malformed_codes,
192 "must fire: malformed freestanding baseline is rejected",
195 _write_probe(root,
".github/unregistered-baseline.json", clean)
196 _rows, unknown_codes = _scan_probe(root, [
".github/unregistered-baseline.json"])
198 "unknown-baseline-file" in unknown_codes,
199 "must fire: unregistered baseline files stay fail-closed",