Drops markdown links in 017/018 and role TODOs that pointed at the
016 and 019 requirement files archived in 027ba06ee. The text
references stay; only the now-broken link targets are removed so the
markdown-links lint passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Root cause of step-08 deploy failures across all 4 test-development
distros in run 26572559126: `make compose-deploy mode=reinstall
apps=web-app-dashboard INFINITO_SERVICES_DISABLED=matomo` (step 07)
made make export the cmdline var into the recipe's shell env, which
reached `runner.py` → `make setup` → `make dotenv`. The dotenv
generator's `setdefault` then baked the runtime-only value into the
on-disk `.env`. Step 08 sourced that .env, filtered `web-app-matomo`
out of its primary apps, and exited with "All primary apps disabled".
Fix:
- Drop the 7 routing knobs (apps, mode, purge, bundles, disable,
full_cycle, variant) from `passthrough.STATIC_KEYS` and from
`default.env`. They are per-invocation; .env is the persistent SPOT
and must not capture them.
- Switch every consumer from `os.environ["KEY"]` strict access to
`os.environ.get("KEY", "")` so the missing-key path stops at "no
filter" instead of a KeyError.
- Rename the env-var surface to match the make-alias surface 1:1
(lowercase): INFINITO_APPS → apps, INFINITO_SERVICES_DISABLED →
disable, INFINITO_BUNDLES → bundles, INFINITO_FULL_CYCLE →
full_cycle, INFINITO_VARIANT → variant, INFINITO_DEPLOY_MODE → mode,
INFINITO_PURGE_ENTITIES → purge. The make alias was the user-facing
name in every doc; routing-knob env vars now use the same name so
the cmdline form, the recipe env-prefix, and the consumer reads
all line up.
- Collapse the Makefile `compose-deploy` recipe to just the two
knobs whose alias differs from the env name (`type` →
INFINITO_DEPLOY_TYPE, `debug` → INFINITO_DEBUG). GNU Make
auto-exports cmdline variables into the recipe's shell env, so the
identical-name `$(if $(apps),apps="$(apps)")` lines were pure
noise.
- Drop `disable: ${disable}` from compose.yml. The dev CLI builds
`extra_env` per `docker exec` call and forwards `disable` via
`-e`, so the container env never needs the value frozen at
compose-up time.
- Update the 3 actual leak call sites
(07/08/09_deploy_*.sh) to the make-alias form
(`disable=matomo`, `full_cycle=true`, `variant=1`).
- Add `SIM112` to ruff's ignore set: the lowercase env names are
the deliberate make/env parity, not a typo.
Repro before fix: `INFINITO_SERVICES_DISABLED=matomo make dotenv`
wrote `INFINITO_SERVICES_DISABLED=matomo` to `.env`. After fix:
`disable=matomo make dotenv` leaves `.env` untouched.
Tests: `make test` and `make autoformat` green (2711 tests, 8 lint
sub-targets).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ran `python -m cli.contributing.requirements.archive` to move the
following fully-checked-off requirement files into the `## Archive`
block of `docs/requirements/README.md` and delete the per-requirement
files:
- 001 - Nextcloud Talk TURN relay
- 002 - Service Registry Refactoring
- 003 - Reduce `applications` and `users` to lookup-only access
- 004 - Generic RBAC role auto-provisioning via OpenLDAP
- 005 - WordPress Multisite support for OIDC-driven RBAC
- 006 - Service-gated Playwright tests
- 007 - WordPress to Discourse post round-trip
- 015 - KIX Service Management integration
- 016 - web-app-hugo
Cross-references from the still-open requirements (015-moodle,
015-opencloud, 017, 018, 019, 021) rewritten from the deleted file
paths to \`README.md#archive\`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace 8 bash env modules with a single Python generator
(cli.meta.env) that materialises env/static.env + runtime context
into a gitignored .env. Each variable lives in its own handler
under utils/env/handlers/; defaults carry inline one-line `# ...`
comments.
Rename to the INFINITO_* schema:
- workflow inputs: APPS, SERVICES_DISABLED, CMD, DEBUG, WHITELIST,
BUNDLES, FULL_CYCLE, VARIANT, RUN_FLAGS, LIMIT_HOST, PARALLEL
- inventory: INVENTORY_DIR / INVENTORY_FILE / HOST_VARS_FILE,
PW_FILE -> INVENTORY_PASSWORD_FILE
- venv: VENV_BASE / VENV_FALLBACK / VENV_NAME
- new SPOT defaults: COMPILE_SILENCE, CONTAINER_NO_CA,
WAIT_HEALTH_TIMEOUT_S, PACKAGE_CACHE_FRONTEND_INIT_IMAGE,
promoted IMAGE_TAG from GHA-only to general passthrough
compose.yml hardening:
- inline \${VAR:-default} removed; strict \${VAR:?...} everywhere
- new integration lint blocks regressions
Tooling:
- scripts/install/all.sh owns the stamp-file install logic
(Makefile target delegates)
- scripts/meta/env/load.sh is the single shell entry point;
8 bash modules deleted
- new shell lint: no INFINITO_* defaults outside env/static.env
Tests:
- 93 new unit tests for utils/env/{builder,parser,runtime,writer}
- restructure tests/lint into repository/ (file-content rules) vs
filesystem/{shell,python,env}/ (filesystem-shape rules)
- drift + smoke integration tests against the generator
Docs:
- variables.md is now a pointer; per-variable docs live next to
the key in env/static.env / env/ci.env
- compose.yml.md drops the Default column
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three classes of drift cleaned up across 85 .md files:
- Em-dashes: replaced ` — ` with the contextually correct separator
(colon for `term: explanation`, period to split clauses across
sentences/source lines, parentheses for asides, semicolon for
tight-linked continuations). Two intentional exceptions remain
in `docs/contributing/documentation.md` (the rule literal) and
inside a fenced ```sh block in `docs/contributing/actions/debugging/ci.md`.
- SPOT self-labels: rewrote "This is the SPOT for X" to describe
the subject directly ("This directory holds X" / "This file
describes X"). Cross-references to other artefacts' canonical
role remain unchanged.
- Heading-emoji position: moved leading-emoji headings (`# 🧩 Title`)
to trailing position (`# Title 🧩`) per the headline rule that
emojis MUST come after the title text.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move the three persona-contract lints from
`tests/lint/ansible/roles/web-app/playwright/test_persona_*.py` into
their own `persona/` subdirectory and drop the now-redundant
`_persona` filename prefix:
* `test_persona_naming.py` -> `persona/test_naming.py`
* `test_persona_required_envs.py` -> `persona/test_required_envs.py`
* `test_persona_strict_mode.py` -> `persona/test_strict_mode.py`
The new `persona/__init__.py` re-anchors `PROJECT_ROOT` one level
deeper (`parents[7]`). Doc references in requirements 017, 018, and
019 now point at the new paths.
Renames are tracked via `git mv`, so commit history is preserved.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fold the recently-landed Playwright lint guards into the three
playwright-related requirement docs so the rules table and per-rule
"Enforced by" column point at the actual mechanical enforcement
rather than at "review (this requirement)".
* 019 Rule 1 now distinguishes the dashboard treatment for
`web-app-*` consumers (per-consumer flag exemption via
`*_TARGET_ROLES_JSON`, owned by the provider's own spec) from the
hard prohibition for non-`web-app-*` roles
(`test_dashboard_integration_scope.py` forbids any truthy
`dashboard.{enabled,shared}` declaration outside `web-app-*`).
* 019 Rule 3 / Rule 11 / Rule 12 now reference
`test_persona_naming.py`, `test_persona_required_envs.py`, and
`test_persona_strict_mode.py` as the enforcing lints.
* 019 "Closure paths" gains a dashboard-scope-exception paragraph:
paths 1 (render flag) and 3 (`# nocheck` annotation) collapse for
non-`web-app-*` roles; only path 2 (drop the entry) or a static
`dashboard: { enabled: false, shared: false }` declaration remain.
* 019 matrix: `dashboard` removed from the "fehlende Flags" column
of `web-svc-cdn`, `web-svc-libretranslate`, and `web-svc-simpleicons`
(no longer a closure target on these roles).
* 019 Verification block: four new green-tree-wide check items for
the persona / dashboard-scope lints.
* 017 + 018 each gain a Policy bullet anchoring the
`<persona>: <flow>` naming convention to 019 Rule 3 and the
`test_persona_naming.py` lint, and 018 explicitly forbids parallel
ungated `ldap login` tests (per 019 Rule 5).
* Touched-rule cleanup: replace existing em-dash clause separators in
Rule 3 and Rule 11 with `;` / `,` per the documentation style guide.
006 stays untouched: it is already a closed retro doc with the
`MODE_CI`-retired banner.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a lint that rejects empty/tautological/TODO-marked persona and
contract test bodies in roles/<role>/files/playwright.spec.js, plus
the spec-contract doc updates (playwright.specs.js.md, req-017/018/019)
and the integration-test parity-guard tweak that articulate it.
Reason: previous batch updates produced "contract: <svc> gate is wired"
stubs whose bodies only proved what the gate itself already proved; the
lint catches both the title shape and the body shape so a rename is not
enough.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The meta-tests reorganisation in 8d8576e53 renamed and moved
``tests/integration/roles/meta/test_services_dynamic_flags.py`` to
``tests/integration/roles/meta/services/test_dynamic_flags.py``
and shifted the dependency-graph cluster from
``tests/integration/roles/dependencies/`` to
``tests/integration/roles/meta/dependencies/``. Four markdown
links still pointed at the pre-rename paths and tripped
``test_markdown_relative_links_resolve``:
- ``docs/contributing/actions/testing/suppression.md:62`` (the
``dynamic-flag`` row of the suppression catalog)
- ``docs/requirements/017-playwright-biber-rbac-coverage.md:46``
- ``docs/requirements/018-playwright-ldap-coverage.md:47``
- ``tests/integration/roles/README.md:5`` (also added a pointer
to the sibling ``meta/services/run_after/`` cluster that owns
the ``run_after`` checks)
Verification: ``test_markdown_relative_links_resolve`` passes; no
other content changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>