mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
The role was a scaffold: tasks/main.yml was a two-line comment, there was no compose.yml.j2, no domains.yml, no volumes.yml, no env.j2. It deployed nothing while carrying a Playwright spec and two matrix variants. It also described the wrong project. meta/main.yml and meta/info.yml pointed at jaywink/socialhome -- a Django ActivityPub hub. The target here is social-home-io/socialhome: created 2026-04-21, MPL-2.0, aiohttp + SQLite + Preact, federating peer-to-peer over Ed25519/WebRTC rather than ActivityPub. Different codebase, no fork relationship. It turns out to be the simplest web-app in the repo. One published multi-arch image (ghcr.io/social-home-io/socialhome:2026.6.16, pinned), no Postgres, no Redis, no queue, no worker, no collectstatic -- SQLite in one volume, one port, migrations applied in-process at startup. Two things the source forced that reading the README would not have: - [standalone].external_url is reachable only through the TOML file, never through SH_* env (config.py:238-261). Without it routes/pairing.py answers 422 NOT_CONFIGURED and federation pairing is dead, so the role renders a config and mounts it as type: config. - provision_admin() runs from SH_ADMIN_PASSWORD but never calls mark_complete(), so / keeps serving the setup wizard instead of the login form -- upstream's own docstring claims otherwise. 01_setup.yml closes it with an idempotent POST to /api/setup/standalone. No SSO sidecar, deliberately, against the pgadmin model this otherwise copies: oauth2-proxy would redirect POST /federation/inbox and /api/pairing/accept to Keycloak and break the one thing the software exists for. Verified against the real image rather than reasoned about. The http_status probe's exact argv ran inside the container and returned 0. /healthz answers with the byte-for-byte shape the spec asserts. The setup POST returns 201 then 409 and flips setup_required true -> false, which is the whole justification for 01_setup.yml existing. [standalone].external_url lands in the inbox_url of POST /api/pairing/initiate. The container runs as uid 10001, matching meta/users.yml. Both persona blocks are proven, not assumed: biber gets 401 from the token endpoint, and the 97 static files contain zero occurrences of logout / sign out / abmelden, so utils/logout.js has nothing to click. Injecting a control the way web-app-prometheus does was rejected -- that model points its button at OIDC.CLIENT.LOGOUT_URL, which does not exist for a role with no OIDC. swarm stays disabled for the first round. The orchestrator chains swarm -> compose -> host under mode_fail_fast, and sequencing measures serial at 198 jobs, so a red swarm job here would skip 92 unrelated jobs and leave 85 roles untested. Compose-only drops that to 10. Flip it once compose is green. Adversarial review caught five defects before this landed, three of them certain rather than likely: - SOCIALHOME_INTERNAL_URL hardcoded 127.0.0.1, which sys-svc-container rewrites to the bridge gateway whenever DOCKER_IN_CONTAINER is set -- from inside the Ansible container that address is the Ansible container, so both setup tasks would have burned five minutes of retries and failed the play. - SH_WEBRTC_STUN_URL sat outside the coturn guard while the TURN pair sat inside it. Upstream reads by env PRESENCE, so the empty value would have beaten the in-app default and left WebRTC with no STUN at all. - meta/csp.yml whitelisted blob: on worker-src. The bundle registers no service worker and constructs no Worker; the only blob of JavaScript is an audio worklet, and worklet modules load under script-src. Voice recording would have died with the app's own "Audio processing unavailable". - tasks/main.yml hand-rolled meta: flush_handlers instead of including sys-svc-compose's finalize.yml, which silently skipped utils/post_deploy.yml. - 01_setup.yml was gated on IS_STACK_HOST but not run_once, so a three-manager swarm would fire three concurrent setup POSTs at one ingress port. TODO.md carried a claim that steered the CSP design and was simply false -- that img-src is not a directive csp_filters.py emits. It appends "img-src * data: blob:" unconditionally at line 383. lifecycle: alpha puts the role in the CI deploy matrix before it has ever run anywhere, deliberately: the first CI round is its first execution. README and TODO say so rather than claiming a maturity it does not have. Still unverified: no browser has enforced the CSP, the swarm path was only rendered, TURN against a real coturn is untested, and arm64 has not been exercised. TODO.md lists them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
29 lines
1.0 KiB
YAML
29 lines
1.0 KiB
YAML
---
|
|
# Exception: upstream provisions the admin from SH_ADMIN_PASSWORD in
|
|
# platform/standalone/adapter.py on_startup but never calls mark_complete(), so the SPA keeps
|
|
# rendering the setup wizard. Re-posting the same credentials is a no-op for provision_admin()
|
|
# and flips the setup flag; 409 means a previous run already did it.
|
|
|
|
- name: "⏳ Wait for Social Home at {{ SOCIALHOME_INTERNAL_URL }}/healthz"
|
|
uri_retry:
|
|
url: "{{ SOCIALHOME_INTERNAL_URL }}/healthz"
|
|
method: GET
|
|
status_code: 200
|
|
register: socialhome_health
|
|
retries: 30
|
|
delay: 5
|
|
until: socialhome_health.status == 200
|
|
|
|
- name: "🔐 Mark the standalone first-boot setup complete"
|
|
uri_retry:
|
|
url: "{{ SOCIALHOME_INTERNAL_URL }}/api/setup/standalone"
|
|
method: POST
|
|
body_format: json
|
|
body:
|
|
username: "{{ SOCIALHOME_ADMIN_USERNAME }}"
|
|
password: "{{ SOCIALHOME_ADMIN_PASSWORD }}"
|
|
status_code: [201, 409]
|
|
register: socialhome_setup
|
|
changed_when: socialhome_setup.status == 201
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|