From d43bfb3fcba51794a62990ab2c1728440347cdcd Mon Sep 17 00:00:00 2001 From: gnezim Date: Sun, 19 Apr 2026 00:44:45 +0300 Subject: [PATCH] Fix URL truncation from bash \${VAR:=default} with braces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deployed build had MAP_TILE_URL truncated to 'https://.../tile/{z' — Leaflet then URL-encoded it to '%7Bz' and fetched garbage tile paths. Root cause: build-docker.sh used : "\${MAP_TILE_URL:=https://flights.test.aeroflot.ru/map/api/tile/{z}/{x}/{y}.jpeg}" and bash parameter expansion terminates the default value at the FIRST unescaped '}', leaving '{z' and discarding the rest. The env passed to `pnpm build:standalone` was already truncated, so every downstream step (base64 encode → HTML inject → client decode) faithfully carried the broken value through. Fix by moving the defaults to Dockerfile's ARG lines — ARG defaults are plain strings, not shell-parsed — and simplify build-docker.sh to only forward MAP_TILE_URL / API_BASE_URL as --build-arg when the caller explicitly sets them. Quote the k8s env values for defensive YAML hygiene as well. --- Dockerfile.react | 19 +++++++++++++------ deployment/build-docker.sh | 30 ++++++++++++++++++------------ deployment/k8s/flights-ui.yaml | 7 +++++-- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/Dockerfile.react b/Dockerfile.react index 48aba330..29378bbf 100644 --- a/Dockerfile.react +++ b/Dockerfile.react @@ -20,13 +20,20 @@ COPY src/ src/ # broken backgrounds, missing tile icons). COPY config/ config/ -# Runtime-tunable env vars. modern.config.ts reads these when Modern.js -# boots the SSR server at container start, so values set via k8s env -# propagate without a rebuild. The ARG line lets CI also bake a value -# into the image if the cluster can't set env at runtime. -ARG MAP_TILE_URL +# Public env values baked into dist/standalone/html/main/index.html by +# modern.config.ts at build time. Defaults target the devwebzavod cluster +# (no /map/api/** or /api/** ingress rule → hit the upstream that the +# real Aeroflot ingress terminates). Production overrides via +# --build-arg, e.g. +# --build-arg MAP_TILE_URL=/map/api/tile/{z}/{x}/{y}.jpeg +# --build-arg API_BASE_URL=/api +# Defaults live here rather than in deployment/build-docker.sh because +# bash `${VAR:=default}` stops at the first unescaped `}` — the literal +# `{z}/{x}/{y}` in the URL was being truncated to `{z`. Dockerfile ARG +# defaults are plain strings, no shell parsing. +ARG MAP_TILE_URL=https://flights.test.aeroflot.ru/map/api/tile/{z}/{x}/{y}.jpeg ENV MAP_TILE_URL=${MAP_TILE_URL} -ARG API_BASE_URL +ARG API_BASE_URL=https://flights.test.aeroflot.ru/api ENV API_BASE_URL=${API_BASE_URL} RUN pnpm build:standalone diff --git a/deployment/build-docker.sh b/deployment/build-docker.sh index 8a1844f4..27e422bf 100644 --- a/deployment/build-docker.sh +++ b/deployment/build-docker.sh @@ -13,18 +13,24 @@ function build { # MAP_TILE_URL / API_BASE_URL must flow as build-args (not just runtime # env) because Modern.js bakes html.tags into the HTML template at # `pnpm build:standalone` time. Values set only on the pod don't change - # the served HTML. The defaults match the devwebzavod cluster (no - # /map/api/** or /api/** ingress rule — hit the upstream that the real - # Aeroflot ingress terminates). Prod overrides with same-origin. - : "${MAP_TILE_URL:=https://flights.test.aeroflot.ru/map/api/tile/{z}/{x}/{y}.jpeg}" - : "${API_BASE_URL:=https://flights.test.aeroflot.ru/api}" - export MAP_TILE_URL API_BASE_URL - docker build -t aeroflot.$K8NAMESPACE/$1:v$VERSION.$BUILD_NUMBER \ - --build-arg ENVIRONMENT=${ENVIRONMENT} \ - --build-arg=NPM_PROXY \ - --build-arg MAP_TILE_URL=${MAP_TILE_URL} \ - --build-arg API_BASE_URL=${API_BASE_URL} \ - -f "$2/Dockerfile" $2 + # the served HTML. Defaults for both live in Dockerfile's ARG lines — + # keeping them there avoids bash `${VAR:=default}` parsing the `{z}/ + # {x}/{y}` pattern as balanced braces (it stops at the first `}` and + # truncates the URL to `/tile/{z`). CI can still override by exporting + # MAP_TILE_URL / API_BASE_URL before running this script. + docker_args=( + --build-arg "ENVIRONMENT=${ENVIRONMENT}" + --build-arg=NPM_PROXY + ) + if [ -n "${MAP_TILE_URL:-}" ]; then + docker_args+=(--build-arg "MAP_TILE_URL=${MAP_TILE_URL}") + fi + if [ -n "${API_BASE_URL:-}" ]; then + docker_args+=(--build-arg "API_BASE_URL=${API_BASE_URL}") + fi + docker build -t "aeroflot.$K8NAMESPACE/$1:v$VERSION.$BUILD_NUMBER" \ + "${docker_args[@]}" \ + -f "$2/Dockerfile" "$2" } build flights-ui "../Aeroflot.Flights.Front" diff --git a/deployment/k8s/flights-ui.yaml b/deployment/k8s/flights-ui.yaml index 2df82e1e..9dc04313 100644 --- a/deployment/k8s/flights-ui.yaml +++ b/deployment/k8s/flights-ui.yaml @@ -36,8 +36,11 @@ spec: # Both MAP_TILE_URL and API_BASE_URL are also wired as docker # build-args because Modern.js bakes html.tags into the HTML at # build time; the k8s env still flows to the Node SSR process. + # Quoted explicitly to keep `{z}/{x}/{y}` out of YAML flow-mapping + # ambiguity — parsers are fine today but plain scalars starting + # close to `{` are best kept in quotes. - name: MAP_TILE_URL - value: https://flights.test.aeroflot.ru/map/api/tile/{z}/{x}/{y}.jpeg + value: "https://flights.test.aeroflot.ru/map/api/tile/{z}/{x}/{y}.jpeg" - name: API_BASE_URL - value: https://flights.test.aeroflot.ru/api + value: "https://flights.test.aeroflot.ru/api" $IMAGE_PULL_SECRETS