|
25 | 25 |
|
26 | 26 | from __future__ import annotations |
27 | 27 |
|
| 28 | +import argparse |
28 | 29 | import importlib |
29 | 30 | import json |
30 | 31 | import sys |
|
122 | 123 |
|
123 | 124 | LINUX_MANIFEST_SCHEMA_VERSION = 1 |
124 | 125 | LINUX_MANIFEST_FILENAME = "f4-linux-tools.json" |
| 126 | +EXIT_OK = 0 |
| 127 | +EXIT_INVALID = 1 |
| 128 | +EXIT_OFFICIAL_EVIDENCE_DRIFT = 2 |
125 | 129 |
|
126 | 130 | LINUX_PACKAGE_MANAGER_ARTIFACT_IDS: tuple[str, ...] = ( |
127 | 131 | "deb", |
@@ -1356,6 +1360,17 @@ def linux_official_distro_evidence_drift_errors() -> list[str]: |
1356 | 1360 | return errors |
1357 | 1361 |
|
1358 | 1362 |
|
| 1363 | +def linux_official_distro_evidence_audit_report() -> dict[str, Any]: |
| 1364 | + """Return a deterministic release-facing official evidence audit report.""" |
| 1365 | + drift_errors = linux_official_distro_evidence_drift_errors() |
| 1366 | + return { |
| 1367 | + "summary": linux_official_distro_evidence_summary(), |
| 1368 | + "matrix": list(linux_official_distro_evidence_matrix()), |
| 1369 | + "drift_errors": drift_errors, |
| 1370 | + "ok": not drift_errors, |
| 1371 | + } |
| 1372 | + |
| 1373 | + |
1359 | 1374 | def _generated_official_distro_evidence_record( |
1360 | 1375 | row: Mapping[str, Any], |
1361 | 1376 | ) -> tuple[LinuxDistroMappingEvidenceRecord | None, str | None]: |
@@ -2780,3 +2795,59 @@ def _tool_path_errors( |
2780 | 2795 | except (KeyError, TypeError, ValueError) as exc: |
2781 | 2796 | errors.append(f"{prefix}: {exc}") |
2782 | 2797 | return errors |
| 2798 | + |
| 2799 | + |
| 2800 | +class _ContractArgumentParser(argparse.ArgumentParser): |
| 2801 | + def error(self, message: str) -> None: # type: ignore[override] |
| 2802 | + self.print_usage(sys.stderr) |
| 2803 | + print(f"{self.prog}: error: {message}", file=sys.stderr) |
| 2804 | + raise SystemExit(EXIT_INVALID) |
| 2805 | + |
| 2806 | + |
| 2807 | +def build_parser() -> argparse.ArgumentParser: |
| 2808 | + parser = _ContractArgumentParser( |
| 2809 | + prog="f4_linter_linux_provisioning.py", |
| 2810 | + description="Audit Linux F4 linter provisioning policy metadata.", |
| 2811 | + ) |
| 2812 | + mode = parser.add_mutually_exclusive_group(required=True) |
| 2813 | + mode.add_argument( |
| 2814 | + "--official-evidence-audit", |
| 2815 | + action="store_true", |
| 2816 | + help="print the official distro evidence audit report as JSON", |
| 2817 | + ) |
| 2818 | + mode.add_argument( |
| 2819 | + "--check-official-evidence-drift", |
| 2820 | + action="store_true", |
| 2821 | + help="fail if official distro evidence drift is detected", |
| 2822 | + ) |
| 2823 | + return parser |
| 2824 | + |
| 2825 | + |
| 2826 | +def _official_evidence_drift_check_message(drift_errors: list[str]) -> str: |
| 2827 | + if not drift_errors: |
| 2828 | + return "PASS: Linux official distro evidence drift audit clean" |
| 2829 | + lines = ["FAIL: Linux official distro evidence drift detected"] |
| 2830 | + lines.extend(f"ERROR: {error}" for error in drift_errors) |
| 2831 | + return "\n".join(lines) |
| 2832 | + |
| 2833 | + |
| 2834 | +def main(argv: list[str] | None = None) -> int: |
| 2835 | + args = build_parser().parse_args(argv) |
| 2836 | + if args.official_evidence_audit: |
| 2837 | + print( |
| 2838 | + json.dumps( |
| 2839 | + linux_official_distro_evidence_audit_report(), |
| 2840 | + indent=2, |
| 2841 | + sort_keys=True, |
| 2842 | + ) |
| 2843 | + ) |
| 2844 | + return EXIT_OK |
| 2845 | + |
| 2846 | + drift_errors = linux_official_distro_evidence_drift_errors() |
| 2847 | + message = _official_evidence_drift_check_message(drift_errors) |
| 2848 | + print(message, file=sys.stderr if drift_errors else sys.stdout) |
| 2849 | + return EXIT_OFFICIAL_EVIDENCE_DRIFT if drift_errors else EXIT_OK |
| 2850 | + |
| 2851 | + |
| 2852 | +if __name__ == "__main__": |
| 2853 | + raise SystemExit(main()) |
0 commit comments