#!/usr/bin/env bash # Clean-room install rehearsal (plan: per-release clean-VM install.sh # rehearsal): assemble a REAL signed bundle from the built images, run # the customer's install path end to end — offline verify, docker load, # compose up — and assert the platform answers before tearing down. # # Requires: clawmates/server:latest + clawmates/frontend:latest built # (POSTGRES_PASSWORD=x docker compose -f deploy/compose/docker-compose.yml build). set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" WORK="$(mktemp -d)" export CLAWMATES_HOME="$WORK/opt" cleanup() { docker compose --project-directory "$CLAWMATES_HOME" down -v >/dev/null 2>&1 || true rm -rf "$WORK" } trap cleanup EXIT echo "==> Building bundler + signing key" cargo build -q -p clawmates-bundler BUNDLER="$ROOT/target/debug/clawmates-bundler" "$BUNDLER" keygen "$WORK/release.key" "$WORK/release.pub" echo "==> Saving runtime images" mkdir -p "$WORK/images" docker pull -q postgres:16-alpine >/dev/null docker pull -q tecnativa/docker-socket-proxy:0.3 >/dev/null docker save clawmates/server:latest -o "$WORK/images/server.tar" docker save clawmates/frontend:latest -o "$WORK/images/frontend.tar" docker save clawmates/broker:latest -o "$WORK/images/broker.tar" docker save postgres:16-alpine -o "$WORK/images/postgres.tar" docker save tecnativa/docker-socket-proxy:0.3 -o "$WORK/images/socket-proxy.tar" echo "==> Assembling the signed bundle" ARTIFACTS="" for tar in "$WORK"/images/*.tar; do ARTIFACTS="$ARTIFACTS $tar=images/$(basename "$tar")" done # shellcheck disable=SC2086 "$BUNDLER" assemble "$WORK/bundle" "rehearsal" "$WORK/release.key" \ "$ROOT/deploy/compose/docker-compose.yml=compose/docker-compose.yml" \ "$ROOT/deploy/compose/clawmates.toml=compose/clawmates.toml" \ "$ROOT/deploy/compose/.env.example=compose/.env.example" \ "$ROOT/deploy/airgapped/install.sh=install.sh" \ "$BUNDLER=bin/clawmates-bundler" \ $ARTIFACTS chmod +x "$WORK/bundle/bin/clawmates-bundler" "$WORK/bundle/install.sh" echo "==> Customer install: verify -> load -> stage" "$WORK/bundle/install.sh" "$WORK/bundle" "$WORK/release.pub" echo "==> First boot" echo "POSTGRES_PASSWORD=rehearse-$$" > "$CLAWMATES_HOME/.env" docker compose --project-directory "$CLAWMATES_HOME" up -d --no-build echo "==> Waiting for the platform" for _ in $(seq 1 60); do if curl -fsS http://127.0.0.1:8080/healthz >/dev/null 2>&1; then echo "==> Server is healthy" if curl -fsS http://127.0.0.1:3000/login | grep -q clawmates; then echo "==> Frontend serves the login page" echo "REHEARSAL OK" exit 0 fi fi sleep 2 done echo "REHEARSAL FAILED: platform never became healthy" docker compose --project-directory "$CLAWMATES_HOME" logs --tail 30 exit 1