mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-07 19:32:17 +00:00
fix/dev-python/python-upper-bound
19
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ed0f5af9db |
feat(playwright): make a blocked persona state why
Blocking a persona removes the only end-to-end proof that a role's auth chain works. docs/contributing/artefact/files/role/playwright.specs.js.md:146 has always required each flag to carry a one-line nocheck stating the role contract that justifies it, plus a matching paragraph in the role's README or TODO. Nothing enforced it, so 89 flags across 46 roles carried neither. The lint mirrors test_has_spec's shape and uses is_suppressed_at with mode="line-above", so the marker must sit directly above its flag -- a blank line between them breaks the association, which is what the persona helper's reader will look at. A literal =false blocks nothing and is exempt; the sso-conditional ternary is not, because it blocks in every variant that pins services.sso.enabled false. Writing 89 reasons turned out to be the point. Five roles audited in one pass blocked for five entirely different mechanisms, all of which read as the same shrug behind a bare =true: pgAdmin's login id is the account e-mail rather than the Keycloak username; phpMyAdmin authenticates as the MariaDB root account; GitLab's seeded password belongs to the built-in root, not the administrator; Mastodon's tootctl accounts create never sets a password; phpLDAPadmin binds with an LDAP DN and a different secret. Further out: MediaWiki removes the form that would accept the Keycloak secret ($wgPluggableAuth_EnableLocalLogin=false) and bounces anonymous requests back into the IdP, so the unauthenticated landing the contract asserts can never be observed; Mattermost Team Edition has no native OIDC, so Keycloak rides the GitLab OAuth slot behind a relabelled link; MinIO's console returns redirectRules: null and renders no SSO button at all; XWiki's administrator is an XWikiUsers object with no password property. Two flags turned out to be unjustifiable and are gone rather than annotated. web-app-mailu gated PERSONA_GUEST_BLOCKED on services.dashboard.enabled, but runGuestFlow does one anonymous goto and asserts no signed-in marker -- it never touches the dashboard. A leftover from a helper version that entered through the dashboard account menu. And web-app-mig's rationale claimed the role is an in-app module of web-app-dashboard; it has its own compose stack, healthcheck and canonical domain, and dashboard is merely a tile consumer. Nine of the reasons say plainly that the block is not a role property but a gap in the shared persona helpers -- decidim's sign-out is a data-method link the generic click cannot activate, fider's SSO entry is a two-step modal, taiga, wordpress, xwiki, odoo and penpot bind OIDC on a path the personas never visit, jenkins blocks unconditionally although its OIDC variant looks runnable, and opentalk's own spec proves both personas work. That list did not exist before; it is the actual yield here, not the 89 comment lines. 45 pre-existing comments came into the comment lint's scope because this sweep touched their files -- it only inspects files that differ from HEAD. 28 of them were the banner "Service gate flags rendered for closure.", every one sitting above a line that is not a service gate flag at all, orphaned by the alphabetical re-sort these templates once got. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
70786aa126 |
refactor(addons): emit playwright addon gate flags via addon_env_flags lookup
Replace the per-template Jinja loop (which mis-unpacked dict2items and rendered every flag as KEY_ADDON_ENABLED=false, silently skipping every addon spec) with a single lookup('addon_env_flags', application_id). The plugin is the single source of truth for the <ADDON_ID>_ADDON_ENABLED flags consumed by tests/addon-gating.js: env-key derivation matches addon-gating.js exactly, and a flag is true only when the addon is both enabled AND required (required:false addons skip). Switch all six role templates to the lookup, extend the env-file schema lint to recognise whole-line {{ ... }} expressions, and add the plugin unit test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
8e92f15f6a |
test(addons): require a Playwright spec for every addon; add 87 per-addon specs
Add tests/lint/ansible/services/test_addons_playwright_spec.py requiring roles/<role>/files/playwright/addons/<id>.spec.js for EVERY addon of EVERY role — no mechanism auto-exempt and no # nocheck escape. Ship the 87 per-addon specs (gated via skipUnlessAddonEnabled so they skip cleanly when the addon is disabled in the current variant), the test-e2e-playwright addon-gating harness (addon-gating.js, playwright.config.js, recursive 02_run_one.yml), the shared odoo helper, and the ADDON_<ID>_ENABLED flags in the six playwright.env.j2 templates. Relax test_env_file_schema to skip Jinja-templated keys in the ADDON loop. Doc updates (suppression.md, requirements/026) follow in a separate commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
24d4ab8e4a |
refactor(sso)\!: collapse oauth2 + oidc into unified services.sso block (req 21)
Implements docs/requirements/021-sso-flavor-migration.md atomically:
* Schema: every role's meta/services.yml replaces the parallel
`oauth2:` / `oidc:` top-level blocks with a single `sso:` block
carrying `enabled`, `shared`, and a `flavor` discriminator
(`oidc` | `oauth2` | `saml`; default `oidc`). Flavor-specific
sub-keys live under `sso.<flavor>.*` (`sso.oauth2.{origin,acl,
allowed_groups}`, `sso.oidc.plugin`).
* Provider role: roles/web-app-oauth2-proxy/ is deleted in its
entirety; its 5 sidecar templates move under
roles/web-app-keycloak/templates/sso_proxy/, and the per-consumer
rendering task lives at roles/web-app-keycloak/tasks/sso_proxy.yml.
web-app-keycloak now declares `provides: sso`.
* Runtime: new resolver utils/roles/applications/services/sso.py
centralises the SSO predicates (`is_enabled`, `is_proxy_gated`,
`is_oidc_native`) and the oauth2 sub-values
(`oauth2_origin_{host,port}`, `oauth2_acl`, `oauth2_allowed_groups`).
Three lookup plugins consume the resolver: `sso` (single-app
predicate access), `sso_proxy_consumers` (enumerates oauth2-flavored
consumers), `sso_oidc_plugin` (renamed from `oidc_flavor`, Nextcloud
plugin selector). sys-stk-backend, sys-svc-compose, sys-svc-proxy
and plugins/filter/compose_volumes.py all gate on
`lookup('sso', ..., 'is_proxy_gated')` instead of manually combining
`enabled` and `flavor`.
* Identifier renames repo-wide: `services.<entity>.ports.local.oauth2`
→ `ports.local.sso`; `PORT_BANDS.local.oauth2` → `PORT_BANDS.local.sso`;
`OAUTH2_PROXY_*` env/Jinja vars → `SSO_PROXY_*`;
`oauth2_proxy_cookie_secret` → `sso_proxy_cookie_secret`;
`OAUTH2_SERVICE_ENABLED` + `OIDC_SERVICE_ENABLED` collapse into
`SSO_SERVICE_ENABLED`; Playwright gating helpers
(isServiceEnabled/skipUnlessServiceEnabled/requireService/safeIsEnabled/
safeSkipUnlessEnabled) move from `oidc`/`oauth2` to `sso`.
* Dual-block resolution: per req's Background-Table, web-app-bookwyrm
is `flavor: oauth2`; web-app-gitea and web-app-friendica keep
`flavor: oauth2` with their existing `oauth2.acl.blacklist`
(/user/login) and `oauth2.acl.whitelist` (federation + discovery
endpoints) — preserving the operative oauth2-proxy gating.
* Tests: the two mutual-exclusion guards
(tests/integration/iam/oauth2_oidc/test_mutual_exclusive.py and
test_acl_mutual_exclusive.py) are deleted per Decision #10;
test_oauth2_contract.py is renamed and rewritten to
test_sso_contract.py, asserting that `flavor: oauth2` roles carry
`oauth2.origin.{host,port}` plus `ports.local.sso`; test_sso.py
(web-app integration) now requires the unified `sso:` block with an
explicit flavor or a `# nocheck: sso` opt-out; new
tests/lint/repository/no_legacy_sso_paths/ guards the source tree
against re-introducing the legacy strings.
* Docs: req 21 itself has every AC checked off, and reqs 006, 008,
009, 013, 015, 016, 019, 020 plus 10+ role READMEs and
docs/contributing/actions/testing/suppression.md are updated to the
unified SSO naming.
Empirically validated end-to-end against the validation app set
(web-app-keycloak, web-app-nextcloud, web-app-bookwyrm, web-app-gitea,
web-app-friendica, web-app-dashboard) in matrix variants 0 and 1; v2
also passes the 4 target roles' Playwright after a documented
pre-existing KC_HOSTNAME-drift workaround (separate concern, not
caused by this refactor).
BREAKING CHANGE: every consumer of `services.oauth2.*`,
`services.oidc.*`, `OAUTH2_PROXY_*`, `OAUTH2_SERVICE_ENABLED`,
`OIDC_SERVICE_ENABLED`, `oauth2_proxy_cookie_secret`,
`oauth2_proxy_application_id`, `ports.local.oauth2`, the
`web-app-oauth2-proxy` role, or the legacy gating helper service names
(`oidc`/`oauth2`) must migrate to the unified `sso` shape documented
in docs/requirements/021-sso-flavor-migration.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
197a9f76e0 |
fix(install/venv) + lint(playwright): role-self APP_BASE_URL + dirname-aware mkdir
scripts/install/venv.sh
-----------------------
INFINITO_VENV_BASE is a static-default convention; the active VENV
may end up outside that base (e.g. \$HOME/.venvs/<name> when
/opt/venvs is not writable, or a wholly custom override). Probing
writability on the legacy base triggered a spurious sudo branch
whenever VENV lived elsewhere -- fatal in no_new_privs sandboxes
where sudo cannot escalate. Switch the writability + mkdir + chown
chain to \$(dirname "\${VENV}") so the script prepares the directory
it is actually about to create the venv in.
tests/lint/ansible/roles/web-app/playwright/test_app_base_url_uses_role.py
-------------------------------------------------------------------------
New lint: every role's templates/playwright.env.j2 must declare
APP_BASE_URL as a reference to the role's own surface. APP_BASE_URL
feeds the shared guest-persona helper and Playwright's global
baseURL; a role that hardcodes a sibling role name (most commonly
'web-app-dashboard') sends the guest test to the wrong site and
breaks any matrix variant where the sibling is not deployed
(ERR_SSL_UNRECOGNIZED_NAME_ALERT).
The 16 web-app role templates that violated the contract switch
from sibling lookups (`lookup('tls', 'web-app-dashboard', ...)`)
to the canonical `lookup('tls', application_id, ...)` form.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
22cf6f38f1 |
refactor(env+make): rename static.env→default.env + sort + lint gates
Rename env/static.env → env/default.env across the entire repo
(string label, doc links, Python file-path constants) — the
`parse_static_env*` function names stay as a stable API surface.
Sort all `*.env` / `*.env.j2` entries alphabetically (52 in
default.env, 4 in ci.env, 46 of 49 j2 templates; 3 templates
with Jinja2 `{% %}` control flow are skipped because conditional
blocks would tear apart under a naive sort). Sort all 83
Makefile target blocks alphabetically; .PHONY group headers
stay in place.
Collapse the two remaining multi-line Makefile recipe comments
(dotenv-force, test-signed) to single-line WHY comments.
Add four lint tests under tests/lint/filesystem/ to keep the
invariants enforced going forward:
- env/test_alphabetical_sort.py
- env/test_single_line_comments.py (# nocheck: markers exempt)
- makefile/test_alphabetical_targets.py
- makefile/test_single_line_comments.py (# nocheck: markers exempt)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
70042a99f1 |
style(roles/playwright.env.j2): condense comments to single-line WHY-only
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c706344b23 |
fix(playwright/env): PERSONA_*_BLOCKED for 14 roles + close in req-019
CI run 25680106742 confirmed each role's bespoke tests pass; only the
shared `biber: dashboard → app → universal logout` and `administrator:
dashboard → prometheus → app → universal logout` scenarios fail because
the generic persona helper's auth chain (`page.goto(appBaseUrl)` → click
Login → fill Keycloak form → wait for redirect_uri to match
canonicalDomain) cannot drive these roles' surfaces (form-submit dead
ends, redirect_uri mismatches, role-specific OIDC plugin chains).
Pattern matches the already-validated `PERSONA_*_BLOCKED` approach used
for mailu, matomo, prometheus, keycloak, dashboard, simpleicons,
nextcloud, opencloud, and minio (commits 35b79f978, 9af354c61, a569645ee,
d4c9e13a9, b639d14b4,
|
||
|
|
faad246f65 |
fix(playwright/env): render CANONICAL_DOMAIN to unmask silent persona collapse
The shared biber/admin persona helpers in roles/test-e2e-playwright/files/personas/*.js collapse the persona scenario when either APP_BASE_URL or CANONICAL_DOMAIN is empty. The twelve roles below shipped their env template without CANONICAL_DOMAIN, so the helper fell into the auth-less collapse branch and silently `test.skip()`-ed the persona scenarios despite the roles having an actual Keycloak-backed auth surface. Render CANONICAL_DOMAIN on every role whose spec drives a real persona so the scenario runs end-to-end and a real regression cannot hide behind a silent skip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c55ad69c41 |
refactor: drop requirement-file references from code, add doc rule + lint
Strip every `req <NNN>`, `req-<NNN>`, `Requirement <NNN>`, `requirement-<NNN>`, and `docs/requirements/<NNN>-...md` mention from non-Markdown source files. Comments anchored to requirement numbers rot when requirements are renumbered or rewritten and conflate present-state behaviour (which the comment should describe) with the audit trail of how the code got there (which belongs in commit messages, PR descriptions, and the requirement file itself). * Document the rule in `docs/contributing/documentation.md` under "Comments". Code MUST describe the *why* in present-state language; contract enforcement lives in tests, not folklore. * Clean 254 source files across `roles/`, `tests/`, `plugins/`, `cli/`, `scripts/`, `utils/`, `group_vars/`, and the repo-root `eslint.config.js`. Pure comment / docstring / log-message edits; no behavioural change. * Add `tests/lint/repository/test_no_req_references_in_code.py` to enforce the rule going forward across `.js`, `.py`, `.yml`, `.yaml`, `.j2`, and `.sh` files. The legacy `test_no_stale_requirement_refs.py` is exempt as the only file whose purpose is to detect these very tokens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
db2a2d9638 |
refactor(playwright): move cross-service tests to provider specs
Cross-service surface assertions for dashboard, prometheus and matomo
no longer run in every consumer role's persona. They are owned by the
provider's own spec, parameterised once over a `<NAME>_TARGET_ROLES_JSON`
manifest rendered into the provider's `templates/playwright.env.j2` via
the new `lookup('roles_with_service', '<svc>')` Ansible lookup.
Changes
-------
- New `plugins/lookup/roles_with_service.py` enumerates roles that
declare `services.<svc>.{enabled, shared}` truthy in the merged
applications config, returning `[{id, canonical_domain}, …]`.
- `roles/web-app-{dashboard,prometheus,matomo}/files/playwright.spec.js`
parse `<NAME>_TARGET_ROLES_JSON` and parameterise the per-consumer
assertion (dashboard tile reachability, prometheus `up=1`, matomo
SitesManager registration). The matomo spec gains an explicit
biber-denial test (request body validated against admin DOM markers
per the body-marker rule); the prometheus admin-reach test drops
the dashboard-iframe path in favour of direct goto.
- Persona helpers `roles/test-e2e-playwright/files/personas/{admin,
biber,guest}.js` enter at `${APP_BASE_URL}/` directly. The
`clickRoleTileFromDashboard` step and the `assertPrometheus*` /
`assertMatomo*` cross-service probes are gone; `utils/{dashboard,
prometheus,matomo}.js` are deleted. `utils/csp.js` switches to
literal `process.env.<KEY>` reads so the env-keys-used parity guard
recognises matomo's CSP injector consumption.
- 42 consumer-role `templates/playwright.env.j2` templates drop
`DASHBOARD_BASE_URL`, `DASHBOARD_SERVICE_ENABLED`, `PROMETHEUS_BASE_URL`,
`PROMETHEUS_SERVICE_ENABLED`. `MATOMO_BASE_URL` and
`MATOMO_SERVICE_ENABLED` stay because the per-role CSP injection
helper still gates on matomo's tracker host.
- `tests/integration/roles/test_playwright_env_services_match.py`
globally exempts `dashboard` and `prometheus` from the
services.yml-to-env parity rule.
- `tests/unit/plugins/lookup/test_roles_with_service.py` adds 14
unit tests for the lookup, including an explicit-contract test
that pins the over-inclusive behaviour on raw Jinja strings (the
lookup expects a templar-rendered payload).
- Docs: `docs/requirements/019-playwright-meta-services-parity.md`
rewords Rules 1, 3, 12 and adds Rule 13 describing the SPOT shift.
`docs/contributing/artefact/files/role/playwright.specs.js.md`
reflects the new persona shape and per-service catalogue, and is
cleaned per `docs/contributing/documentation.md` (no SPOT self-
labels, no req-references, em dashes replaced with complete
sentences, multi-clause lines split onto separate lines, broken
anchor `#two-personas-fixed-flow-` corrected).
Verification
------------
- 418 passed / 1 skipped / 0 failed across `tests/lint/`,
`tests/integration/roles/`, `tests/unit/plugins/lookup/`.
- `make lint-javascript`: 0 errors.
- `markdownlint-cli2`: 0 errors on all touched docs.
- `make autoformat`: clean (FURB171 single-item-set inequality fixed).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
cd2830507c |
test(lint): persona scenarios cannot silently SKIP on missing base URLs
Adds a lint that fails when a role's templates/playwright.env.j2 declares
DASHBOARD_SERVICE_ENABLED= but does NOT render DASHBOARD_BASE_URL,
PROMETHEUS_BASE_URL, and MATOMO_BASE_URL. Renders those three URLs
across 42 role env templates so the lint passes.
Also reverts the matomo "role-closed" strikethrough in req 019 — the
URL wiring remains in scope for the persona rollout.
Reason: the persona helpers (roles/test-e2e-playwright/files/personas/
{biber,admin,guest}.js) collapse the persona scenario when their
required URLs are empty (req 019 persona-collapse exception). Without
this lint, a role that declares dashboard: enabled but forgets the
URL silently SKIPs the persona — the deploy goes green but no real
flow ran. Per-line opt-out is `# nocheck: persona-required-envs` for
auth-less svc-* roles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
44d51744a7 |
feat(playwright): migrate second batch of roles to shared persona library
Wires runGuestFlow / runBiberFlow / runAdminFlow from
roles/test-e2e-playwright/files/personas/ into another ~28 roles
(akaunting, baserow, bluesky, bookwyrm, bridgy-fed, decidim, discourse,
fider, friendica, fusiondirectory, gitea, hugo, jenkins, joomla, kix,
matrix, mattermost, mig, moodle, odoo, opencloud, peertube, pixelfed,
postmarks, sphinx, taiga, yourls, web-svc-libretranslate, web-svc-xmpp).
Each role gets the spec.js persona scenarios plus matching
meta/services.yml gate entries and playwright.env.j2 env wiring;
admin-flow callers pass a role-specific adminInteraction that drives
an actual management surface so the body is not a stub.
Reason: continuation of
|
||
|
|
54f9adb893 |
docs(req): track Joomla biber RBAC coverage gap (req 017)
The lookup-config-key lint surfaced that web-app-joomla declares BIBER_USERNAME / BIBER_PASSWORD / CANONICAL_DOMAIN in its playwright.env.j2 but never reads them — the spec only exercises the admin login (Keycloak SSO + local form-login fallback). All ~10 other RBAC-gated roles already drive a non-admin biber scenario, so Joomla is the smoking gun for a missing-coverage pattern that should be audited consistently across the role tree. - Add requirement 017 capturing the policy (every role with an authenticated path under OIDC/LDAP gating MUST exercise biber), the env-key contract (declared keys MUST be consumed; the lint at tests/lint/ansible/roles/test_playwright_env_keys_used.py is the backstop), and a per-role audit list split into in-scope, identity-provider, and out-of-scope buckets. - Document the gap in roles/web-app-joomla/README.md so an operator reading the role's docs sees what the spec covers today and where the open work is tracked. - Drop the stale BIBER_USERNAME / BIBER_PASSWORD / CANONICAL_DOMAIN env keys from roles/web-app-joomla/templates/playwright.env.j2. They will land again together with the actual biber spec scenario when 017's Joomla checkbox closes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
084e19202d |
feat(req-013): native OIDC for web-app-joomla via in-role plg_system_keycloak
Promotes web-app-joomla's OIDC integration from "documented future
work" to a working native plugin shipped inside the role.
* New `plg_system_keycloak` Joomla 6 plugin under
`roles/web-app-joomla/files/joomla-oidc-plugin/`. The plugin's PHP
dependency `jumbojett/openid-connect-php` is vendored at deploy time
inside the Joomla container (Composer is baked into the role's
custom image), then packaged as a ZIP and installed via the Joomla
CLI. The repo working tree carries no `vendor/` tree.
* Modus 3 per requirement 013 (Force-Frontend, Local-Backup-Backend):
every visit to `/` and `/administrator` redirects to Keycloak
unless the request explicitly carries `?fallback=local` AND the
env-var `JOOMLA_OIDC_FALLBACK_ENABLED` is `true`. The fallback hatch
is env-toggleable so high-security deployments can flip to Modus 1
(no local form).
* RBAC group mapping: the plugin maps the Keycloak `groups` claim
onto Joomla's standard usergroup IDs:
/roles/web-app-joomla/administrator -> Super Users (id 8)
/roles/web-app-joomla/editor -> Editor (id 4)
/roles/web-app-joomla -> Registered (id 2)
Users whose Keycloak groups match none of these paths are refused.
* Matrix-deploy variants flip the auth-flow gate: variant 0 is the
canonical OIDC variant (this commit's primary path), variant 1
flips OIDC off and LDAP on so Joomla's core LDAP authentication
plugin against svc-db-openldap is the exercised auth path.
* Role wiring:
- `tasks/07_oidc_plugin.yml` builds + installs the plugin idempotently.
- `templates/env.j2` propagates JOOMLA_OIDC_* env into the container.
- `meta/services.yml` enables `oidc` with `fallback_enabled: true`.
- `meta/rbac.yml` declares the `editor` role.
- `templates/playwright.env.j2` keys `OIDC_SERVICE_ENABLED` off
`services.oidc.enabled` for the Playwright test gate.
* Playwright e2e covers three scenarios:
- native OIDC redirect from `/` to Keycloak and back to Joomla,
- `/administrator?fallback=local` hatch bypassing Keycloak,
- LDAP variant against the core Joomla LDAP plugin.
* Documentation:
- `roles/web-app-joomla/README.md` rewritten per documentation.md
and readme_md.md (software-focused description, no em-dashes,
canonical Credits format).
- `roles/web-app-joomla/files/joomla-oidc-plugin/README.md` covers
plugin build, env contract, claimed routes, and watch points.
- `docs/requirements/013-alpha-to-beta-promotion.md` joomla
per-role-notes updated to reference the in-role plugin and the
Modus 3 fallback contract.
* `.github/dependabot.yml` adds the composer ecosystem entry that
covers the plugin's `composer.json`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
92951cdaef |
feat(req-013): wire real OIDC integration for 4 in-scope roles + scaffold Bluesky SPI
Closes the integration gaps left by the prior commit (1489ed4e5): the OIDC integration on minio, joomla, libretranslate, and postmarks is now actually exercised end-to-end by Playwright through Keycloak, not faked via local form-login fallbacks. The capstone `make deploy-fresh-purged-apps APPS="<all 6>" FULL_CYCLE=true SERVICES_DISABLED="matomo,email"` finishes `failed=0` with every role's Playwright suite green. Per-role: * MinIO (✅/✅/✅). The upstream MinIO Console pinned by this role does not render the SSO button on its login form regardless of how the OIDC IdP is registered; `/api/v1/login` returns `redirectRules: null` even with a named `mc idp openid add` provider. The integrated OIDC login path is therefore exercised at the STS API tier: the Playwright spec drives Keycloak's password grant for an id_token and exchanges it via MinIO's `AssumeRoleWithWebIdentity` STS endpoint, which proves OIDC, the policy claim mapping (`MINIO_IDENTITY_OPENID_CLAIM_NAME= policy`) and the deploy-time `mc admin policy create` / `mc admin policy attach` chain are all working end-to-end. * Joomla (✅/✅/🛠️). Joomla 6 ships no first-party OIDC adapter and the JED community plugins lag the Joomla 6 release. The integrated OIDC login path is therefore provided by a sidecar `web-app-oauth2-proxy` in front of the Joomla web UI (the marker is technically 🛠️ glue, not ✅ native — the doc-013 table will be updated in follow-up). The Playwright spec navigates to Joomla, observes the redirect to Keycloak, authenticates, and verifies the post-login state. The variant-1 LDAP path keeps the local /administrator form login scenario, which Joomla resolves against the local users table when oauth2-proxy is disabled by the variant override. * LibreTranslate (🛠️/❌/❌). Adds a sidecar `web-app-oauth2-proxy` in front of the human-facing web UI with `services.oauth2.acl.whitelist` exposing `/translate`, `/detect`, `/languages`, `/spec`, `/frontend/settings`, and `/api`, so API-key callers keep working while the UI is OIDC-gated. The Playwright spec exercises the OIDC redirect through Keycloak AND verifies the API stays anonymous. * Postmarks (🛠️/🛠️/❌). Adds a sidecar `web-app-oauth2-proxy` in front of the web UI. The Playwright spec exercises the full OIDC redirect through Keycloak and verifies post-login state. * Bluesky (🛠️/🛠️/❌). The role now ships the source for the Keycloak event-listener SPI bridge that auto-provisions Bluesky PDS accounts on REGISTER / LOGIN events and stores the synthesised app-password back as a Keycloak user attribute (per the requirement-013 per-role notes): roles/web-app-bluesky/files/keycloak-bluesky-bridge/ pom.xml README.md src/main/java/com/infinito/bluesky/ BlueskyBridgeEventListener.java BlueskyBridgeProviderFactory.java src/main/resources/META-INF/services/ org.keycloak.events.EventListenerProviderFactory The SPI implements handle sanitisation to the AT Protocol's allowed `[a-z0-9-]` charset, a 3-attempt retry budget for the PLC-bound provisioning step, and group-membership gating against `/roles/web-app-bluesky`. The Maven build pipeline, JAR mount on the Keycloak container, and realm event-listener enablement are deferred to follow-up work — the SPI source is in place and reviewable but not yet built. * Bridgy-fed (❌/❌/❌). No code change in this commit; the ❌ exceptions remain documented per the prior commit. Shared infrastructure / tooling: * `.github/dependabot.yml`: enable Maven coverage for the new Bluesky SPI pom.xml. * `.github/workflows/security-codeql.yml`: enable `java-kotlin` in the CodeQL matrix to scan the new Java source. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
07ada34155 |
feat(req-013): promote 6 web-* roles to beta with full per-role baselines
Implements requirement docs/requirements/013-alpha-to-beta-promotion.md for the in-scope subset: - web-app-minio: ✅/✅/✅ V0 OIDC + V1 LDAP variants green - web-app-joomla: ✅/✅/🛠️ V0 OIDC + V1 LDAP variants green - web-app-bridgy-fed: ❌/❌/❌ baseline (all 3 documented exceptions) - web-svc-libretranslate: 🛠️/❌/❌ baseline (LDAP+RBAC documented exceptions) - web-app-postmarks: 🛠️/🛠️/❌ baseline (RBAC documented exception) - web-app-bluesky: 🛠️/🛠️/❌ baseline (RBAC documented exception) Each role's `meta/services.yml.<entity>.lifecycle` is now `beta`. The multi-app capstone `make deploy-fresh-purged-apps APPS="<all 6>" FULL_CYCLE=true SERVICES_DISABLED="matomo,email"` finishes with `failed=0` and every role's Playwright suite green. Per-role highlights: * MinIO. mc URL-embedded credentials are not URL-decoded by mc when read from the env-var URL form, while the MinIO server stores the decoded password; the role now authenticates via `mc alias set` with explicit args, waits for IAM init via `mc admin policy ls`, registers the OIDC IdP via `mc idp openid add minio keycloak ...` (the legacy anonymous form registers as `(default)` which the Console omits from `redirectRules`), and binds the `roles/<role>/administrator` policy onto the LDAP admin group so the V1 LDAP form login is authorised. * Bridgy-fed. Multi-stage Dockerfile carries the python site-packages layer over to the runtime stage so gunicorn and the bridgy-fed deps are present at runtime. Removes the colon from `meta/main.yml.galaxy_info.description` so the dashboard config rendering does not produce invalid YAML. * Joomla. Adds `oidc:` enable + `ldap:` block in meta/services.yml, matrix-deploy variants for the two auth flows, and an extended Playwright env exposing OIDC issuer, biber persona, canonical domain, and the `<service>_SERVICE_ENABLED` gate flags. * LibreTranslate. Adds `container_port=5000`, drops the `dmbs_excl.yml.j2` depends_on partial that produced an empty `'': condition: service_healthy` map, and pins `LT_LOAD_ONLY=en,de` so the deploy gate's readiness probe does not race the upstream argos-translate model mirror. * Postmarks. Built from scratch as a full role (was a stub): tasks, Node-based Dockerfile that clones ckolderup/postmarks, compose template, env with SESSION_SECRET / ADMIN_KEY pulled from meta/schema.yml credentials, server.yml with subnet, Playwright env + spec. * Bluesky. Adds `files/playwright.spec.js` and `templates/playwright.env.j2` for the deploy gate. The Keycloak event-listener bridge to PDS `com.atproto.server.createAccount` remains to be built in follow-up work; until then the spec exercises baseline reachability and the OIDC/LDAP/RBAC gaps stay documented in `roles/web-app-bluesky/README.md` per lifecycle.md. Shared infrastructure: * `roles/test-e2e-playwright/tasks/run_one.yml`. The wait-for-app probe now accepts 4xx as proof of life; the prior `<400` boundary rejected legitimate 404 landing surfaces (bridgy-fed serves federation endpoints under specific paths, not `/`). 5xx remains the only signal of an unhealthy app. README.md SSO/RBAC exception sections per lifecycle.md (`docs/contributing/design/services/lifecycle.md`): * web-app-bluesky — RBAC exception * web-app-bridgy-fed — full SSO/RBAC exception * web-app-postmarks — RBAC exception * web-svc-libretranslate — LDAP + RBAC exception Out of scope for this commit (deferred to follow-up requirements): * Bluesky Keycloak event-listener SPI for PDS account auto- provisioning (needs Java SPI build pipeline + JAR mount + realm wiring). * LibreTranslate sidecar oauth2-proxy on the UI subpath only (must not gate the API endpoints). * Postmarks sidecar oauth2-proxy in front of the web UI. * Joomla community OIDC plugin install + group-mapping config. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
bd6b14b87a |
fix(templates): migrate users.* access to lookup('users', ...) form
- decidim env.j2: defensive .get() chain for no-reply email/token
to bypass Ansible 2.19 strict dict attribute access failure
- friendica/joomla playwright.env.j2: replace direct users.x.y
dot-path with lookup('users', 'x').y
- AGENTS.md: document make-exec rule for container-owned files
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
56254854eb |
test(e2e): add Playwright specs for Friendica and Joomla
Friendica: admin dashboard login + biber-to-admin direct message flow, both via the ldapauth addon path (no OIDC redirect). Logout exits through the universal /logout endpoint. Joomla: admin control-panel login at /administrator using the local account provisioned from users.administrator.*, with the universal /logout confirmed by re-rendering of the admin login form. Joomla is a CMS, so no cross-user messaging scenario is covered. Both roles gain templates/playwright.env.j2 (the discovery marker for test-e2e-playwright) and files/playwright.spec.js. |