mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Follow-up to the v1.0.0 port, closing holes a review and a local run found: - WebUI sign-in: WebUI v2 sends an http:// client-metadata-document id on the onion origin, which Stalwart v1.0.0 rejects (unknown http ids get no CIMD fallback, trusted hosts require TLS). The recovery admin under SSO hit the same wall with the bare id 'stalwart-webui'. Register a public first-party x:OAuthClient 'stalwart-webui' with the WebUI's callback and login URIs on the served origin, and always inject it as the Application's oauthClientId. Native sign-in now shows Stalwart's consent step; test-login-native.js clicks it and also runs under SSO. - Store guard: the previous guard only checked a running 0.16 server; a local run showed v1 writing into a 0.16 store whose server was stopped. The guard now reads the store whenever one exists (shared: pg_database, dedicated: volume) and fails on the 0.16 bigint layout. A host marker written at the end of a successful v1 deploy lets restores and redeploys with a stopped dedicated database pass; without the marker, a stopped dedicated database fails with an explicit message instead of a masked psql error. Queries retry while the database recovers. - README: WebUI sign-in, guard semantics, restore and redeploy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
3.5 KiB
YAML
92 lines
3.5 KiB
YAML
---
|
|
# The WebUI bundle (a JMAP "Application" record) is staged locally in 00_core;
|
|
# point the record's resourceUrl at that file:// path and re-unpack.
|
|
|
|
- name: "📖 List Stalwart Application records"
|
|
include_tasks: jmap_call.yml
|
|
vars:
|
|
stalwart_jmap_body: "{{ STALWART_JMAP_APPLICATION_GET }}"
|
|
|
|
- name: "🔍 Resolve the WebUI Application record"
|
|
ansible.builtin.set_fact:
|
|
stalwart_webui_apps: >-
|
|
{{ stalwart_jmap.methodResponses[0][1].list
|
|
| selectattr('description', 'equalto', STALWART_WEBUI_APP_DESCRIPTION)
|
|
| list }}
|
|
|
|
- name: "✅ Ensure the WebUI Application record was found"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- stalwart_webui_apps | length > 0
|
|
fail_msg: >-
|
|
No Stalwart Application record with description
|
|
'{{ STALWART_WEBUI_APP_DESCRIPTION }}' among the records this Stalwart
|
|
reports:
|
|
{{ stalwart_jmap.methodResponses[0][1].list | map(attribute='description') | list }}
|
|
quiet: true
|
|
|
|
- name: "🔍 Resolve the WebUI Application id"
|
|
ansible.builtin.set_fact:
|
|
stalwart_webui_app_id: "{{ stalwart_webui_apps[0].id }}"
|
|
|
|
- name: "📖 List Stalwart OAuth clients"
|
|
include_tasks: jmap_call.yml
|
|
vars:
|
|
stalwart_jmap_body: "{{ lookup('template', 'jmap/oauth_client/get.json.j2') }}"
|
|
|
|
- name: "🔍 Resolve the WebUI OAuth client"
|
|
ansible.builtin.set_fact:
|
|
stalwart_webui_oauth_client: "{{ lookup('template', 'jmap/oauth_client/webui.json.j2') | from_json }}"
|
|
stalwart_webui_oauth_clients: >-
|
|
{{ stalwart_jmap.methodResponses[0][1].list
|
|
| selectattr('clientId', 'equalto', STALWART_WEBUI_OAUTH_CLIENT_ID)
|
|
| list }}
|
|
vars:
|
|
stalwart_webui_url_prefixes: "{{ stalwart_webui_apps[0].urlPrefix | list }}"
|
|
|
|
- name: "📁 Register the WebUI OAuth client"
|
|
include_tasks: jmap_call.yml
|
|
vars:
|
|
stalwart_jmap_body: "{{ lookup('template', 'jmap/oauth_client/create.json.j2') }}"
|
|
when: stalwart_webui_oauth_clients | length == 0
|
|
|
|
- name: "🔄 Align the WebUI OAuth client with the origin the WebUI is served from"
|
|
include_tasks: jmap_call.yml
|
|
vars:
|
|
stalwart_jmap_body: "{{ lookup('template', 'jmap/oauth_client/update.json.j2') }}"
|
|
when:
|
|
- stalwart_webui_oauth_clients | length > 0
|
|
- >-
|
|
(stalwart_webui_oauth_clients[0] | dict2items
|
|
| selectattr('key', 'in', stalwart_webui_oauth_client) | items2dict)
|
|
!= stalwart_webui_oauth_client
|
|
|
|
- name: "🔗 Point the WebUI Application at the locally-staged bundle and its OAuth client"
|
|
include_tasks: jmap_call.yml
|
|
vars:
|
|
stalwart_jmap_body: >-
|
|
{{ {'using': ['urn:ietf:params:jmap:core', 'urn:stalwart:jmap'],
|
|
'methodCalls': [['x:Application/set',
|
|
{'update': {stalwart_webui_app_id: {'resourceUrl': STALWART_WEBUI_LOCAL_URL,
|
|
'oauthClientId': STALWART_WEBUI_OAUTH_CLIENT_ID}}},
|
|
'c0']]} | to_json }}
|
|
|
|
- name: "📦 Unpack the WebUI bundle from the local file"
|
|
include_tasks: jmap_call.yml
|
|
vars:
|
|
stalwart_jmap_body: >-
|
|
{{ {'using': ['urn:ietf:params:jmap:core', 'urn:stalwart:jmap'],
|
|
'methodCalls': [['x:Action/set',
|
|
{'create': {'a': {'@type': 'UpdateApps'}}},
|
|
'c0']]} | to_json }}
|
|
|
|
- name: "🔧 Verify the WebAdmin is served after unpack"
|
|
ansible.builtin.shell: >-
|
|
container exec -i {{ STALWART_CONTAINER_ADDRESS }}
|
|
{{ 30 | curl }} -sS -o /dev/null -w "%{http_code}" {{ STALWART_LOCAL_BASE_URL }}/
|
|
register: stalwart_webui_probe
|
|
changed_when: false
|
|
retries: 6
|
|
delay: 5
|
|
until: stalwart_webui_probe.stdout in ['200', '301', '302']
|