Admit live E2 from a value-safe custody receipt

WH-ENG-20260822-AUDIT-E2-02 projected and then aborted: admit-plane had no
receipt adapter, so the runner sent zero packets. Consume custody receipts
as handles only, keep unconnected admission fail-closed, and retire -02.

Assistant: grok
Assistant-Session: 01a02670-3345-76f2-a014-70fde8e2a2bb
This commit is contained in:
tegwick 2026-08-22 21:31:49 +02:00
parent b6c1806680
commit 45548e44a2
14 changed files with 221 additions and 42 deletions

View file

@ -10,7 +10,7 @@ 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, UnconnectedCustodyBroker,
KillSwitch, LocalBroker, RateWatcher, ReceiptBroker, UnconnectedCustodyBroker,
admit, cleanup, retired_ids,
)
from whitehat_security.reporting import queue_risk_nexus
@ -71,6 +71,7 @@ def test_retired_ids_include_cancelled_records():
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
def test_fixture_plane_admits_and_projects_handles_without_secrets(tmp_path):
@ -165,6 +166,63 @@ def test_unconnected_broker_requests_no_credential(tmp_path):
)
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"],