File size: 5,471 Bytes
5729d24 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | """
Primordial OS Runtime β Audit Store (Phase 10)
Safe JSONL file writer and reader for hash-chained audit events.
Writes one JSON object per line (JSONL). Parent directory must exist before
writing. Hidden file paths are rejected. File is created on first append;
existing content is preserved on subsequent appends.
No raw prompts, user input, PHI, PII, or clinical content is written β
only the structural runtime fields that already exist in AuditEvent.
Pre-validation architecture. Not clinical software. Not a medical device.
No health-domain inference, treatment, or decision-making functionality
is present or intended.
"""
from __future__ import annotations
import json
from pathlib import Path
from primordial_os.audit_log import AuditEvent, verify_audit_chain
# ---------------------------------------------------------------------------
# Serialization
# ---------------------------------------------------------------------------
def audit_event_to_dict(event: AuditEvent) -> dict:
"""Return a plain dict of structural runtime fields only.
Explicit field enumeration ensures no unexpected keys are written.
No raw prompts, user input, PHI, PII, or clinical content is included.
"""
return {
"timestamp": event.timestamp,
"event_type": event.event_type,
"final_gate_state": event.final_gate_state,
"hard_stop": event.hard_stop,
"resonance": event.resonance,
"pressure_adjusted_stability": event.pressure_adjusted_stability,
"max_oam_severity": event.max_oam_severity,
"summary": event.summary,
"previous_hash": event.previous_hash,
"current_hash": event.current_hash,
}
def audit_event_from_dict(data: dict) -> AuditEvent:
"""Reconstruct an AuditEvent from a plain dict (e.g. parsed from JSONL)."""
return AuditEvent(
timestamp=data["timestamp"],
event_type=data["event_type"],
final_gate_state=data["final_gate_state"],
hard_stop=data["hard_stop"],
resonance=data["resonance"],
pressure_adjusted_stability=data["pressure_adjusted_stability"],
max_oam_severity=data["max_oam_severity"],
summary=data["summary"],
previous_hash=data["previous_hash"],
current_hash=data["current_hash"],
)
# ---------------------------------------------------------------------------
# Path safety
# ---------------------------------------------------------------------------
def _validate_write_path(path: Path) -> None:
"""Raise for unsafe or invalid write targets.
Checks:
- hidden file paths (name starts with '.')
- parent directory does not exist
"""
if path.name.startswith("."):
raise ValueError(f"Hidden file paths are not permitted: {path}")
if not path.parent.exists():
raise FileNotFoundError(
f"Parent directory does not exist: {path.parent}"
)
# ---------------------------------------------------------------------------
# JSONL I/O
# ---------------------------------------------------------------------------
def append_audit_event_jsonl(path: str | Path, event: AuditEvent) -> None:
"""Append one AuditEvent as a single JSON line to the JSONL file at path.
Safety requirements:
- Parent directory must exist; will not be created automatically.
- Hidden file paths (name starts with '.') are rejected.
- File is created if absent; existing lines are never modified.
- Encoding: UTF-8.
- Format: one compact JSON object per line, keys sorted, no trailing spaces.
- No raw prompts, PHI, PII, or clinical content is written.
"""
p = Path(path)
_validate_write_path(p)
line = json.dumps(
audit_event_to_dict(event),
sort_keys=True,
separators=(",", ":"),
ensure_ascii=False,
)
with p.open("a", encoding="utf-8") as f:
f.write(line + "\n")
def read_audit_events_jsonl(path: str | Path) -> tuple[AuditEvent, ...]:
"""Read all AuditEvents from a JSONL file and return them as a tuple.
Events are returned in file order (append order).
Raises:
FileNotFoundError β if the file does not exist.
ValueError β if any line contains malformed JSON.
"""
p = Path(path)
if not p.exists():
raise FileNotFoundError(f"Audit log file not found: {p}")
events: list[AuditEvent] = []
with p.open("r", encoding="utf-8") as f:
for line_num, raw_line in enumerate(f, start=1):
line = raw_line.strip()
if not line:
continue
try:
data = json.loads(line)
except json.JSONDecodeError as exc:
raise ValueError(
f"Malformed JSON on line {line_num} of {p}: {exc}"
) from exc
events.append(audit_event_from_dict(data))
return tuple(events)
def verify_audit_jsonl(path: str | Path) -> bool:
"""Return True if the JSONL file at path contains a valid, unbroken audit chain.
Returns False β without raising β when:
- the file is missing
- the chain hash linkage is broken
- any event hash does not match its stored fields
An empty file is treated as a valid (empty) chain and returns True.
"""
p = Path(path)
try:
events = read_audit_events_jsonl(p)
except FileNotFoundError:
return False
return verify_audit_chain(events)
|