mirror of
https://github.com/netbirdio/docs.git
synced 2026-08-24 16:51:26 +02:00
* harden: non-root container with tini, healthcheck, and a robust entrypoint entrypoint.sh: escape sed metacharacters (\, &, #) so any future DocSearch value substitutes literally instead of crashing the pass or corrupting the bundle; rewrite only files that still contain the placeholder, making restarts no-ops; on substitution failure, log a warning and start the server anyway rather than crash-looping under restart: unless-stopped. Dockerfile: run as the built-in non-root node user (artifacts chowned so the runtime sed keeps write access); add tini as PID 1 so SIGTERM actually reaches node and docker stop takes ~1s instead of the 10s kill grace; add a HEALTHCHECK so a dead server shows as unhealthy instead of silently Up. Container-tested: boots 202ms, all routes/assets/redirects OK, metacharacter-laden values injected literally, uid 1000, health reaches healthy, restart idempotent (no rewrites, value intact), docker stop 0s. * harden: substitute DocSearch placeholders independently; strip CR/LF from values Review findings: the three substitutions were &&-chained, so one failing value skipped the remaining valid ones; and a raw newline in a value breaks the single-line sed command. Run each substitution independently, accumulating failures into one warning, and strip CR/LF in escape() (no legitimate DocSearch token contains them). Container-tested: newline-laden appId is sanitized and all three placeholders still apply with no warning; forced full failure logs all three sed errors plus one warning and the server still starts healthy. --------- Co-authored-by: Brandon Hopkins <brandon@techhut.tv>
48 lines
2.0 KiB
Bash
48 lines
2.0 KiB
Bash
#!/bin/sh
|
|
|
|
# Substitutes the APP_NEXT_PUBLIC_DOCSEARCH_* placeholders baked into the
|
|
# client bundle at build time (from the committed .env) with the real values
|
|
# passed via the container environment, then starts the server.
|
|
#
|
|
# NEXT_PUBLIC_* values are compiled into the client bundle, so this rewrite is
|
|
# what lets one image serve any environment's DocSearch credentials.
|
|
|
|
set -eu
|
|
|
|
NEXT_PUBLIC_DOCSEARCH_APP_ID=${NEXT_PUBLIC_DOCSEARCH_APP_ID:-"none"}
|
|
NEXT_PUBLIC_DOCSEARCH_API_KEY=${NEXT_PUBLIC_DOCSEARCH_API_KEY:-"none"}
|
|
NEXT_PUBLIC_DOCSEARCH_INDEX_NAME=${NEXT_PUBLIC_DOCSEARCH_INDEX_NAME:-"none"}
|
|
|
|
# Escape the characters that are special in a sed replacement (\ and &) and
|
|
# our s### delimiter (#), so values containing them substitute literally.
|
|
# CR/LF are stripped first: a one-line s### command cannot carry a raw
|
|
# newline, and no legitimate DocSearch token contains one.
|
|
escape() {
|
|
printf '%s' "$1" | tr -d '\r\n' | sed -e 's/[\\&#]/\\&/g'
|
|
}
|
|
|
|
# Rewrite only the files that still contain the placeholder — after the first
|
|
# boot substituted everything, restarts touch nothing. grep exiting 1 on zero
|
|
# matches is fine: xargs -r then runs nothing and the pipeline succeeds.
|
|
substitute() {
|
|
grep -rlZ "$1" /usr/app/.next | xargs -0 -r sed -i "s#$1#$2#g"
|
|
}
|
|
|
|
# Each substitution runs independently: one failing value must not stop the
|
|
# remaining placeholders from being applied.
|
|
ok=1
|
|
substitute APP_NEXT_PUBLIC_DOCSEARCH_APP_ID "$(escape "$NEXT_PUBLIC_DOCSEARCH_APP_ID")" || ok=0
|
|
substitute APP_NEXT_PUBLIC_DOCSEARCH_API_KEY "$(escape "$NEXT_PUBLIC_DOCSEARCH_API_KEY")" || ok=0
|
|
substitute APP_NEXT_PUBLIC_DOCSEARCH_INDEX_NAME "$(escape "$NEXT_PUBLIC_DOCSEARCH_INDEX_NAME")" || ok=0
|
|
|
|
if [ "$ok" = 1 ]; then
|
|
echo "DocSearch configuration applied"
|
|
else
|
|
# Serve the docs even if search wiring failed — a docs site with broken
|
|
# search beats a crash-looping container. The warning makes it visible.
|
|
echo "WARNING: DocSearch placeholder substitution failed; search may be broken" >&2
|
|
fi
|
|
|
|
echo "starting Next.js"
|
|
exec "$@"
|