fastapi-gsap/gsap_broker/chronicle/client.py
2026-04-08 13:49:18 -04:00

34 lines
1.4 KiB
Python

"""Chronicle CloudEvents client. Optional per GSAP §1.4.
# TODO(M6.2): replace this Forgejo-format webhook poster with a direct
# gRPC RecordEvent call once Chronicle exposes the Rekor-backed gRPC
# surface (per ADR-001 D2 + SPEC-CHRONICLE-0001 §8.5). The same pattern
# is duplicated in capstone/apps/governance/chronicle.py and
# capstone/apps/connectors/chronicle.py; all four will be replaced
# together when M6.2 ships.
"""
import hashlib, json, logging
from datetime import datetime, UTC
import httpx
from gsap_broker.settings import settings
logger = logging.getLogger(__name__)
async def emit(kind: str, payload: dict) -> str:
url = settings.chronicle_webhook_url
if not url:
return ""
try:
event_json = json.dumps({"kind": kind, **payload}, sort_keys=True, default=str)
cid = "sha256:" + hashlib.sha256(event_json.encode()).hexdigest()
async with httpx.AsyncClient(timeout=5.0) as client:
await client.post(url, json={
"pusher": {"login": payload.get("principal_did", settings.broker_did)},
"ref": f"refs/gsap/{kind}",
"repository": {"full_name": "gsap-broker/governance"},
"commits": [{"message": f"{kind}: {json.dumps(payload, default=str)}"}],
}, headers={"X-Forgejo-Event": "push"})
return cid
except Exception as e:
logger.warning(f"Chronicle emit failed: {kind}: {e}")
return ""