max / makenotwork
| 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 | # |
| 26 | # The seed's harness phase (login-capable accounts plus the OAuth client for the |
| 27 | # write-enabled mt on astra) runs only when MT_HARNESS_PASSWORD and |
| 28 | # MT_HARNESS_REDIRECT_URI are both set. They are read from $ENV_FILE, which the |
| 29 | # systemd-run below already passes through, so nothing here needs to know them. |
| 30 | # A box without them reseeds the catalog alone and the mt browser harness loses |
| 31 | # its login — see multithreaded/deploy/README.md. |
| 32 | |
| 33 | |
| 34 | SSH_TARGET="" |
| 35 | DB="" |
| 36 | SERVICE="makenotwork.service" |
| 37 | BIN="" |
| 38 | BIN_DIR="" |
| 39 | BIN_NAME="" |
| 40 | ENV_FILE="" |
| 41 | SEED_USER="" |
| 42 | |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | # Drop every non-system schema (migrations create custom schemas like |
| 50 | # tower_sessions that survive DROP SCHEMA public CASCADE). Recreate public OWNED |
| 51 | # BY the app role: on PG15+ a postgres-owned public grants no CREATE to other |
| 52 | # roles, so boot migrations would fail with "no schema has been selected to |
| 53 | # create in". This is the same reset the prod-refresh used, minus the restore. |
| 54 | |
| 55 | |
| 56 | DO \$\$ |
| 57 | DECLARE s text; |
| 58 | BEGIN |
| 59 | FOR s IN |
| 60 | SELECT nspname FROM pg_namespace |
| 61 | WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema' |
| 62 | LOOP |
| 63 | EXECUTE format('DROP SCHEMA IF EXISTS %I CASCADE', s); |
| 64 | END LOOP; |
| 65 | EXECUTE 'CREATE SCHEMA public AUTHORIZATION '; |
| 66 | END \$\$; |
| 67 | SQL |
| 68 | |
| 69 | # Run the binary as the app user with the seed opt-in flag set. |
| 70 | # `--seed-examples` applies migrations to the empty schema, runs the guarded |
| 71 | # seed, and exits(0) before the server binds a port — so this is safe to run |
| 72 | # while the service is stopped. Use systemd-run with the service's own |
| 73 | # EnvironmentFile rather than shell-sourcing it: systemd parses `KEY=value` |
| 74 | # literally, so secrets containing shell metacharacters (e.g. the DB password) |
| 75 | # load correctly, whereas `. env` would choke on them. |
| 76 | |
| 77 | |
| 78 | -p EnvironmentFile= -p WorkingDirectory= -p User= \ |
| 79 | -E ALLOW_EXAMPLE_SEED=1 --seed-examples" |
| 80 | |
| 81 | |
| 82 | |
| 83 | |
| 84 | # Boot smoke: the app must come back healthy after the reseed. |
| 85 | healthy=0 |
| 86 | for; do |
| 87 | code= |
| 88 | [ && { ; healthy=1; break; } |
| 89 | |
| 90 | done |
| 91 | if [; then |
| 92 | |
| 93 | |
| 94 | fi |
| 95 | |
| 96 | # Content smoke: healthy is not the same as worth showing. A reseed that leaves |
| 97 | # the catalog empty returns 200 on every page, which is exactly how nine of |
| 98 | # eleven items stayed invisible for weeks. Run the thinness check here so the |
| 99 | # reseed and its verification cannot drift apart. |
| 100 | # |
| 101 | # Set SKIP_CONTENT_SMOKE=1 to reseed without it, e.g. when the catalog is |
| 102 | # deliberately mid-change and the baselines have not been re-sealed yet. |
| 103 | if [; then |
| 104 | |
| 105 | |
| 106 | fi |
| 107 | |
| 108 | |
| 109 |