#!/usr/bin/env bash # panama-server against a throwaway HOME, a fixture catalog, and a stubbed # systemctl -- the behaviors that protect a machine's live services: # # * enable seeds .env from .env.example and REFUSES to start while a # CHANGE_ME placeholder survives -- a service brought up with the # placeholder as its database password runs, wrongly, forever # * a completed enable links exactly the tracked files (compose.yml and the # unit), reloads systemd, and enables the unit # * disable removes the unit and nothing else: the .env and data stay # * relink refreshes links for enabled services only, and names a service # whose definition changed since the machine last looked -- without # restarting anything set -uo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" panama_server="$repo_dir/bin/panama-server" findings=() note() { findings+=("$1"); } [[ -x "$panama_server" ]] || { printf 'panama-server contract: %s is not executable\n' "$panama_server" >&2; exit 1; } work="$(mktemp -d)" trap 'rm -rf "$work"' EXIT home="$work/home" catalog="$work/catalog" stub_dir="$work/bin" calls="$work/calls" mkdir -p "$home" "$stub_dir" "$catalog/Example" : >"$calls" cat >"$catalog/Example/compose.yml" <<'YML' services: example: image: docker.io/library/nginx:latest environment: DB_PASSWORD: ${DB_PASSWORD} YML cat >"$catalog/Example/.env.example" <<'ENV' DB_PASSWORD=CHANGE_ME ENV cat >"$catalog/Example/podman-example.service" <<'UNIT' [Unit] Description=Podman Compose: Example [Service] Type=oneshot WorkingDirectory=%h/Server/Example ExecStart=/usr/bin/podman compose up -d ExecStop=/usr/bin/podman compose down RemainAfterExit=yes [Install] WantedBy=default.target UNIT # The stub records every invocation; is-active answers 'inactive' so nothing # here depends on a real systemd. cat >"$stub_dir/systemctl" <>"$calls" case "\$*" in *is-active*) echo inactive; exit 3 ;; *is-enabled*) exit 1 ;; esac exit 0 STUB cat >"$stub_dir/podman" <>"$calls" exit 0 STUB chmod +x "$stub_dir/systemctl" "$stub_dir/podman" run() { HOME="$home" XDG_CONFIG_HOME="$home/.config" XDG_STATE_HOME="$home/.local/state" \ PANAMA_SERVER_DIR="$catalog" PANAMA_SERVER_TARGET="$home/Server" \ PATH="$stub_dir:$PATH" "$panama_server" "$@" } unit_link="$home/.config/systemd/user/podman-example.service" # ── enable stops on placeholders ───────────────────────────────────────────── run enable Example >/dev/null 2>&1 \ && note 'enable exited zero with CHANGE_ME still in the .env' [[ -f "$home/Server/Example/.env" ]] \ || note 'enable did not seed .env from .env.example' [[ -L "$home/Server/Example/compose.yml" ]] \ || note 'enable did not link compose.yml into ~/Server' [[ -e "$unit_link" ]] \ && note 'enable installed the unit despite the placeholder refusal' grep -q 'systemctl .*enable' "$calls" \ && note 'enable reached systemctl despite the placeholder refusal' # ── a filled .env enables ──────────────────────────────────────────────────── printf 'DB_PASSWORD=s3cret\n' >"$home/Server/Example/.env" : >"$calls" run enable Example >/dev/null 2>&1 \ || note 'enable failed with a completed .env' [[ -L "$unit_link" ]] \ || note 'enable did not link the unit into the systemd user directory' grep -q 'systemctl --user daemon-reload' "$calls" \ || note 'enable did not daemon-reload' grep -q 'systemctl --user enable --now podman-example.service' "$calls" \ || note 'enable did not enable --now the unit' [[ "$(cat "$home/Server/Example/.env")" == "DB_PASSWORD=s3cret" ]] \ || note 'enable rewrote an .env that already existed' # ── relink names a changed definition, restarts nothing ────────────────────── printf ' # a changed line\n' >>"$catalog/Example/compose.yml" : >"$calls" relink_out="$(run relink 2>&1)" || note 'relink failed' grep -q 'Example' <<<"$relink_out" \ || note 'relink did not name the service whose definition changed' grep -q 'restart' "$calls" \ && note 'relink restarted something; the restart is deliberately manual' # A second relink with nothing new must not cry wolf. relink_out="$(run relink 2>&1)" || note 'a repeat relink failed' grep -q 'restart podman-example' <<<"$relink_out" \ && note 'relink reports the same change twice' # ── disable removes the unit and only the unit ─────────────────────────────── mkdir -p "$home/Server/Example/data" printf 'precious\n' >"$home/Server/Example/data/keep" : >"$calls" run disable Example >/dev/null 2>&1 || note 'disable failed' [[ -e "$unit_link" ]] \ && note 'disable left the unit installed' grep -q 'systemctl --user disable --now podman-example.service' "$calls" \ || note 'disable did not stop the unit' [[ -f "$home/Server/Example/.env" ]] \ || note 'disable removed the .env' [[ -f "$home/Server/Example/data/keep" ]] \ || note 'disable removed data' # ── an unknown service is a real answer ────────────────────────────────────── run enable NoSuchThing >/dev/null 2>&1 \ && note 'enabling an unknown service exited zero' # ── Report ─────────────────────────────────────────────────────────────────── if (( ${#findings[@]} > 0 )); then mapfile -t findings < <(printf '%s\n' "${findings[@]}" | sort -u) printf 'panama-server contract: %d finding(s)\n' "${#findings[@]}" >&2 printf ' - %s\n' "${findings[@]}" >&2 exit 1 fi printf 'panama-server contract: PASS\n'