Enforce bounded operation guardrails
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a028de-e2c8-7732-8521-46a7fc5db82f
This commit is contained in:
parent
c384f60530
commit
26934e25b9
51 changed files with 1843 additions and 472 deletions
68
src/activity_core/audit_projection.py
Normal file
68
src/activity_core/audit_projection.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
"""Bounded, non-secret projections for durable audit surfaces."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
_SENSITIVE_KEYS = frozenset(
|
||||
{
|
||||
"api_key",
|
||||
"api_token",
|
||||
"access_token",
|
||||
"refresh_token",
|
||||
"authorization",
|
||||
"client_secret",
|
||||
"cookie",
|
||||
"credential",
|
||||
"credentials",
|
||||
"messages",
|
||||
"model_messages",
|
||||
"password",
|
||||
"private_key",
|
||||
"provider_payload",
|
||||
"provider_response",
|
||||
"raw_output",
|
||||
"raw_output_preview",
|
||||
"raw_prompt",
|
||||
"rendered_prompt",
|
||||
"secret",
|
||||
"token",
|
||||
"tool_error",
|
||||
"tool_output",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def bounded_audit_projection(
|
||||
value: Any,
|
||||
*,
|
||||
max_depth: int = 8,
|
||||
max_items: int = 100,
|
||||
max_string: int = 4000,
|
||||
) -> Any:
|
||||
"""Return a JSON-like audit projection without raw or credential fields.
|
||||
|
||||
The projection is intentionally lossy. Workflow evaluation uses the full
|
||||
in-memory context; only the durable audit copy is bounded here.
|
||||
"""
|
||||
|
||||
def project(item: Any, depth: int) -> Any:
|
||||
if depth > max_depth:
|
||||
return "<depth-limit>"
|
||||
if item is None or isinstance(item, (bool, int, float)):
|
||||
return item
|
||||
if isinstance(item, str):
|
||||
return item[:max_string]
|
||||
if isinstance(item, dict):
|
||||
result: dict[str, Any] = {}
|
||||
for raw_key, child in list(item.items())[:max_items]:
|
||||
key = str(raw_key)
|
||||
if key.strip().lower() in _SENSITIVE_KEYS:
|
||||
continue
|
||||
result[key] = project(child, depth + 1)
|
||||
return result
|
||||
if isinstance(item, (list, tuple)):
|
||||
return [project(child, depth + 1) for child in item[:max_items]]
|
||||
return str(item)[:max_string]
|
||||
|
||||
return project(value, 0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue