diff --git a/src/warden/audit.py b/src/warden/audit.py index ec81685..1132c74 100644 --- a/src/warden/audit.py +++ b/src/warden/audit.py @@ -4,6 +4,8 @@ Every ops-warden action appends a JSONL event. Secret values are rejected at wri """ from __future__ import annotations +from warden.clock_attribution import recording_time + import json import os import re @@ -85,6 +87,7 @@ def record_event( if value is None: continue event[key] = value + event.update(recording_time()) _assert_metadata_safe(json.dumps(event, default=str)) state_dir.mkdir(parents=True, exist_ok=True) path = _audit_path(state_dir) diff --git a/src/warden/clock_attribution.py b/src/warden/clock_attribution.py new file mode 100644 index 0000000..6f7c04a --- /dev/null +++ b/src/warden/clock_attribution.py @@ -0,0 +1,17 @@ +"""Optional recording-time evidence; original local timestamps remain intact.""" +import os + +def recording_time(): + if not os.environ.get('WARDEN_CLOCK_TRUST_FILE'): + return {} + try: + from railiance_clock.attribution import from_environment + result = from_environment('WARDEN_CLOCK_TRUST_FILE') + # These are time observations, not raw credentials. Keep audit metadata + # within the existing detector's restrictions without weakening it. + if result.get('railiance_time', {}).get('status') == 'usable': + result['railiance_time'].pop('epoch', None) + result['railiance_time'].pop('sample_id', None) + return result + except (ImportError, OSError, ValueError): + return {'railiance_time': {'status': 'unavailable', 'kind': 'recording_time'}} diff --git a/src/warden/proxy.py b/src/warden/proxy.py index 65e4455..ab451a9 100644 --- a/src/warden/proxy.py +++ b/src/warden/proxy.py @@ -22,6 +22,8 @@ This module shells out but never *interprets* secret bytes in the ``--fetch`` pa """ from __future__ import annotations +from warden.clock_attribution import recording_time + import json import os import re @@ -156,6 +158,7 @@ def write_audit( "policy_decision_id": decision_id, "exit_code": exit_code, } + record.update(recording_time()) with log_path.open("a") as f: f.write(json.dumps(record) + "\n") try: