Skip to main content

max / makenotwork

3.7 KB · 85 lines History Blame Raw
1 #!/usr/bin/env bash
2 # Reset testnot.work to the fabricated example catalog.
3 #
4 # Reseeds from the in-repo `--seed-examples` flow: a self-contained catalog of
5 # fabricated `@example.test` creators and public-domain items. testnot holds no
6 # prod-derived data at all. This replaced a prod-restore refresh that reloaded
7 # the database from a production backup, putting real user data on the staging
8 # box; that path was deleted on 2026-07-22.
9 #
10 # Runs on fw13 (the Sando host, which has tailnet root on testnot via Tailscale
11 # SSH). It stops the app, resets the schema as the postgres superuser (streamed
12 # over Tailscale SSH), then runs the app binary once with `--seed-examples`,
13 # which applies migrations to the empty schema and runs the guarded seed before
14 # exiting. The seed's own guards (ALLOW_EXAMPLE_SEED, testnot-host allowlist,
15 # no-real-users) make it refuse anywhere but a testnot/localhost box.
16 #
17 # Idempotent and safe to re-run: the seed is fixed, and every run rebuilds the
18 # same catalog. Unlike the refresh, there is no pause-flag — the catalog is
19 # stable by construction, so a soak needs no protection from a daily wipe.
20 #
21 # Media (previews/downloads) attaches in-process only when object storage is
22 # configured in the env file (S3_*). Until MinIO is stood up on testnot, items
23 # seed hidden (scan_status stays pending) and the catalog shows creators,
24 # projects, blog posts, and follow counts without media.
25 set -euo pipefail
26
27 SSH_TARGET="${TESTNOT_SSH:-root@testnot}"
28 DB="${TESTNOT_DB:-makenotwork}"
29 SERVICE="makenotwork.service"
30 BIN="${TESTNOT_BIN:-/opt/mnw/current/makenotwork}"
31 BIN_DIR="$(dirname "$BIN")"
32 BIN_NAME="$(basename "$BIN")"
33 ENV_FILE="${TESTNOT_ENV:-/etc/mnw/makenotwork.env}"
34 SEED_USER="${TESTNOT_SEED_USER:-deploy}"
35
36 log() { echo "[$(date -u +%H:%M:%S)] $*"; }
37 ts_ssh() { tailscale ssh "$SSH_TARGET" "$@"; }
38
39 log "stopping $SERVICE on testnot"
40 ts_ssh "systemctl stop $SERVICE"
41
42 # Drop every non-system schema (migrations create custom schemas like
43 # tower_sessions that survive DROP SCHEMA public CASCADE). Recreate public OWNED
44 # BY the app role: on PG15+ a postgres-owned public grants no CREATE to other
45 # roles, so boot migrations would fail with "no schema has been selected to
46 # create in". This is the same reset the prod-refresh used, minus the restore.
47 log "resetting schema"
48 ts_ssh "sudo -u postgres psql -v ON_ERROR_STOP=1 -d $DB" <<SQL
49 DO \$\$
50 DECLARE s text;
51 BEGIN
52 FOR s IN
53 SELECT nspname FROM pg_namespace
54 WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema'
55 LOOP
56 EXECUTE format('DROP SCHEMA IF EXISTS %I CASCADE', s);
57 END LOOP;
58 EXECUTE 'CREATE SCHEMA public AUTHORIZATION $DB';
59 END \$\$;
60 SQL
61
62 # Run the binary as the app user with the seed opt-in flag set.
63 # `--seed-examples` applies migrations to the empty schema, runs the guarded
64 # seed, and exits(0) before the server binds a port — so this is safe to run
65 # while the service is stopped. Use systemd-run with the service's own
66 # EnvironmentFile rather than shell-sourcing it: systemd parses `KEY=value`
67 # literally, so secrets containing shell metacharacters (e.g. the DB password)
68 # load correctly, whereas `. env` would choke on them.
69 log "migrating + seeding the example catalog"
70 ts_ssh "systemd-run --pipe --wait --collect --service-type=exec \
71 -p EnvironmentFile=$ENV_FILE -p WorkingDirectory=$BIN_DIR -p User=$SEED_USER \
72 -E ALLOW_EXAMPLE_SEED=1 $BIN --seed-examples"
73
74 log "starting $SERVICE"
75 ts_ssh "systemctl start $SERVICE"
76
77 # Boot smoke: the app must come back healthy after the reseed.
78 for _ in $(seq 1 20); do
79 code=$(ts_ssh "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/health" || echo 000)
80 [ "$code" = "200" ] && { log "health OK"; exit 0; }
81 sleep 3
82 done
83 echo "testnot did not return healthy after reseed" >&2
84 exit 1
85