Fix: stack-deploy.sh now picks export_raw/export_raw_merged for folder+extras stacks (docker compose config path) vs export/export_merged for single-file stacks, matching envparse.py's dual-escaping fix
This commit is contained in:
+30
-8
@@ -28,6 +28,16 @@
|
||||
# source path exists, and flags suspicious-looking empty Postgres data
|
||||
# dirs, before anything touches Swarm.
|
||||
# 3. docker stack deploy -c <tempfile> <stack>
|
||||
#
|
||||
# Dollar-escaping (2026-08-26, see envparse.py comments for full detail):
|
||||
# - Single-file path (no extras): envsubst does no '$' escaping of its
|
||||
# own, and only Swarm's `docker stack deploy` interpolation pass runs
|
||||
# downstream -> use export/export_merged (escapes '$' -> '$$' once).
|
||||
# - Folder+extras path: `docker compose config` ALSO does its own '$'
|
||||
# escaping on top of Swarm's -> use export_raw/export_raw_merged (no
|
||||
# pre-escaping) or values get doubled twice. Getting this wrong
|
||||
# silently corrupts any secret/hash containing '$' (confirmed impact:
|
||||
# LITELLM keys truncated, IMMICH_KIOSK_BASICAUTH bcrypt hash mismatched).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -94,6 +104,12 @@ for f in "${EXTRAS[@]:-}"; do
|
||||
[ -n "$f" ] && F_FLAGS+=(-f "$f")
|
||||
done
|
||||
|
||||
# Whether the render will go through `docker compose config` (folder mode
|
||||
# with 1+ extras). This determines which escaping mode is correct — see
|
||||
# header comment and envparse.py for why these must differ.
|
||||
USES_COMPOSE_CONFIG=0
|
||||
[ "${#F_FLAGS[@]}" -gt 2 ] && USES_COMPOSE_CONFIG=1
|
||||
|
||||
# ── Load env (global base + optional stack override) ─────────────────────────
|
||||
|
||||
HINT=" Hint: 'secret not found' means Woodpecker hasn't provisioned secrets yet.\n Trigger the pipeline: https://woodpecker.bryanmail.net\n"
|
||||
@@ -103,19 +119,25 @@ STACK_EXISTS=0
|
||||
[ -f "$GLOBAL_ENV" ] && GLOBAL_EXISTS=1
|
||||
[ -f "$ENVFILE" ] && STACK_EXISTS=1
|
||||
|
||||
if [ "$USES_COMPOSE_CONFIG" -eq 1 ]; then
|
||||
EXPORT_MODE="export_raw"; EXPORT_MERGED_MODE="export_raw_merged"
|
||||
else
|
||||
EXPORT_MODE="export"; EXPORT_MERGED_MODE="export_merged"
|
||||
fi
|
||||
|
||||
if [ "$GLOBAL_EXISTS" -eq 1 ] && [ "$STACK_EXISTS" -eq 1 ]; then
|
||||
echo " Env: $GLOBAL_ENV + $ENVFILE (stack overrides global)"
|
||||
eval "$(python3 "$PY" export_merged "$GLOBAL_ENV" "$ENVFILE")"
|
||||
echo " Env: $GLOBAL_ENV + $ENVFILE (stack overrides global) [$EXPORT_MERGED_MODE]"
|
||||
eval "$(python3 "$PY" "$EXPORT_MERGED_MODE" "$GLOBAL_ENV" "$ENVFILE")"
|
||||
VARS="$(python3 "$PY" vars_merged "$GLOBAL_ENV" "$ENVFILE")"
|
||||
|
||||
elif [ "$GLOBAL_EXISTS" -eq 1 ]; then
|
||||
echo " Env: $GLOBAL_ENV (no stack env)"
|
||||
eval "$(python3 "$PY" export "$GLOBAL_ENV")"
|
||||
echo " Env: $GLOBAL_ENV (no stack env) [$EXPORT_MODE]"
|
||||
eval "$(python3 "$PY" "$EXPORT_MODE" "$GLOBAL_ENV")"
|
||||
VARS="$(python3 "$PY" vars "$GLOBAL_ENV")"
|
||||
|
||||
elif [ "$STACK_EXISTS" -eq 1 ]; then
|
||||
echo " Env: $ENVFILE (no global env)"
|
||||
eval "$(python3 "$PY" export "$ENVFILE")"
|
||||
echo " Env: $ENVFILE (no global env) [$EXPORT_MODE]"
|
||||
eval "$(python3 "$PY" "$EXPORT_MODE" "$ENVFILE")"
|
||||
VARS="$(python3 "$PY" vars "$ENVFILE")"
|
||||
|
||||
else
|
||||
@@ -131,7 +153,7 @@ RENDERED="$(mktemp /tmp/stack-deploy.XXXXXX.yml)"
|
||||
trap 'rm -f "$RENDERED"' EXIT
|
||||
|
||||
if [ -n "$VARS" ]; then
|
||||
if [ "${#F_FLAGS[@]}" -gt 2 ]; then
|
||||
if [ "$USES_COMPOSE_CONFIG" -eq 1 ]; then
|
||||
# Folder mode with extras: merge via docker compose config
|
||||
docker compose "${F_FLAGS[@]}" config \
|
||||
| python3 "$PY" strip \
|
||||
@@ -144,7 +166,7 @@ if [ -n "$VARS" ]; then
|
||||
> "$RENDERED"
|
||||
fi
|
||||
else
|
||||
if [ "${#F_FLAGS[@]}" -gt 2 ]; then
|
||||
if [ "$USES_COMPOSE_CONFIG" -eq 1 ]; then
|
||||
docker compose "${F_FLAGS[@]}" config \
|
||||
| python3 "$PY" strip \
|
||||
> "$RENDERED"
|
||||
|
||||
Reference in New Issue
Block a user