from __future__ import annotations import json import unittest from datetime import UTC, datetime 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_forms.backend.db.models import FormDefinitionRevision from govoplan_forms.backend.dsar_provider import ( FORMS_DSAR_CAPABILITY, FormsDsarProvider, ) from govoplan_forms.backend.manifest import manifest NOW = datetime(2026, 8, 22, 12, 0, tzinfo=UTC) class FormsDsarProviderTests(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 = FormsDsarProvider() self.session.add_all( ( FormDefinitionRevision( id="revision-1", tenant_id="tenant-1", form_id="form-1", form_key="secret-form-key-do-not-export", revision="2", publication_state="published", title="Sensitive semantic title do not export", recorded_at=NOW, search_text="search-content-do-not-export", payload={"secret": "schema-payload-do-not-export"}, changed_by="account-1", ), FormDefinitionRevision( id="revision-other", tenant_id="tenant-2", form_id="form-other", form_key="other", revision="1", publication_state="draft", title="Other tenant", recorded_at=NOW, search_text="other", payload={}, changed_by="account-1", ), ) ) self.session.commit() def tearDown(self) -> None: self.session.close() self.engine.dispose() def test_search_is_minimized_tenant_safe_and_narrowable(self) -> None: self.assertIsInstance(self.provider, DsarProvider) subject = DsarSubjectRef(account_id="account-1") records = self.provider.search_subject( self.session, tenant_id="tenant-1", subject=subject ) self.assertEqual(["revision-1"], [record.resource_id for record in records]) exported = json.dumps([record.to_dict() for record in records]) for excluded in ( "secret-form-key-do-not-export", "Sensitive semantic title do not export", "search-content-do-not-export", "schema-payload-do-not-export", ): self.assertNotIn(excluded, exported) narrowed = self.provider.search_subject( self.session, tenant_id="tenant-1", subject=DsarSubjectRef( account_id="account-1", external_references={"forms.form": "form-1"}, ), ) self.assertEqual(1, len(narrowed)) def test_requires_account_and_retains_definition_history(self) -> None: self.assertEqual( (), self.provider.search_subject( self.session, tenant_id="tenant-1", subject=DsarSubjectRef(email="designer@example.test"), ), ) 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)) def test_manifest_registers_provider_and_documentation(self) -> None: self.assertIn(FORMS_DSAR_CAPABILITY, manifest.capability_factories) self.assertIn( "forms.data-subject-requests", {topic.id for topic in manifest.documentation}, ) if __name__ == "__main__": unittest.main()