#!/usr/bin/env bash # Build the linux/amd64 Space image and verify its runtime surface. set -euo pipefail TAG="${1:-img2threejs:verify}" PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" NO_SECRET_CONTAINER="i2t-no-secret-$$" GUARD_CONTAINER="i2t-guard-$$" VERIFY_TMP="$(mktemp -d -t img2threejs-docker-verify.XXXXXX)" cleanup() { docker rm -f "$NO_SECRET_CONTAINER" "$GUARD_CONTAINER" >/dev/null 2>&1 || true rm -rf "$VERIFY_TMP" } trap cleanup EXIT cd "$PROJECT_ROOT" echo "==> docker build --platform=linux/amd64 -t $TAG ." docker build --platform=linux/amd64 -t "$TAG" . echo "==> image size" docker images "$TAG" --format ' {{.Repository}}:{{.Tag}} {{.Size}}' echo "==> runtime image allowlist" docker run --rm --entrypoint sh "$TAG" -c ' set -eu for path in \ /home/user/app/.git \ /home/user/app/.pytest_cache \ /home/user/app/.venv \ /home/user/app/.workflow \ /home/user/app/docs \ /home/user/app/grimoire \ /home/user/app/pytest.ini \ /home/user/app/scripts \ /home/user/app/SKILL.md \ /home/user/app/tests \ /home/user/app/upstream-src \ /home/user/app/verification \ /home/user/app/forge/tests; do test ! -e "$path" done test -z "$(find /home/user/app -type d -name __pycache__ -print -quit)" test -z "$(find /home/user/app -type f \( -name "rollout*.jsonl" -o -name "*.pyc" \) -print -quit)" test -f /home/user/app/app/main.py test -f /home/user/app/forge/stage3_build/generate_threejs_factory.py test -f /home/user/app/LICENSE echo " strict runtime source allowlist ok" ' echo "==> no-secret container: health, UI, and honest 503" docker run -d --name "$NO_SECRET_CONTAINER" -p 17860:7860 "$TAG" >/dev/null curl --fail --silent --show-error \ --retry 45 --retry-all-errors --retry-connrefused --retry-delay 1 \ --connect-timeout 2 --max-time 90 \ http://127.0.0.1:17860/health >"$VERIFY_TMP/health.json" grep -q '"status":"ok"' "$VERIFY_TMP/health.json" grep -q '"llm_configured":false' "$VERIFY_TMP/health.json" curl --fail --silent --show-error http://127.0.0.1:17860/ \ >"$VERIFY_TMP/index.html" grep -q 'img2threejs' "$VERIFY_TMP/index.html" curl --fail --silent --show-error http://127.0.0.1:17860/static/app.js \ >"$VERIFY_TMP/app.js" grep -q 'startJob' "$VERIFY_TMP/app.js" no_secret_code="$(curl --silent --output "$VERIFY_TMP/no-secret-job.json" \ --write-out '%{http_code}' \ -F "file=@tests/fixtures/ref.png;type=image/png" \ http://127.0.0.1:17860/api/jobs)" if [[ "$no_secret_code" != "503" ]]; then echo "FAIL: expected 503 without LLM secrets, got $no_secret_code" >&2 sed -n '1,20p' "$VERIFY_TMP/no-secret-job.json" >&2 exit 1 fi grep -q 'llm_not_configured' "$VERIFY_TMP/no-secret-job.json" if grep -qiE 'sculptRuntime|makeModel|model\.bundle' "$VERIFY_TMP/no-secret-job.json"; then echo "FAIL: no-secret response appears to contain fabricated artifacts" >&2 exit 1 fi echo " health/UI/honest 503 ok" echo "==> configured guard container: invalid upload reaches image validation" docker run -d --name "$GUARD_CONTAINER" -p 17861:7860 \ -e LLM_API_KEY=verification-dummy \ -e LLM_MODEL=verification-dummy \ -e LLM_BASE_URL=http://127.0.0.1:9 \ "$TAG" >/dev/null curl --fail --silent --show-error \ --retry 45 --retry-all-errors --retry-connrefused --retry-delay 1 \ --connect-timeout 2 --max-time 90 \ http://127.0.0.1:17861/health >"$VERIFY_TMP/guard-health.json" grep -q '"llm_configured":true' "$VERIFY_TMP/guard-health.json" printf 'not an image' >"$VERIFY_TMP/not-image.html" guard_code="$(curl --silent --output "$VERIFY_TMP/guard-job.json" \ --write-out '%{http_code}' \ -F "file=@$VERIFY_TMP/not-image.html;type=text/html" \ http://127.0.0.1:17861/api/jobs)" if [[ "$guard_code" != "415" ]]; then echo "FAIL: expected 415 for a declared non-image, got $guard_code" >&2 sed -n '1,20p' "$VERIFY_TMP/guard-job.json" >&2 exit 1 fi grep -q 'unsupported_media_type' "$VERIFY_TMP/guard-job.json" echo " upload content-type guard ok" echo "ALL DOCKER CHECKS PASSED"