mirror of
https://github.com/logos-blockchain/lez-fuzzing.git
synced 2026-07-02 07:49:45 +00:00
93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Fail if any fuzz target registered in fuzz/Cargo.toml is missing from a
|
||
|
|
workflow / script / doc that enumerates the target list.
|
||
|
|
|
||
|
|
`fuzz/Cargo.toml` is the single source of truth: every `[[bin]] name = "fuzz_*"`
|
||
|
|
must be mentioned by name in each of the consumer files below. This guards
|
||
|
|
against the drift that `scripts/add_fuzz_target.py` cannot prevent on its own
|
||
|
|
(it only edits `.github/workflows/fuzz.yml`).
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
python3 scripts/check_target_inventory.py
|
||
|
|
|
||
|
|
Exit code 0 = all consumers list every target; 1 = drift detected (prints the
|
||
|
|
missing target/file pairs). Run from anywhere; paths are resolved relative to
|
||
|
|
the repository root.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import re
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
# Files that enumerate the full target list and must stay in sync with Cargo.toml.
|
||
|
|
# Paths are relative to the repository root.
|
||
|
|
CONSUMERS = [
|
||
|
|
".github/workflows/fuzz.yml",
|
||
|
|
".github/workflows/fuzz-afl.yml",
|
||
|
|
".github/workflows/mutants.yml",
|
||
|
|
"scripts/mutants-corpus-test.sh",
|
||
|
|
"README.md",
|
||
|
|
"docs/fuzzing.md",
|
||
|
|
]
|
||
|
|
|
||
|
|
_BIN_NAME_RE = re.compile(r'name\s*=\s*"(fuzz_[a-z0-9_]+)"')
|
||
|
|
|
||
|
|
|
||
|
|
def registered_targets(cargo_toml: Path) -> list[str]:
|
||
|
|
"""Every `[[bin]] name = "fuzz_*"` in fuzz/Cargo.toml, in file order."""
|
||
|
|
names = _BIN_NAME_RE.findall(cargo_toml.read_text())
|
||
|
|
# Preserve order, drop duplicates defensively.
|
||
|
|
seen: set[str] = set()
|
||
|
|
ordered: list[str] = []
|
||
|
|
for n in names:
|
||
|
|
if n not in seen:
|
||
|
|
seen.add(n)
|
||
|
|
ordered.append(n)
|
||
|
|
return ordered
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
root = Path(__file__).parent.parent # repository root
|
||
|
|
cargo_toml = root / "fuzz" / "Cargo.toml"
|
||
|
|
if not cargo_toml.exists():
|
||
|
|
print(f"ERROR: {cargo_toml} not found", file=sys.stderr)
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
targets = registered_targets(cargo_toml)
|
||
|
|
if not targets:
|
||
|
|
print(f"ERROR: no [[bin]] targets found in {cargo_toml}", file=sys.stderr)
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
missing: list[tuple[str, str]] = []
|
||
|
|
for rel in CONSUMERS:
|
||
|
|
path = root / rel
|
||
|
|
if not path.exists():
|
||
|
|
print(f"ERROR: consumer file not found: {rel}", file=sys.stderr)
|
||
|
|
sys.exit(1)
|
||
|
|
text = path.read_text()
|
||
|
|
for target in targets:
|
||
|
|
if target not in text:
|
||
|
|
missing.append((rel, target))
|
||
|
|
|
||
|
|
if missing:
|
||
|
|
print(
|
||
|
|
f"Target-inventory drift: {len(targets)} targets registered in "
|
||
|
|
f"fuzz/Cargo.toml, but some consumers are missing entries:\n",
|
||
|
|
file=sys.stderr,
|
||
|
|
)
|
||
|
|
for rel, target in missing:
|
||
|
|
print(f" MISSING {rel} -> {target}", file=sys.stderr)
|
||
|
|
print(
|
||
|
|
"\nAdd the target(s) above to each listed file "
|
||
|
|
"(see scripts/add_fuzz_target.py for the canonical insertion points).",
|
||
|
|
file=sys.stderr,
|
||
|
|
)
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
print(f"OK: all {len(CONSUMERS)} consumers list every one of the "
|
||
|
|
f"{len(targets)} registered targets.")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|