test(compose): validate bundle deployment contract

This commit is contained in:
2026-07-12 11:48:43 +02:00
parent 07967bf589
commit 10465917a5
3 changed files with 38 additions and 18 deletions
+2 -1
View File
@@ -28,6 +28,7 @@ harness/sessions
harness/artifacts
harness/indexes
harness/corpus
deploy
deploy/*
!deploy/vector/
deploy/vector/*
!deploy/vector/secret-policy.sh
+7
View File
@@ -24,6 +24,9 @@ Updated:
Compose services without the legacy `external` profile.
- `scripts/test-default-compose.sh` asserts the exact installation command, tracked templates,
and absence of the legacy setup in the guide.
- `scripts/test-container-deployment.sh` now validates the bundle mount and rejects legacy
per-secret references; `.dockerignore` explicitly re-includes only the required vector policy
helper so the Docker build context remains safe.
The docs explicitly state that a PEM CA chain cannot be put in the strict single-line bundle. A
reviewed Compose override/secret-manager mount is required for `THT_SSL_CA`. Direct PostgreSQL
@@ -34,9 +37,13 @@ the base bundle mount is the only default mount.
- `sh -n scripts/docker-smoke.sh scripts/test-default-compose.sh` — passed.
- `./scripts/test-default-compose.sh` — passed.
- `./scripts/test-container-deployment.sh` — passed after migrating its local-vector assertions
to the single bundle and checking the `.dockerignore` deployment allowlist.
- `git diff --check` — passed.
- `./scripts/test-docker-smoke.sh` — passed after updating its static assertion to the default
no-profile invocation.
- `docker buildx build --file docker/core.Dockerfile --check .` — passed; BuildKit reported no
warnings after the `.dockerignore` parent-directory fix.
## Concerns
+28 -16
View File
@@ -6,6 +6,18 @@ 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"
@@ -18,25 +30,20 @@ if grep -q 'THT_[A-Z0-9_]*_SECRET_FILE:' "$tmp/base.yaml"; then
exit 1
fi
for secret in bootstrap migrator local_reader local_writer; do
printf '%s' "contract-$secret" >"$tmp/$secret"
chmod 0600 "$tmp/$secret"
done
THT_VECTOR_BOOTSTRAP_PASSWORD_SECRET_FILE="$tmp/bootstrap" \
THT_VECTOR_MIGRATOR_PASSWORD_SECRET_FILE="$tmp/migrator" \
THT_VECTOR_READER_PASSWORD_SECRET_FILE="$tmp/local_reader" \
THT_VECTOR_WRITER_PASSWORD_SECRET_FILE="$tmp/local_writer" \
docker compose -f compose.yaml -f deploy/compose.local-vector.yaml \
docker compose -f compose.yaml -f deploy/compose.local-vector.yaml \
--profile local-vector config >"$tmp/local-vector.yaml"
grep -q 'THT_VECTOR_READER_PASSWORD_FILE: /run/secrets/vector_reader_password' "$tmp/local-vector.yaml"
grep -q 'THT_VECTOR_WRITER_PASSWORD_FILE: /run/secrets/vector_writer_password' "$tmp/local-vector.yaml"
if grep -q 'contract-local_' "$tmp/local-vector.yaml"; then
echo "rendered local-vector config leaked a direct database secret" >&2
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 \
--profile external config >"$tmp/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
@@ -48,7 +55,7 @@ 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 \
--profile external config >"$tmp/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"
@@ -67,7 +74,7 @@ if grep -q 'must-not-leak' "$tmp/legacy-model.err"; then
echo "legacy model credential leaked through entrypoint diagnostics" >&2
exit 1
fi
if grep -q 'THT_VECTOR_READER_PASSWORD_FILE\|THT_VECTOR_WRITER_PASSWORD_FILE\|target: vector_reader_password\|target: vector_writer_password\|dwh_api_key\|model_api_key' "$tmp/production.yaml"; then
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
@@ -78,4 +85,9 @@ if awk '/^FROM / && $2 !~ /@sha256:/ { found=1 } END { exit !found }' \
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."