stack/docker/local-emulator/entrypoint.sh
Bilal Godil a65022b8f7 emulator fast-start via VM snapshot + live secret rotation
Ships a compressed RAM/device snapshot (stack-emulator-<arch>.savevm.zst)
alongside the qcow2. `emulator start` resumes from it and rotates the
per-install secrets in place, taking cold-boot from 30-120s to ~6-7s.

Build phase adds a STACKCFG runtime ISO so stack.service can boot during
image creation, starts qemu-guest-agent so its virtio-serial port stays
open in the snapshot, then stop+migrate file:+quit via QMP.

Runtime sends fresh secrets through QGA guest-exec input-data, which pipes
them to trigger-fast-rotate and rotate-secrets inside the container:
targeted sed on the placeholder PCK in built JS, UPDATE on the internal
ApiKeySet, supervisorctl restart stack-app + cron-jobs. Placeholder hex
values are baked in instead of random keys under STACK_EMULATOR_BUILD_SNAPSHOT=1
so no real secret ships in the snapshot.

Device topology and SMP must match at capture and resume; runtime adds
phantom seed/bundle drives and pins SMP=4. Cold-boot fallback kicks in
automatically when the snapshot is missing, corrupt, or incompatible.

supervisord.conf now uses stopasgroup/killasgroup for stack-app and
cron-jobs so supervisor restart actually kills the Node children (they
were keeping their port bindings and breaking rotation).
2026-04-15 11:49:52 -07:00

45 lines
1.8 KiB
Bash

#!/bin/bash
set -e
PGDATA=/data/postgres
PG_BIN=/usr/lib/postgresql/16/bin
if [ -z "$(ls -A "$PGDATA" 2>/dev/null)" ]; then
gosu postgres "$PG_BIN/initdb" -D "$PGDATA" --no-sync --auth-local=trust --auth-host=md5
{
echo "host all all 0.0.0.0/0 md5"
echo "host all all ::/0 md5"
} >> "$PGDATA/pg_hba.conf"
echo "shared_preload_libraries = 'pg_stat_statements'" >> "$PGDATA/postgresql.conf"
echo "pg_stat_statements.track = all" >> "$PGDATA/postgresql.conf"
gosu postgres "$PG_BIN/pg_ctl" -D "$PGDATA" start -w \
-o "-c listen_addresses=127.0.0.1 -c shared_preload_libraries=pg_stat_statements"
gosu postgres psql -c "ALTER USER postgres PASSWORD 'PASSWORD-PLACEHOLDER--uqfEC1hmmv';"
gosu postgres psql -c "CREATE DATABASE stackframe;"
gosu postgres psql -c "CREATE DATABASE svix;"
gosu postgres psql -d stackframe -c "CREATE EXTENSION IF NOT EXISTS pg_stat_statements;"
gosu postgres psql -d stackframe -c "CREATE ROLE anon NOLOGIN;"
gosu postgres psql -d stackframe -c "CREATE ROLE authenticated NOLOGIN;"
gosu postgres "$PG_BIN/pg_ctl" -D "$PGDATA" stop -w
fi
# Generate a fresh CRON_SECRET per container start. The cron endpoints are
# internal — nothing outside the container calls them — so we don't want the
# baked-in mock value from .env.development to be a usable credential against
# a running emulator. Overriding here propagates to both the backend and the
# run-cron-jobs.sh loop via supervisord's inherited environment.
#
# In snapshot-build mode the VM supplies a deterministic placeholder via the
# --env-file so the baked snapshot doesn't contain a real secret; on resume,
# /usr/local/bin/rotate-secrets swaps in a fresh per-install value.
if [ -z "${CRON_SECRET:-}" ]; then
export CRON_SECRET="$(openssl rand -hex 32)"
fi
exec /usr/bin/supervisord -n -c /etc/supervisor/conf.d/supervisord.conf