From 1dabd78921e385e4c54a246103e3d4f0a9c82fe7 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Mon, 19 Jan 2026 23:27:10 -0300 Subject: [PATCH] fix: force mailu sync before vaultwarden --- ariadne/manager/provisioning.py | 9 +++++-- ariadne/services/mailu.py | 4 ++-- tests/test_provisioning.py | 2 +- tests/test_services.py | 42 +++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/ariadne/manager/provisioning.py b/ariadne/manager/provisioning.py index 38ef388..82ca26f 100644 --- a/ariadne/manager/provisioning.py +++ b/ariadne/manager/provisioning.py @@ -313,7 +313,7 @@ class ProvisioningManager: self._upsert_task(conn, request_code, "mailu_sync", "ok", detail) self._record_task(request_code, "mailu_sync", "ok", detail, start) else: - mailu.sync(reason="ariadne_access_approve") + mailu.sync(reason="ariadne_access_approve", force=True) self._upsert_task(conn, request_code, "mailu_sync", "ok", None) self._record_task(request_code, "mailu_sync", "ok", None, start) except Exception as exc: @@ -401,7 +401,12 @@ class ProvisioningManager: start = datetime.now(timezone.utc) try: if not mailu.wait_for_mailbox(mailu_email, settings.mailu_mailbox_wait_timeout_sec): - raise RuntimeError("mailbox not ready") + try: + mailu.sync(reason="ariadne_vaultwarden_retry", force=True) + except Exception: + pass + if not mailu.wait_for_mailbox(mailu_email, settings.mailu_mailbox_wait_timeout_sec): + raise RuntimeError("mailbox not ready") result = vaultwarden.invite_user(mailu_email) if result.ok: diff --git a/ariadne/services/mailu.py b/ariadne/services/mailu.py index 5ded199..3a2e632 100644 --- a/ariadne/services/mailu.py +++ b/ariadne/services/mailu.py @@ -39,13 +39,13 @@ class MailuService: time.sleep(2) return False - def sync(self, reason: str) -> None: + def sync(self, reason: str, force: bool = False) -> None: if not settings.mailu_sync_url: return with httpx.Client(timeout=settings.mailu_sync_wait_timeout_sec) as client: resp = client.post( settings.mailu_sync_url, - json={"ts": int(time.time()), "wait": True, "reason": reason}, + json={"ts": int(time.time()), "wait": True, "reason": reason, "force": force}, ) if resp.status_code != 200: raise RuntimeError(f"mailu sync failed status={resp.status_code}") diff --git a/tests/test_provisioning.py b/tests/test_provisioning.py index 8205fbe..da13a09 100644 --- a/tests/test_provisioning.py +++ b/tests/test_provisioning.py @@ -107,7 +107,7 @@ def test_provisioning_filters_flag_groups(monkeypatch) -> None: admin = DummyAdmin() monkeypatch.setattr(prov, "keycloak_admin", admin) - monkeypatch.setattr(prov.mailu, "sync", lambda reason: None) + monkeypatch.setattr(prov.mailu, "sync", lambda reason, force=False: None) monkeypatch.setattr(prov.mailu, "wait_for_mailbox", lambda email, timeout: True) monkeypatch.setattr(prov.nextcloud, "sync_mail", lambda username, wait=True: {"status": "ok"}) monkeypatch.setattr(prov.wger, "sync_user", lambda username, email, password, wait=True: {"status": "ok"}) diff --git a/tests/test_services.py b/tests/test_services.py index eb55dec..5acef9a 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -5,6 +5,7 @@ import types import pytest from ariadne.services.firefly import FireflyService +from ariadne.services.mailu import MailuService from ariadne.services.nextcloud import NextcloudService from ariadne.services.wger import WgerService @@ -24,6 +25,24 @@ class DummySpawner: return {"job": "test", "status": "queued"} +class DummyClient: + def __init__(self): + self.url = "" + self.payload = None + self.status_code = 200 + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + return False + + def post(self, url, json=None): + self.url = url + self.payload = json + return types.SimpleNamespace(status_code=self.status_code) + + def test_nextcloud_sync_mail_builds_env(monkeypatch) -> None: dummy = types.SimpleNamespace( nextcloud_namespace="nextcloud", @@ -88,6 +107,29 @@ def test_firefly_sync_user_env(monkeypatch) -> None: assert env_map["FIREFLY_USER_EMAIL"] == "alice@bstein.dev" +def test_mailu_sync_includes_force(monkeypatch) -> None: + dummy_settings = types.SimpleNamespace( + mailu_sync_url="http://mailu", + mailu_sync_wait_timeout_sec=10.0, + mailu_db_host="localhost", + mailu_db_port=5432, + mailu_db_name="mailu", + mailu_db_user="mailu", + mailu_db_password="secret", + ) + client = DummyClient() + + monkeypatch.setattr("ariadne.services.mailu.settings", dummy_settings) + monkeypatch.setattr("ariadne.services.mailu.httpx.Client", lambda *args, **kwargs: client) + + svc = MailuService() + svc.sync("provision", force=True) + + assert client.url == "http://mailu" + assert client.payload["wait"] is True + assert client.payload["force"] is True + + def test_nextcloud_missing_config(monkeypatch) -> None: dummy = types.SimpleNamespace( nextcloud_namespace="",