diff --git a/scripts/load-stack-stop.sh b/scripts/load-stack-stop.sh index d66ae8f..8088803 100755 --- a/scripts/load-stack-stop.sh +++ b/scripts/load-stack-stop.sh @@ -4,6 +4,7 @@ set -eu ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd) ENV_FILE=${WNH_LOAD_ENV_FILE:-"$ROOT/output/runtime/load.env"} LOAD_TOOLS_IMAGE=${WNH_LOAD_TOOLS_IMAGE:-who-need-help:load-tools} +RUNTIME_OWNER_IMAGE=python:3.14.6-alpine3.23@sha256:b165067c5afc37fa5608a3c05609cc3d51aafd808a30fbfd822ee594fef55ad4 if [ ! -f "$ENV_FILE" ]; then echo "Missing $ENV_FILE; no load-profile project was selected." >&2 @@ -22,6 +23,13 @@ if [ "$LOAD_PROJECT" = who_need_help ]; then exit 1 fi +case "$LOAD_PROJECT" in + *[!a-z0-9_-]* | '') + echo "LOAD_PROJECT contains unsupported characters." >&2 + exit 1 + ;; +esac + cd "$ROOT" docker compose \ --env-file "$ENV_FILE" \ @@ -53,4 +61,27 @@ if image_id=$(docker image inspect --format '{{.Id}}' "$LOAD_TOOLS_IMAGE" 2>/dev fi fi -echo "Removed the isolated load-profile containers and networks; its named volumes remain." +# Prometheus and Grafana read run-scoped files under their container UIDs. Once +# every container and network for this exact isolated project is gone, restore +# the host owner and remove only that project's generated runtime directory. +# Without this step, an otherwise successful cleanup can leave empty UID-owned +# directories that the invoking user cannot remove. +observability_runtime="$ROOT/tmp/observability/$LOAD_PROJECT" +if [ -d "$observability_runtime" ]; then + if [ -n "$(docker ps -aq --filter "label=com.docker.compose.project=$LOAD_PROJECT")" ] || + [ -n "$(docker network ls -q --filter "label=com.docker.compose.project=$LOAD_PROJECT")" ]; then + echo "Refusing to remove observability runtime while project resources remain." >&2 + exit 1 + fi + + docker run --rm \ + --user 0:0 \ + --volume "$observability_runtime:/runtime" \ + --entrypoint /bin/sh \ + "$RUNTIME_OWNER_IMAGE" \ + -euc "chown -R $(id -u):$(id -g) /runtime; chmod -R u+rwX /runtime" + + find "$observability_runtime" -xdev -depth -delete +fi + +echo "Removed the isolated load-profile containers, networks, and generated observability runtime; its named volumes remain."