Define governed platform event envelope
Some checks failed
Dependency Audit / dependency-audit (push) Has been cancelled
Module Matrix / module-matrix (push) Has been cancelled

This commit is contained in:
2026-07-10 17:48:33 +02:00
parent 0a130962d3
commit 81f0f649b5
3 changed files with 142 additions and 3 deletions

View File

@@ -7,7 +7,7 @@ from contextvars import ContextVar
from dataclasses import dataclass, field
from datetime import datetime, timezone
import re
from typing import Any
from typing import Any, Literal
import uuid
@@ -31,6 +31,39 @@ class EventTrace:
causation_id: str | None = None
EventClassification = Literal["public", "internal", "confidential", "restricted"]
@dataclass(frozen=True, slots=True)
class EventActorRef:
type: str
id: str | None = None
label: str | None = None
def to_dict(self) -> dict[str, Any]:
return _compact_dict({"type": self.type, "id": self.id, "label": self.label})
@dataclass(frozen=True, slots=True)
class EventTenantRef:
id: str
slug: str | None = None
label: str | None = None
def to_dict(self) -> dict[str, Any]:
return _compact_dict({"id": self.id, "slug": self.slug, "label": self.label})
@dataclass(frozen=True, slots=True)
class EventObjectRef:
type: str
id: str | None = None
label: str | None = None
def to_dict(self) -> dict[str, Any]:
return _compact_dict({"type": self.type, "id": self.id, "label": self.label})
_current_trace: ContextVar[EventTrace | None] = ContextVar("govoplan_event_trace", default=None)
@@ -43,6 +76,27 @@ class PlatformEvent:
event_id: str = field(default_factory=new_event_id)
correlation_id: str | None = None
causation_id: str | None = None
actor: EventActorRef | None = None
tenant: EventTenantRef | None = None
subject: EventObjectRef | None = None
resource: EventObjectRef | None = None
classification: EventClassification = "internal"
def to_dict(self) -> dict[str, Any]:
return {
"type": self.type,
"module_id": self.module_id,
"payload": dict(self.payload),
"occurred_at": self.occurred_at.isoformat(),
"event_id": self.event_id,
"correlation_id": self.correlation_id,
"causation_id": self.causation_id,
"actor": self.actor.to_dict() if self.actor else None,
"tenant": self.tenant.to_dict() if self.tenant else None,
"subject": self.subject.to_dict() if self.subject else None,
"resource": self.resource.to_dict() if self.resource else None,
"classification": self.classification,
}
EventHandler = Callable[[PlatformEvent], None]
@@ -90,6 +144,11 @@ def ensure_event_trace(event: PlatformEvent) -> PlatformEvent:
event_id=event.event_id,
correlation_id=trace.correlation_id,
causation_id=trace.causation_id,
actor=event.actor,
tenant=event.tenant,
subject=event.subject,
resource=event.resource,
classification=event.classification,
)
@@ -107,3 +166,7 @@ class EventBus:
handler(traced)
for handler in self._subscribers.get("*", ()):
handler(traced)
def _compact_dict(value: Mapping[str, Any]) -> dict[str, Any]:
return {key: item for key, item in value.items() if item is not None}