#!/usr/bin/env bash # replay_build.sh — native replay of every Dockerfile build step. # # This script replays the Dockerfile stages natively as a fast, independent # check. The final verification ladder still performs the real Docker build. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT" WORK="$(mktemp -d /tmp/i2t-build-replay-XXXXXX)" trap 'rm -rf "$WORK"' EXIT echo "==> [static] COPY sources exist in build context" python3 - "$ROOT" <<'PY' import pathlib, shlex, sys root = pathlib.Path(sys.argv[1]) missing = [] for raw in (root / "Dockerfile").read_text(encoding="utf-8").splitlines(): if not raw.startswith("COPY "): continue words = shlex.split(raw) if any(word.startswith("--from=") for word in words[1:]): continue operands = [word for word in words[1:] if not word.startswith("--")] for source in operands[:-1]: path = root / source.rstrip("/") if not path.exists(): missing.append(source) if missing: for source in missing: print(f" MISSING: {source}") raise SystemExit(1) print(" all COPY sources present") PY echo "==> [static] .dockerignore sanity" python3 - "$ROOT" <<'PY' import fnmatch, pathlib, sys root = pathlib.Path(sys.argv[1]) patterns = [l.strip() for l in (root/".dockerignore").read_text().splitlines() if l.strip() and not l.startswith("#")] def ignored(rel): for pat in patterns: p = pat.rstrip("/") if fnmatch.fnmatch(rel, p) or fnmatch.fnmatch(rel, p+"/*") or rel == p \ or any(fnmatch.fnmatch(part, p) for part in rel.split("/")): return True return False must_be_ignored = ["upstream-src", ".venv", "node_modules", "rollout.jsonl", ".workflow"] must_ship = ["Dockerfile", "README.md", "requirements.txt", "package.json", "app/main.py", "forge/stage3_build/generate_threejs_factory.py", "tests/fixtures/canned_spec.json", "scripts/node_smoke.mjs"] ok = True for rel in must_be_ignored: if not ignored(rel): print(f" NOT IGNORED (should be): {rel}"); ok = False for rel in must_ship: if ignored(rel): print(f" IGNORED (must ship): {rel}"); ok = False print(" .dockerignore ok" if ok else " .dockerignore BROKEN") sys.exit(0 if ok else 1) PY echo "==> [stage 1: fixture] regenerate fixture factory via real pipeline" python3 scripts/build_fixture_factory.py "$WORK/factory_fixture.ts" echo "==> [stage 2: nodesmoke] npm ci (fresh dir) + bundle + node smoke" mkdir -p "$WORK/node" cp package.json package-lock.json "$WORK/node/" (cd "$WORK/node" && npm ci --omit=dev --no-audit --no-fund >/dev/null) cp "$WORK/factory_fixture.ts" "$WORK/node/factory.ts" mkdir -p "$WORK/node/app/static" "$WORK/node/scripts" cp app/static/viewer-core.js "$WORK/node/app/static/" cp scripts/node_smoke.mjs "$WORK/node/scripts/" (cd "$WORK/node" && \ factory_export=$(grep -oE 'export function create[A-Za-z0-9]+Model' factory.ts | head -1 | awk '{print $3}') && \ pascal=$(echo "$factory_export" | sed -E 's/^create//; s/Model$//') && \ printf 'export { %s as makeModel, create%sLookDevLights as makeLights } from "./factory.ts";\nexport { mountViewer } from "%s";\n' \ "$factory_export" "$pascal" "$WORK/node/app/static/viewer-core.js" > entry.js && \ node_modules/.bin/esbuild entry.js --bundle --format=esm --target=es2022 --minify --outfile=model.bundle.js && \ node scripts/node_smoke.mjs "$WORK/node/model.bundle.js") echo "==> [stage 3: runtime] pip install -r requirements.txt (fresh venv)" python3 -m venv "$WORK/venv" "$WORK/venv/bin/pip" install -q --disable-pip-version-check -r requirements.txt echo "==> [runtime] boot app as the image would (python -m app.main), probe health/UI/503" RUNS_DIR="$WORK/runs" PORT=17861 env -u LLM_API_KEY -u LLM_MODEL -u LLM_BASE_URL \ -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN -u ANTHROPIC_BASE_URL -u ANTHROPIC_MODEL \ "$WORK/venv/bin/python" -m app.main > "$WORK/server.log" 2>&1 & SERVER_PID=$! trap 'kill $SERVER_PID 2>/dev/null || true; rm -rf "$WORK"' EXIT curl --fail --silent --show-error \ --retry 30 --retry-all-errors --retry-connrefused --retry-delay 1 \ --connect-timeout 2 --max-time 60 \ http://127.0.0.1:17861/health > "$WORK/health.json" grep -q '"status":"ok"' "$WORK/health.json" && echo " /health ok" grep -q '"llm_configured":false' "$WORK/health.json" && echo " llm_configured=false ok" curl -fsS http://127.0.0.1:17861/ | grep -q img2threejs && echo " / ok" code=$(curl -s -o "$WORK/job.json" -w '%{http_code}' \ -F "file=@tests/fixtures/ref.png;type=image/png" http://127.0.0.1:17861/api/jobs) [ "$code" = "503" ] && grep -q llm_not_configured "$WORK/job.json" && echo " honest 503 ok" ! grep -qiE 'sculptRuntime|makeModel' "$WORK/job.json" && echo " no fabrication ok" kill $SERVER_PID 2>/dev/null || true echo "==> [runtime] pytest suite inside the fresh venv" "$WORK/venv/bin/python" -m pytest tests/ -q 2>&1 | tail -2 echo echo "BUILD REPLAY: ALL STAGES OK"