from __future__ import annotations from datetime import datetime, timezone from types import SimpleNamespace import unittest from unittest.mock import patch from sqlalchemy import create_engine from sqlalchemy.orm import Session from govoplan_access.backend.db.models import Account, User from govoplan_core.auth import ApiPrincipal from govoplan_core.core.access import PrincipalRef from govoplan_core.core.search import ( SearchAuthorizationRequest, SearchBackfillRequest, SearchResourceReference, ) from govoplan_core.db.base import Base from govoplan_mail.backend.db.models import ( MailMailboxMessageIndex, MailServerProfile, ) from govoplan_mail.backend.search_source import ( MailSearchSource, PROVIDER_ID, RESOURCE_TYPE, ) class MailSearchSourceTests(unittest.TestCase): def setUp(self) -> None: self.engine = create_engine("sqlite://") Base.metadata.create_all( self.engine, tables=( Account.__table__, User.__table__, MailServerProfile.__table__, MailMailboxMessageIndex.__table__, ), ) self.session = Session(self.engine) self.session.add_all( ( Account( id="account-1", email="one@example.test", normalized_email="one@example.test", ), User( id="user-1", tenant_id="tenant-1", account_id="account-1", email="one@example.test", ), MailServerProfile( id="profile-1", tenant_id="tenant-1", scope_type="user", scope_id="user-1", name="Personal mailbox", slug="personal", smtp_config={}, imap_config={"host": "imap.example.test"}, ), MailMailboxMessageIndex( id="message-1", tenant_id="tenant-1", profile_id="profile-1", folder="INBOX", uid="42", subject="Permit status", from_header="service@example.test", body_preview="Your permit is ready", indexed_at=datetime(2026, 8, 5, tzinfo=timezone.utc), ), ) ) self.session.commit() self.source = MailSearchSource() def tearDown(self) -> None: self.session.close() self.engine.dispose() def test_mailbox_backfill_and_profile_recheck_are_bounded(self) -> None: page = self.source.backfill( self.session, request=SearchBackfillRequest( tenant_id="tenant-1", provider_id=PROVIDER_ID, resource_type=RESOURCE_TYPE, rebuild_id="rebuild-1", ), ) self.assertEqual(("message-1",), tuple(doc.resource_id for doc in page.documents)) self.assertNotIn("password", str(page.documents[0].metadata).casefold()) reference = SearchResourceReference( tenant_id="tenant-1", module_id="mail", resource_type=RESOURCE_TYPE, resource_id="message-1", ) request = SearchAuthorizationRequest(reference=reference, source_revision="1") with patch( "govoplan_mail.backend.search_source.mail_profile_visible_to_actor", return_value=True, ): allowed = self.source.authorize( self.session, _principal(), requests=(request,), ) self.assertTrue(allowed[reference.key]) self.assertFalse( self.source.authorize( self.session, _principal(scopes={"mail:mailbox:read"}), requests=(request,), )[reference.key] ) def _principal( *, scopes: set[str] | None = None, ) -> ApiPrincipal: return ApiPrincipal( principal=PrincipalRef( account_id="account-1", membership_id="user-1", tenant_id="tenant-1", scopes=frozenset( scopes or {"mail:mailbox:read", "mail:profile:use"} ), ), account=SimpleNamespace(id="account-1"), user=SimpleNamespace(id="user-1"), ) if __name__ == "__main__": unittest.main()