41 lines
1.4 KiB
Python
41 lines
1.4 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from datetime import datetime
|
|
from typing import List
|
|
|
|
from .models import PlanDelta
|
|
|
|
|
|
class GovernanceLedger:
|
|
def __init__(self) -> None:
|
|
self.chain: List[dict] = [] # each entry: {index, hash, prev_hash, delta, ts}
|
|
|
|
def _hash_entry(self, prev_hash: str, entry: dict) -> str:
|
|
data = json.dumps({"prev_hash": prev_hash, "entry": entry}, sort_keys=True)
|
|
return hashlib.sha256(data.encode("utf-8")).hexdigest()
|
|
|
|
def append(self, delta: PlanDelta) -> str:
|
|
prev_hash = self.chain[-1]["hash"] if self.chain else "0" * 64
|
|
entry = {
|
|
"version": delta.version,
|
|
"plan": delta.plan,
|
|
"provenance": delta.provenance,
|
|
"signature": delta.signature,
|
|
"ts": datetime.utcnow().isoformat() + "Z",
|
|
}
|
|
entry_hash = self._hash_entry(prev_hash, entry)
|
|
self.chain.append({"index": len(self.chain), "hash": entry_hash, "prev_hash": prev_hash, "entry": entry})
|
|
return entry_hash
|
|
|
|
def root(self) -> str:
|
|
if not self.chain:
|
|
return "0" * 64
|
|
return self.chain[-1]["hash"]
|
|
|
|
def attest(self, delta: PlanDelta, key: str = "ledger") -> str:
|
|
# Lightweight attest placeholder
|
|
payload = delta.to_json()
|
|
return hashlib.sha256((payload + "::" + key).encode("utf-8")).hexdigest()
|