Files
computer-playbook/scripts/container/purge/apps.sh
T
kevinveenbirkenbachandClaude Opus 4.7 8e293bd921 fix(compose-deploy): stop persisting runtime routing knobs into .env
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>
2026-05-28 17:47:03 +02:00

90 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# App-keyed purge orchestrator. Maps each app id in $apps to its
# compose entity, then for each entity runs the entity-keyed primitives
# (db, compose, dir) and finally wipes the matching token-store entries
# via utils.data.tokens. Tokens live outside /opt/compose and would
# otherwise survive entity purges, breaking matrix-deploy variant
# transitions (stale token slips past the empty-token guard in
# sys-front-inj-matomo and the next round 502s on the public matomo URL).
#
# Expects:
# apps (required) e.g. "web-app-nextcloud" or "web-app-keycloak,web-app-matomo"
#
# Designed to be invoked from the host via:
# docker exec -e apps="${apps}" <container> \
# bash ${INFINITO_SRC_DIR}/scripts/container/purge/apps.sh # nocheck: self-path-reference
set -euo pipefail
: "${INFINITO_SRC_DIR:?INFINITO_SRC_DIR must be set by the container environment}"
cd "${INFINITO_SRC_DIR}"
: "${apps:?apps is not set (e.g. apps=web-app-nextcloud)}"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ENTITY_DIR="${SCRIPT_DIR}/entity"
apps_raw="${apps//,/ }"
read -r -a apps <<<"${apps_raw}"
if [[ "${#apps[@]}" -lt 1 ]]; then
echo "!!! WARNING: apps is empty after parsing: skipping purge"
exit 0
fi
if [[ -f "scripts/meta/env/load.sh" ]]; then
# shellcheck source=scripts/meta/env/load.sh
source "scripts/meta/env/load.sh"
fi
python_bin="${PYTHON:-python3}"
declare -A seen_entities=()
entities=()
for app in "${apps[@]}"; do
[[ -n "${app}" ]] || continue
entity="$("${python_bin}" -c 'from utils.roles.entity_name import get_entity_name; import sys; print(get_entity_name(sys.argv[1]) or "")' "${app}")"
if [[ -z "${entity}" ]]; then
echo "!!! WARNING: could not derive entity from apps=${app}: skipping"
continue
fi
if [[ -z "${seen_entities[${entity}]:-}" ]]; then
seen_entities[${entity}]=1
entities+=("${entity}")
echo ">>> Derived entity from apps=${app}: ${entity}"
fi
done
echo ">>> Wiping token-store entries for: ${apps[*]}"
"${python_bin}" -m utils.cleanup.tokens "${apps[@]}" || true
echo ">>> Wiping databases.csv entries for: ${apps[*]}"
"${python_bin}" -m utils.cleanup.databases_csv "${apps[@]}" || true
if [[ "${#entities[@]}" -lt 1 ]]; then
echo "!!! WARNING: no valid entities found: skipping entity purge"
exit 0
fi
for entity in "${entities[@]}"; do
echo
echo ">>> Purging entity: ${entity}"
bash "${ENTITY_DIR}/nginx.sh" "${entity}" || true
if [[ -d "/opt/compose/${entity}" ]]; then
bash "${ENTITY_DIR}/db.sh" "${entity}" || true
bash "${ENTITY_DIR}/compose.sh" "${entity}" || true
bash "${ENTITY_DIR}/dir.sh" "${entity}" || true
bash "${ENTITY_DIR}/network.sh" "${entity}" || true
else
echo ">>> /opt/compose/${entity} not present — skipping compose/db/dir/network purges"
fi
done
if docker info >/dev/null 2>&1; then
docker network prune -f
else
echo ">>> docker daemon not reachable — skipping 'docker network prune'"
fi