Files
computer-playbook/roles/web-app-stalwart/tasks/main.yml
kevinveenbirkenbachandClaude Opus 5.5 7bb0383e38 fix(web-app-stalwart): drop a replaced bot app password only after the load
The recover drill between the two CI passes restores /var/lib/infinito/secrets
with rsync --delete, so PASS 2 starts with an empty token store and the role
replaces the app password of every bot. It destroyed the old one at once,
while alertmanager, OpenWebUI and Baserow, rendered in PASS 1, kept sending
with it until the preload rendered them again 15 to 25 minutes later.
Stalwart counts every refused login against the client's address, which for
host-originated and cross-bridge clients is the Docker gateway 192.168.200.1.
After 100 refusals it banned that address for good, openresty's upstream,
alertmanager and the msmtp health check had their connections reset, and
Baserow#0 of #869 failed with exit 76. The rescue artifact shows 31 of those
refusals, all from alertmanager; Stalwart's own log, which names the account
behind the ban, was not collected.

A replaced app password is now renamed to
STALWART_BOT_APP_PASSWORD_RETIRED_DESCRIPTION once the new one is stored, and
destroyed in the service-loader post-load flush next to the deferred OIDC
restart, after the preload has rendered every consumer with the new one. Each
deploy also collects retired passwords an earlier deploy left behind, so a
deploy that stops before the flush neither replaces the password a second
time nor drops the one it handed out.

Verified: on Stalwart v0.16.25, 100 refused logins from one container address
banned it permanently (BlockedIp, reason authFailure, expiresAt null) and new
connections from it were reset, as in the CI log, and an app password's
description can be updated in place. A playbook running the changed task
files with JMAP stubbed (ansible-core 2.21.4) shows that a PASS 2 replacement
destroys the old ids only in the flush; that a deploy failing after the
Stalwart preload destroys nothing, while the next one mints nothing and
destroys only the retired ids; and that outside the service loader each bot's
old password is destroyed right after its new one is stored.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 15:09:39 +02:00

24 lines
803 B
YAML

---
- include_tasks: 00_core.yml
when: run_once_web_app_stalwart is not defined
vars:
application_id: "web-app-stalwart"
- name: "📥 Run the work deferred to the service-loader post-load flush"
when:
- run_once_web_app_stalwart is defined
- not (service_loader_preloading | default(false) | bool)
- IS_STACK_HOST | bool
block:
- name: "🗑️ Drop the retired app passwords"
include_tasks: 04_manage_user/app_password_drop.yml
when: stalwart_app_password_stale | length > 0
vars:
application_id: "web-app-stalwart"
- name: "🔄 Restart Stalwart to activate the OIDC directory"
include_tasks: 11_oidc_restart.yml
when: stalwart_oidc_restart_pending | default(false) | bool
vars:
application_id: "web-app-stalwart"