whitehat-security/tests/test_v_observation.py
tegwick eebcc39a12 Classify I and A as mechanical and calibrate V observations offline.
WHITEHAT-WP-0012 records that identity and authorization evidence belongs in the declaring service's CI, and adds an in-process V2/V3/V4 observation judge that injects no failure. Live E4, R4, and V stay wait on an unnamed owner or operator, so the plan is blocked. No packet is authorized.

Assistant: grok
Assistant-Session: 01a10450-dda4-7253-91a9-b8dccb2f0173
2026-10-04 11:15:01 +02:00

93 lines
4 KiB
Python

import json
from pathlib import Path
import pytest
from whitehat_security.engagement import AuthorizationError
from whitehat_security.targets import load_registration
from whitehat_security.v import VObservation, evaluate, v_calibration
def test_restart_and_missing_injection_are_not_a_pass():
restart = evaluate(VObservation(
"restart", claimed_level="V2", operation="read", failure_injected=True,
failure_kind="restart", traffic_continued_or_recovered=True,
rto_recorded=True, rpo_recorded=True, shared_failure_domain_recorded=True,
))
assert restart.outcome == "finding"
absent = evaluate(VObservation(
"absent", claimed_level="V2", operation="read", failure_injected=False,
failure_kind="instance-terminated", traffic_continued_or_recovered=True,
rto_recorded=True, rpo_recorded=True, shared_failure_domain_recorded=True,
))
assert absent.outcome == "finding"
def test_missing_measurements_stay_inconclusive():
missing = evaluate(VObservation(
"rto", claimed_level="V2", operation="read", failure_injected=True,
failure_kind="instance-terminated", traffic_continued_or_recovered=True,
rto_recorded=False, rpo_recorded=True, shared_failure_domain_recorded=True,
))
assert missing.outcome == "inconclusive"
unnamed = evaluate(VObservation(
"operation", claimed_level="V2", operation=" ", failure_injected=True,
failure_kind="instance-terminated", traffic_continued_or_recovered=True,
rto_recorded=True, rpo_recorded=True, shared_failure_domain_recorded=True,
))
assert unnamed.outcome == "inconclusive"
def test_v1_is_not_adversarial_evidence_from_this_harness():
result = evaluate(VObservation(
"v1", claimed_level="V1", operation="read", failure_injected=True,
failure_kind="restart", rto_recorded=True,
))
assert result.outcome == "inconclusive"
def test_v3_and_v4_reject_the_wrong_shape():
wrong = evaluate(VObservation(
"v3", claimed_level="V3", operation="read", failure_injected=True,
failure_kind="instance-terminated", rto_recorded=True, rpo_recorded=True,
critical_path_observed=True, degraded_modes_observed=True,
))
assert wrong.outcome == "finding"
region = evaluate(VObservation(
"v4", claimed_level="V4", operation="read", failure_injected=True,
failure_kind="region-unavailable", rto_recorded=True, rpo_recorded=True,
alternate_region_recovered=False,
))
assert region.outcome == "finding"
def test_unknown_claim_aborts():
assert evaluate(VObservation("nope", claimed_level="V9")).outcome == "aborted"
def test_calibration_fails_known_bad_before_trusting_a_pass():
report = v_calibration()
assert report["known_bad_failed_first"] is True
assert report["failure_injected_by_harness"] is False
assert report["evidence_class"] == "fixture"
assert report["outcome"] == "pass"
assert "pass" not in {item["outcome"] for item in report["known_bad"]}
assert {item["outcome"] for item in report["known_good"]} == {"pass"}
assert any("no cluster" in item.lower() or "no instance" in item.lower()
for item in report["limitations"])
def test_fixture_v_projects_no_credential_and_no_live_class(tmp_path: Path):
registration = json.loads(Path("targets/fixture-v.json").read_text(encoding="utf-8"))
assert registration["identities"]["count"] == 0
assert registration["approval_classes"] == ["fixture-v"]
registration["identities"]["count"] = 1
path = tmp_path / "counted.json"
path.write_text(json.dumps(registration), encoding="utf-8")
with pytest.raises(AuthorizationError, match="project no credential"):
load_registration(path)
registration["identities"]["count"] = 0
registration["approval_classes"] = ["fixture-v", "capacity"]
path.write_text(json.dumps(registration), encoding="utf-8")
with pytest.raises(AuthorizationError, match="cannot carry a live approval class"):
load_registration(path)