74 lines
3.0 KiB
Bash
74 lines
3.0 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
|
|
fail_secret() {
|
|
echo "ContextForge secret-file validation failed" >&2
|
|
exit 78
|
|
}
|
|
|
|
fail_session_topology() {
|
|
echo "ContextForge multi-worker session topology is unsafe: Redis-backed stateful session affinity is required" >&2
|
|
exit 78
|
|
}
|
|
|
|
fail_runtime_contract() {
|
|
echo "ContextForge strict runtime contract verification failed" >&2
|
|
exit 78
|
|
}
|
|
|
|
read_secret() {
|
|
[ -f "$1" ] && [ -r "$1" ] && [ -s "$1" ] || fail_secret
|
|
mode="$(stat -c '%a' "$1" 2>/dev/null || true)"
|
|
case "$mode" in 400|600) ;; *) fail_secret ;; esac
|
|
[ "$(stat -c '%u' "$1" 2>/dev/null || true)" = "${SECRET_EXPECTED_UID:?}" ] || fail_secret
|
|
[ "$(stat -c '%g' "$1" 2>/dev/null || true)" = "${SECRET_EXPECTED_GID:?}" ] || fail_secret
|
|
value="$(tr -d '\r\n' < "$1")"
|
|
[ -n "$value" ] || fail_secret
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
cf_password="$(read_secret /run/secrets/contextforge_database_password)"
|
|
export DATABASE_URL="postgresql+psycopg://contextforge:${cf_password}@postgres:5432/contextforge"
|
|
export JWT_SECRET_KEY="$(read_secret /run/secrets/contextforge_jwt_secret)"
|
|
export AUTH_ENCRYPTION_SECRET="$(read_secret /run/secrets/contextforge_auth_encryption_secret)"
|
|
export BASIC_AUTH_USER="itworx-contextforge-admin"
|
|
export BASIC_AUTH_PASSWORD="$(read_secret /run/secrets/contextforge_admin_credential)"
|
|
export PLATFORM_ADMIN_EMAIL="${PLATFORM_ADMIN_EMAIL:-contextforge-admin@example.com}"
|
|
export PLATFORM_ADMIN_PASSWORD="$BASIC_AUTH_PASSWORD"
|
|
|
|
# Base/dev defaults retain the historical safe multi-worker topology. Production
|
|
# overrides these values to the separately tested stateless single-worker
|
|
# contract. Multi-worker mode is never allowed to weaken its affinity controls.
|
|
export CACHE_TYPE="${CACHE_TYPE:-redis}"
|
|
export USE_STATEFUL_SESSIONS="${USE_STATEFUL_SESSIONS:-true}"
|
|
export MCPGATEWAY_SESSION_AFFINITY_ENABLED="${MCPGATEWAY_SESSION_AFFINITY_ENABLED:-true}"
|
|
export MCPGATEWAY_SESSION_AFFINITY_TTL="${MCPGATEWAY_SESSION_AFFINITY_TTL:-3600}"
|
|
|
|
case "${GUNICORN_WORKERS:-auto}" in
|
|
1) ;;
|
|
*)
|
|
[ "$CACHE_TYPE" = "redis" ] || fail_session_topology
|
|
[ "$USE_STATEFUL_SESSIONS" = "true" ] || fail_session_topology
|
|
[ "$MCPGATEWAY_SESSION_AFFINITY_ENABLED" = "true" ] || fail_session_topology
|
|
;;
|
|
esac
|
|
|
|
if [ "${REDIS_AUTH_ENABLED:-false}" = "true" ]; then
|
|
redis_password="$(read_secret /run/secrets/redis_password)"
|
|
export REDIS_URL="redis://:${redis_password}@redis:6379/0"
|
|
unset redis_password
|
|
else
|
|
export REDIS_URL="${REDIS_URL:-redis://redis:6379/0}"
|
|
fi
|
|
|
|
# Production strict mode is a hard startup gate. The verifier is read-only: it
|
|
# proves the embedded compatibility tuple, installed MCP SDK/API, image Alembic
|
|
# head, database revision and transport settings. It never installs packages or
|
|
# runs migration mutations. Any failure stops before ContextForge/Gunicorn.
|
|
if [ "${ITWORX_CONTEXTFORGE_CONTRACT_MODE:-relaxed}" = "strict" ]; then
|
|
[ -r /opt/itworx/contextforge-runtime-contract.py ] || fail_runtime_contract
|
|
/app/.venv/bin/python /opt/itworx/contextforge-runtime-contract.py --startup || fail_runtime_contract
|
|
fi
|
|
|
|
exec /app/docker-entrypoint.sh
|