From 0367244d2adb9d246c073e0f6b4068477b5526ec Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 21 Oct 2026 00:15:21 -0700 Subject: [PATCH] fix(deploy): client allowlist was missing cadvisor, gpu-exporter, prowlarr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deploy.sh's valid_service and deploy-remote.sh's service_is_allowed are two gates for the same door, and they drifted: the remote gate gained cadvisor (2026-10-20) and gpu-exporter (2026-10-21) while the client gate never did, so `--service cadvisor|gpu-exporter` died with "is not deployed on " at the client — the first-ever deploy of a new service is exactly the case that needs the client gate to know it. dankserver:prowlarr (planner can emit it for dankserver) was remote-only too. Adds the four missing pairs to the client gate and a deployment_flow contract test that diffs the two extracted lists per target — the test the cadvisor PR should have carried. searxng-network stays the one sanctioned client-only exception (network unit, no remote handler), documented inline. --- scripts/deploy.sh | 8 +++++--- tests/deployment_flow.bats | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 35e4ce9..b9f77db 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -133,13 +133,15 @@ fi valid_service() { local service="$1" case "$TARGET:$service" in + # dankclaw:searxng-network is client-only: a network quadlet with no + # remote dispatch handler, so the remote gate does not (must not) list it. dankclaw:caddy|dankclaw:gluetun|dankclaw:searxng-network|dankclaw:searxng-valkey|\ dankclaw:searxng|dankclaw:marreta|dankclaw:pihole|dankclaw:open-webui|dankclaw:gitea-postgres|\ dankclaw:gitea-server|dankclaw:homepage|\ dankclaw:comfyui|dankclaw:hermes|dankclaw:hermes-dashboard|\ dankclaw:hermes-webui|dankclaw:prometheus|dankclaw:grafana|dankclaw:loki|dankclaw:alloy|\ dankclaw:alertmanager|\ - dankclaw:node-exporter|dankclaw:authentik-postgres|dankclaw:authentik-server|\ + dankclaw:node-exporter|dankclaw:cadvisor|dankclaw:gpu-exporter|dankclaw:authentik-postgres|dankclaw:authentik-server|\ dankclaw:authentik-worker|dankclaw:authentik-outpost|dankclaw:authentik-outpost-ldap|dankclaw:anubis|dankclaw:seerr|\ dankclaw:open-notebook|\ dankclaw:frank-tts-engine|dankclaw:frank-tts|\ @@ -147,8 +149,8 @@ valid_service() { dankserver:romm-mariadb|dankserver:romm-redis|dankserver:romm|\ dankserver:copyparty|dankserver:jellyfin|dankserver:calibre-web|dankserver:calibre-server|dankserver:plex|dankserver:tautulli|\ dankserver:qbittorrent|dankserver:radarr|dankserver:sonarr|\ - dankserver:lidarr|dankserver:readarr|dankserver:node-exporter|\ - dankserver:frank-archon|\ + dankserver:lidarr|dankserver:readarr|dankserver:node-exporter|dankserver:cadvisor|dankserver:gpu-exporter|\ + dankserver:prowlarr|dankserver:frank-archon|\ frankbook-pro:gluetun|frankbook-pro:qbittorrent|frankbook-pro:prowlarr|\ frankbook-pro:radarr|frankbook-pro:sonarr|frankbook-pro:lidarr|\ frankbook-pro:readarr) diff --git a/tests/deployment_flow.bats b/tests/deployment_flow.bats index c529dd5..0caf284 100644 --- a/tests/deployment_flow.bats +++ b/tests/deployment_flow.bats @@ -125,3 +125,28 @@ load helpers [ ! -e "$sandbox/frank-default-sightsound" ] [ -e "$BATS_TEST_TMPDIR/.AGENTTRASH/$(date +%Y%m%d)-retired-deploy-state/frank-default-sightsound" ] } + +@test "the client and remote allowlists agree per target" { + # Two gates guard `deploy.sh --service X`: the client's valid_service and + # the remote runner's service_is_allowed. When only one side gained a + # service the other answered "is not deployed on " and the only + # repair path was a fleet-wide drain — cadvisor and gpu-exporter both fell + # through this crack within a day of each other. The lists MUST agree; + # searxng-network is the one sanctioned exception (client-only network + # unit, no remote dispatch handler). + run env OUT="$BATS_TEST_TMPDIR" bash -c ' + grep -oE "dank(claw|server):[a-z0-9-]+" \ + <(sed -n "/^valid_service()/,/^}/p" "$1/scripts/deploy.sh") \ + | grep -v "dankclaw:searxng-network" | sort -u > "$OUT/cli" + grep -oE "dank(claw|server):[a-z0-9-]+" \ + <(sed -n "/^service_is_allowed()/,/^}/p" "$1/scripts/deploy-remote.sh") \ + | sort -u > "$OUT/rem" + diff "$OUT/cli" "$OUT/rem" + ' _ "$REPO_ROOT" + [ "$status" -eq 0 ] || { echo "deploy.sh vs deploy-remote.sh allowlist drift:"; echo "$output"; return 1; } + # Drift aside, the gate must actually know the host-process exporters — + # their first-ever deploy has to pass the client gate. + for pair in dankclaw:cadvisor dankclaw:gpu-exporter dankserver:cadvisor dankserver:gpu-exporter; do + grep -q "$pair" "$BATS_TEST_TMPDIR/cli" || { echo "client gate missing $pair"; return 1; } + done +}