# sovereign_audit_chain.py from __future__ import annotations import json import hashlib import os from typing import Dict, Any, List AUDIT_CHAIN_FILE = "sovereign_audit_chain.jsonl" def _hash(data: str) -> str: return hashlib.sha256(data.encode("utf-8")).hexdigest() def _serialize(obj: Dict[str, Any]) -> str: return json.dumps(obj, sort_keys=True, ensure_ascii=False) def _load_chain() -> List[Dict[str, Any]]: if not os.path.exists(AUDIT_CHAIN_FILE): return [] with open(AUDIT_CHAIN_FILE, "r", encoding="utf-8") as f: return [json.loads(line) for line in f if line.strip()] def _get_last_hash(chain: List[Dict[str, Any]]) -> str: if not chain: return "GENESIS" return chain[-1]["hash"] def append_audit_event(event: Dict[str, Any]) -> Dict[str, Any]: chain = _load_chain() prev_hash = _get_last_hash(chain) record = { "event": event, "prev_hash": prev_hash, } record_str = _serialize(record) current_hash = _hash(record_str) record["hash"] = current_hash with open(AUDIT_CHAIN_FILE, "a", encoding="utf-8") as f: f.write(json.dumps(record, ensure_ascii=False) + "\n") return { "ok": True, "hash": current_hash, "prev_hash": prev_hash, } def verify_chain() -> Dict[str, Any]: chain = _load_chain() if not chain: return {"ok": True, "message": "empty_chain"} prev_hash = "GENESIS" for idx, record in enumerate(chain): expected_prev = record.get("prev_hash") if expected_prev != prev_hash: return { "ok": False, "error": "broken_chain", "index": idx, } record_copy = { "event": record["event"], "prev_hash": record["prev_hash"], } recalculated = _hash(_serialize(record_copy)) if recalculated != record.get("hash"): return { "ok": False, "error": "tampered_record", "index": idx, } prev_hash = record["hash"] return { "ok": True, "length": len(chain), "status": "valid", }