from __future__ import annotations import unittest from types import SimpleNamespace from govoplan_core.security.secrets import decrypt_secret, encrypt_secret from govoplan_mail.backend.config import ImapConfig, SmtpConfig from govoplan_mail.backend.mail_profiles import ( EffectiveMailProfilePolicy, _apply_profile_transport_update, _merge_policy, _next_profile_transport_state, _policy_parent_lock_message, _policy_parent_lock_violations, ) class MailProfileTransportHelperTests(unittest.TestCase): def test_next_transport_state_uses_saved_profile_credentials(self): profile = SimpleNamespace( tenant_id="tenant-1", scope_type="tenant", scope_id=None, smtp_config={"host": "smtp.example.org", "port": 587, "security": "starttls", "timeout_seconds": 30}, smtp_username="saved-smtp", smtp_password_encrypted=encrypt_secret("smtp-secret"), imap_config={"host": "imap.example.org", "port": 993, "security": "tls", "sent_folder": "Sent", "timeout_seconds": 30}, imap_username="saved-imap", imap_password_encrypted=encrypt_secret("imap-secret"), ) smtp, imap = _next_profile_transport_state(profile, smtp=None, imap=None, clear_imap=False) self.assertEqual(smtp.username, "saved-smtp") self.assertEqual(smtp.password, "smtp-secret") self.assertIsNotNone(imap) self.assertEqual(imap.username, "saved-imap") self.assertEqual(imap.password, "imap-secret") _, cleared_imap = _next_profile_transport_state(profile, smtp=None, imap=None, clear_imap=True) self.assertIsNone(cleared_imap) def test_apply_transport_update_preserves_unsupplied_passwords(self): profile = SimpleNamespace( smtp_config={"host": "smtp.example.org", "port": 587, "security": "starttls", "timeout_seconds": 30}, smtp_username="saved-smtp", smtp_password_encrypted=encrypt_secret("smtp-secret"), imap_config={"host": "imap.example.org", "port": 993, "security": "tls", "sent_folder": "Sent", "timeout_seconds": 30}, imap_username="saved-imap", imap_password_encrypted=encrypt_secret("imap-secret"), ) _apply_profile_transport_update( profile, smtp=SmtpConfig(host="smtp2.example.org", username="new-smtp"), imap=ImapConfig(host="imap2.example.org", username="new-imap"), clear_imap=False, ) self.assertEqual(profile.smtp_config["host"], "smtp2.example.org") self.assertEqual(profile.smtp_username, "new-smtp") self.assertEqual(decrypt_secret(profile.smtp_password_encrypted), "smtp-secret") self.assertEqual(profile.imap_config["host"], "imap2.example.org") self.assertEqual(profile.imap_username, "new-imap") self.assertEqual(decrypt_secret(profile.imap_password_encrypted), "imap-secret") _apply_profile_transport_update(profile, smtp=None, imap=None, clear_imap=True) self.assertIsNone(profile.imap_config) self.assertIsNone(profile.imap_username) self.assertIsNone(profile.imap_password_encrypted) class MailProfilePolicyHelperTests(unittest.TestCase): def test_merge_policy_respects_locked_lower_level_limits(self): policy = EffectiveMailProfilePolicy() _merge_policy( policy, { "blacklist": {"smtp_hosts": ["*.blocked.example"]}, "allow_lower_level_limits": {"blacklist.smtp_hosts": False}, }, source="system", ) _merge_policy( policy, {"blacklist": {"smtp_hosts": ["*.tenant.example"]}}, source="tenant", source_id="tenant-1", ) self.assertEqual(policy.blacklist_patterns["smtp_hosts"], ["*.blocked.example"]) self.assertFalse(policy.allow_lower_level_limits["blacklist.smtp_hosts"]) def test_parent_lock_violations_are_reported_per_field(self): violations = _policy_parent_lock_violations( { "allow_user_profiles": False, "smtp_credentials.inherit": False, "blacklist.smtp_hosts": False, }, { "allow_user_profiles": True, "smtp_credentials": {"inherit": False}, "blacklist": {"smtp_hosts": ["*.blocked.example"]}, "allow_lower_level_limits": {"allow_user_profiles": True}, }, ) self.assertEqual( violations, [ "allow_user_profiles", "blacklist.smtp_hosts", "smtp_credentials.inherit", "allow_lower_level_limits.allow_user_profiles", ], ) self.assertEqual( _policy_parent_lock_message("smtp_credentials.inherit"), "SMTP credential inheritance is locked by an ancestor policy", ) if __name__ == "__main__": unittest.main()