#!/bin/sh set -eu cd "$(dirname "$0")/.." tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT HUP INT TERM bundle="$tmp/thothii.secrets" cat >"$bundle" <<'EOF' # disposable deployment-contract bundle THT_MODEL_API_KEY=test-model THT_VECTOR_BOOTSTRAP_PASSWORD=contract-bootstrap THT_VECTOR_MIGRATOR_PASSWORD=contract-migrator THT_VECTOR_READER_PASSWORD=contract-reader THT_VECTOR_WRITER_PASSWORD=contract-writer EOF chmod 0600 "$bundle" export THT_SECRETS_FILE="$bundle" docker compose config >"$tmp/base.yaml" grep -q '^ core:' "$tmp/base.yaml" grep -q '^ frontend:' "$tmp/base.yaml" grep -q 'host_ip: 127.0.0.1' "$tmp/base.yaml" grep -q 'AUTH_MODE: none' "$tmp/base.yaml" grep -q 'THOTH_PUBLIC_EXPOSURE: "false"' "$tmp/base.yaml" grep -q 'THT_SECRETS_FILE: /run/secrets/thothii.secrets' "$tmp/base.yaml" if grep -q 'THT_[A-Z0-9_]*_SECRET_FILE:' "$tmp/base.yaml"; then echo "base Compose must not require legacy secret-file variables" >&2 exit 1 fi docker compose -f compose.yaml -f deploy/compose.local-vector.yaml \ --profile local-vector config >"$tmp/local-vector.yaml" grep -q 'target: thothii.secrets' "$tmp/local-vector.yaml" if grep -Eq 'vector_(bootstrap|migrator|reader|writer)_password|THT_[A-Z0-9_]+_SECRET_FILE' "$tmp/local-vector.yaml"; then echo "rendered local-vector config contains legacy per-secret references" >&2 exit 1 fi if grep -q 'contract-' "$tmp/local-vector.yaml"; then echo "rendered local-vector config leaked a bundle secret value" >&2 exit 1 fi docker compose -f compose.yaml -f deploy/compose.local.yaml \ config >"$tmp/local.yaml" if grep -q 'env_file:' "$tmp/local.yaml"; then echo "local Compose must use the root .env interpolation file" >&2 exit 1 fi printf '%s\n' 'THT_MODEL_API_KEY=test-model' >"$tmp/thothii.secrets" chmod 0600 "$tmp/thothii.secrets" THT_SECRETS_FILE="$tmp/thothii.secrets" \ THT_DB_NAME=test THT_DWH_REST_URL=https://dwh.example.test \ THT_VEC_REST_URL=https://vector.example.test THT_OLLAMA_URL=https://embed.example.test \ docker compose -f compose.yaml -f deploy/compose.production.yaml \ config >"$tmp/production.yaml" grep -q 'AUTH_MODE: upstream' "$tmp/production.yaml" grep -q 'THOTH_PUBLIC_EXPOSURE: "true"' "$tmp/production.yaml" grep -q 'THT_SECRETS_FILE: /run/secrets/thothii.secrets' "$tmp/production.yaml" grep -q 'target: thothii.secrets' "$tmp/production.yaml" if grep -q 'test-model' "$tmp/production.yaml"; then echo "rendered production config leaked the model API key" >&2 exit 1 fi if PI_PROVIDER_API_KEY='must-not-leak' ./docker/core-entrypoint.sh doctor 2>"$tmp/legacy-model.err"; then echo "legacy generic model credential was accepted" >&2 exit 1 fi grep -q 'PI_PROVIDER_API_KEY is unsupported' "$tmp/legacy-model.err" if grep -q 'must-not-leak' "$tmp/legacy-model.err"; then echo "legacy model credential leaked through entrypoint diagnostics" >&2 exit 1 fi printf 'THT_VECTOR_READER_PASSWORD=one\nTHT_VECTOR_READER_PASSWORD=two\n' >"$tmp/invalid-bundle" chmod 0600 "$tmp/invalid-bundle" if THT_SECRETS_FILE="$tmp/invalid-bundle" ./docker/core-entrypoint.sh doctor \ >"$tmp/invalid-bundle.out" 2>"$tmp/invalid-bundle.err"; then echo "entrypoint accepted an invalid secret bundle" >&2 exit 1 fi grep -q 'THT_SECRETS_FILE points to an invalid secret bundle' "$tmp/invalid-bundle.err" if grep -q 'THT_VECTOR_READER_PASSWORD' "$tmp/invalid-bundle.err"; then echo "invalid bundle diagnostics leaked key material" >&2 exit 1 fi before_tmp=$(find "${TMPDIR:-/tmp}" -maxdepth 1 -type d -name 'thothii-secrets.*' -print | sort) THT_SECRETS_FILE="$bundle" ./docker/core-entrypoint.sh doctor >/dev/null 2>&1 || true after_tmp=$(find "${TMPDIR:-/tmp}" -maxdepth 1 -type d -name 'thothii-secrets.*' -print | sort) test "$before_tmp" = "$after_tmp" if grep -Eq 'THT_VECTOR_(BOOTSTRAP|MIGRATOR|READER|WRITER)_PASSWORD_FILE|target: vector_(bootstrap|migrator|reader|writer)_password|dwh_api_key|model_api_key|THT_[A-Z0-9_]+_SECRET_FILE' "$tmp/production.yaml"; then echo "production external config contains local direct vector secrets" >&2 exit 1 fi if awk '/^FROM / && $2 !~ /@sha256:/ { found=1 } END { exit !found }' \ docker/core.Dockerfile docker/frontend.Dockerfile; then echo "every Dockerfile base must include an immutable digest" >&2 exit 1 fi grep -qx 'deploy/\*' .dockerignore grep -qx '!deploy/vector/' .dockerignore grep -qx 'deploy/vector/\*' .dockerignore grep -qx '!deploy/vector/secret-policy.sh' .dockerignore echo "container deployment security contract passed."