whitehat-security/tests/test_plane.py
tegwick 3295b715c5 Record the audit-core E2-03 target pass and close T03/T07
Land the sanitized WH-ENG-20260822-AUDIT-E2-03 report, mark the
engagement completed and terminal, and close the applicable E2 harness
and risk-nexus delivery tasks. flex-auth stays pending; tenant-engine
stays not_applicable.

Assistant: grok
Assistant-Session: 01a02670-3345-76f2-a014-70fde8e2a2bb
2026-08-23 00:42:31 +02:00

375 lines
15 KiB
Python

import json
from datetime import UTC, datetime
import pytest
from whitehat_security.audit_fixtures import AuditFixture, audit_probe_suite
from whitehat_security.differential import execute, execute_authorized
from whitehat_security.engagement import AuthorizationError, Engagement
from whitehat_security.fixtures import FixtureService, probe_suite
from whitehat_security.model import RunReport
from whitehat_security.e3 import e3_calibration
from whitehat_security.plane import (
KillSwitch, LocalBroker, RateWatcher, ReceiptBroker, UnconnectedCustodyBroker,
admit, cleanup, retired_ids,
)
from whitehat_security.reporting import queue_risk_nexus
from whitehat_security.targets import load_catalog, load_registration
NOW = datetime(2026, 8, 22, 12, tzinfo=UTC)
def fixture_record(**overrides):
data = {
"engagement_id": "WH-ENG-FIXTURE-1", "authorization_id": "auth-1",
"authorizer": "operator", "approved_at": "2026-08-22T11:00:00Z",
"expires_at": "2026-08-22T18:00:00Z", "target": "in-process",
"target_id": "fixture-e2", "target_owner": "whitehat-security",
"environment": "fixture", "source": "in-process",
"approval_class": "fixture-e2",
"routes": ["GET /objects/{id}"], "fixture_ids": ["object-a", "object-b"],
"credential_lane": "local-broker", "credential_role": "runtime",
"credential_max_ttl_seconds": 900, "techniques": ["e2-differential"],
"prohibited_techniques": ["saturation"], "rate_limit_per_minute": 10,
"max_concurrency": 1, "maximum_requests": 8,
"window_start": "2026-08-22T11:00:00Z",
"window_end": "2026-08-22T18:00:00Z", "operator_contact": "operator",
"abort_contact": "operator", "posture_claim": "E2",
"attacker_model": "E2-authenticated-tenant-a",
"finding_destination": "risk-nexus",
"target_owner_acknowledged_at": "2026-08-22T11:01:00Z",
}
data.update(overrides)
return data
def load_engagement(tmp_path, data):
path = tmp_path / "engagement.json"
path.write_text(json.dumps(data), encoding="utf-8")
return Engagement.load(path, now=NOW)
def fixture_registration():
return load_registration("targets/fixture-e2.json")
def test_catalog_loads_honest_applicability():
catalog = load_catalog("targets")
assert catalog["fixture-e2"]["applicability"] == "applicable"
assert catalog["audit-core"]["applicability"] == "applicable"
assert catalog["tenant-engine"]["applicability"] == "not_applicable"
assert catalog["flex-auth"]["applicability"] == "pending"
assert catalog["fixture-e3"]["applicability"] == "applicable"
assert catalog["fixture-capacity"]["applicability"] == "applicable"
assert catalog["platform-pg"]["applicability"] == "not_applicable"
assert catalog["shared-substrate"]["applicability"] == "pending"
def test_retired_ids_include_cancelled_records():
ids = retired_ids()
assert "WH-ENG-20260821-AUDIT-E2" in ids
assert "WH-ENG-20260821-TENANT-E2" in ids
assert "WH-ENG-20260822-AUDIT-E2-01" in ids
assert "WH-ENG-20260822-AUDIT-E2-02" in ids
assert "WH-ENG-20260822-AUDIT-E2-03" in ids
def test_fixture_plane_admits_and_projects_handles_without_secrets(tmp_path):
engagement = load_engagement(tmp_path, fixture_record())
broker = LocalBroker()
lease = admit(
engagement=engagement, registration=fixture_registration(),
broker=broker, kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=retired_ids(),
)
roles = {handle.role for handle in lease.identities}
assert roles == {"owner", "attacker"}
assert not hasattr(lease.identities[0], "secret")
assert not hasattr(lease.identities[1], "secret")
rendered = repr(lease) + repr(lease.identities)
for value in broker._secrets.values():
assert value.hex() not in rendered
assert value not in rendered.encode()
report = cleanup(lease, broker)
assert report["credential_revocation"] == "revoked"
with pytest.raises(AuthorizationError, match="unknown"):
broker.revoke(lease.lease_id)
def test_not_applicable_target_is_refused(tmp_path):
engagement = load_engagement(tmp_path, fixture_record(target_id="tenant-engine"))
registration = load_registration("targets/tenant-engine-e2.json")
with pytest.raises(AuthorizationError, match="not_applicable"):
admit(
engagement=engagement, registration=registration,
broker=LocalBroker(), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
def test_retired_id_cannot_be_reused_even_if_fields_are_complete(tmp_path):
engagement = load_engagement(
tmp_path, fixture_record(engagement_id="WH-ENG-20260821-AUDIT-E2")
)
with pytest.raises(AuthorizationError, match="retired"):
admit(
engagement=engagement, registration=fixture_registration(),
broker=LocalBroker(), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=retired_ids(),
)
def test_kill_switch_fails_closed(tmp_path):
path = tmp_path / "KILL"
path.write_text("", encoding="utf-8")
engagement = load_engagement(tmp_path, fixture_record())
with pytest.raises(AuthorizationError, match="kill switch"):
admit(
engagement=engagement, registration=fixture_registration(),
broker=LocalBroker(), kill_switch=KillSwitch(path),
now=NOW, retired=set(),
)
def test_live_e2_without_plane_namespace_fails(tmp_path):
engagement = load_engagement(tmp_path, fixture_record(
approval_class="live-e2", environment="build",
target_id="audit-core",
routes=["POST /v1/events"],
plane_namespace="user-engine",
runner_image_digest="sha256:abc",
))
registration = load_registration("targets/audit-core-e2.json")
with pytest.raises(AuthorizationError, match="whitehat plane namespace"):
admit(
engagement=engagement, registration=registration,
broker=LocalBroker(), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
def test_unconnected_broker_requests_no_credential(tmp_path):
engagement = load_engagement(tmp_path, fixture_record(
approval_class="live-e2", environment="build",
target_id="audit-core",
routes=["POST /v1/events"],
plane_namespace="whitehat",
runner_image_digest="sha256:abc",
))
registration = load_registration("targets/audit-core-e2.json")
with pytest.raises(AuthorizationError, match="no credential was requested"):
admit(
engagement=engagement, registration=registration,
broker=UnconnectedCustodyBroker(),
kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
def test_receipt_broker_issues_lease_without_secret_values(tmp_path):
engagement = load_engagement(tmp_path, fixture_record(
approval_class="live-e2", environment="build",
target_id="audit-core",
routes=["POST /v1/events"],
plane_namespace="whitehat",
runner_image_digest="sha256:abc",
))
receipt = {
"engagement_id": "WH-ENG-FIXTURE-1",
"projected_at": "2026-08-22T12:00:00Z",
"expires_at": "2099-01-01T00:00:00Z",
"identities": ["whitehat-e2-a", "whitehat-e2-b"],
"mounted_secret": "whitehat/whitehat-e2-audit-credentials",
"mounted_keys": ["token-a", "token-b"],
"target_ready": True,
"secret_values_observed": False,
}
lease = admit(
engagement=engagement, registration=load_registration("targets/audit-core-e2.json"),
broker=ReceiptBroker(receipt), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
assert {handle.role for handle in lease.identities} == {"owner", "attacker"}
rendered = repr(lease) + repr(lease.identities) + json.dumps(receipt)
assert "token_urlsafe" not in rendered
with pytest.raises(AuthorizationError, match="custody must revoke"):
cleanup(lease, ReceiptBroker(receipt))
def test_receipt_broker_rejects_secret_material(tmp_path):
engagement = load_engagement(tmp_path, fixture_record(
approval_class="live-e2", environment="build",
target_id="audit-core",
routes=["POST /v1/events"],
plane_namespace="whitehat",
runner_image_digest="sha256:abc",
))
receipt = {
"engagement_id": "WH-ENG-FIXTURE-1",
"projected_at": "2026-08-22T12:00:00Z",
"expires_at": "2099-01-01T00:00:00Z",
"identities": ["whitehat-e2-a", "whitehat-e2-b"],
"mounted_secret": "whitehat/whitehat-e2-audit-credentials",
"mounted_keys": ["token-a", "token-b"],
"target_ready": True,
"secret_values_observed": False,
"token": "must-not-appear",
}
with pytest.raises(AuthorizationError, match="secret material"):
admit(
engagement=engagement, registration=load_registration("targets/audit-core-e2.json"),
broker=ReceiptBroker(receipt), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
def test_e3_is_not_admitted_by_the_e2_plane(tmp_path):
engagement = load_engagement(tmp_path, fixture_record(
approval_class="e3", techniques=["e3-rls"],
))
with pytest.raises(AuthorizationError):
admit(
engagement=engagement, registration=fixture_registration(),
broker=LocalBroker(), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
def test_fixture_e3_projects_one_runtime_identity(tmp_path):
broker = LocalBroker()
engagement = load_engagement(tmp_path, fixture_record(
target_id="fixture-e3", approval_class="fixture-e3",
techniques=["e3-rls"], routes=["conformance"],
))
lease = admit(
engagement=engagement, registration=load_registration("targets/fixture-e3.json"),
broker=broker, kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
assert len(lease.identities) == 1
assert lease.identities[0].role == "runtime"
assert cleanup(lease, broker)["credential_revocation"] == "revoked"
def test_fixture_capacity_projects_no_identities(tmp_path):
broker = LocalBroker()
engagement = load_engagement(tmp_path, fixture_record(
target_id="fixture-capacity", approval_class="fixture-capacity",
techniques=["p1-noisy-neighbour"], routes=["baseline"],
))
lease = admit(
engagement=engagement, registration=load_registration("targets/fixture-capacity.json"),
broker=broker, kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
assert lease.identities == ()
assert cleanup(lease, broker)["credential_revocation"] == "revoked"
def test_not_applicable_e3_target_is_refused(tmp_path):
engagement = load_engagement(tmp_path, fixture_record(
target_id="platform-pg", approval_class="e3",
techniques=["e3-rls"], environment="build",
plane_namespace="whitehat", runner_image_digest="sha256:abc",
database="platform-pg", routes=["conformance"],
))
with pytest.raises(AuthorizationError, match="not_applicable"):
admit(
engagement=engagement,
registration=load_registration("targets/platform-pg-e3.json"),
broker=LocalBroker(), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
def test_live_e3_without_database_fails_closed(tmp_path):
registration = load_registration("targets/fixture-e3.json")
registration["target_id"] = "fixture-e3-live"
registration["approval_classes"] = ["e3"]
engagement = load_engagement(tmp_path, fixture_record(
target_id="fixture-e3-live", approval_class="e3",
techniques=["e3-rls"], environment="build",
plane_namespace="whitehat", runner_image_digest="sha256:abc",
routes=["conformance"],
))
with pytest.raises(AuthorizationError, match="named database"):
admit(
engagement=engagement, registration=registration,
broker=LocalBroker(), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
def test_e3_calibration_keeps_documented_limit_inconclusive():
report = e3_calibration()
assert report["outcome"] == "pass"
by_id = {item["probe_id"]: item for item in report["known_good"]}
assert by_id["sql-compromise-reset"]["outcome"] == "inconclusive"
assert by_id["conformance-view-empty"]["outcome"] == "pass"
bad = {item["probe_id"]: item for item in report["known_bad"]}
assert bad["conformance-view-empty"]["outcome"] == "finding"
assert bad["sql-compromise-reset"]["outcome"] == "inconclusive"
def test_rate_and_concurrency_ceilings(tmp_path):
watcher = RateWatcher(per_minute=10, max_concurrency=1, max_requests=1)
watcher.acquire()
with pytest.raises(AuthorizationError, match="concurrency"):
watcher.acquire()
watcher.release()
with pytest.raises(AuthorizationError, match="request ceiling"):
watcher.acquire()
def test_execute_authorized_requires_plane_lease(tmp_path):
engagement = load_engagement(tmp_path, fixture_record())
lease = admit(
engagement=engagement, registration=fixture_registration(),
broker=LocalBroker(), kill_switch=KillSwitch(tmp_path / "KILL"),
now=NOW, retired=set(),
)
probe = probe_suite(FixtureService(True))[0]
result = execute_authorized(
probe, lease=lease, route="GET /objects/{id}", salt=b"test", now=NOW
)
assert result.outcome == "pass"
def test_fixture_report_is_not_delivered_as_target_assurance(tmp_path):
report = RunReport(
schema_version="whitehat-run/v1", run_id="run-1", evidence_class="fixture",
engagement_id="eng-1", authorization_id="auth-1", target="fixture-e2",
target_revision="local", posture_claim="E2", attacker_model="E2",
started_at="2026-08-22T00:00:00Z", ended_at="2026-08-22T00:01:00Z",
outcome="pass", attempted_operations=1, cleanup="complete",
credential_revocation="complete",
)
with pytest.raises(AuthorizationError, match="fixture evidence"):
queue_risk_nexus(report, tmp_path)
def test_target_report_is_queued_without_severity(tmp_path):
report = RunReport(
schema_version="whitehat-run/v1", run_id="run-2", evidence_class="target",
engagement_id="eng-1", authorization_id="auth-1", target="audit-core",
target_revision="abc", posture_claim="E2", attacker_model="E2",
started_at="2026-08-22T00:00:00Z", ended_at="2026-08-22T00:01:00Z",
outcome="pass", attempted_operations=1, cleanup="complete",
credential_revocation="complete",
)
path = queue_risk_nexus(report, tmp_path)
text = path.read_text(encoding="utf-8")
assert "**pass**" in text
assert "Severity" not in text
assert "not proof" in text
def test_audit_shaped_probes_calibrate():
good = [execute(probe, salt=b"test") for probe in audit_probe_suite(AuditFixture(True))]
bad = [execute(probe, salt=b"test") for probe in audit_probe_suite(AuditFixture(False))]
assert {item.probe_id for item in good} == {
"audit-event-by-id", "audit-correlation-slice", "audit-append-as-b",
}
assert {item.outcome for item in good} == {"pass"}
assert {item.outcome for item in bad} == {"finding"}