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

@@ -80,6 +80,30 @@ class CampaignPartialValidationTests(unittest.TestCase):
class CampaignSemanticValidationTests(unittest.TestCase):
def test_send_mode_requires_campaign_owned_sender_for_each_inline_entry(self) -> None:
config = CampaignConfig.model_validate({
"version": "1.0",
"campaign": {"id": "campaign-1", "name": "Campaign", "mode": "send"},
"server": {
"mail_profile_id": "profile-1",
"profile_capabilities": {"smtp_available": True},
},
"recipients": {"allow_individual_from": True},
"template": {"subject": "Subject", "text": "Body", "body_mode": "text"},
"entries": {
"inline": [
{"id": "ready", "from": [{"email": "sender@example.local"}]},
{"id": "missing"},
]
},
})
report = validate_campaign_config(config)
missing_sender = [issue for issue in report.issues if issue.code == "missing_sender"]
self.assertEqual(1, len(missing_sender))
self.assertEqual("/entries/inline/1/from", missing_sender[0].path)
def test_semantic_validation_reports_zip_delivery_and_external_mapping_issues(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
@@ -139,8 +163,7 @@ class CampaignSemanticValidationTests(unittest.TestCase):
self.assertIn("unknown_global_value", codes)
self.assertIn("zip_global_password_value_missing", codes)
self.assertIn("zip_archive_unknown", codes)
self.assertIn("delivery_imap_enabled_without_server_imap", codes)
self.assertIn("missing_smtp_config", codes)
self.assertIn("missing_mail_profile", codes)
self.assertIn("unknown_mapping_target", codes)
self.assertIn("mapping_target_not_overridable", codes)
self.assertIn("mapping_columns_missing", codes)