96 lines
4.4 KiB
Bash
Executable File
96 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
tmp=$(mktemp -d)
|
|
project="thothii-task5-$(date +%s)-$$"
|
|
expected_pi_version=$(sed -n 's/^ARG PI_VERSION=//p' docker/core.Dockerfile)
|
|
trap 'docker compose --project-name "$project" -f compose.yaml -f deploy/compose.local.yaml down --volumes --remove-orphans >/dev/null 2>&1 || true; rm -rf "$tmp"' EXIT HUP INT TERM
|
|
|
|
test -n "$expected_pi_version"
|
|
printf '%s\n' '{"zai":{"type":"api_key","key":"fixture-native-auth-key"}}' >"$tmp/pi-auth.json"
|
|
chmod 0600 "$tmp/pi-auth.json"
|
|
printf '%s\n' 'THT_MODEL_API_KEY=fixture-model-api-key' >"$tmp/thothii.secrets"
|
|
chmod 0600 "$tmp/thothii.secrets"
|
|
printf '%s\n' 'schemaVersion: 2' >"$tmp/thothii-installation.yaml"
|
|
chmod 0600 "$tmp/thothii-installation.yaml"
|
|
printf '%s' 'fixture-catalog-runtime-password' >"$tmp/catalog-runtime-password"
|
|
printf '%s' 'fixture-catalog-migrator-password' >"$tmp/catalog-migrator-password"
|
|
chmod 0600 "$tmp/catalog-runtime-password" "$tmp/catalog-migrator-password"
|
|
|
|
export PI_AUTH_FILE="$tmp/pi-auth.json"
|
|
export THT_SECRETS_FILE="$tmp/thothii.secrets"
|
|
export THT_INSTALLATION_CONFIG_SOURCE="$tmp/thothii-installation.yaml"
|
|
export THT_CATALOG_RUNTIME_PASSWORD_SOURCE="$tmp/catalog-runtime-password"
|
|
export THT_CATALOG_MIGRATOR_PASSWORD_SOURCE="$tmp/catalog-migrator-password"
|
|
export THT_WORKSPACE_GIT_REMOTE="https://git.example.invalid/thothii/workspaces.git"
|
|
# Let Docker assign loopback ports so this isolated contract test never collides with an operator stack.
|
|
export THOTH_CORE_HTTP_PORT=0
|
|
export THOTH_HTTP_PORT=0
|
|
|
|
context_check="$tmp/build-context"
|
|
mkdir -p "$context_check/deploy"
|
|
cp .dockerignore "$context_check/.dockerignore"
|
|
printf '%s\n' 'task-5-context-sentinel' >"$context_check/deploy/thothii.env"
|
|
cat >"$context_check/Dockerfile" <<'EOF'
|
|
FROM scratch
|
|
COPY deploy/thothii.env /sentinel
|
|
EOF
|
|
if docker build --quiet -f "$context_check/Dockerfile" "$context_check" >"$tmp/context-check.out" 2>&1; then
|
|
echo "deploy/thothii.env entered the Docker build context" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! awk '
|
|
$1 == "FROM" && $2 !~ /^[^@]+@sha256:[0-9a-f]{64}$/ {
|
|
print FILENAME ":" FNR ": unpinned base image: " $0 > "/dev/stderr"
|
|
bad = 1
|
|
}
|
|
END { exit bad }
|
|
' docker/core.Dockerfile docker/frontend.Dockerfile; then
|
|
echo "every production FROM reference must use tag@sha256" >&2
|
|
exit 1
|
|
fi
|
|
|
|
while IFS= read -r base_image; do
|
|
manifest=$(docker buildx imagetools inspect "$base_image")
|
|
printf '%s\n' "$manifest" | grep -Eq 'Platform:[[:space:]]+linux/amd64'
|
|
printf '%s\n' "$manifest" | grep -Eq 'Platform:[[:space:]]+linux/arm64'
|
|
done < <(awk '$1 == "FROM" { print $2 }' docker/core.Dockerfile docker/frontend.Dockerfile | sort -u)
|
|
|
|
docker compose --project-name "$project" -f compose.yaml -f deploy/compose.local.yaml build --pull
|
|
|
|
core_label=$(docker image inspect --format '{{ index .Config.Labels "io.thothii.pi.version" }}' thothii-core:local)
|
|
test "$core_label" = "$expected_pi_version"
|
|
test "$(docker image inspect --format '{{ index .Config.Labels "org.opencontainers.image.title" }}' thothii-core:local)" = "thothii-core"
|
|
test "$(docker image inspect --format '{{ index .Config.Labels "org.opencontainers.image.title" }}' thothii-frontend:local)" = "thothii-frontend"
|
|
|
|
docker compose --project-name "$project" -f compose.yaml -f deploy/compose.local.yaml up --detach --wait --wait-timeout 90
|
|
|
|
docker compose --project-name "$project" -f compose.yaml -f deploy/compose.local.yaml exec -T core sh -ceu '
|
|
test "$(id -u)" = 10001
|
|
test "$(pi --version)" = "$PI_VERSION"
|
|
command -v pi >/dev/null
|
|
test ! -e /var/run/docker.sock
|
|
test -r /home/thoth/.pi/agent/auth.json
|
|
test -r /run/secrets/thothii.secrets
|
|
touch /data/.task5-writable
|
|
rm /data/.task5-writable
|
|
if find /app /home /data -xdev \( -iname "*chirone*" -o -iname "*omics*portal*" \) -print -quit | grep -q .; then
|
|
echo "portal or Chirone path found in core image" >&2
|
|
exit 1
|
|
fi
|
|
'
|
|
|
|
if docker compose --project-name "$project" -f compose.yaml -f deploy/compose.local.yaml config | grep -Eqi 'docker\.sock|/var/run/docker|docker[-_]?daemon'; then
|
|
echo "Compose must not mount a Docker socket or daemon" >&2
|
|
exit 1
|
|
fi
|
|
|
|
frontend_address=$(docker compose --project-name "$project" -f compose.yaml -f deploy/compose.local.yaml port frontend 8080 | head -n 1)
|
|
curl --fail --silent --show-error "http://$frontend_address/" >/dev/null
|
|
curl --fail --silent --show-error "http://$frontend_address/api/health" >/dev/null
|
|
|
|
echo "Task 5 container deployment contract passed."
|