vaultwarden: skip sync when no pending work

This commit is contained in:
Brad Stein 2026-01-21 13:36:04 -03:00
parent 50561b7957
commit 698c5683c8
2 changed files with 58 additions and 3 deletions

View File

@ -150,6 +150,27 @@ def _cooldown_active(status: str, synced_ts: float | None) -> bool:
return time.time() - synced_ts < settings.vaultwarden_retry_cooldown_sec
def _has_pending_failures(users: list[dict[str, Any]]) -> bool:
for user in users:
username = (user.get("username") if isinstance(user.get("username"), str) else "") or ""
username = username.strip()
if not username or user.get("enabled") is False:
continue
if user.get("serviceAccountClientId") or username.startswith("service-account-"):
continue
attrs = user.get("attributes") if isinstance(user.get("attributes"), dict) else {}
status = _extract_attr(attrs, VAULTWARDEN_STATUS_ATTR)
synced_at = _extract_attr(attrs, VAULTWARDEN_SYNCED_AT_ATTR)
synced_ts = _parse_synced_at(synced_at)
if not status:
return True
if status in {"invited", "already_present"} and not synced_at:
return True
if status in {"error", "rate_limited"} and not _cooldown_active(status, synced_ts):
return True
return False
def _set_sync_status(username: str, status: str) -> None:
try:
_set_user_attribute(username, VAULTWARDEN_STATUS_ATTR, status)
@ -234,7 +255,15 @@ def run_vaultwarden_sync() -> VaultwardenSyncSummary:
)
return summary
users = keycloak_admin.iter_users(page_size=200, brief=False)
users = list(keycloak_admin.iter_users(page_size=200, brief=False))
if not _has_pending_failures(users):
summary = counters.summary(detail="no pending failures")
logger.info(
"vaultwarden sync skipped",
extra={"event": "vaultwarden_sync", "status": "skip", "detail": summary.detail},
)
return summary
for user in users:
status, ok = _sync_user(user, counters)
if status is None:

View File

@ -39,6 +39,32 @@ def test_vaultwarden_sync_requires_admin(monkeypatch) -> None:
assert summary.detail == "keycloak admin not configured"
def test_vaultwarden_sync_skips_without_pending_failures(monkeypatch) -> None:
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
dummy = DummyAdmin(
users=[
{
"id": "1",
"username": "alice",
"enabled": True,
"attributes": {"vaultwarden_status": ["invited"], "vaultwarden_synced_at": [now]},
}
],
attrs={
"1": {
"id": "1",
"username": "alice",
"attributes": {"vaultwarden_status": ["invited"], "vaultwarden_synced_at": [now]},
}
},
)
monkeypatch.setattr(vaultwarden_sync, "keycloak_admin", dummy)
summary = vaultwarden_sync.run_vaultwarden_sync()
assert summary.detail == "no pending failures"
assert summary.processed == 0
def test_vaultwarden_sync_skips_when_missing_mailbox(monkeypatch) -> None:
dummy = DummyAdmin(
users=[{"id": "1", "username": "alice", "enabled": True, "attributes": {"mailu_email": ["alice@bstein.dev"]}}],
@ -103,7 +129,7 @@ def test_vaultwarden_sync_respects_retry_cooldown(monkeypatch) -> None:
monkeypatch.setattr(vaultwarden_sync.mailu, "mailbox_exists", lambda email: True)
summary = vaultwarden_sync.run_vaultwarden_sync()
assert summary.skipped == 1
assert summary.detail == "no pending failures"
def test_vaultwarden_sync_bails_after_failures(monkeypatch) -> None:
@ -271,7 +297,7 @@ def test_vaultwarden_sync_skips_disabled_and_service_accounts(monkeypatch) -> No
monkeypatch.setattr(vaultwarden_sync, "keycloak_admin", dummy)
summary = vaultwarden_sync.run_vaultwarden_sync()
assert summary.skipped == 3
assert summary.detail == "no pending failures"
def test_vaultwarden_sync_get_user_failure(monkeypatch) -> None: