Extend Postbox access classification contract

This commit is contained in:
2026-07-31 18:21:36 +02:00
parent 50a8d459e7
commit e37d8fee94
+62 -1
View File
@@ -5,6 +5,8 @@ from dataclasses import dataclass, field
from datetime import datetime
from typing import Literal, Protocol, runtime_checkable
from govoplan_core.core.events import EventClassification
POSTBOX_MODULE_ID = "postbox"
CAPABILITY_POSTBOX_DIRECTORY = "postbox.directory"
@@ -14,9 +16,62 @@ CAPABILITY_POSTBOX_DELIVERY = "postbox.delivery"
CAPABILITY_POSTBOX_EVIDENCE = "postbox.evidence"
CAPABILITY_POSTBOX_ROUTING = "postbox.routing"
PostboxAction = Literal["discover", "read", "send", "acknowledge", "administer"]
PostboxAction = Literal[
"discover",
"read",
"send",
"reply",
"acknowledge",
"administer",
]
PostboxMessageListState = Literal["all", "unread", "read", "acknowledged"]
PostboxMessageAvailability = Literal["available", "withdrawn", "expired"]
PostboxBindingStatus = Literal[
"active",
"missing",
"not_effective",
"unit_missing",
"unit_inactive",
"unit_tenant_mismatch",
"function_missing",
"function_inactive",
"function_tenant_mismatch",
"function_reassigned",
"directory_unavailable",
]
POSTBOX_CLASSIFICATIONS: tuple[EventClassification, ...] = (
"public",
"internal",
"confidential",
"restricted",
)
_POSTBOX_CLASSIFICATION_RANK = {
value: rank for rank, value in enumerate(POSTBOX_CLASSIFICATIONS)
}
def normalize_postbox_classification(
value: str,
) -> EventClassification | None:
candidate = value.strip().casefold()
if candidate not in _POSTBOX_CLASSIFICATION_RANK:
return None
return candidate # type: ignore[return-value]
def postbox_classification_allows(
ceiling: str,
content: str,
) -> bool:
normalized_ceiling = normalize_postbox_classification(ceiling)
normalized_content = normalize_postbox_classification(content)
if normalized_ceiling is None or normalized_content is None:
return False
return (
_POSTBOX_CLASSIFICATION_RANK[normalized_content]
<= _POSTBOX_CLASSIFICATION_RANK[normalized_ceiling]
)
@dataclass(frozen=True, slots=True)
@@ -26,6 +81,9 @@ class PostboxActorRef:
selected_assignment_id: str | None = None
acting_for_account_id: str | None = None
authorized_actions: frozenset[PostboxAction] = frozenset()
authorized_classifications: frozenset[EventClassification] = frozenset(
{"public", "internal"}
)
@dataclass(frozen=True, slots=True)
@@ -91,6 +149,9 @@ class PostboxAccessDecisionRef:
selected_assignment_id: str | None = None
holder_count: int = 0
vacant: bool = True
classification: str = "internal"
classification_allowed: bool = True
binding_status: PostboxBindingStatus = "active"
@dataclass(frozen=True, slots=True)