Commit Graph
652 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.8 a08ec88c03 feat(deploy): always run the full variant matrix (remove runtime time-cut)
Drop the RuntimeBudget guard and its INFINITO_MAX_RUNTIME /
INFINITO_VARIANT_TIME_OVERFLOW env handlers: the deploy round loop now runs
every variant unconditionally instead of skipping (cut) or aborting (fail)
when the projected runtime would exceed the budget. Removes runtime_budget.py,
both env handlers + their registration, the budget calls in deploy.py, the
obsolete unit tests + the TestHandlerBudget class, and the docs reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 02:50:56 +02:00
kevinveenbirkenbachandClaude Opus 4.8 35c2ff5f26 feat(deploy): runner-split variant bundles + unified variant selector
Thread a single `variant` selector (CSV) end-to-end so CI can split a
role's matrix deploy across runners.

- variant_select.py (SPOT, shared by init + deploy): one --variant taking
  a CSV (2 pins one round, 0,1,2 is a runner bundle, empty = full matrix);
  replaces the old separate --variant/--variants.
- planner.filter_plan_to_variants filters the plan to a round subset.
- CI discovery (utils/github/variant_bundles.py) splits roles with more
  than INFINITO_VARIANT_BUNDLE_SIZE (default 3) variants into bundles of
  consecutive indices, one matrix runner each (5 -> 0,1,2 + 3,4), threaded
  via the variant env. test-deploy-{local,universal,workstation,server}.yml
  switch to matrix.include with a comma-free variant_slug for artifact/job
  names (GitHub expressions have no replace()).
- runtime_budget honours INFINITO_VARIANT_TIME_OVERFLOW (cut|fail) when a
  runner cannot finish its slice within INFINITO_MAX_RUNTIME.

Unit tests + docs (variants.md, deploy.md) included.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:52:50 +02:00
kevinveenbirkenbach 21e484bf30 Merge origin/main into feature/026-unified-addon-syntax
Resolve conflicts: keep 026's bond/field/addon additions (services.yml, variants.yml,
yourls leaky-proxy fix, nextcloud per-file addons), take main's 027 integration-matrix
(generated artifact). Verified: all 44 main inline-plugins are covered by meta/addons/.
2026-06-21 06:32:17 +02:00
kevinveenbirkenbachandClaude Opus 4.8 d2f5efa7fe feat(test-e2e-playwright): parallel workers via plugin + tunable timeouts; split role vars by precedence
Add plugins/lookup/playwright_workers.py computing a conservative parallel-worker count (CPU/RAM-derived, app-under-test concurrency-capped, reduced on CI) and wire test_e2e_playwright_workers + test_e2e_playwright_fully_parallel + test_e2e_playwright_test_timeout into playwright.config.js (read from env) and 02_run_one.yml (passed via -e). fullyParallel stays false so parallelism is file-level only and intra-file ordering assumptions stay safe. Raise run_timeout to 3600 for addon-heavy roles (nextcloud ~50 specs).

Split the role's variables by Ansible precedence and intent: derived/fixed constants live in vars/main.yml (UPPERCASE, high precedence, not operator-tuned), operator-tunable knobs live in defaults/main.yml (lowercase, overridable). VARIANT_INDEX stays UPPERCASE with a single definition. Update references across tasks/templates/inventory/docs accordingly. Includes a unit test for playwright_workers and an autoformat pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 06:03:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 cdb7c49f69 docs(addons): document req-026 syntax; exclude desk-* roles from per-addon spec rule
Document the unified addon syntax (req-026) and drop the non-existent '# nocheck: playwright-addon-spec' escape hatch so the docs match the no-exemption lint. Exclude desktop desk-* roles from the per-addon Playwright spec requirement — they drive no web surface a spec could exercise — and harden the lint to FORBID spec files under desk-* roles; remove the 8 desk-chromium/desk-firefox/desk-gnome addon specs accordingly. Web-facing roles still require a spec per addon with no exemption.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:16:55 +02:00
kevinveenbirkenbachandClaude Opus 4.8 9f65b558dc docs(026): unified addon syntax spec + acceptance check-off
Per-file meta/addons/<id>.yml convention throughout; 18 end-to-end-verified acceptance criteria checked off, 37 held (matrix-wiring backlog, audit/update automation, deploy-gated per-role).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:30:47 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4e807e64c2 docs(027): regenerate integration matrix from data module (req 026)
Split the generator data into integration_matrix_data.py and regenerate 027-integration-matrix.md (82x82, 523 wired + 96 upstream edges). Artifact is generated, not hand-edited.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:30:47 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e317f08ac9 feat(addons): unified meta/addons contract (req 026)
Per-file meta/addons/<id>.yml loader, schema + bridge-parity lints, shared update SPOT, unit/external tests, and layout.md/plugins README docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:30:45 +02:00
kevinveenbirkenbach 920268fe42 fix(ci): pin variant[2] seaweedfs in matrix/shopware/snipe-it/taiga and nocheck flaky baserow URL 2026-06-17 11:30:38 +02:00
kevinveenbirkenbach 0310629287 fix(integration-matrix): clear generator lints and replace 2 dead edge URLs 2026-06-17 11:30:38 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e8c1657c37 docs(requirements): fold resolved decisions into unified-addon-syntax + renumber 028->026
Renumber the addon-syntax requirement 028 -> 026 (trio: 025-mcp -> 026-unified-addon
-> 027-integration-matrix) and bake in the agreed decisions:

- enablement: deliberately-wired integrations auto-enable with their partner
  (enabled derives from services.<target>.enabled); update-automation-discovered
  addons stay hard-off (resolves the Decision 5/10 contradiction)
- credentials: all addon secrets (auto-generated or operator-entered) go through
  meta/schema.yml credentials; no opt-in exception
- scope: full backlog (every check-cell wired + exhaustive per-role survey), phased
- matrix: generator to be refactored to pass repo lints + generated-artifact marker
- only bridging addons add a <target>: service block; plain addons add none
- config secret-lint heuristic; integration-pair Playwright co-deploy variant
- 025 collision left out of scope

Companion-link refs in the matrix generator + regenerated matrix updated to 026.
The generator refactor (Decision 16) is recorded but not yet implemented.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:37 +02:00
kevinveenbirkenbachandClaude Opus 4.8 0e0dad26d6 docs(requirements): emit markdownlint-clean Notes block in the matrix generator
Add the blank line after `Notes:` (markdownlint MD032) in the generator HEADER so
a fresh `027-integration-matrix.gen.py` run stays lint-clean and idempotent with
autoformat. Regenerate the matrix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:37 +02:00
kevinveenbirkenbachandClaude Opus 4.8 45188939bb chore(requirements): mark integration-matrix generator executable (ruff EXE001)
The generator carries a `#\!/usr/bin/env python3` shebang; make the file
executable so ruff's flake8-executable check passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:37 +02:00
kevinveenbirkenbachandClaude Opus 4.8 2281535162 docs(requirements): renumber MCP matrix + addon-syntax (026 -> 027/028) after merge
feature/mcp's 026-integration-matrix and 026-unified-addon-syntax collided with
main's numbering on merge. Renumber both and fix every cross-reference:
- 026-integration-matrix.{md,gen.py} -> 027-integration-matrix.{md,gen.py}
- 026-unified-addon-syntax.md        -> 028-unified-addon-syntax.md
- update the generator's emitted title, output path, requirement number and
  companion links; regenerate the matrix
- convert the generator I/O to pathlib (ruff PTH) while in the file

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:37 +02:00
kevinveenbirkenbach a58e7e53a2 Merge branch 'feature/mcp' into fix/ci-deploy-server-failures
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2026-06-17 11:30:36 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3b60b36fb2 fix(web-app-peertube): repair the SeaweedFS object-store e2e test for PeerTube v8.2.1
The test timed out: the publish-button locator no longer matched the v8.2.1
manage-video wizard, and the inline 78-byte MP4 stub was structurally invalid,
so PeerTube rejected the upload as "Video file unreadable" and left the Save
button disabled.

- test-seaweedfs.js: target the v8.2.1 save control (.save-button > button),
  upload PeerTube's real video_short.mp4 fixture, and assert a version-tolerant
  saved marker.
- add fixture roles/web-app-peertube/files/playwright/fixtures/video_short.mp4.
- test-e2e-playwright: stage role-local files/playwright/fixtures/ next to the
  tests (the *.js glob ships neither binaries nor subdirectories), so specs load
  a fixture via path.join(__dirname, "fixtures", <name>).
- docs: document the fixtures/ folder and the per-scenario test-*.js split in the
  playwright spec contract and the runner README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:36 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3158ecadcf docs(role-loop): make matrix-variant command selection unambiguous
Replace the prose that an agent could read as 'no variant passed implies mode=reinstall' with an explicit situation-to-command table plus a FORBIDDEN list: every mode=update is variant-pinned, and a no-variant mode=reinstall is reserved for the initial baseline and the final gate only. A failing variant is retried with mode=update variant=<idx>, never by restarting the whole matrix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:34 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1ed0afcd61 test(objstore): require seaweedfs for database-backed web-app roles
Add a meta lint asserting every web-app role with postgres or mariadb declares a seaweedfs object-store service, exemptable via the seaweedfs-required nocheck marker. Mark the 33 database-backed roles that do not use object storage, and register the rule in the suppression catalog.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:33 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8a34d47165 docs(requirements): add 026 cross-role integration matrix
Add the generated role×role integration matrix (026-integration-matrix.md
+ generator) and expand 026 with: required-gated install-failure handling,
mechanism=bridge for network bridges, addon variant/matrix axis, and the
matrix-backed cross-role integration backlog. The matrix scans every role's
meta/services.yml for infinito-native wired edges (☑️) and overlays curated,
web-verified upstream plugin edges (✅/🪙): 511 wired + 96 upstream across 82
roles. Header repeats every 10 rows and columns for readability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:30 +02:00
kevinveenbirkenbachandClaude Opus 4.8 9a8a84cde8 docs(requirements): add 026 unified addon syntax
Promote per-app addon/plugin/extension/module/bridge declarations to a
single file-rooted meta/addons.yml contract: unified schema, explicit
cross-role bridge rule, required-gated install-failure handling (hard
fail vs warn+skip), addon state as a variants.yml matrix axis, network
bridges (Matrix mautrix) as mechanism=bridge addons, external drift
monitoring, and a Playwright test per user-facing addon. Audit expanded
to matrix, discourse, pretix, mattermost, desk-chromium/firefox/gnome;
mobilizon/bookwyrm DB extensions classified out of scope.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:30 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e6570e1486 docs(requirements): add 025 MCP role integration
Define the unified MCP service, identity, proxy, and test contract for
server and client roles, with a repo-wide audit, bridge discovery via
roles_with_service, and a Playwright test per integrated role.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:30 +02:00
kevinveenbirkenbach f29ed13b3d fix(ci): pin variant[2] seaweedfs in matrix/shopware/snipe-it/taiga and nocheck flaky baserow URL 2026-06-13 19:55:03 +02:00
kevinveenbirkenbach c1be4241aa fix(integration-matrix): clear generator lints and replace 2 dead edge URLs 2026-06-13 18:20:39 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6ee047caa6 docs(requirements): fold resolved decisions into unified-addon-syntax + renumber 028->026
Renumber the addon-syntax requirement 028 -> 026 (trio: 025-mcp -> 026-unified-addon
-> 027-integration-matrix) and bake in the agreed decisions:

- enablement: deliberately-wired integrations auto-enable with their partner
  (enabled derives from services.<target>.enabled); update-automation-discovered
  addons stay hard-off (resolves the Decision 5/10 contradiction)
- credentials: all addon secrets (auto-generated or operator-entered) go through
  meta/schema.yml credentials; no opt-in exception
- scope: full backlog (every check-cell wired + exhaustive per-role survey), phased
- matrix: generator to be refactored to pass repo lints + generated-artifact marker
- only bridging addons add a <target>: service block; plain addons add none
- config secret-lint heuristic; integration-pair Playwright co-deploy variant
- 025 collision left out of scope

Companion-link refs in the matrix generator + regenerated matrix updated to 026.
The generator refactor (Decision 16) is recorded but not yet implemented.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 16:59:05 +02:00
kevinveenbirkenbachandClaude Opus 4.8 0837630ac9 docs(requirements): emit markdownlint-clean Notes block in the matrix generator
Add the blank line after `Notes:` (markdownlint MD032) in the generator HEADER so
a fresh `027-integration-matrix.gen.py` run stays lint-clean and idempotent with
autoformat. Regenerate the matrix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:53:08 +02:00
kevinveenbirkenbachandClaude Opus 4.8 a0a0eac61e chore(requirements): mark integration-matrix generator executable (ruff EXE001)
The generator carries a `#\!/usr/bin/env python3` shebang; make the file
executable so ruff's flake8-executable check passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:53:08 +02:00
kevinveenbirkenbachandClaude Opus 4.8 48f8000c6e docs(requirements): renumber MCP matrix + addon-syntax (026 -> 027/028) after merge
feature/mcp's 026-integration-matrix and 026-unified-addon-syntax collided with
main's numbering on merge. Renumber both and fix every cross-reference:
- 026-integration-matrix.{md,gen.py} -> 027-integration-matrix.{md,gen.py}
- 026-unified-addon-syntax.md        -> 028-unified-addon-syntax.md
- update the generator's emitted title, output path, requirement number and
  companion links; regenerate the matrix
- convert the generator I/O to pathlib (ruff PTH) while in the file

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:53:07 +02:00
kevinveenbirkenbach 6332071668 Merge branch 'feature/mcp' into fix/ci-deploy-server-failures
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2026-06-13 15:29:56 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6c38fcf5c8 docs(requirements): add 026 cross-role integration matrix
Add the generated role×role integration matrix (026-integration-matrix.md
+ generator) and expand 026 with: required-gated install-failure handling,
mechanism=bridge for network bridges, addon variant/matrix axis, and the
matrix-backed cross-role integration backlog. The matrix scans every role's
meta/services.yml for infinito-native wired edges (☑️) and overlays curated,
web-verified upstream plugin edges (✅/🪙): 511 wired + 96 upstream across 82
roles. Header repeats every 10 rows and columns for readability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:29:54 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8772d2fac7 docs(requirements): add 026 unified addon syntax
Promote per-app addon/plugin/extension/module/bridge declarations to a
single file-rooted meta/addons.yml contract: unified schema, explicit
cross-role bridge rule, required-gated install-failure handling (hard
fail vs warn+skip), addon state as a variants.yml matrix axis, network
bridges (Matrix mautrix) as mechanism=bridge addons, external drift
monitoring, and a Playwright test per user-facing addon. Audit expanded
to matrix, discourse, pretix, mattermost, desk-chromium/firefox/gnome;
mobilizon/bookwyrm DB extensions classified out of scope.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:29:54 +02:00
kevinveenbirkenbachandClaude Opus 4.8 dc84016f9d docs(requirements): add 025 MCP role integration
Define the unified MCP service, identity, proxy, and test contract for
server and client roles, with a repo-wide audit, bridge discovery via
roles_with_service, and a Playwright test per integrated role.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:29:54 +02:00
kevinveenbirkenbachandClaude Opus 4.8 70ad33bc13 fix(web-app-peertube): repair the SeaweedFS object-store e2e test for PeerTube v8.2.1
The test timed out: the publish-button locator no longer matched the v8.2.1
manage-video wizard, and the inline 78-byte MP4 stub was structurally invalid,
so PeerTube rejected the upload as "Video file unreadable" and left the Save
button disabled.

- test-seaweedfs.js: target the v8.2.1 save control (.save-button > button),
  upload PeerTube's real video_short.mp4 fixture, and assert a version-tolerant
  saved marker.
- add fixture roles/web-app-peertube/files/playwright/fixtures/video_short.mp4.
- test-e2e-playwright: stage role-local files/playwright/fixtures/ next to the
  tests (the *.js glob ships neither binaries nor subdirectories), so specs load
  a fixture via path.join(__dirname, "fixtures", <name>).
- docs: document the fixtures/ folder and the per-scenario test-*.js split in the
  playwright spec contract and the runner README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 14:07:03 +02:00
kevinveenbirkenbachandClaude Opus 4.8 7c84617758 docs(role-loop): make matrix-variant command selection unambiguous
Replace the prose that an agent could read as 'no variant passed implies mode=reinstall' with an explicit situation-to-command table plus a FORBIDDEN list: every mode=update is variant-pinned, and a no-variant mode=reinstall is reserved for the initial baseline and the final gate only. A failing variant is retried with mode=update variant=<idx>, never by restarting the whole matrix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 22:38:56 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bc075906d7 test(objstore): require seaweedfs for database-backed web-app roles
Add a meta lint asserting every web-app role with postgres or mariadb declares a seaweedfs object-store service, exemptable via the seaweedfs-required nocheck marker. Mark the 33 database-backed roles that do not use object storage, and register the rule in the suppression catalog.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 21:00:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3bdc8180c7 chore(changelog): archive releases past active window
Trim CHANGELOG.md to the active window and move older entries (4.0.3 through 8.0.4) into docs/changelog/; regenerate the Debian and Fedora package changelogs from the kept entries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 10:46:05 +02:00
evangelostsak 72a56b8aa8 fix(web-app-penpot): derive native_login/registration from sso flag (variant-aware)
The all-off matrix variant pins services.sso.enabled=false while
web-app-keycloak stays in group_names, so the previous group_names-based
defaults yielded disable-login-with-password AND no OIDC — leaving no usable
login method, and the native Playwright test failed (no password form).

Derive both toggles from PENPOT_SSO_ENABLED (the variant-aware sso flag),
matching how the oidc/ldap flags are already computed:
- native_login = not sso  (off under OIDC, on otherwise)
- registration = sso       (on under OIDC for JIT provisioning)

Drops the services.penpot.native_login / registration_enabled meta keys
(a group_names default can't see variant overrides). README + req-023 updated.
2026-06-10 18:03:04 +02:00
evangelostsak e7a799f542 feat(web-app-penpot): disable native login under OIDC (Kevin review)
- meta/services.yml: new `penpot.native_login` toggle, default off when
  web-app-keycloak is present (forces SSO), on otherwise.
- vars: PENPOT_FLAGS renders enable-/disable-login-with-password from it.
- tasks: administrator local-password bootstrap gated on native_login.
- playwright: test-login-native.js skips when `sso` is enabled.
- meta/main.yml: drop the Figma parenthetical from the description.
- README + req-023 updated.
2026-06-10 15:35:03 +02:00
evangelostsak e6afb12078 Merge upstream/main into feature/web-app-penpot
# Conflicts:
#	docs/requirements/README.md
2026-06-10 14:07:51 +02:00
evangelostsak 4c051d9939 fix(web-app-penpot): registration on for OIDC JIT + split login specs per persona
Biber OIDC login failed the deploy with `?error=registration-disabled`:
Penpot routes first-time OIDC logins through the registration path, so a
disabled flag blocks JIT-provisioning of not-yet-seen federated users
(admin already existed, biber did not). LDAP self-provisions without it.

- meta/services.yml: registration_enabled now follows OIDC (on when
  web-app-keycloak is present), off otherwise; native admin is bootstrapped
  and LDAP needs no registration. vars/README/req-023 updated to match.
- playwright: split the combined OIDC and LDAP login specs into one file
  per persona — test-login-{oidc,ldap}-{admin,biber}.js — wired through the
  orchestrator; README Testing section updated.
2026-06-10 01:02:55 +02:00
evangelostsakandClaude Opus 4.8 532c2893d6 feat(web-app-penpot): native local-password login + docs
Bootstrap a local password for the administrator profile via the backend
PREPL (enable-prepl-server) so native email/password login works alongside
OIDC/LDAP. Adds enable-login-with-password and a registration toggle driven
by services.penpot.registration_enabled (off once OIDC is the login path).

- vars: PENPOT_FLAGS gains password login + prepl + conditional registration;
  PENPOT_REGISTRATION_ENABLED and PENPOT_ADMIN_{EMAIL,PASSWORD,FULLNAME}.
- tasks: idempotent create-profile / update-profile bootstrap (no_log).
- playwright: test-login-native.js drives the local password Login button.
- README + requirement 023: native login, registration toggle, canonical
  domain penpot.design, CA-trust gating, spec split; tick project/asset
  coverage; fix header 235 -> 023.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 23:21:20 +02:00
evangelostsak ae3eb76e6a add trailing new_line no meet CI tests 2026-06-06 17:33:51 +02:00
evangelostsak 771c449c8f feat(web-app-penpot) add missing requirement file used by the agent and its necessary documentation 2026-06-06 17:24:05 +02:00
evangelostsak 83ab973dfa feat(web-app-penpot): live-verify OIDC/LDAP + project/asset; JVM CA-trust fix; archive req 235
Deployed Penpot + Keycloak + OpenLDAP end to end and drove the per-role
Playwright suite green against the live stack (8 passed, 2 skipped):
TLS baseline, OIDC (administrator + biber), LDAP (administrator + biber),
project creation, and image asset upload. The two skips are the generic
biber/administrator persona scenarios, declared blocked via
PERSONA_*_BLOCKED (mirroring web-app-taiga): Penpot's in-app "OpenID"
login entry and SPA user-menu logout are not driveable by the generic
persona helper, so both users' real auth is exercised by the dedicated
OIDC + LDAP scenarios.

Fixes found during bring-up:
- OIDC JVM CA trust: the backend command imports the internal CA into a
  writable cacerts copy and points the JVM at it via JAVA_TOOL_OPTIONS.
  with-ca-trust.sh covers OS/NSS/env trust but not the JVM truststore, so
  server-side token/userinfo calls to Keycloak failed with "PKIX path
  building failed". CA path hardcoded (the CA-override double-escapes a $).
- disable-onboarding added to PENPOT_FLAGS so users land on the dashboard.
- Playwright env: ADMIN_EMAIL/BIBER_EMAIL for the LDAP form; alphabetised.

Requirement 235 is fully checked off and archived out of docs/requirements/.
2026-06-06 08:22:13 +02:00
evangelostsak edef635fbb feat(web-app-penpot): add Penpot design platform role (req 235)
Add a new `web-app-penpot` role deploying Penpot's frontend + backend +
exporter containers behind the standard reverse proxy, with shared
svc-db-postgres and a svc-db-redis sidecar. Wires native OIDC (Keycloak)
and LDAP (OpenLDAP) login via PENPOT_FLAGS, CSP/vhost via sys-stk-full,
backup-ready asset volume, marketplace tags, matrix variants
(all-on/all-off/LDAP-only), and a service-gated Playwright spec with
guest/biber/administrator personas plus separate OIDC and LDAP scenarios.

Implements docs/requirements/235-setup-penpot.md. Live-deploy DoD items
(fresh-host deploy, domain reachability, full in-container `make test`)
remain unverified in the sandbox and are left unchecked.
2026-06-06 08:22:13 +02:00
evangelostsak 4757a639b0 revert: clean branch to upstream main state
Remove the entire web-app-penpot role, all associated docs, and all other
changes accumulated on this branch. Working tree now matches origin/main
exactly. Commit history preserved for reference.
2026-06-06 08:22:13 +02:00
evangelostsak d57c0aca2d feat(web-app-penpot): complete role setup with playwright e2e tests
- Move playwright spec to roles/web-app-penpot/files/playwright/ (standard location)
- Fix APP_BASE_URL: use normalizeUrl() to strip dotenv_quote double-quotes
- Gate biber/admin tests with safeSkipUnlessEnabled('oidc') (penpot requires OIDC)
- Add meta/variants.yml with all-true, all-false, LDAP-only variants
- Fix templates: use container_depends_on lookup, correct LDAP group vars
- Align services.yml: javascript service static false with nocheck comment
- Update playwright.env.j2: OIDC_SERVICE_ENABLED env var for service gate
- All make test targets pass (lint, test-unit, test-integration, test-lint, test-external)
2026-06-06 08:22:13 +02:00
evangelostsak 07344e2ca7 feat(penpot): add setup documentation for Penpot integration in Infinito.Nexus 2026-06-06 08:22:10 +02:00
kevinveenbirkenbachandClaude Opus 4.7 70c1a03f13 feat(web-app-matrix): add ansible flavor via unified compose.yml.j2
Implements requirement 025 (docs/requirements/025-web-app-matrix-ansible-flavor.md).

Architecture:
- services.matrix.flavor: ansible | compose
- Single templates/compose.yml.j2 branches on matrix_flavor
- ansible flavor: defines matrix-mdad-runner one-shot compose service that
  DiD-executes upstream matrix-docker-ansible-deploy (pinned ref + migration
  validated version). MDAD writes /etc/systemd/system/matrix-*.service units
  on the host; post-up Ansible task container-waits the runner, then probes
  loopback ports + wires sys-stk-front-proxy.
- compose flavor: legacy in-repo stack (synapse/element/coturn/bridges) kept
  for regression coverage, marked deprecated.

Variant-switch ansible -> compose:
- 00_cleanup_mdad_residue.yml tears down MDAD-installed systemd units +
  leftover matrix-* containers before compose-flavor brings up its own
  matrix-synapse (else: name conflict, compose down doesn't touch
  systemd-managed state).

Reorganization:
- roles/web-app-matrix/{tasks,templates,files}/flavor/{ansible,compose}/
- Renamed legacy compose-flavor task files into flavor/compose/
- New runner Dockerfile (multi-stage, ARG-parameterized FROM via build-args)

Verified: 3 variants x 2 passes (sync+async) full_cycle green, all 6
PLAY RECAPs failed=0. V1 (ansible all-on), V2 (ansible no-auth), V3
(compose deprecated all-on). Playwright matrix tests pass per variant.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 10:21:41 +02:00
kevinveenbirkenbachandClaude Opus 4.7 a71c5a2de6 docs(requirements): add 025 web-app-matrix ansible flavor
New requirement for adding a second deployment flavor to web-app-matrix
that delegates to the upstream matrix-docker-ansible-deploy (MDAD)
playbook. The existing role-internal compose stack stays selectable as
the `compose` flavor for one deprecation window.

Captures 12 proposed design decisions for operator review before
implementation: flavor dispatch in services.matrix.flavor (ansible
default; compose deprecated), MDAD pulled in as a pinned git checkout at
deploy time (not vendored), MDAD inventory templated from
lookup('config', ...), every supported bridge + Jitsi + Element Call
enabled by default when no operator-issued third-party token is needed,
central svc-db-postgres + svc-db-redis + Mailu reuse, sys-svc-proxy
fronts MDAD's services (MDAD's bundled traefik disabled), four variants
(V1 ansible all-on, V2 ansible all-off, V3 ansible ldap-only, Vcompose-1
regression), two new Playwright specs (element-call, bridge-roster),
lifecycle: alpha on the new flavor.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-03 12:01:19 +02:00
kevinveenbirkenbachandClaude Opus 4.7 014fa54ad3 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-02 21:01:38 +02:00