Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a0217e-8c4c-7383-be6b-f50a6e485306
276 lines
9.3 KiB
Python
276 lines
9.3 KiB
Python
"""Non-secret evidence writer.
|
|
|
|
Every privileged or noteworthy action emits an evidence record to a local
|
|
append-only JSONL log and, best-effort, to the State Hub progress API. Records
|
|
are scrubbed of anything that looks like a secret value before they are written.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import urllib.error
|
|
import urllib.request
|
|
import uuid
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from secrets_engine.errors import DecisionError, SecretsEngineError
|
|
from secrets_engine.redact import looks_secret, redact_text
|
|
|
|
# Keys that must never carry a value into evidence regardless of nesting.
|
|
_FORBIDDEN_VALUE_KEYS = {"value", "secret", "token", "password", "raw"}
|
|
|
|
|
|
def _scrub(obj: Any) -> Any:
|
|
"""Recursively drop secret-looking keys and redact token shapes in strings."""
|
|
if isinstance(obj, dict):
|
|
out = {}
|
|
for k, v in obj.items():
|
|
if k.lower() in _FORBIDDEN_VALUE_KEYS or looks_secret(k):
|
|
out[k] = "<omitted: non-secret evidence only>"
|
|
else:
|
|
out[k] = _scrub(v)
|
|
return out
|
|
if isinstance(obj, list):
|
|
return [_scrub(v) for v in obj]
|
|
if isinstance(obj, str):
|
|
return redact_text(obj)
|
|
return obj
|
|
|
|
|
|
@dataclass
|
|
class EvidenceWriter:
|
|
evidence_dir: Path
|
|
hub_url: str = ""
|
|
topic_id: str = ""
|
|
workstream_id: str = ""
|
|
author: str = "secrets-engine"
|
|
repo_slug: str = "secrets-engine"
|
|
actor: str = field(default_factory=lambda: os.environ.get("USER", "unknown"))
|
|
|
|
def __post_init__(self) -> None:
|
|
self.evidence_dir = Path(self.evidence_dir)
|
|
|
|
def _log_path(self) -> Path:
|
|
self.evidence_dir.mkdir(parents=True, exist_ok=True)
|
|
day = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
return self.evidence_dir / f"evidence-{day}.jsonl"
|
|
|
|
def _append_local(self, record: dict[str, Any]) -> None:
|
|
"""Append one record before any best-effort external delivery."""
|
|
path = self._log_path()
|
|
with path.open("a", encoding="utf-8") as fh:
|
|
fh.write(json.dumps(record, sort_keys=True) + "\n")
|
|
|
|
def record(
|
|
self,
|
|
action: str,
|
|
*,
|
|
result: str,
|
|
catalog_id: str = "",
|
|
stage: str = "",
|
|
decision_id: str = "",
|
|
detail: dict[str, Any] | None = None,
|
|
hub: bool = True,
|
|
) -> dict[str, Any]:
|
|
"""Append one non-secret evidence record. Returns the stored record."""
|
|
record_id = str(uuid.uuid4())
|
|
hub_requested = bool(hub and self.hub_url)
|
|
record = {
|
|
"record_id": record_id,
|
|
"ts": datetime.now(timezone.utc).isoformat(),
|
|
"action": action,
|
|
"result": result,
|
|
"actor": self.actor,
|
|
"catalog_id": catalog_id,
|
|
"stage": stage,
|
|
"decision_id": decision_id,
|
|
"detail": _scrub(detail or {}),
|
|
"hub_delivery_requested": hub_requested,
|
|
}
|
|
self._append_local(record)
|
|
if hub_requested:
|
|
delivery = self._post_hub(
|
|
action,
|
|
result,
|
|
catalog_id,
|
|
stage,
|
|
decision_id,
|
|
record_id=record_id,
|
|
)
|
|
# Append-only companion evidence makes an unavailable State Hub
|
|
# visible without rewriting or delaying the primary local record.
|
|
self._append_local(
|
|
{
|
|
"record_id": str(uuid.uuid4()),
|
|
"related_record_id": record_id,
|
|
"ts": datetime.now(timezone.utc).isoformat(),
|
|
"action": "evidence-delivery",
|
|
"result": delivery.status,
|
|
"actor": self.actor,
|
|
"catalog_id": catalog_id,
|
|
"stage": stage,
|
|
"decision_id": decision_id,
|
|
"detail": {"outbox_id": delivery.outbox_id}
|
|
if delivery.outbox_id
|
|
else {},
|
|
"hub_delivery_requested": False,
|
|
}
|
|
)
|
|
return record
|
|
|
|
def _post_hub(
|
|
self,
|
|
action: str,
|
|
result: str,
|
|
catalog_id: str,
|
|
stage: str,
|
|
decision_id: str,
|
|
*,
|
|
record_id: str,
|
|
) -> "HubDelivery":
|
|
"""Best-effort progress note; return a non-secret delivery outcome."""
|
|
if not self.topic_id:
|
|
return HubDelivery("skipped-no-topic")
|
|
summary = f"secrets-engine {action}: {result}"
|
|
if catalog_id:
|
|
summary += f" [{catalog_id}{'/' + stage if stage else ''}]"
|
|
payload: dict[str, Any] = {
|
|
"topic_id": self.topic_id,
|
|
"event_type": "note",
|
|
"summary": summary,
|
|
"author": self.author,
|
|
}
|
|
if self.workstream_id:
|
|
payload["workplan_id"] = self.workstream_id
|
|
if decision_id:
|
|
payload["detail"] = {"decision_id": decision_id, "catalog_id": catalog_id}
|
|
try:
|
|
idempotency_key = f"secrets-engine:{record_id}"
|
|
req = urllib.request.Request(
|
|
self.hub_url.rstrip("/") + "/progress/",
|
|
data=json.dumps(payload).encode(),
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
"Idempotency-Key": idempotency_key,
|
|
"X-StateHub-Source-Agent": self.author,
|
|
"X-StateHub-Repo-Slug": self.repo_slug,
|
|
},
|
|
method="POST",
|
|
)
|
|
response = urllib.request.urlopen(req, timeout=3)
|
|
body = response.read()
|
|
status = getattr(response, "status", 200)
|
|
if status == 202:
|
|
try:
|
|
receipt = json.loads(body or b"{}")
|
|
except (json.JSONDecodeError, TypeError):
|
|
receipt = {}
|
|
if isinstance(receipt, dict) and receipt.get("queued") is True:
|
|
outbox_id = receipt.get("outbox_id", "")
|
|
if isinstance(outbox_id, str):
|
|
try:
|
|
if str(uuid.UUID(outbox_id)) == outbox_id:
|
|
return HubDelivery("queued", outbox_id=outbox_id)
|
|
except ValueError:
|
|
pass
|
|
return HubDelivery("failed")
|
|
return HubDelivery("delivered")
|
|
except (urllib.error.URLError, OSError, ValueError):
|
|
# Hub being offline must never block secret work or leak anything.
|
|
return HubDelivery("failed")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class HubDelivery:
|
|
"""Non-secret outcome returned by State Hub or its edge relay."""
|
|
|
|
status: str
|
|
outbox_id: str = ""
|
|
|
|
|
|
@dataclass
|
|
class PrivilegedActionEvidence:
|
|
"""Record one privileged command's attempt, approval, and terminal result."""
|
|
|
|
writer: EvidenceWriter
|
|
action: str
|
|
catalog_id: str
|
|
stage: str
|
|
decision_ref: str = ""
|
|
approval_required: bool = False
|
|
detail: dict[str, Any] = field(default_factory=dict)
|
|
decision_id: str = ""
|
|
approval_status: str = "pending"
|
|
completed: bool = False
|
|
|
|
def __post_init__(self) -> None:
|
|
if not self.approval_required:
|
|
self.approval_status = "not-required"
|
|
|
|
def _detail(self, extra: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
merged = dict(self.detail)
|
|
merged.update(
|
|
{
|
|
"approval_status": self.approval_status,
|
|
"decision_ref": self.decision_ref,
|
|
}
|
|
)
|
|
if extra:
|
|
merged.update(extra)
|
|
return merged
|
|
|
|
def __enter__(self) -> "PrivilegedActionEvidence":
|
|
self.writer.record(
|
|
self.action,
|
|
result="attempt",
|
|
catalog_id=self.catalog_id,
|
|
stage=self.stage,
|
|
detail=self._detail(),
|
|
)
|
|
return self
|
|
|
|
def mark_approved(self, decision: object | None) -> None:
|
|
if decision is None:
|
|
self.approval_status = "not-required"
|
|
return
|
|
self.decision_id = str(getattr(decision, "id", ""))
|
|
self.approval_status = "approved"
|
|
|
|
def finish(
|
|
self, result: str, *, detail: dict[str, Any] | None = None
|
|
) -> dict[str, Any]:
|
|
self.completed = True
|
|
return self.writer.record(
|
|
self.action,
|
|
result=result,
|
|
catalog_id=self.catalog_id,
|
|
stage=self.stage,
|
|
decision_id=self.decision_id,
|
|
detail=self._detail(detail),
|
|
)
|
|
|
|
def __exit__(self, exc_type, exc, _traceback) -> bool:
|
|
if exc_type is None:
|
|
if not self.completed:
|
|
self.finish("failed-incomplete")
|
|
return False
|
|
if isinstance(exc, DecisionError):
|
|
self.approval_status = "rejected"
|
|
if isinstance(exc, (KeyboardInterrupt, SystemExit)):
|
|
result = "interrupted"
|
|
elif isinstance(exc, SecretsEngineError):
|
|
result = f"failed-{type(exc).__name__}"
|
|
else:
|
|
result = "failed-unexpected"
|
|
self.writer.record(
|
|
self.action,
|
|
result=result,
|
|
catalog_id=self.catalog_id,
|
|
stage=self.stage,
|
|
decision_id=self.decision_id,
|
|
detail=self._detail({"error_type": type(exc).__name__}),
|
|
)
|
|
return False
|