3"""Both-direction fixtures for the suppression inventory scanner."""
5from __future__
import annotations
8from pathlib
import Path
10from selftest_assert
import expect, report
11from suppression_build_controls
import compiler_records
12from suppression_catalog
import REQUIRED_FAMILIES
13from suppression_compiler_selftest
import (
14 assert_clang_tidy_config_fail_closed,
15 assert_compiler_controls,
16 assert_compiler_tool_probes,
18from suppression_debt_selftest
import assert_baseline_ceiling_controls
19from suppression_governance_selftest
import assert_governance_parsers
20from suppression_identity_selftest
import assert_identity_semantics
21from suppression_ledger_selftest
import assert_ledger_gate
22from suppression_mcdc_selftest
import assert_mcdc_macro_binding
23from suppression_model
import Inventory, Suppression
24from suppression_scan
import decode_git_paths, scan_paths
25from suppression_selftest_fixtures
import FIXTURES
26from suppression_selftest_integrity
import assert_identity_and_structure
27from suppression_stranded_selftest
import (
28 assert_stranded_branch_markers,
29 assert_stranded_line_markers,
31from suppression_tool_selftest
import assert_tool_control_syntax_awareness
33EXPECTED_CLANG_ROWS = 14
34EXPECTED_BROAD_NOLINT_ROWS = 3
35EXPECTED_OPTIONAL_INACTIVE = 2
36EXPECTED_CENTRAL_ROWS = 4
37EXPECTED_BUILD_ROWS = 37
38EXPECTED_PROJECT_ROWS = 3
39EXPECTED_PYTHON_REGION_ROWS = 2
40EXPECTED_RUFF_CONFIG_ROWS = 3
41EXPECTED_SHELLCHECK_ROWS = 11
42EXPECTED_SHELLCHECK_GLOBAL_ROWS = 4
43EXPECTED_ACTIVE_SHELL_STATUS_ROWS = 4
44EXPECTED_EMBEDDED_SHELL_STATUS_ROWS = 2
45EXPECTED_JUST_SHELL_STATUS_ROWS = 2
46EXPECTED_YAML_SHELL_STATUS_ROWS = 5
47EXPECTED_ANSIBLE_CONTROL_ROWS = 4
48EXPECTED_CTEST_CONTROL_ROWS = 3
49EXPECTED_PYTHON_CONTROL_ROWS = 13
50EXPECTED_WORKFLOW_CONTROL_ROWS = 3
51EXPECTED_MALFORMED_NATIVE_SKIP_ROWS = 2
52EXPECTED_BASELINE_ROWS = 4
54EXPECTED_NATIVE_SKIP_ROWS = 3
55EXPECTED_COVERAGE_MASK_ROWS = 3
56EXPECTED_YAML_BUILD_ROWS = 8
57EXPECTED_CMAKE_WNO_DEV_ROWS = 8
58EXPECTED_COMPILER_WNO_DEV_ROWS = 3
59SHELL_ARGUMENT_TOOL_LINE = 6
60EXPECTED_DEAD_ANCHOR_FINDINGS = 2
63def _write_fixture(root: Path) -> list[str]:
64 """Write the deterministic ASCII fixture and return its relative paths."""
65 for rel, text
in FIXTURES.items():
67 target.parent.mkdir(parents=
True, exist_ok=
True)
68 target.write_text(text, encoding=
"ascii")
69 return sorted(FIXTURES)
72def _assert_families(inventory: Inventory, failures: list[str]) ->
None:
73 """Assert every phase-one recognizer fires through the production scanner."""
74 seen = {item.family
for item
in inventory.suppressions}
76 "ansible-lint-config",
77 "checker-nonfatal-control",
78 "checker-scope-control",
79 "ci-parity-exemption",
80 "documentation-control",
82 "other-language-control",
83 "security-analysis-control",
85 for family
in sorted(REQUIRED_FAMILIES - repository_bound):
86 expect(family
in seen, f
"must fire: {family}", failures)
89def _assert_python_syntax_awareness(inventory: Inventory, failures: list[str]) ->
None:
90 """Assert Python controls fire only in active comments and carry reasons."""
91 python_rows = [item
for item
in inventory.suppressions
if item.path ==
"sample.py"]
92 python_rules = {item.rule
for item
in python_rows}
94 {
"S603",
"S607"} <= python_rules,
95 "must fire: comma-separated noqa rules become separate rows",
98 tools = {item.tool
for item
in python_rows}
100 {
"bandit",
"coverage.py",
"mypy",
"pylint",
"pyright",
"ruff-format"} <= tools,
101 "must fire: every Python analyzer, formatter, and coverage control",
105 not any(
"blank-reason" in item.concerns
for item
in python_rows),
106 "quiet: every supported Python fixture carries a local reason",
109 bare_rows = [item
for item
in inventory.suppressions
if item.path ==
"bare_python_controls.py"]
111 all(
"blank-reason" in item.concerns
for item
in bare_rows),
112 "must fire: bare Python controls retain blank-reason concerns",
116 len([item
for item
in python_rows
if item.tool ==
"coverage.py"]) == 1
117 and len([item
for item
in python_rows
if item.tool ==
"pylint"])
118 == EXPECTED_PYTHON_REGION_ROWS
119 and len([item
for item
in python_rows
if item.tool ==
"ruff-format"])
120 == EXPECTED_PYTHON_REGION_ROWS,
121 "quiet: directive-looking Python strings do not add inventory rows",
126def _assert_control_syntax_awareness(inventory: Inventory, failures: list[str]) ->
None:
127 """Assert test and infrastructure controls use active language syntax."""
128 python_rows = [item
for item
in inventory.suppressions
if item.path ==
"controls.py"]
130 len(python_rows) == EXPECTED_PYTHON_CONTROL_ROWS,
131 "must fire: Python skip and strict-xfail calls/decorators",
135 len([item
for item
in python_rows
if "non-strict-xfail" in item.concerns]) == 1,
136 "must fire: permissive marker xfail is distinct from strict/runtime xfail",
139 ctest_rows = [item
for item
in inventory.suppressions
if item.family ==
"ctest"]
141 len(ctest_rows) == EXPECTED_CTEST_CONTROL_ROWS,
142 "must fire: active CTest fail, disabled, and skip properties",
146 not any(
"blank-reason" in item.concerns
for item
in ctest_rows),
147 "quiet: getters, strings, and comments are not CTest controls",
150 workflow_rows = [item
for item
in inventory.suppressions
if item.family ==
"workflow"]
152 len(workflow_rows) == EXPECTED_WORKFLOW_CONTROL_ROWS,
153 "must fire: workflow soft failure and both missing-artifact modes",
156 ansible_rows = [item
for item
in inventory.suppressions
if item.family ==
"ansible"]
158 len(ansible_rows) == EXPECTED_ANSIBLE_CONTROL_ROWS,
159 "must fire: every requested active Ansible result/log control",
163 not any(
"blank-reason" in item.concerns
for item
in workflow_rows + ansible_rows),
164 "quiet: YAML block payloads and explicit false controls stay inactive",
169def _assert_global_shellcheck_controls(
170 inventory: Inventory, shellcheck_rows: list[Suppression], failures: list[str]
172 """Assert local and repository-wide ShellCheck controls are distinct."""
174 len(shellcheck_rows) == EXPECTED_SHELLCHECK_ROWS,
175 "quiet: quoted strings and heredoc payloads are not ShellCheck controls",
178 controls = {item.directive
for item
in shellcheck_rows}
182 "shellcheck external-sources",
185 "shellcheck source-path",
188 "must fire: every supported ShellCheck analysis control",
193 for item
in inventory.suppressions
194 if item.directive
in {
"SHELLCHECK_OPTS exclude",
".shellcheckrc exclude"}
197 len(global_rows) == EXPECTED_SHELLCHECK_GLOBAL_ROWS
198 and not any(item.concerns
for item
in global_rows),
199 "must fire: reasoned global ShellCheck exclusions, but not quoted lookalikes",
204def _assert_shell_syntax_awareness(inventory: Inventory, failures: list[str]) ->
None:
205 """Assert shell controls fire only where their syntax is executable."""
206 shell_rows = [item
for item
in inventory.suppressions
if item.path ==
"sample.sh"]
207 shellcheck_rows = [item
for item
in shell_rows
if item.family ==
"shellcheck"]
208 _assert_global_shellcheck_controls(inventory, shellcheck_rows, failures)
209 status_rows = [item
for item
in shell_rows
if item.family ==
"shell-status"]
210 active_status = [item
for item
in status_rows
if item.scope ==
"command-list"]
211 embedded_status = [item
for item
in status_rows
if item.scope ==
"embedded-shell-or-heredoc"]
213 len(active_status) == EXPECTED_ACTIVE_SHELL_STATUS_ROWS,
214 "must fire: direct and multiline masks while strings stay inactive",
218 len(embedded_status) == EXPECTED_EMBEDDED_SHELL_STATUS_ROWS,
219 "must fire: quoted and heredoc masks remain visible for embedded-shell review",
223 active_status[0].reason ==
"fixture cleanup status is intentionally ignored",
224 "must fire: active status mask carries its same-line rationale",
229 for item
in inventory.suppressions
230 if item.path ==
"just/sample.just" and item.family ==
"shell-status"
233 len(just_status) == EXPECTED_JUST_SHELL_STATUS_ROWS
234 and all(item.scope ==
"command-list" for item
in just_status),
235 "must fire: Just recipe shell masks are inventoried as active syntax",
240def _assert_debt_control_families(inventory: Inventory, failures: list[str]) ->
None:
241 """Assert the four newly-supported debt/control grammars in both directions."""
242 baseline_rows = [item
for item
in inventory.suppressions
if item.family ==
"baseline-ratchet"]
244 len(baseline_rows) == EXPECTED_BASELINE_ROWS,
245 "must fire: exact baseline schemas become source-located rows",
248 codes = {item.code
for item
in inventory.findings}
251 "duplicate-baseline-row",
252 "stale-baseline-path",
253 "malformed-baseline-row",
254 "unknown-baseline-file",
258 "must fire: duplicate, malformed, unknown, growing, and path-missing baseline debt",
261 mcdc_rows = [item
for item
in inventory.suppressions
if item.family ==
"mcdc-deactivation"]
263 len(mcdc_rows) == EXPECTED_MCDC_ROWS
264 and any(item.scope ==
"function" for item
in mcdc_rows),
265 "must fire: exact comment and literal macro MC/DC grammars",
269 any(item.scope.startswith(
"decision-line:")
for item
in mcdc_rows),
270 "must fire: a reasoned MC/DC marker pairs to one compound decision",
275 "malformed-mcdc-deactivation",
276 "duplicate-mcdc-deactivation",
277 "unpaired-mcdc-deactivation",
278 "unknown-mcdc-macro",
279 "malformed-mcdc-macro",
282 "must fire: malformed, duplicate, unpaired, and unknown MC/DC controls",
285 assert_mcdc_macro_binding(inventory, failures)
286 _assert_native_coverage_controls(inventory, failures)
289def _assert_native_coverage_controls(inventory: Inventory, failures: list[str]) ->
None:
290 """Assert native-test skips and gcovr masks fire only on active syntax."""
291 native_rows = [item
for item
in inventory.suppressions
if item.path ==
"native_test.cpp"]
293 len(native_rows) == EXPECTED_NATIVE_SKIP_ROWS
294 and len([item
for item
in native_rows
if "blank-reason" in item.concerns]) == 1,
295 "must fire: GTest and both Unity skip forms while strings stay quiet",
299 item
for item
in inventory.findings
if item.code ==
"malformed-native-test-skip"
302 len(malformed_skips) == EXPECTED_MALFORMED_NATIVE_SKIP_ROWS,
303 "must fire: malformed GTest and Unity skip calls",
306 coverage_rows = [item
for item
in inventory.suppressions
if item.family ==
"coverage-mask"]
308 len(coverage_rows) == EXPECTED_COVERAGE_MASK_ROWS
309 and not any(item.concerns
for item
in coverage_rows),
310 "must fire: active shell and gcovr.cfg masks while inactive values stay quiet",
313 config_rules = {item.rule
for item
in coverage_rows
if item.path ==
"config/gcovr.cfg"}
316 == {
"gcov-ignore-parse-errors=negative_hits.warn",
"exclude-unreachable-branches"},
317 "quiet: false gcovr.cfg booleans do not become active masks",
320 codes = {item.code
for item
in inventory.findings}
322 {
"duplicate-coverage-mask",
"malformed-coverage-mask"} <= codes,
323 "must fire: duplicate and invalid gcovr.cfg controls fail closed",
328 item.code ==
"malformed-coverage-mask" and item.path ==
"invalid/gcovr.cfg"
329 for item
in inventory.findings
332 item.code ==
"duplicate-coverage-mask" and item.path ==
"config/gcovr.cfg"
333 for item
in inventory.findings
335 "must fire: gcovr.cfg invalid and duplicate branches are both exercised",
340def _assert_syntax_awareness(root: Path, inventory: Inventory, failures: list[str]) ->
None:
341 """Assert directive-looking strings and prose stay outside the inventory."""
342 c_rows = [item
for item
in inventory.suppressions
if item.path ==
"sample.c"]
343 clang_rows = [item
for item
in c_rows
if item.family ==
"clang-tidy"]
345 len(clang_rows) == EXPECTED_CLANG_ROWS,
346 "must fire: clang-tidy raw-source NOLINT semantics are inventoried",
349 clang_rules = {item.rule
for item
in clang_rows}
354 "readability-magic-numbers",
355 "readability/fn_size",
358 "must fire: strings, identifiers, splices, and live vendor NOLINT forms",
362 len([item
for item
in clang_rows
if item.rule ==
"*"]) == EXPECTED_BROAD_NOLINT_ROWS,
363 "must fire: bare and bracket NOLINT forms follow clang-tidy semantics",
366 _assert_shell_syntax_awareness(inventory, failures)
367 prose_rows = [item
for item
in inventory.suppressions
if item.path ==
"policy.md"]
369 len(prose_rows) == EXPECTED_PROJECT_ROWS,
370 "quiet: prose, fenced, and inline-code directive examples are ignored",
373 bare = [item
for item
in prose_rows
if item.rule ==
"MAGIC-OK"]
375 bool(bare
and "blank-reason" in bare[0].concerns),
376 "must fire: bare project marker has a blank reason",
379 _assert_python_syntax_awareness(inventory, failures)
380 cpplint = [item
for item
in c_rows
if item.rule ==
"whitespace/line_length"]
382 bool(cpplint
and cpplint[0].tool ==
"cpplint"),
383 "quiet: cpplint slash rule is classified without an unknown finding",
386 splice = [item
for item
in c_rows
if item.rule ==
"readability-redundant-string-init"]
387 expect(bool(splice),
"must fire: directive in a spliced C line comment", failures)
388 _assert_control_syntax_awareness(inventory, failures)
389 assert_tool_control_syntax_awareness(root, inventory, failures)
392def _assert_integrity_findings(inventory: Inventory, failures: list[str]) ->
None:
393 """Assert unknown and duplicate syntax fail closed instead of disappearing."""
394 codes = [item.code
for item
in inventory.findings]
396 not any(item.code ==
"unsupported-category" for item
in inventory.findings),
397 "quiet: every formerly unsupported class has a typed recognizer",
400 expect(
"unknown-directive" in codes,
"must fire: unknown project marker", failures)
402 "unterminated-html-comment" in codes,
403 "must fire: unterminated multiline HTML comment",
406 expect(
"malformed-heredoc" in codes,
"must fire: empty heredoc delimiter", failures)
407 expect(
"unterminated-heredoc" in codes,
"must fire: unterminated heredoc body", failures)
409 "unterminated-shell-quote" in codes,
410 "must fire: unterminated multiline shell quote",
414 "unterminated-line-comment-splice" in codes,
415 "must fire: C line-comment splice reaching EOF",
418 malformed = [item
for item
in inventory.findings
if item.path ==
"malformed.py"]
419 malformed_messages = {item.message
for item
in malformed}
421 "noqa: F401 E402" in malformed_messages,
422 "must fire: whitespace-separated multi-rule noqa",
426 "pragma: no cover because fixture",
428 "mypy: disable-error-code",
432 "ruff: noqa: E402 F401",
435 directive
in malformed_messages,
436 f
"must fire: malformed Python control {directive}",
439 malformed_nolint = [item
for item
in inventory.findings
if "NOLINT(foo,,bar)" in item.message]
440 expect(bool(malformed_nolint),
"must fire: empty NOLINT rule ID", failures)
441 expect(
"duplicate-directive" in codes,
"must fire: duplicate central waiver", failures)
442 malformed_cppcheck = [
443 item
for item
in inventory.findings
if item.code ==
"malformed-cppcheck-list"
445 expect(bool(malformed_cppcheck),
"must fire: bogus cppcheck rule ID", failures)
446 broad = [item
for item
in inventory.suppressions
if item.rule ==
"-w"]
448 bool(broad
and "broad-rule" in broad[0].concerns),
449 "must fire: blanket compiler warning disable",
454def _assert_yaml_and_ruff_config(inventory: Inventory, failures: list[str]) ->
None:
455 """Assert executable YAML blocks and central Ruff controls are distinct."""
456 yaml_rows = [item
for item
in inventory.suppressions
if item.path ==
"sample.yml"]
457 yaml_shell_rows = [item
for item
in yaml_rows
if item.family ==
"shell-status"]
459 len(yaml_shell_rows) == EXPECTED_YAML_SHELL_STATUS_ROWS
460 and all(item.provenance ==
"yaml-shell-block" for item
in yaml_shell_rows),
461 "must fire: content, workflow run, and Ansible shell YAML payloads",
465 item
for item
in yaml_rows
if item.provenance
not in {
"yaml-shell-block",
"build-config"}
468 len(syntax_rows) == 1,
469 "quiet: non-executable YAML block payloads are not active syntax",
473 not any(item.path ==
"windows.yml" for item
in inventory.findings),
474 "quiet: PowerShell workflow blocks do not emit Bash parser findings",
479 for item
in inventory.suppressions
480 if item.provenance ==
"central-config" and item.tool ==
"ruff"
483 len(ruff_config) == EXPECTED_RUFF_CONFIG_ROWS,
484 "must fire: every active Ruff global/per-file/path waiver is inventoried",
488 not any(item.concerns
for item
in ruff_config),
489 "quiet: Ruff central waivers have precise local reasons",
494def _assert_regions_and_config(inventory: Inventory, failures: list[str]) ->
None:
495 """Assert region structure and repository-global waivers use the real model."""
496 region_findings = [item
for item
in inventory.findings
if "region" in item.code]
498 not any(item.path ==
"sample.c" for item
in region_findings),
499 "quiet: balanced regions are accepted",
503 any(item.path ==
"unmatched.c" for item
in region_findings),
504 "must fire: unmatched region end",
507 unmatched_messages =
" ".join(
508 item.message
for item
in region_findings
if item.path ==
"unmatched.c"
511 "GCOVR_EXCL_BR" in unmatched_messages
512 and "LCOV_EXCL" in unmatched_messages
513 and "GCOVR_EXCL" in unmatched_messages,
514 "must fire: coverage tool and BR/non-BR region identities do not cross-close",
517 central = [item
for item
in inventory.suppressions
if item.provenance ==
"central-list"]
519 len(central) == EXPECTED_CENTRAL_ROWS,
520 "must fire: global cppcheck config is inventoried",
523 reasons = {item.rule: item.reason
for item
in central}
525 "paired divider rationale" in reasons[
"unusedFunction"],
526 "quiet: paired cppcheck section rationale is frozen",
530 "local rationale A" in reasons[
"unreadVariable"],
531 "quiet: adjacent local rationale replaces grouped rationale",
535 "local rationale B" in reasons[
"unknownMacro"],
536 "quiet: second adjacent local rationale does not accumulate",
539 _assert_yaml_and_ruff_config(inventory, failures)
540 _assert_build_config(inventory, failures)
543def _assert_build_config(inventory: Inventory, failures: list[str]) ->
None:
544 """Dispatch the unchanged build-control assertion groups."""
545 build = [item
for item
in inventory.suppressions
if item.provenance ==
"build-config"]
547 len(build) == EXPECTED_BUILD_ROWS,
548 "must fire: build-config warning controls are inventoried",
551 _assert_yaml_build_config(inventory, failures)
552 _assert_shell_path_build_config(build, failures)
553 _assert_cmake_family_build_config(build, failures)
554 _assert_cmake_dev_build_config(build, failures)
555 _assert_build_reason_capture(failures)
556 _assert_yaml_build_reason_capture(failures)
559def _assert_build_reason_capture(failures: list[str]) ->
None:
560 """Assert warning controls retain only locally attached rationales."""
561 source =
"""# Suppression rationale: pinned compiler emits a false positive.
562target_compile_options(
564 -Wno-shadow # ABI callback parameter cannot change
567# Unrelated prose must not approve a control.
568target_compile_options(other PRIVATE -Wno-unused-parameter)
569# Suppression rationale:
570target_compile_options(empty PRIVATE -Wno-padded)
572 records = compiler_records(
"CMakeLists.txt", source)
573 reasons = {item.rule: item.reason
for item
in records}
575 reasons.get(
"-Wno-shadow") ==
"ABI callback parameter cannot change"
576 and reasons.get(
"-Wno-cast-align") ==
"pinned compiler emits a false positive.",
577 "quiet: inline and command-level compiler reasons are retained",
581 not reasons.get(
"-Wno-unused-parameter")
and not reasons.get(
"-Wno-padded"),
582 "must fire: unrelated or empty comments do not become reasons",
585 missing = {item.rule
for item
in records
if "blank-reason" in item.concerns}
587 {
"-Wno-unused-parameter",
"-Wno-padded"} <= missing,
588 "must fire: reasonless build controls retain blank-reason concerns",
593def _assert_yaml_build_reason_capture(failures: list[str]) ->
None:
594 """Assert YAML command rationales bind locally in both block styles."""
597 # Suppression rationale: pinned YAML compiler wrapper.
598 clang -Wno-shadow sample.c
599 clang -Wno-padded sample.c # generated ABI contract
601 clang -Wno-conversion sample.c
603 # Suppression rationale: folded command uses the pinned wrapper.
605 clang -Wno-cast-align sample.c
607 records = compiler_records(
"workflow.yml", source)
608 reasons = {item.rule: item.reason
for item
in records}
610 reasons.get(
"-Wno-shadow") ==
"pinned YAML compiler wrapper."
611 and reasons.get(
"-Wno-padded") ==
"generated ABI contract"
612 and reasons.get(
"-Wno-cast-align") ==
"folded command uses the pinned wrapper.",
613 "quiet: literal and folded YAML compiler reasons are retained",
617 (item
for item
in records
if item.rule ==
"-Wno-conversion"),
621 conversion
is not None and not conversion.reason
and "blank-reason" in conversion.concerns,
622 "must fire: unrelated YAML comments do not become compiler reasons",
627def _assert_yaml_build_config(inventory: Inventory, failures: list[str]) ->
None:
628 """Assert YAML command ownership and folded-line source mapping."""
629 yaml_rows = [item
for item
in inventory.suppressions
if item.path ==
"sample.yml"]
631 len([item
for item
in yaml_rows
if item.provenance ==
"build-config"])
632 == EXPECTED_YAML_BUILD_ROWS,
633 "must fire: active YAML cflags are inventoried",
637 (item.line, item.column, item.family, item.rule)
638 for item
in yaml_rows
639 if item.line
in {14, 17}
644 (14, 7,
"cmake",
"-Wno-dev"),
645 (17, 7,
"compiler",
"-Wno-conversion"),
647 "must fire: folded YAML command flags retain exact source ownership",
651 len([item
for item
in yaml_rows
if item.family ==
"python"]) == 1,
652 "quiet: YAML block-scalar payload is not active YAML syntax",
657 for item
in yaml_rows
658 if item.provenance ==
"build-config" and item.line
in {3, 21, 28}
662 "quiet: literal and folded YAML data blocks stay outside command syntax",
667def _assert_shell_path_build_config(build: list[Suppression], failures: list[str]) ->
None:
668 """Assert absolute, quoted, and escaped executable path ownership."""
672 if item.path ==
"sample.sh" and item.line
in {16, 17, 18, 19, 20, 21, 22, 23}
675 {(item.line, item.family, item.rule)
for item
in shell_build}
677 (17,
"cmake",
"-Wno-dev"),
678 (18,
"compiler",
"-Wno-sign-conversion"),
679 (20,
"cmake",
"-Wno-dev"),
680 (21,
"compiler",
"-Wno-float-conversion"),
681 (22,
"compiler",
"-Wno-padded"),
683 "quiet: CMake data stays quiet while quoted and nested absolute tools fire",
686 spaced_path_build = [
689 if item.path ==
"sample.sh" and item.line
in {24, 25, 26, 27, 28, 29, 30, 31, 32}
692 {(item.line, item.family, item.rule)
for item
in spaced_path_build}
694 (24,
"compiler",
"-Wno-error"),
695 (25,
"cmake",
"-Wno-dev"),
696 (26,
"compiler",
"-Wno-shadow"),
697 (27,
"compiler",
"-Wno-padded"),
698 (28,
"compiler",
"-Wno-switch"),
699 (29,
"compiler",
"-Wno-cast-align"),
701 "quiet: quoted/escaped path data stays quiet while executable words fire",
706def _assert_cmake_family_build_config(build: list[Suppression], failures: list[str]) ->
None:
707 """Assert exact CMake diagnostic options retain CMake ownership."""
708 cmake_family_fixture_locations = {
717 (
"CMakeLists.txt", 6),
718 (
"CMakeLists.txt", 7),
719 (
"CMakeLists.txt", 8),
721 cmake_family_rows = [
722 item
for item
in build
if (item.path, item.line)
in cmake_family_fixture_locations
725 {(item.path, item.line, item.family, item.rule)
for item
in cmake_family_rows}
727 (
"sample.sh", 33,
"cmake",
"-Wno-deprecated"),
728 (
"sample.sh", 34,
"cmake",
"-Wno-error=dev"),
729 (
"sample.sh", 35,
"cmake",
"-Wno-error=deprecated"),
730 (
"sample.sh", 36,
"compiler",
"-Wno-deprecated"),
731 (
"sample.sh", 37,
"compiler",
"-Wno-deprecated"),
732 (
"CMakeLists.txt", 6,
"cmake",
"-Wno-deprecated"),
733 (
"CMakeLists.txt", 7,
"compiler",
"-Wno-deprecated"),
735 "quiet: CMake data stays quiet while exact diagnostic and compiler owners fire",
738 argument_tool_names = [
739 item
for item
in build
if item.path ==
"sample.sh" and item.line == SHELL_ARGUMENT_TOOL_LINE
742 not argument_tool_names,
743 "quiet: compiler-looking arguments are not executable command words",
748def _assert_cmake_dev_build_config(build: list[Suppression], failures: list[str]) ->
None:
749 """Assert -Wno-dev ownership and shell blanket controls."""
750 cmake_controls = [item
for item
in build
if item.rule ==
"-Wno-dev"]
752 len([item
for item
in cmake_controls
if item.family ==
"cmake"])
753 == EXPECTED_CMAKE_WNO_DEV_ROWS,
754 "must fire: configure-mode CMake -Wno-dev has CMake ownership",
758 len([item
for item
in cmake_controls
if item.family ==
"compiler"])
759 == EXPECTED_COMPILER_WNO_DEV_ROWS,
760 "must fire: compiler and target_compile_options -Wno-dev stay compiler-owned",
766 if item.path ==
"CMakeLists.txt" and item.line
in {4, 5}
and item.rule ==
"-Wno-dev"
770 "quiet: CMake data strings containing -Wno-dev are not controls",
773 shell_blanket = [item
for item
in build
if item.path ==
"sample.sh" and item.rule ==
"-w"]
775 len(shell_blanket) == 1,
776 "quiet: shell test/fold -w stay quiet while the compiler option array fires",
781def _assert_nonvacuity(root: Path, failures: list[str]) ->
None:
782 """Assert a collapsed scan reports vacuity rather than a clean result."""
783 tiny = scan_paths(root, [
"sample.py"], enforce_floors=
True)
784 codes = {item.code
for item
in tiny.findings}
785 expect(
"vacuous-files" in codes,
"must fire: collapsed file census", failures)
786 expect(
"vacuous-inventory" in codes,
"must fire: collapsed directive census", failures)
787 expect(
"missing-family" in codes,
"must fire: collapsed family coverage", failures)
789 {
"vacuous-family",
"vacuous-baseline-files",
"vacuous-baseline-rows"} <= codes,
790 "must fire: audited family and baseline census floors",
795 item.code ==
"missing-family" and item.message ==
"test-control"
796 for item
in tiny.findings
798 "quiet: the audited exact native-skip population is present",
801 injected = scan_paths(root, [
"native_test.cpp"], enforce_floors=
True)
803 any(item.code ==
"unexpected-family-count" for item
in injected.findings),
804 "must fire: an injected native skip violates the audited exact family contract",
809def _assert_ruff_config_fail_closed(root: Path, failures: list[str]) ->
None:
810 """Assert valid Ruff syntax outside the source locator cannot disappear."""
811 pyproject = root /
"pyproject.toml"
812 text = pyproject.read_text(encoding=
"ascii")
813 pyproject.write_text(
814 text.replace(
'["SLF001"]',
'["SLF001", "S603"]'),
817 inventory = scan_paths(root, [
"pyproject.toml"])
819 any(item.code ==
"malformed-ruff-config" for item
in inventory.findings),
820 "must fire: unsupported-but-valid Ruff config shape fails closed",
825def _assert_tool_config_fail_closed(root: Path, failures: list[str]) ->
None:
826 """Assert malformed central tool ignore syntax cannot disappear."""
827 config = root /
".hadolint.yaml"
828 text = config.read_text(encoding=
"ascii")
829 config.write_text(text.replace(
"- DL3008",
"- not-a-rule"), encoding=
"ascii")
830 inventory = scan_paths(root, [
".hadolint.yaml"])
832 any(item.code ==
"malformed-tool-config" for item
in inventory.findings),
833 "must fire: malformed Hadolint central ignore fails closed",
838def _assert_optional_tool_activation(root: Path, failures: list[str]) ->
None:
839 """Assert unused Prettier/markdownlint comments are not active waivers."""
840 inventory = scan_paths(root, [
"docs/format_controls.md"])
841 optional = {item.tool
for item
in inventory.suppressions} & {
"prettier",
"markdownlint"}
842 inactive = [item
for item
in inventory.findings
if item.code ==
"inactive-tool-control"]
844 not optional
and len(inactive) >= EXPECTED_OPTIONAL_INACTIVE,
845 "quiet: optional formatter/linter controls require repository configuration",
850def _assert_path_safety(root: Path, inventory: Inventory, failures: list[str]) ->
None:
851 """Assert invalid Git names and escaping symlinks fail closed."""
852 paths, findings = decode_git_paths(b
"bad-\xff-name\0", root)
853 expect(
not paths
and bool(findings),
"must fire: non-UTF-8 Git path", failures)
854 paths, findings = decode_git_paths(b
"missing-or-broken\0", root)
856 paths == [
"missing-or-broken"]
and not findings,
857 "quiet: Git paths are preserved for fail-closed read validation",
860 unsafe = [item
for item
in inventory.findings
if item.code ==
"unsafe-symlink"]
861 expect(bool(unsafe),
"must fire: symlink escaping repository", failures)
864 for item
in inventory.findings
865 if item.code ==
"read-error" and item.path ==
"broken-link"
867 expect(bool(broken),
"must fire: broken symlink is not silently omitted", failures)
868 encoding = [item
for item
in inventory.findings
if item.code ==
"invalid-text-encoding"]
869 expect(bool(encoding),
"must fire: invalid UTF-8 authored text", failures)
872 for item
in inventory.suppressions
873 if item.family ==
"encoding-exemption"
874 and item.owner ==
"vendor"
875 and item.scope.startswith(
"blob:sha256:")
879 "quiet: vendored legacy encoding is inventoried as an exemption",
884def run_selftest() -> int:
885 """Drive production entry points through must-fire and must-stay-quiet cases."""
886 print(
"check_suppressions.py selftest:")
887 failures: list[str] = []
888 with tempfile.TemporaryDirectory(prefix=
"ra8-suppressions-")
as temp:
892 paths = _write_fixture(root)
893 outside = base /
"outside.txt"
894 outside.write_text(
"# noqa: F401 -- must not be followed\n", encoding=
"ascii")
895 (root /
"outside-link").symlink_to(outside)
896 paths.append(
"outside-link")
897 (root /
"broken-link").symlink_to(root /
"does-not-exist")
898 paths.append(
"broken-link")
899 (root /
"invalid.txt").write_bytes(b
"authored-\xff-text\n")
900 paths.append(
"invalid.txt")
901 vendor = root /
"libs/third_party/vendor/legacy.txt"
902 vendor.parent.mkdir(parents=
True, exist_ok=
True)
903 vendor.write_bytes(b
"vendored-\xff-text\n")
904 paths.append(
"libs/third_party/vendor/legacy.txt")
905 inventory = scan_paths(root, paths)
906 assert_identity_and_structure(root, inventory, failures, EXPECTED_DEAD_ANCHOR_FINDINGS)
907 _assert_families(inventory, failures)
908 _assert_syntax_awareness(root, inventory, failures)
909 assert_stranded_branch_markers(failures)
910 assert_stranded_line_markers(failures)
911 _assert_debt_control_families(inventory, failures)
912 assert_compiler_controls(inventory, root, failures)
913 assert_compiler_tool_probes(root, failures)
914 assert_clang_tidy_config_fail_closed(root, failures)
915 _assert_integrity_findings(inventory, failures)
916 _assert_regions_and_config(inventory, failures)
917 _assert_ruff_config_fail_closed(root, failures)
918 _assert_tool_config_fail_closed(root, failures)
919 _assert_optional_tool_activation(root, failures)
920 _assert_nonvacuity(root, failures)
921 _assert_path_safety(root, inventory, failures)
922 assert_governance_parsers(root, failures)
923 assert_baseline_ceiling_controls(base, failures)
924 assert_identity_semantics(base, failures)
925 assert_ledger_gate(base, failures)
926 return report(failures)