from __future__ import annotations import unittest from sqlalchemy import create_engine from sqlalchemy.orm import Session from govoplan_policy.backend.campaign_archive_encryption import ( CampaignArchiveEncryptionPolicyError, campaign_archive_encryption_policy_state, resolve_campaign_archive_encryption_rows, save_campaign_archive_encryption_policy, ) from govoplan_policy.backend.db.models import PolicyOverride class CampaignArchiveEncryptionPolicyTests(unittest.TestCase): def setUp(self) -> None: self.engine = create_engine("sqlite:///:memory:") PolicyOverride.__table__.create(self.engine) def test_secure_default_denies_legacy(self) -> None: decision = resolve_campaign_archive_encryption_rows(()) self.assertEqual(frozenset({"aes"}), decision.allowed_password_encryption_methods) self.assertNotIn("zip_standard", decision.allowed_password_encryption_methods) self.assertEqual("system", decision.source_path[0].path) self.assertTrue(decision.policy_hash) def test_child_scope_can_narrow_but_not_loosen_parent(self) -> None: with Session(self.engine) as session: save_campaign_archive_encryption_policy( session, tenant_id="tenant-1", scope_type="system", scope_id=None, owner_type=None, owner_id=None, policy={"allowed_password_encryption_methods": ["aes", "zip_standard"]}, actor_id="admin", ) tenant = save_campaign_archive_encryption_policy( session, tenant_id="tenant-1", scope_type="tenant", scope_id=None, owner_type=None, owner_id=None, policy={"allowed_password_encryption_methods": ["aes"]}, actor_id="admin", ) self.assertEqual( frozenset({"aes"}), tenant.effective.allowed_password_encryption_methods, ) with self.assertRaises(CampaignArchiveEncryptionPolicyError): save_campaign_archive_encryption_policy( session, tenant_id="tenant-1", scope_type="user", scope_id="owner-1", owner_type=None, owner_id=None, policy={"allowed_password_encryption_methods": ["aes", "zip_standard"]}, actor_id="admin", ) def test_owner_and_campaign_sources_are_complete(self) -> None: with Session(self.engine) as session: for scope_type, scope_id, methods in ( ("system", None, ["aes", "zip_standard"]), ("tenant", None, ["aes", "zip_standard"]), ("group", "owner-group", ["aes", "zip_standard"]), ("campaign", "campaign-1", ["aes"]), ): save_campaign_archive_encryption_policy( session, tenant_id="tenant-1", scope_type=scope_type, scope_id=scope_id, owner_type="group" if scope_type == "campaign" else None, owner_id="owner-group" if scope_type == "campaign" else None, policy={"allowed_password_encryption_methods": methods}, actor_id="admin", ) state = campaign_archive_encryption_policy_state( session, tenant_id="tenant-1", scope_type="campaign", scope_id="campaign-1", owner_type="group", owner_id="owner-group", ) self.assertEqual( ["system", "tenant", "group", "campaign"], [step.scope_type for step in state.effective.source_path], ) self.assertEqual( frozenset({"aes"}), state.effective.allowed_password_encryption_methods, ) if __name__ == "__main__": unittest.main()