feat: govern legacy archive encryption

This commit is contained in:
2026-08-20 12:24:36 +02:00
parent d5b874c469
commit 75e8f864a7
19 changed files with 1102 additions and 24 deletions
+53 -2
View File
@@ -13,6 +13,10 @@ from govoplan_campaign.backend.campaign.mail_profile_boundary import (
CAMPAIGN_MAIL_SERVER_KEYS,
campaign_mail_profile_id,
)
from govoplan_campaign.backend.archive_encryption import (
CampaignArchiveEncryptionError,
stamp_legacy_zipcrypto_acknowledgements,
)
from govoplan_campaign.backend.db.models import (
Campaign,
CampaignIssue,
@@ -388,7 +392,9 @@ def _update_campaign_version_detail_response(
autosave: bool,
audit_action: str,
) -> CampaignVersionDetailResponse:
_get_campaign_for_principal(session, campaign_id, principal, write=True)
campaign = _get_campaign_for_principal(
session, campaign_id, principal, write=True
)
current_version = _get_version_for_tenant(session, version_id, principal.tenant_id)
if payload.base_revision is None:
error = MissingPreconditionError(
@@ -421,9 +427,40 @@ def _update_campaign_version_detail_response(
) from exc
if _recipient_sections_changed(current_version.raw_json, payload.campaign_json):
_require_permission(principal, "campaigns:recipient:write")
acknowledgements: list[dict[str, Any]] = []
try:
payload.campaign_json, acknowledgements = (
stamp_legacy_zipcrypto_acknowledgements(
session,
campaign,
current_version.raw_json
if isinstance(current_version.raw_json, dict)
else {},
payload.campaign_json,
principal=principal,
)
)
except CampaignArchiveEncryptionError as exc:
audit_from_principal(
session,
principal,
action="campaign.archive_encryption_denied",
object_type="campaign_version",
object_id=version_id,
details={"campaign_id": campaign_id, "reason": str(exc)},
commit=True,
)
raise HTTPException(
status_code=(
status.HTTP_403_FORBIDDEN
if "Missing scope:" in str(exc)
else status.HTTP_422_UNPROCESSABLE_CONTENT
),
detail=str(exc),
) from exc
_require_mail_profile_use_if_needed(principal, payload.campaign_json)
try:
return _campaign_version_detail_response(
result = _campaign_version_detail_response(
session,
principal,
campaign_id,
@@ -462,9 +499,23 @@ def _update_campaign_version_detail_response(
}
),
"legacy_mail_settings_migrated": payload.migrate_legacy_mail_settings,
"legacy_zipcrypto_acknowledgements": acknowledgements,
},
validation_error_status=status.HTTP_422_UNPROCESSABLE_CONTENT,
)
for acknowledgement in acknowledgements:
audit_from_principal(
session,
principal,
action="campaign.legacy_zipcrypto_acknowledged",
object_type="campaign_version",
object_id=version_id,
details={"campaign_id": campaign_id, **acknowledgement},
commit=False,
)
if acknowledgements:
session.commit()
return result
except RevisionConflictError as exc:
session.rollback()
audit_from_principal(