feat: govern campaign archive encryption
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
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()
|
||||
@@ -5,6 +5,7 @@ import tomllib
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.policy import (
|
||||
CAPABILITY_POLICY_CAMPAIGN_ARCHIVE_ENCRYPTION,
|
||||
CAPABILITY_POLICY_DEFINITION_GOVERNANCE,
|
||||
CAPABILITY_POLICY_FUNCTION_ASSIGNMENT_GOVERNANCE,
|
||||
CAPABILITY_POLICY_PRIVACY_RETENTION,
|
||||
@@ -56,6 +57,7 @@ class PolicyModuleContractTests(unittest.TestCase):
|
||||
CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY,
|
||||
CAPABILITY_POLICY_VIEW_GOVERNANCE,
|
||||
CAPABILITY_POLICY_ACCESS_EXPLANATION_SUBJECTS,
|
||||
CAPABILITY_POLICY_CAMPAIGN_ARCHIVE_ENCRYPTION,
|
||||
},
|
||||
set(manifest.capability_factories),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user