All checks were successful
release-tag / release-image (push) Successful in 10m52s
91 lines
3.8 KiB
Bash
91 lines
3.8 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
|
|
ENV_FILE=${ENV_FILE:-.env}
|
|
STATIC_ONLY=false
|
|
[ "${1:-}" = "--static" ] && STATIC_ONLY=true
|
|
|
|
fail() { echo "preflight: ERROR: $*" >&2; exit 1; }
|
|
info() { echo "preflight: $*"; }
|
|
|
|
[ -f docker-compose.yml ] || fail "run from the repository root"
|
|
|
|
# Production compose must never silently fall back to source builds or broad .env injection.
|
|
if grep -Eq '^[[:space:]]+build:' docker-compose.yml; then fail "production docker-compose.yml contains build:"; fi
|
|
if grep -Eq '^[[:space:]]+env_file:' docker-compose.yml; then fail "production docker-compose.yml contains env_file:"; fi
|
|
for image in neuroforge neuroforge-worker agent agent-data-init knowledge control; do
|
|
grep -Fq "git.send.nrw/sendnrw/glpi-neuroforge-mega-${image}:\${IMAGE_TAG:" docker-compose.yml || fail "registry image mapping missing for ${image}"
|
|
done
|
|
|
|
if [ "$STATIC_ONLY" = true ]; then
|
|
if grep -Eq '^IMAGE_TAG[[:space:]]*=[[:space:]]*latest([[:space:]]|$)' .env.example; then fail ".env.example sets IMAGE_TAG=latest"; fi
|
|
info "static compose/source checks passed"
|
|
exit 0
|
|
fi
|
|
|
|
[ -f "$ENV_FILE" ] || fail "$ENV_FILE not found (copy .env.example and replace every placeholder)"
|
|
getv() { sed -n "s/^$1=//p" "$ENV_FILE" | tail -n 1 | tr -d '\r'; }
|
|
check_not_placeholder() {
|
|
name=$1; value=$(getv "$name")
|
|
[ -n "$value" ] || fail "$name is empty"
|
|
upper=$(printf '%s' "$value" | tr '[:lower:]' '[:upper:]')
|
|
case "$upper" in *CHANGE_ME*|*CHANGEME*|*PLACEHOLDER*) fail "$name still contains a placeholder";; esac
|
|
}
|
|
check_secret() {
|
|
name=$1; min=$2
|
|
check_not_placeholder "$name"
|
|
value=$(getv "$name")
|
|
[ "${#value}" -ge "$min" ] || fail "$name must contain at least $min characters"
|
|
}
|
|
|
|
tag=$(getv IMAGE_TAG)
|
|
[ -n "$tag" ] || fail "IMAGE_TAG is empty"
|
|
[ "$tag" != latest ] || fail "IMAGE_TAG=latest is forbidden for production"
|
|
case "$tag" in *[!A-Za-z0-9._-]*) fail "IMAGE_TAG contains invalid characters";; esac
|
|
|
|
for spec in \
|
|
NEUROFORGE_ADMIN_TOKEN:24 \
|
|
NEUROFORGE_APP_API_KEY:24 \
|
|
NEUROFORGE_INTEGRATION_TOKEN:24 \
|
|
NEUROFORGE_CONTROL_READ_TOKEN:24 \
|
|
NEUROFORGE_WORKER_TOKEN:24 \
|
|
NEUROFORGE_METRICS_TOKEN:24 \
|
|
KB_INTEGRATION_TOKEN:24 \
|
|
CONTROL_READ_TOKEN:24 \
|
|
BASIC_AUTH_PASSWORD:12 \
|
|
CONTROL_BASIC_AUTH_PASSWORD:12 \
|
|
WEB_PASSWORD:12; do
|
|
check_secret "${spec%%:*}" "${spec##*:}"
|
|
done
|
|
|
|
for name in GLPI_URL GLPI_CLIENT_ID GLPI_CLIENT_SECRET GLPI_USERNAME GLPI_PASSWORD; do
|
|
check_not_placeholder "$name"
|
|
done
|
|
web_anon=$(printf '%s' "$(getv WEB_ALLOW_ANONYMOUS)" | tr '[:upper:]' '[:lower:]')
|
|
if [ "$web_anon" != "true" ]; then
|
|
check_not_placeholder WEB_USERNAME
|
|
fi
|
|
research=$(printf '%s' "$(getv NEUROFORGE_SEARXNG_ENABLED)" | tr '[:upper:]' '[:lower:]')
|
|
if [ "$research" = "true" ]; then
|
|
check_secret SEARXNG_SECRET 24
|
|
fi
|
|
|
|
# Trust-boundary tokens must not be reused across roles.
|
|
seen=''
|
|
for name in NEUROFORGE_ADMIN_TOKEN NEUROFORGE_APP_API_KEY NEUROFORGE_INTEGRATION_TOKEN NEUROFORGE_CONTROL_READ_TOKEN NEUROFORGE_WORKER_TOKEN NEUROFORGE_METRICS_TOKEN KB_INTEGRATION_TOKEN CONTROL_READ_TOKEN; do
|
|
value=$(getv "$name")
|
|
case "|$seen|" in *"|$value|"*) fail "$name reuses another service token";; esac
|
|
seen=${seen:+$seen|}$value
|
|
done
|
|
|
|
command -v docker >/dev/null 2>&1 || fail "docker is not installed"
|
|
docker compose version >/dev/null 2>&1 || fail "Docker Compose v2 is unavailable"
|
|
docker compose --env-file "$ENV_FILE" config -q || fail "docker compose config validation failed"
|
|
images=$(docker compose --env-file "$ENV_FILE" config --images)
|
|
for image in neuroforge neuroforge-worker agent agent-data-init knowledge control; do
|
|
expected="git.send.nrw/sendnrw/glpi-neuroforge-mega-${image}:${tag}"
|
|
printf '%s\n' "$images" | grep -Fxq "$expected" || fail "resolved image missing: $expected"
|
|
done
|
|
printf '%s\n' "$images" | grep -E 'git\.send\.nrw/sendnrw/glpi-neuroforge-mega-.*:latest$' >/dev/null && fail "a project image resolved to latest"
|
|
info "production preflight passed for IMAGE_TAG=$tag"
|