303 lines
10 KiB
Python
303 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
"""Twenty host-only guardrails for the Phase-0.9E provenance audit."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import copy
|
|
import importlib.util
|
|
from pathlib import Path
|
|
import sys
|
|
from types import ModuleType
|
|
from typing import Callable
|
|
|
|
|
|
def load_module(name: str, path: Path) -> ModuleType:
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
if spec is None or spec.loader is None:
|
|
raise RuntimeError(f"could not load {path}")
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def require(condition: bool, message: str) -> None:
|
|
if not condition:
|
|
raise RuntimeError(message)
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--root", type=Path, required=True)
|
|
args = parser.parse_args()
|
|
root = args.root.resolve()
|
|
validator = load_module(
|
|
"phase09e_validator", root / "tools/validate_phase09e_bootstrap.py"
|
|
)
|
|
manifest = validator.load_json(
|
|
root / "manifests/runtime/phase-0.9e-bootstrap-provenance.json"
|
|
)
|
|
protocol_manifest = validator.load_json(
|
|
root / "manifests/runtime/phase-0.9e-loader-protocol.json"
|
|
)
|
|
cases: list[tuple[str, Callable[[], None]]] = []
|
|
|
|
def case(name: str) -> Callable[[Callable[[], None]], Callable[[], None]]:
|
|
def register(function: Callable[[], None]) -> Callable[[], None]:
|
|
cases.append((name, function))
|
|
return function
|
|
|
|
return register
|
|
|
|
@case("01 public upstream is not exact-used without provenance")
|
|
def _() -> None:
|
|
artifact = copy.deepcopy(manifest["artifacts"][11])
|
|
artifact["confidence"] = "EXACT_USED"
|
|
require(
|
|
bool(validator.provenance_errors(artifact)),
|
|
"public upstream was promoted to exact-used",
|
|
)
|
|
|
|
@case("02 opaque binary gets no invented source commit")
|
|
def _() -> None:
|
|
artifact = copy.deepcopy(manifest["artifacts"][1])
|
|
artifact["source_commit"] = "0" * 40
|
|
require(
|
|
bool(validator.provenance_errors(artifact)),
|
|
"opaque binary accepted an invented source commit",
|
|
)
|
|
|
|
@case("03 missing bootstrap implementation is classified")
|
|
def _() -> None:
|
|
require(
|
|
validator.rescue_classification(actual_package_available=False)
|
|
== "BOOTSTRAP_IMPLEMENTATION_MISSING",
|
|
"missing implementation was not blocked",
|
|
)
|
|
|
|
@case("04 an elfldr dependency is not independent")
|
|
def _() -> None:
|
|
require(
|
|
validator.rescue_classification(
|
|
actual_package_available=True, requires_elfldr=True
|
|
)
|
|
== "SELF_OR_CROSS_DEPENDENT",
|
|
"elfldr-dependent bootstrap was marked independent",
|
|
)
|
|
|
|
@case("05 a Payload Manager dependency is not independent")
|
|
def _() -> None:
|
|
require(
|
|
validator.rescue_classification(
|
|
actual_package_available=True, requires_payload_manager=True
|
|
)
|
|
== "SELF_OR_CROSS_DEPENDENT",
|
|
"manager-dependent bootstrap was marked independent",
|
|
)
|
|
|
|
@case("06 live replacement cannot be a safe rescue executor")
|
|
def _() -> None:
|
|
require(
|
|
validator.rescue_classification(
|
|
actual_package_available=True, replaces_live_component=True
|
|
)
|
|
== "NO_INDEPENDENT_RESCUE_PATH",
|
|
"live-replacement bootstrap was accepted",
|
|
)
|
|
|
|
@case("07 host-to-memory needs receive mapping and entrypoint code")
|
|
def _() -> None:
|
|
partials = (
|
|
(True, False, False),
|
|
(False, True, False),
|
|
(False, False, True),
|
|
(True, True, False),
|
|
)
|
|
for receive, mapping, entrypoint in partials:
|
|
require(
|
|
validator.host_to_memory_classification(
|
|
receive_code=receive,
|
|
mapping_code=mapping,
|
|
entrypoint_code=entrypoint,
|
|
)
|
|
!= "PROVEN_FROM_SOURCE",
|
|
"incomplete host-to-memory evidence passed",
|
|
)
|
|
|
|
@case("08 conceptual port-9020 text is not protocol proof")
|
|
def _() -> None:
|
|
require(
|
|
bool(validator.validate_protocol(protocol_manifest)) is False,
|
|
"canonical unknown protocol does not validate",
|
|
)
|
|
require(
|
|
protocol_manifest["classification"]
|
|
== "CONCEPTUAL_9020_DESCRIPTION_IS_NOT_PROTOCOL_PROOF",
|
|
"conceptual protocol was promoted",
|
|
)
|
|
|
|
@case("09 full protocol model requires framing length and partial I/O")
|
|
def _() -> None:
|
|
protocol = copy.deepcopy(protocol_manifest["protocol"])
|
|
protocol["maximum_payload_size"] = 1024
|
|
protocol["headers"] = "FIXED"
|
|
protocol["length_fields"] = "U32"
|
|
protocol["bounds_checks"] = "PRESENT"
|
|
protocol["short_read_detection"] = "PRESENT"
|
|
require(
|
|
validator.protocol_model_complete(protocol) is False,
|
|
"protocol without short-write handling passed",
|
|
)
|
|
protocol["short_write_detection"] = "PRESENT"
|
|
require(
|
|
validator.protocol_model_complete(protocol) is True,
|
|
"complete synthetic protocol shape was rejected",
|
|
)
|
|
|
|
@case("10 a temporary socket is not automatically brick relevant")
|
|
def _() -> None:
|
|
require(
|
|
validator.risk_classification(temporary_socket=True)
|
|
!= "BRICK_RELEVANT",
|
|
"temporary socket was overclassified",
|
|
)
|
|
|
|
@case("11 live filesystem write is brick relevant")
|
|
def _() -> None:
|
|
require(
|
|
validator.risk_classification(live_filesystem_write=True)
|
|
== "BRICK_RELEVANT",
|
|
"live filesystem write was underclassified",
|
|
)
|
|
|
|
@case("12 autoload activation is brick relevant")
|
|
def _() -> None:
|
|
require(
|
|
validator.risk_classification(autoload_activation=True)
|
|
== "BRICK_RELEVANT",
|
|
"autoload activation was underclassified",
|
|
)
|
|
|
|
@case("13 automatic retry remains forbidden")
|
|
def _() -> None:
|
|
changed = copy.deepcopy(manifest)
|
|
changed["authorization"]["automatic_retry"] = True
|
|
changed["decisions"]["automatic_retry"] = True
|
|
require(
|
|
bool(validator.validate_manifest(changed)),
|
|
"automatic retry was accepted",
|
|
)
|
|
|
|
@case("14 general expectation cannot prove reboot recovery")
|
|
def _() -> None:
|
|
require(
|
|
validator.reboot_classification(
|
|
exact_package=False,
|
|
source_design_restartable=False,
|
|
hardware_observed=False,
|
|
)
|
|
== "REBOOT_RECOVERY_UNPROVEN",
|
|
"general reboot expectation was promoted to proof",
|
|
)
|
|
|
|
@case("15 restartable description without exact package is at most partial")
|
|
def _() -> None:
|
|
require(
|
|
validator.rescue_classification(
|
|
actual_package_available=False,
|
|
all_required_properties_proven=True,
|
|
)
|
|
!= "INDEPENDENT_RESCUE_EXECUTOR_CANDIDATE",
|
|
"description-only chain was marked independent",
|
|
)
|
|
|
|
@case("16 Phase 0.9F is blocked when implementation is missing")
|
|
def _() -> None:
|
|
require(
|
|
validator.phase09f_design_allowed(
|
|
actual_package_available=False,
|
|
independent_from_elfldr=True,
|
|
independent_from_payload_manager=True,
|
|
no_live_replacement=True,
|
|
)
|
|
is False,
|
|
"Phase 0.9F was allowed without implementation",
|
|
)
|
|
|
|
@case("17 Phase 0.9F is blocked by component dependency")
|
|
def _() -> None:
|
|
require(
|
|
validator.phase09f_design_allowed(
|
|
actual_package_available=True,
|
|
independent_from_elfldr=False,
|
|
independent_from_payload_manager=True,
|
|
no_live_replacement=True,
|
|
)
|
|
is False,
|
|
"Phase 0.9F was allowed with elfldr dependency",
|
|
)
|
|
|
|
@case("18 no target source is added")
|
|
def _() -> None:
|
|
errors = validator.phase09e_path_errors(
|
|
{"docs/runtime/phase-0.9e-note.md", "src/backends/ps5/rescue.c"}
|
|
)
|
|
require(
|
|
any("target path" in error or "target artifact/source" in error for error in errors),
|
|
"target source guard did not fire",
|
|
)
|
|
require(
|
|
not validator.phase09e_path_errors(
|
|
{"docs/runtime/phase-0.9e-note.md"}
|
|
),
|
|
"documentation was rejected as target source",
|
|
)
|
|
|
|
@case("19 no target artifact is added")
|
|
def _() -> None:
|
|
require(
|
|
bool(
|
|
validator.phase09e_path_errors(
|
|
{"packaging/phase09e/rescue.elf"}
|
|
)
|
|
),
|
|
"target artifact guard did not fire",
|
|
)
|
|
|
|
@case("20 every authorization field remains false")
|
|
def _() -> None:
|
|
require(
|
|
all(
|
|
manifest["authorization"].get(field) is False
|
|
for field in validator.AUTHORIZATION_FIELDS
|
|
),
|
|
"authorization field became true",
|
|
)
|
|
changed = copy.deepcopy(manifest)
|
|
changed["authorization"]["transfer_authorized"] = True
|
|
require(
|
|
bool(validator.validate_manifest(changed)),
|
|
"true authorization was accepted",
|
|
)
|
|
|
|
failures: list[str] = []
|
|
for name, function in cases:
|
|
try:
|
|
function()
|
|
except Exception as error: # noqa: BLE001 - test harness reports all cases.
|
|
failures.append(f"{name}: {error}")
|
|
if len(cases) != 20:
|
|
failures.append(f"expected 20 cases, found {len(cases)}")
|
|
if failures:
|
|
for failure in failures:
|
|
print(f"FAIL: {failure}")
|
|
return 1
|
|
print("Phase-0.9E bootstrap guardrails: 20/20 PASS")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|