from __future__ import annotations import json import unittest from sqlalchemy import create_engine from sqlalchemy.orm import Session from govoplan_core.core.dsar import DsarProvider, DsarSubjectRef from govoplan_core.db.base import Base from govoplan_policy.backend.db.models import PolicyOverride from govoplan_policy.backend.dsar_provider import ( POLICY_DSAR_CAPABILITY, PolicyDsarProvider, ) from govoplan_policy.backend.manifest import manifest class PolicyDsarProviderTests(unittest.TestCase): def setUp(self) -> None: self.engine = create_engine("sqlite+pysqlite:///:memory:") Base.metadata.create_all(self.engine) self.session = Session(self.engine) self.provider = PolicyDsarProvider() self.session.add_all( ( PolicyOverride( id="override-1", policy_family="retention", target_key="target-secret-do-not-export", tenant_id="tenant-1", scope_type="user", scope_id="scope-subject-do-not-export", scope_key="scope-key-do-not-export", policy={"secret": "policy-payload-do-not-export"}, revision=2, created_by="account-1", updated_by="account-1", ), PolicyOverride( id="override-system", policy_family="retention", target_key="system", tenant_id=None, scope_type="system", scope_key="system", policy={}, revision=1, created_by="account-1", updated_by="account-1", ), PolicyOverride( id="override-other", policy_family="retention", target_key="other", tenant_id="tenant-2", scope_type="tenant", scope_key="tenant-2", policy={}, revision=1, created_by="account-1", updated_by="account-1", ), ) ) self.session.commit() def tearDown(self) -> None: self.session.close() self.engine.dispose() def test_search_is_tenant_safe_and_minimized(self) -> None: self.assertIsInstance(self.provider, DsarProvider) records = self.provider.search_subject( self.session, tenant_id="tenant-1", subject=DsarSubjectRef(account_id="account-1"), ) self.assertEqual(["override-1"], [record.resource_id for record in records]) exported = json.dumps([record.to_dict() for record in records]) for excluded in ( "target-secret-do-not-export", "scope-subject-do-not-export", "scope-key-do-not-export", "policy-payload-do-not-export", ): self.assertNotIn(excluded, exported) def test_requires_exact_account_and_supports_narrowing(self) -> None: self.assertEqual( (), self.provider.search_subject( self.session, tenant_id="tenant-1", subject=DsarSubjectRef(email="policy@example.test"), ), ) records = self.provider.search_subject( self.session, tenant_id="tenant-1", subject=DsarSubjectRef( account_id="account-1", external_references={"policy.override": "override-1"}, ), ) self.assertEqual(1, len(records)) def test_records_are_retained_and_manifest_is_complete(self) -> None: subject = DsarSubjectRef(account_id="account-1") records = self.provider.search_subject( self.session, tenant_id="tenant-1", subject=subject ) actions = self.provider.plan_erasure( self.session, tenant_id="tenant-1", subject=subject, records=records, ) self.assertTrue(all(action.kind == "retain" for action in actions)) self.assertIn(POLICY_DSAR_CAPABILITY, manifest.capability_factories) self.assertIn( "policy.data-subject-requests", {topic.id for topic in manifest.documentation}, ) if __name__ == "__main__": unittest.main()