Build authorization-gated tenancy evidence harness

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0260c-4067-7052-9647-ad000d576e38
This commit is contained in:
tegwick 2026-08-21 23:53:27 +02:00
parent 2c8e1d41ad
commit beab2a04d1
32 changed files with 1816 additions and 11 deletions

View file

@ -0,0 +1,83 @@
from __future__ import annotations
import json
from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
from urllib.parse import urlparse
class AuthorizationError(ValueError):
pass
REQUIRED = {
"engagement_id", "authorization_id", "authorizer", "approved_at", "expires_at",
"target", "target_owner", "environment", "source", "routes", "fixture_ids",
"credential_lane", "credential_role", "credential_max_ttl_seconds", "techniques",
"prohibited_techniques", "rate_limit_per_minute", "max_concurrency", "window_start",
"window_end", "operator_contact", "abort_contact", "posture_claim", "attacker_model",
"finding_destination", "target_owner_acknowledged_at",
}
@dataclass(frozen=True)
class Engagement:
raw: dict[str, Any]
@classmethod
def load(cls, path: str | Path, *, now: datetime | None = None) -> "Engagement":
data = json.loads(Path(path).read_text(encoding="utf-8"))
missing = sorted(REQUIRED - data.keys())
if missing:
raise AuthorizationError(f"incomplete engagement; missing: {', '.join(missing)}")
engagement = cls(data)
engagement.validate(now=now)
return engagement
def validate(self, *, now: datetime | None = None) -> None:
current = now or datetime.now(UTC)
start = _timestamp(self.raw["window_start"])
end = _timestamp(self.raw["window_end"])
expiry = _timestamp(self.raw["expires_at"])
approved = _timestamp(self.raw["approved_at"])
acknowledged = _timestamp(self.raw["target_owner_acknowledged_at"])
if not approved <= current <= min(end, expiry):
raise AuthorizationError("engagement is outside its approved time/expiry window")
if current < start:
raise AuthorizationError("engagement window has not started")
if acknowledged < approved:
raise AuthorizationError("target-owner acknowledgement predates approval")
if acknowledged > current:
raise AuthorizationError("target-owner acknowledgement is in the future")
if start < approved:
raise AuthorizationError("engagement window starts before approval")
if self.raw["max_concurrency"] != 1:
raise AuthorizationError("v0.1 permits exactly one in-flight API/database operation")
if not 1 <= self.raw["rate_limit_per_minute"] <= 60:
raise AuthorizationError("API rate ceiling must be between 1 and 60 per minute")
if self.raw["environment"] == "production" and not self.raw.get("production_approval"):
raise AuthorizationError("production requires production-specific approval")
if self.raw["finding_destination"] != "risk-nexus":
raise AuthorizationError("finding destination must be risk-nexus")
parsed = urlparse(self.raw["target"])
if parsed.scheme and parsed.scheme not in {"http", "https", "postgresql"}:
raise AuthorizationError("unsupported target scheme")
if not self.raw["fixture_ids"]:
raise AuthorizationError("at least one disposable fixture id is required")
if not 1 <= self.raw["credential_max_ttl_seconds"] <= 3600:
raise AuthorizationError("credential TTL must be between 1 and 3600 seconds")
def permits(self, *, technique: str, route: str) -> None:
if technique not in self.raw["techniques"]:
raise AuthorizationError(f"technique not authorized: {technique}")
if route not in self.raw["routes"]:
raise AuthorizationError(f"route not authorized: {route}")
def _timestamp(value: str) -> datetime:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
if parsed.tzinfo is None:
raise AuthorizationError("engagement timestamps must include a timezone")
return parsed.astimezone(UTC)