Correct audit engagement and idempotent fixture setup
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a0260c-4067-7052-9647-ad000d576e38
This commit is contained in:
parent
edc9df0491
commit
8a97fac17f
5 changed files with 34 additions and 10 deletions
|
|
@ -6,7 +6,8 @@
|
||||||
"expires_at": "2026-08-21T23:15:00Z",
|
"expires_at": "2026-08-21T23:15:00Z",
|
||||||
"target": "http://audit-core.audit-core.svc.cluster.local:8080",
|
"target": "http://audit-core.audit-core.svc.cluster.local:8080",
|
||||||
"target_owner": "audit-core / infrastructure operator",
|
"target_owner": "audit-core / infrastructure operator",
|
||||||
"target_owner_acknowledged_at": "2026-08-21T21:56:00Z",
|
"target_owner_acknowledged_at": null,
|
||||||
|
"target_owner_acknowledgement_status": "pending corrected adapter/record review; target review received 2026-08-21T22:04:19Z",
|
||||||
"environment": "production",
|
"environment": "production",
|
||||||
"production_approval": "Explicit user approval of engagements/2026-08-21-e2-proposals.md in the coordinating session",
|
"production_approval": "Explicit user approval of engagements/2026-08-21-e2-proposals.md in the coordinating session",
|
||||||
"namespace": "audit-core",
|
"namespace": "audit-core",
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,9 @@ invented tenant claim is not acceptable evidence.
|
||||||
|
|
||||||
## Explicitly excluded
|
## Explicitly excluded
|
||||||
|
|
||||||
These E2 approvals do not cover direct PostgreSQL access, RLS probes, schema or
|
These E2 approvals cover only the two exact named production deployments and
|
||||||
role changes, connection/load saturation, recovery, production, adjacent
|
do not cover any other production target, direct PostgreSQL access, RLS
|
||||||
|
probes, schema or role changes, connection/load saturation, recovery, adjacent
|
||||||
services, real tenant identifiers, or collection of response bodies. E3 and
|
services, real tenant identifiers, or collection of response bodies. E3 and
|
||||||
P1/P2 each receive a separate approval package after E2 establishes the safe
|
P1/P2 each receive a separate approval package after E2 establishes the safe
|
||||||
execution path.
|
execution path.
|
||||||
|
|
|
||||||
|
|
@ -80,12 +80,8 @@ class Client:
|
||||||
self.args.base_url + path,
|
self.args.base_url + path,
|
||||||
data=raw,
|
data=raw,
|
||||||
method=method,
|
method=method,
|
||||||
headers={
|
headers=request_headers(token, self.args.engagement_id,
|
||||||
"Authorization": f"Bearer {token}",
|
self.args.correlation, payload),
|
||||||
"Content-Type": "application/json",
|
|
||||||
"User-Agent": f"whitehat-security/{self.args.engagement_id}",
|
|
||||||
"X-Correlation-ID": self.args.correlation,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
started = time.monotonic()
|
started = time.monotonic()
|
||||||
try:
|
try:
|
||||||
|
|
@ -141,6 +137,19 @@ def _p95(samples: list[float]) -> float:
|
||||||
return ordered[max(0, math.ceil(len(ordered) * .95) - 1)]
|
return ordered[max(0, math.ceil(len(ordered) * .95) - 1)]
|
||||||
|
|
||||||
|
|
||||||
|
def request_headers(token: str, engagement_id: str, correlation: str,
|
||||||
|
payload: dict[str, Any] | None) -> dict[str, str]:
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": f"whitehat-security/{engagement_id}",
|
||||||
|
"X-Correlation-ID": correlation,
|
||||||
|
}
|
||||||
|
if payload is not None:
|
||||||
|
headers["Idempotency-Key"] = str(payload["id"])
|
||||||
|
return headers
|
||||||
|
|
||||||
|
|
||||||
def event(event_id: str, tenant: str, correlation: str) -> dict[str, Any]:
|
def event(event_id: str, tenant: str, correlation: str) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"id": event_id,
|
"id": event_id,
|
||||||
|
|
@ -276,4 +285,3 @@ def main() -> None:
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ class Engagement:
|
||||||
end = _timestamp(self.raw["window_end"])
|
end = _timestamp(self.raw["window_end"])
|
||||||
expiry = _timestamp(self.raw["expires_at"])
|
expiry = _timestamp(self.raw["expires_at"])
|
||||||
approved = _timestamp(self.raw["approved_at"])
|
approved = _timestamp(self.raw["approved_at"])
|
||||||
|
if not self.raw["target_owner_acknowledged_at"]:
|
||||||
|
raise AuthorizationError("target-owner acknowledgement is pending")
|
||||||
acknowledged = _timestamp(self.raw["target_owner_acknowledged_at"])
|
acknowledged = _timestamp(self.raw["target_owner_acknowledged_at"])
|
||||||
if not approved <= current <= min(end, expiry):
|
if not approved <= current <= min(end, expiry):
|
||||||
raise AuthorizationError("engagement is outside its approved time/expiry window")
|
raise AuthorizationError("engagement is outside its approved time/expiry window")
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,15 @@ def test_event_is_synthetic_and_correlation_bound():
|
||||||
def test_p95_is_conservative_for_small_runs():
|
def test_p95_is_conservative_for_small_runs():
|
||||||
assert runner._p95([10, 20, 30]) == 30
|
assert runner._p95([10, 20, 30]) == 30
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_headers_bind_idempotency_key_to_event_id():
|
||||||
|
headers = runner.request_headers(
|
||||||
|
"secret-not-rendered", "eng-1", "corr-1", {"id": "event-1"}
|
||||||
|
)
|
||||||
|
assert headers["Idempotency-Key"] == "event-1"
|
||||||
|
assert headers["User-Agent"] == "whitehat-security/eng-1"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_headers_have_no_idempotency_key():
|
||||||
|
headers = runner.request_headers("secret", "eng-1", "corr-1", None)
|
||||||
|
assert "Idempotency-Key" not in headers
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue