34 lines
1.4 KiB
Python
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 ""
|