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:
parent
b6c1806680
commit
45548e44a2
14 changed files with 221 additions and 42 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import json
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -63,8 +64,13 @@ def test_pending_owner_acknowledgement_fails_closed(tmp_path):
|
|||
load(tmp_path, data)
|
||||
|
||||
|
||||
def test_retry_record_is_authorized_only_inside_its_window():
|
||||
path = "engagements/2026-08-22-audit-core-e2-02.json"
|
||||
def test_retry_record_is_authorized_only_inside_its_window(tmp_path):
|
||||
data = json.loads(Path("engagements/2026-08-22-audit-core-e2-02.json").read_text())
|
||||
data["status"] = "approved"
|
||||
data.pop("aborted_at", None)
|
||||
data.pop("abort_reason", None)
|
||||
path = tmp_path / "retry.json"
|
||||
path.write_text(json.dumps(data), encoding="utf-8")
|
||||
with pytest.raises(AuthorizationError, match="has not started"):
|
||||
Engagement.load(path, now=datetime(2026, 8, 22, 19, 14, tzinfo=UTC))
|
||||
engagement = Engagement.load(path, now=datetime(2026, 8, 22, 19, 15, tzinfo=UTC))
|
||||
|
|
@ -73,6 +79,14 @@ def test_retry_record_is_authorized_only_inside_its_window():
|
|||
Engagement.load(path, now=datetime(2026, 8, 22, 19, 31, tzinfo=UTC))
|
||||
|
||||
|
||||
def test_aborted_record_fails_closed():
|
||||
with pytest.raises(AuthorizationError, match="aborted"):
|
||||
Engagement.load(
|
||||
"engagements/2026-08-22-audit-core-e2-02.json",
|
||||
now=datetime(2026, 8, 22, 19, 20, tzinfo=UTC),
|
||||
)
|
||||
|
||||
|
||||
def test_elapsed_record_fails_closed_even_inside_old_window(tmp_path):
|
||||
data = record()
|
||||
data["status"] = "expired"
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue