Skip to main content

max / makenotwork

4.5 KB · 112 lines History Blame Raw
1 #!/usr/bin/env bash
2 # Reset the astra mt instance to its seeded state.
3 #
4 # astra runs the write-enabled mt: reachable over the tailnet only, logged into
5 # with real MNW accounts, and driven by the browser axis of an audit run through
6 # thread create, reply, flag and moderation. That is a surface that accumulates
7 # junk by design, so it needs a way back to a known state, and this is it.
8 #
9 # Hard reset, not incremental: drop every schema, let the binary re-migrate and
10 # re-seed. Nobody is looking at this instance, so there is nothing to preserve
11 # and no reason to make the reset clever. Two audit runs a week apart should see
12 # the same forum.
13 #
14 # What it does NOT reset is the MNW side. The accounts the harness logs in as
15 # live on testnot and are recreated by testnot's own reseed
16 # (`sando/deploy/mnw-testnot-seed.sh`, harness phase). The two are deliberately
17 # independent: mt's state is disposable, the identities behind it are not.
18 #
19 # Usage:
20 # deploy/reset-astra.sh # stop, wipe, migrate, seed, start, verify
21 #
22 # Env:
23 # MT_ASTRA_SSH ssh target (default: astra)
24 # MT_ASTRA_DB database name (default: multithreaded)
25 set -euo pipefail
26
27 SSH_TARGET="${MT_ASTRA_SSH:-astra}"
28 DB="${MT_ASTRA_DB:-multithreaded}"
29 SERVICE="multithreaded.service"
30 APP_DIR="/opt/multithreaded"
31 BIN="$APP_DIR/multithreaded"
32 ENV_FILE="$APP_DIR/.env"
33 APP_USER="multithreaded"
34 PORT="${MT_ASTRA_PORT:-3400}"
35
36 log() { echo "[$(date -u +%H:%M:%S)] $*"; }
37 on_astra() { ssh "$SSH_TARGET" "$@"; }
38
39 log "stopping $SERVICE on $SSH_TARGET"
40 on_astra "sudo systemctl stop $SERVICE"
41
42 # Drop every non-system schema rather than just `public`: tower-sessions creates
43 # its own, and a surviving session table would carry logins across a reset that
44 # is supposed to have removed the users they point at. Recreate `public` OWNED BY
45 # the app role, because on PG15+ a postgres-owned public grants the app no
46 # CREATE and the boot migrations fail with "no schema has been selected".
47 log "resetting schema in $DB"
48 on_astra "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 $APP_USER';
59 END \$\$;
60 SQL
61
62 # `--seed` migrates the empty schema, seeds, and exits before binding a port, so
63 # it is safe with the service stopped. systemd-run with the service's own
64 # EnvironmentFile rather than sourcing it in a shell: systemd parses KEY=value
65 # literally, so a secret containing shell metacharacters survives.
66 log "migrating + seeding"
67 on_astra "sudo systemd-run --pipe --wait --collect --service-type=exec \
68 -p EnvironmentFile=$ENV_FILE -p WorkingDirectory=$APP_DIR -p User=$APP_USER \
69 $BIN --seed"
70
71 log "starting $SERVICE"
72 on_astra "sudo systemctl start $SERVICE"
73
74 healthy=0
75 for _ in $(seq 1 20); do
76 code=$(on_astra "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:$PORT/api/health" || echo 000)
77 [ "$code" = "200" ] && { log "health OK"; healthy=1; break; }
78 sleep 3
79 done
80 if [ "$healthy" -ne 1 ]; then
81 echo "mt did not return healthy after the reset" >&2
82 exit 1
83 fi
84
85 # Healthy is not the same as usable. A browser run that logs in and finds no
86 # membership fails at the first write with a 403, which reads like a permissions
87 # bug in mt rather than a seed that did not finish. Assert the harness
88 # preconditions here so the reset and its verification cannot drift apart:
89 # the three accounts exist, and the owner account really is Owner somewhere.
90 log "verifying harness preconditions"
91 counts=$(on_astra "sudo -u postgres psql -v ON_ERROR_STOP=1 -At -d $DB" <<'SQL'
92 SELECT count(*) FROM users
93 WHERE mnw_account_id IN (
94 '00000000-0000-0000-0000-00000000f001',
95 '00000000-0000-0000-0000-00000000f002',
96 '00000000-0000-0000-0000-00000000f003');
97 SELECT count(*) FROM memberships
98 WHERE user_id = '00000000-0000-0000-0000-00000000f003' AND role = 'owner';
99 SELECT count(*) FROM threads;
100 SQL
101 )
102 accounts=$(sed -n 1p <<<"$counts")
103 owner_rows=$(sed -n 2p <<<"$counts")
104 threads=$(sed -n 3p <<<"$counts")
105
106 [ "$accounts" = "3" ] || { echo "expected 3 harness accounts, found ${accounts:-none}" >&2; exit 1; }
107 [ "${owner_rows:-0}" -ge 1 ] || { echo "harness owner holds no owner membership" >&2; exit 1; }
108 [ "${threads:-0}" -gt 0 ] || { echo "no threads seeded" >&2; exit 1; }
109 log "harness OK: 3 accounts, owner membership present, $threads threads"
110
111 log "done"
112