Prepare GovOPlaN self-hosted release workflow
Some checks failed
Dependency Audit / dependency-audit (push) Failing after 50s
Module Matrix / module-matrix (push) Failing after 49s

This commit is contained in:
2026-07-10 21:57:22 +02:00
parent 8dd5123aab
commit 94236a7d7e
51 changed files with 3576 additions and 803 deletions

View File

@@ -1,12 +1,14 @@
from __future__ import annotations
from collections.abc import Mapping
from uuid import uuid4
from typing import Any
from sqlalchemy.orm import Session
from govoplan_core.auth import ApiPrincipal
from govoplan_core.core.change_sequence import record_change
from govoplan_core.core.access import AuditEvent, AuditRecordRef, AuditRecorder, CAPABILITY_AUDIT_RECORDER
from govoplan_core.core.events import (
EventActorRef,
EventObjectRef,
@@ -16,8 +18,8 @@ from govoplan_core.core.events import (
normalize_trace_id,
publish_platform_event,
)
from govoplan_core.core.runtime import get_registry
from govoplan_core.privacy.retention import sanitize_audit_details_for_policy
from govoplan_audit.backend.db.models import AuditLog
AUDIT_MODULE_ID = "audit"
@@ -47,6 +49,7 @@ _ACTION_MODULE_PREFIXES = {
"configuration_change": "access",
"configuration_package": "access",
"group": "access",
"idm": "idm",
"profile": "access",
"role": "access",
"system_access": "access",
@@ -169,7 +172,33 @@ def _module_id_for_audit_action(action: str) -> str:
return _ACTION_MODULE_PREFIXES.get(prefix, prefix or AUDIT_MODULE_ID)
def _publish_audit_platform_event(item: AuditLog) -> None:
def _audit_recorder() -> AuditRecorder:
registry = get_registry()
if registry is None or not hasattr(registry, "has_capability") or not registry.has_capability(CAPABILITY_AUDIT_RECORDER):
return _NullAuditRecorder()
capability = registry.require_capability(CAPABILITY_AUDIT_RECORDER)
if not isinstance(capability, AuditRecorder):
raise RuntimeError("Audit recorder capability is invalid")
return capability
class _NullAuditRecorder:
def record_event(self, session: object, event: AuditEvent) -> AuditRecordRef:
del session
return AuditRecordRef(
id=str(uuid4()),
scope=event.scope,
tenant_id=event.tenant_id,
user_id=event.user_id,
api_key_id=event.api_key_id,
action=event.action,
object_type=event.resource_type,
object_id=event.resource_id,
details=dict(event.details or {}),
)
def _publish_audit_platform_event(item: AuditRecordRef) -> None:
trace = _compact_trace(item.details.get("_trace") if isinstance(item.details, Mapping) else None)
publish_platform_event(
PlatformEvent(
@@ -206,7 +235,7 @@ def audit_event(
correlation_id: str | None = None,
causation_id: str | None = None,
commit: bool = False,
) -> AuditLog:
) -> AuditRecordRef:
"""Persist one audit event.
The function deliberately accepts primitive IDs so it can be used from API
@@ -227,18 +256,17 @@ def audit_event(
trace,
)
item = AuditLog(
item = _audit_recorder().record_event(session, AuditEvent(
event_type=action,
action=action,
scope=scope,
tenant_id=tenant_id,
user_id=user_id,
api_key_id=api_key_id,
action=action,
object_type=object_type,
object_id=object_id,
resource_type=object_type,
resource_id=object_id,
details=stored_details,
)
session.add(item)
session.flush()
))
record_change(
session,
module_id=AUDIT_MODULE_ID,
@@ -269,7 +297,7 @@ def audit_from_principal(
correlation_id: str | None = None,
causation_id: str | None = None,
commit: bool = False,
) -> AuditLog:
) -> AuditRecordRef:
return audit_event(
session,
tenant_id=principal.tenant_id,