key-amnesia 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ """key-amnesia: encrypted vault with human-prompt routing and output scrubbing."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version as _version
4
+
5
+ try:
6
+ __version__ = _version("key-amnesia")
7
+ except PackageNotFoundError:
8
+ __version__ = "0.0.0"
@@ -0,0 +1,4 @@
1
+ from key_amnesia.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
key_amnesia/audit.py ADDED
@@ -0,0 +1,55 @@
1
+ """JSONL audit log — never records secret values."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from datetime import datetime, timezone
7
+ from pathlib import Path
8
+ from typing import Any, Iterable
9
+
10
+ from key_amnesia.paths import audit_log_path
11
+
12
+ VALID_ROUTES = frozenset({"inline", "spawned-console", "guard-session"})
13
+ VALID_RESULTS = frozenset({"allowed", "denied", "timeout"})
14
+
15
+
16
+ def _utc_now_iso() -> str:
17
+ return datetime.now(timezone.utc).replace(microsecond=0).isoformat()
18
+
19
+
20
+ def audit_event(
21
+ action: str,
22
+ *,
23
+ secret_names: Iterable[str] | None = None,
24
+ command: list[str] | str | None = None,
25
+ route: str,
26
+ result: str,
27
+ reason: str = "",
28
+ path: Path | None = None,
29
+ ) -> dict[str, Any]:
30
+ """Append one audit record. Never includes secret values or passwords."""
31
+ if route not in VALID_ROUTES:
32
+ raise ValueError(f"Invalid audit route: {route}")
33
+ if result not in VALID_RESULTS:
34
+ raise ValueError(f"Invalid audit result: {result}")
35
+
36
+ if isinstance(command, list):
37
+ cmd_field: str | list[str] | None = list(command)
38
+ else:
39
+ cmd_field = command
40
+
41
+ record: dict[str, Any] = {
42
+ "timestamp": _utc_now_iso(),
43
+ "action": action,
44
+ "secret_names": list(secret_names or []),
45
+ "command": cmd_field,
46
+ "route": route,
47
+ "result": result,
48
+ "reason": reason,
49
+ }
50
+
51
+ p = path or audit_log_path()
52
+ p.parent.mkdir(parents=True, exist_ok=True)
53
+ with p.open("a", encoding="utf-8") as f:
54
+ f.write(json.dumps(record, separators=(",", ":")) + "\n")
55
+ return record