kevinveenbirkenbach and Claude Fable 5
8ebc912d7a
fix(users): opt service bots out of identity provisioning
...
Keycloak's realm import enforces the ^[a-z0-9]+$ username pattern, so
the LDAP-disabled seeding path (Ensure non-reserved users exist) died
on every hyphenated bot: "Username is reserved or contains invalid
characters". These are API/basic-auth accounts that never need an SSO
identity; accounts: [] takes them out of the seeding loop (semaphore's
breakglass-administrator convention), and no-reply keeps only its
mailbox account.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-08 02:37:27 +02:00
kevinveenbirkenbach and Claude Opus 4.7
39c990a7ad
feat(web-app-erpnext): ship ERPNext role with OIDC SSO, LDAP, outbound mail
...
Implements requirement docs/requirements/024-web-app-erpnext.md.
Stack (per frappe_docker v15 single-image multi-role pattern):
- configurator (one-shot bench set-config: db_host/port, three redis URLs
split by DB number 0/1/2 for cache/queue/socketio, socketio_port, host_name
HTTPS)
- backend (gunicorn), frontend (nginx-entrypoint.sh), websocket (socketio),
scheduler, queue-short (--queue short,default), queue-long
(--queue long,default,short)
Central-service consumer pattern (Decision #7 ):
- ERPNEXT_DB_ROOT_PASSWORD branches on services.mariadb.shared: central
svc-db-mariadb root pw when true, per-role MariaDB consumer pw when false
- Redis via in-compose `redis` alias, 3-DB-number split for Frappe's logical
buses
- Explicit erpnext_assets volume mount on every container (image's
VOLUME ['sites/assets'] otherwise creates anonymous volumes that fail the
hlth-volumes check)
Bench bootstrap (Decision #9 ):
- bench new-site --install-app erpnext with 30-min hard timeout
- Post-install restart of all long-lived Frappe containers (otherwise the
cached app set serves HTTP 500 on /login)
- TCP-port readiness probe (HTTP would 404 pre-site)
- API-bot user seed + setup_complete=1 via apply_api_bot.py
OIDC (Decisions #4 + #5 ):
- redirect_uris filter auto-includes ERPNext in the shared Keycloak client
- Social Login Key wired via apply_oidc_settings.py with
social_login_provider=Keycloak (delete+recreate due to set_only_once),
custom_base_url=1, relative authorize/token/userinfo paths,
auth_url_data={response_type:code,scope:openid}, login_via_keycloak
redirect path
- Group-to-Frappe-role mapping persisted as a frappe.db default; per-login
reconciliation hook deferred to follow-up (documented in README)
LDAP (V3): LDAP Settings doctype applied via apply_ldap_source.py. End-to-end
LDAP login (auto-create Frappe user from LDAP bind) deferred to follow-up;
LDAP-login Playwright specs intentionally absent in v1 (documented).
Email (Decision #8 , outbound only): outbound Email Account applied via
apply_email_account.py using db_insert/db_update to bypass Frappe's
deploy-time SMTP socket validation. IMAP inbound deferred to follow-up.
Variant matrix (Decision #11 ): V1 sso+ldap, V2 all-false, V3 ldap-only.
Three variants verified end-to-end via
`make compose-deploy mode=reinstall apps=web-app-erpnext full_cycle=true
purge=true` — 6 PLAY RECAPs, all failed=0, all Playwright runs
passed-or-skipped with no failures.
Playwright specs: test-landing, test-csp-headers, test-login-administrator
(OIDC), test-login-biber (OIDC), test-login-native-administrator
(break-glass local login, always runs), test-guest-persona. _shared.js
exposes signInViaErpnextOidc + signInViaErpnextLocal.
Repo-wide lint addition: tests/lint/ansible/modules/test_task_name_length.py
caps Ansible task `name:` strings at 120 chars (opt-out via
`# nocheck: name-length`). Fixed two pre-existing violations in
web-app-keycloak/tasks/update/ldap/per_app_mapper_one.yml.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-03 09:53:56 +02:00