Ctrl K
ComunidadGuías…

scripts/test-docker-nonroot.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env sh
# Verifies the runtime image's non-root contract:
#   1. The container runs as numeric uid 100 / gid 101 (so Kubernetes can
#      verify `runAsNonRoot: true` without an explicit runAsUser).
#   2. Default local storage mode works without root: /app/updates is
#      writable, so migrations (.migrationhistory) and boot succeed with no
#      volume mounted.
#   3. (Linux only) A root-owned bind mount is correctly rejected — this is
#      the scenario the docs tell users to fix with chown 100:101 / fsGroup.
#
# Usage: ./scripts/test-docker-nonroot.sh [image-tag]
set -eu

IMAGE="${1:-xprem:nonroot-test}"
CONTAINER="xprem-nonroot-test"

fail() { echo "FAIL: $1" >&2; docker logs "$CONTAINER" 2>&1 | tail -5 >&2 || true; docker rm -f "$CONTAINER" >/dev/null 2>&1 || true; exit 1; }
cleanup() { docker rm -f "$CONTAINER" >/dev/null 2>&1 || true; }
trap cleanup EXIT

echo "==> Building image"
docker build -q -t "$IMAGE" .

echo "==> 1/3 container runs as numeric uid 100 / gid 101"
uid="$(docker run --rm "$IMAGE" id -u)"
gid="$(docker run --rm "$IMAGE" id -g)"
[ "$uid" = "100" ] || fail "expected uid 100, got $uid"
[ "$gid" = "101" ] || fail "expected gid 101, got $gid"
echo "    ok (uid=$uid gid=$gid)"

echo "==> 2/3 default local mode boots without root (writes to /app/updates)"
docker run -d --name "$CONTAINER" -p 13000:3000 \
  -e STORAGE_MODE=local \
  -e BASE_URL=http://localhost:13000 \
  -e JWT_SECRET=test-secret \
  -e EXPO_ACCESS_TOKEN=test -e EXPO_APP_ID=test \
  "$IMAGE" >/dev/null
i=0
until curl -sf http://localhost:13000/hc >/dev/null 2>&1; do
  i=$((i+1)); [ "$i" -lt 20 ] || fail "server did not become healthy on default LOCAL_BUCKET_BASE_PATH"
  sleep 0.5
done
# migrations write .migrationhistory into the bucket path — prove the write happened as uid 100
owner="$(docker exec "$CONTAINER" stat -c '%u' /app/updates/.migrationhistory 2>/dev/null || echo missing)"
[ "$owner" = "100" ] || fail "expected .migrationhistory owned by uid 100, got: $owner"
docker rm -f "$CONTAINER" >/dev/null
echo "    ok"

echo "==> 3/3 root-owned bind mount is rejected (Linux only)"
if [ "$(uname -s)" = "Linux" ]; then
  tmpdir="$(mktemp -d)"
  # root-owned, no group/other write — the situation the docs warn about
  chmod 755 "$tmpdir"
  docker run -d --name "$CONTAINER" \
    -e STORAGE_MODE=local -e LOCAL_BUCKET_BASE_PATH=/updates \
    -e BASE_URL=http://localhost:3000 -e JWT_SECRET=test-secret \
    -e EXPO_ACCESS_TOKEN=test -e EXPO_APP_ID=test \
    -v "$tmpdir":/updates "$IMAGE" >/dev/null
  sleep 3
  if docker exec "$CONTAINER" true 2>/dev/null && [ "$(docker inspect -f '{{.State.Running}}' "$CONTAINER")" = "true" ]; then
    fail "expected boot failure on root-owned bind mount, but server is running"
  fi
  docker rm -f "$CONTAINER" >/dev/null 2>&1 || true
  rm -rf "$tmpdir"
  echo "    ok (boot failed as expected; fix per docs: chown 100:101)"
else
  echo "    skipped (bind-mount ownership semantics only apply on Linux hosts)"
fi

echo "PASS: non-root contract holds"