security: harden Campaign delivery effects and reconciliation

This commit is contained in:
2026-07-21 17:14:33 +02:00
parent 057e660b17
commit 09c63de813
25 changed files with 2079 additions and 708 deletions

View File

@@ -6,15 +6,6 @@ from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from govoplan_core.mail.config import (
ImapConfig,
ImapServerConfig,
SmtpConfig,
SmtpServerConfig,
TransportCredentials,
normalize_split_transport_credentials,
)
class StrictModel(BaseModel):
model_config = ConfigDict(extra="forbid", populate_by_name=True)
@@ -115,37 +106,14 @@ class FieldDefinition(StrictModel):
can_override: bool = True
class MailServerCredentials(StrictModel):
smtp: TransportCredentials = Field(default_factory=TransportCredentials)
imap: TransportCredentials = Field(default_factory=TransportCredentials)
class MailProfileCapabilities(StrictModel):
smtp_available: bool = False
imap_available: bool = False
class ServerConfig(StrictModel):
mail_profile_id: str | None = None
inherit_smtp_credentials: bool = True
inherit_imap_credentials: bool = True
smtp: SmtpServerConfig | None = None
imap: ImapServerConfig | None = None
credentials: MailServerCredentials = Field(default_factory=MailServerCredentials)
@model_validator(mode="before")
@classmethod
def normalize_legacy_credentials(cls, value: Any) -> Any:
return normalize_split_transport_credentials(value)
def runtime_smtp_config(self) -> SmtpConfig | None:
if self.smtp is None:
return None
payload = self.smtp.model_dump(mode="json")
payload.update(self.credentials.smtp.model_dump(mode="json", exclude_none=True))
return SmtpConfig.model_validate(payload)
def runtime_imap_config(self) -> ImapConfig | None:
if self.imap is None:
return None
payload = self.imap.model_dump(mode="json")
payload.update(self.credentials.imap.model_dump(mode="json", exclude_none=True))
return ImapConfig.model_validate(payload)
profile_capabilities: MailProfileCapabilities = Field(default_factory=MailProfileCapabilities)
class RecipientConfig(StrictModel):