Commit Graph
10 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.7 398aeb19f4 fix(purge/apps): skip 'docker network prune' when daemon is unreachable
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 01:09:03 +02:00
kevinveenbirkenbachandClaude Opus 4.7 094cc5b54c fix(purge): always run nginx vhost purge, gate compose/db/dir/network on stack presence
The early `/opt/compose/${entity}` check in apps.sh skipped redirect-only
entities (cdn, css, asset, file — no compose stack, only nginx vhost
files) before nginx.sh could run, leaving their per-domain vhosts
behind across matrix-deploy variant transitions.

Concretely chess CI Run 25997888664: variant-0 deployed web-svc-css
which rendered css.infinito.example.conf; the inter-round purge for
variant-1 skipped css with `\!\!\! WARNING: /opt/compose/css not found`;
the vhost survived; hlth-csp's headless browser then probed
https://css.infinito.example/ and got ERR_CERT_COMMON_NAME_INVALID
(the surviving vhost falls back to the default_server cert).

Moves the compose-dir guard from the entity-collection loop into the
purge loop and runs nginx.sh unconditionally before the
compose-dependent purges. The else branch prints the skip reason so
operators retain the trace signal for redirect-only entities.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 01:09:02 +02:00
kevinveenbirkenbachandClaude Opus 4.7 16bdbf03d7 docs: fix repo-wide drift against documentation.md style rules
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>
2026-05-15 20:12:07 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d1de165e9c feat(purge): drop orphan default networks per entity + global prune
`docker compose down --remove-orphans` only deletes networks that
compose itself created (those carrying
`com.docker.compose.network=default` + `com.docker.compose.project=<name>`
labels). When the per-entity default network ends up unlabeled or
project-mislabeled — typical after an inter-round matrix-deploy
purge, or when a `community.docker.docker_network` Ansible call
materialised the network before compose ran — compose deliberately
leaves it untouched, and a subsequent `compose up` aborts with
  network <entity> was found but has incorrect label
  com.docker.compose.network set to "" (expected: "default")
The matrix-deploy CI rounds for web-app-matrix, web-app-gitea and
others reliably reproduce this.

Add a new entity-keyed purge primitive
`scripts/container/purge/entity/network.sh <ENTITY>` that runs after
the compose / dir / nginx primitives. It is idempotent: no-op when
the network does not exist, skips removal while active container
endpoints prove the network belongs to a shared service still in
use (svc-db-mariadb, svc-db-postgres, svc-db-openldap, svc-ai-ollama,
…), and otherwise drops the orphan network with `docker network rm`.
`docker network rm` failures are logged and tolerated — the next
`compose up` will surface the same problem with an actionable error.

Wire the primitive into `scripts/container/purge/apps.sh` immediately
after the existing `nginx.sh` call, so every entity-keyed purge
collects its own default network on the same pass.

Finally, after the entity loop, run a single bare `docker network
prune -f` to sweep orphan networks whose name does NOT correspond
to a purged entity (left over from renamed roles, abandoned
matrix-deploy rounds, etc.). The sweep is bare on purpose — no
`|| true` guard — so a daemon-side prune failure aborts the purge
loudly via the script's `set -euo pipefail`. Performance: ~13× faster
than calling prune inside `network.sh` per entity (one ~200 ms
listing pass vs. N × 200 ms for N entities).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 11:45:44 +02:00
kevinveenbirkenbachandClaude Opus 4.7 820fb0a222 fix(purge): clear stale nginx vhosts between matrix-deploy rounds
Matrix-deploy variant transitions left per-domain vhost files behind:
when a service dropped out of a round's include set, sys-svc-compose's
docker prune removed its container but the vhost under
<NGINX_DIR>/conf.d/servers/{http,https}/<domain>.conf survived, making
the next round's HTTPS probe see 502 instead of TLS-error 000 (5 failed
test-development jobs on run 25705903504).

The inter-round purge in cli.administration.deploy.development.deploy
already invokes scripts/tests/deploy/local/purge/entity.sh with the
previous round's full include — the missing piece was an entity-keyed
nginx primitive next to db/compose/dir. Add it:

- utils.roles.entity_apps.apps_for_entity: reverse of get_entity_name,
  walks roles/*/vars/main.yml to map entity -> [application_id]
- utils.cleanup.nginx_vhosts: resolves entity -> apps -> canonical+alias
  domains (via build_applications_from_roles + iter_app_domains so it
  stays ansible-free) and removes the matching vhost files
- scripts/container/purge/entity/nginx.sh: thin bash wrapper,
  symmetric to db/compose/dir
- scripts/container/purge/apps.sh: drive nginx.sh inside the entity
  loop, alongside db/compose/dir

Tests: 14 new unit tests covering the reverse-lookup edge cases and
the purge iterator (existing-only / aliases / multi-entity / no-op CLI).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 02:17:26 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d3afe0bc81 test(lint): forbid a file from referencing its own path as a string
Hard-coded self-path references rot the moment the file moves: a header
comment ``# utils/foo/bar.py`` at the top of a module, a docstring
mentioning ``utils/foo/bar.py``, or a docs entry linking
``utils/foo/bar.py`` from inside ``utils/foo/bar.py`` itself all silently
desync from reality after the next ``git mv``.

The new lint walks every project file, computes its POSIX-style relative
path from PROJECT_ROOT, and reports any line whose text contains that
path as a substring. Files at the repo root (no ``/`` in their relative
path) and setuptools-generated ``*.egg-info/`` artefacts are exempt.
Per-line opt-out via ``# nocheck: self-path-reference`` on the offending
line, registered in the suppression catalog.

Existing offenders cleaned up:
- 72 redundant ``# <self-path>`` header lines removed across roles,
  cli, plugins, scripts, tests, and utils.
- 4 prometheus templates that told consumers to "update
  <self-template-path>" rewritten to drop the redundant self-reference.
- 8 docstring/comment self-references in cli, plugins, tests, utils,
  and the dashboard oidc.js.j2 header rewritten to describe the layout
  without naming the file's own path.
- 17 legitimate usage examples (shell scripts, test data lists, one
  template self-include doc-block) marked with ``nocheck:
  self-path-reference``.
- ``container.sh`` heredoc usage strings switched to ``${0}`` so the
  marker stays out of the user-visible help output.
- ``healthcheck/http.yml.j2`` doc-block rewritten to prose because
  ``{# ... #}`` Jinja comments cannot host an inner ``{# nocheck #}``
  (the inner ``#}`` closes the outer comment).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 03:53:44 +02:00
kevinveenbirkenbachandClaude Opus 4.7 85f1caccc7 refactor(utils): consolidate role-scoped helpers under utils/roles and split templating
Tighten the utils namespace so each subpackage owns one concern:

- utils/applications/* moves under utils/roles/applications/* (helpers
  that operate on the runtime applications dict and meta/services.yml).
- utils/service_registry.py and utils/database_service.py move under
  utils/roles/applications/services/ as registry.py and database.py.
- utils/entity_name_utils.py becomes utils/roles/entity_name.py.
- utils/invokable.py, utils/valid_deploy_id.py, and the existing
  utils/roles/resource_validation.py group under utils/roles/validation/
  as invokable.py, deploy_id.py, and resources.py.
- utils/templating.py and utils/jinja_strict.py split into
  utils/templating/ansible.py (Templar + TrustedAsTemplate, lookup-env
  shortcut) and utils/templating/jinja.py (vanilla Jinja2 Environment,
  multi-pass strict render).

Every caller in utils, cli, plugins, roles/<role>/{filter,lookup}_plugins,
tests, and the docs that link to the moved files is updated to the new
import paths. Test files mirror the new source layout
(tests/unit/utils/{roles,templating}/...).

New READMEs at utils/cleanup/, utils/roles/, utils/roles/applications/services/,
utils/roles/validation/, and utils/templating/ follow the
documentation.md and readme_md.md guidelines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 03:53:43 +02:00
kevinveenbirkenbachandClaude Opus 4.7 5325fe3cf0 refactor(purge): app-keyed orchestrator + wipe stale tokens between rounds
The token store at /var/lib/infinito/secrets/tokens.yml survived
compose+volumes purges, so matrix-deploy variant transitions left a
stale matomo token in place. On the next round the token-empty guard
in sys-front-inj-matomo never fired and the public-URL probe hit an
empty openresty upstream, returning 502.

- utils/cleanup/tokens.py: wipes users.<user>.tokens.<app_id> entries
  via utils.cache.yaml (load_yaml_any / dump_yaml).
- scripts/container/purge/apps.sh: app-keyed orchestrator that maps
  $APPS to compose entities, drives entity/{db,compose,dir}.sh, and
  invokes utils.cleanup.tokens for the same app set.
- scripts/tests/deploy/local/purge/entity.sh becomes a thin
  docker-exec wrapper invoking apps.sh inside the runner.
- Drop scripts/container/purge/entity/all.sh; its trivial loop and
  unused --wipe-data-only / --db-only flags fold into apps.sh.
- tests/unit/utils/cleanup/test_tokens.py covers wipe paths (single
  app, multi-user, multi-app, no-match no-rewrite, missing file,
  user-without-tokens, non-dict user) plus the __main__ shim.
- READMEs updated for the new layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 02:25:04 +02:00
Environment TestandClaude Sonnet 4.6 5c1a963d30 docs(tools): restructure security and framework docs, add cleanup workflow
- Move flow/security/ghcr.md to tools/ghcr/authentication.md
- Move flow/security/mirror-cleanup.md to tools/ghcr/cleanup.md
- Move flow/security/branch.md to tools/github/branch.md
- Move flow/security/repository.md to tools/github/repository.md
- Move code/frameworks/ansible.md to tools/ansible.md
- Merge code/frameworks/Makefile.md into tools/make.md and extract file rules to artefact/files/makefile.md
- Rename tools/makefile.md to tools/make.md
- Add .github/workflows/images-mirror-cleanup.yml for manual GHCR cleanup
- Apply documentation.md standards: emojis on headlines, no em dashes, filename link text
- Fix all cross-references broken by directory restructuring

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 16:31:22 +02:00
kevinveenbirkenbach 0200b22298 Normalize scripts layout and Make targets 2026-03-28 09:00:38 +01:00