Skip to main content

max / makenotwork

9.1 KB · 231 lines History Blame Raw
1 # Sando daemon config (production).
2 # Install at /etc/sando/sando-daemon.toml on the Sando host.
3 #
4 # Deploy-API auth is NOT configured here — the bearer token lives in the
5 # EnvironmentFile (/etc/sando/sando.env: SANDO_API_TOKEN), generated by
6 # bootstrap-sandod-host.sh. With a non-loopback `listen` (below) the daemon
7 # REFUSES TO START unless that token is set (CF2): a tailnet bind is reachable
8 # by every tailnet node, so deploy authority must be gated by more than network
9 # position.
10
11 listen = "100.103.89.95:7766" # fw13 tailnet IP; bind tailnet-only, not 0.0.0.0 — requires SANDO_API_TOKEN
12 db_path = "/srv/sando/state/sando.db"
13 topology_path = "/etc/sando/sando.toml"
14 # Hostname (/proc/sys/kernel/hostname) this daemon is permitted to build on.
15 # build::run refuses to compile on any other host, so a sandod misdeployed onto
16 # a prod node cannot build there ("never build on prod" as an invariant).
17 # Required — there is no safe default.
18 build_host = "fw13"
19 workdir = "/srv/sando/work"
20 release_root = "/srv/sando"
21 # Name the user explicitly. libpq (psql) defaults a missing user to the OS user,
22 # but sqlx in a minimal systemd env (no USER/LOGNAME) defaults it to "anonymous",
23 # so an unqualified URL peer-auth-fails and crash-loops sandod at the startup
24 # scratch preflight (--check-config does not catch it — no DB connect). See the
25 # maintainer notes / memory reference_sando_scratch_db.
26 scratch_db_url = "postgres:///sando_scratch?host=/var/run/postgresql&user=sando"
27 bin_names = ["makenotwork", "mnw-admin"]
28 logs_root = "/srv/sando/logs"
29 # Shared cargo target dir across per-sha worktrees. Without it every /rebuild
30 # clean-compiles a fresh worktree (~10 min) even for a 1-line diff; with it the
31 # incremental rebuild reuses the previous sha's compiled deps (1–2 min). Safe
32 # because builds are serialized (a new /rebuild aborts the in-flight one). The
33 # sando user must be able to write it; cargo creates it if absent.
34 cargo_target_dir = "/srv/sando/cargo-target"
35
36 # Databases the migration_dry_run gate dry-runs, in order: restore that
37 # database's prod dump into a scratch DB, then run the worktree's migrations on
38 # top. `backup` names a [[backup]] entry in the topology (sando.toml). Omit the
39 # whole key to get just the first entry, which is the historical behavior.
40 #
41 # The server check leaves `scratch_db` unset, so it runs against scratch_db_url
42 # itself and leaves it in migrated state for the cargo_test gate to reuse. Every
43 # other check must name its own database; the daemon creates it (DROP + CREATE)
44 # at the start of the check, so a new entry owes no host bootstrap step.
45 [[migration_check]]
46 dir = "server/migrations"
47 backup = "server"
48
49 # multithreaded applies its own 36+ migrations at boot (multithreaded/src/main.rs,
50 # `sqlx::migrate!()`) against its own database, so it carried the server's
51 # exposure with none of the server's gate: an edited already-applied migration
52 # would not fail a dry run, it would fail to boot in prod. `owner_role` is that
53 # dump's owner — pg_dump emits `ALTER ... OWNER TO multithreaded` for every
54 # object, and the role must exist in the scratch cluster before the restore.
55 [[migration_check]]
56 dir = "multithreaded/migrations"
57 backup = "multithreaded"
58 scratch_db = "sando_scratch_mt"
59 owner_role = "multithreaded"
60
61 # TypeScript frontends the code_smoke gate compiles (npm run build), before it
62 # creates a database or boots anything. Both crates compile these from a build
63 # script that reports a tsc error as a cargo::warning and lets the Rust build
64 # succeed against whatever static/dist/ already holds — deliberately, so a type
65 # error in a chat widget cannot stop the forum from compiling. The consequence is
66 # that nothing downstream noticed either: the deploy rsynced the previous build's
67 # bundle. This is the one place that failure is fatal.
68 [[frontend_build]]
69 dir = "server/frontend"
70
71 [[frontend_build]]
72 dir = "multithreaded/frontend"
73
74 # Crates built from the same worktree/sha as the server and staged into the
75 # release bundle as `companions/<name>`, so a service that shares the server's
76 # contract cannot drift out of lockstep. This list only says what to BUILD and
77 # stage; which nodes install which companion is per-node in the topology (see
78 # the [[tier.node.companion]] blocks in sando.toml).
79 #
80 # mnw-cli is the public git-SSH server that proxies to /api/internal/* — a
81 # two-month drift there is what broke git hosting during the 0.10.14 deploy.
82 [[companion]]
83 name = "mnw-cli"
84 manifest_dir = "mnw-cli"
85 bin = "mnw-cli"
86
87 # multithreaded (forums.makenot.work) runs on alpha-west-1, the same host as the
88 # server and the same architecture, so the build host can compile it. Replaces
89 # multithreaded/deploy/deploy-hetzner.sh, which cross-compiled on macOS via
90 # cargo zigbuild and scp'd to root@ — against the native-build rule, and the
91 # real deploy path until 2026-08-02.
92 #
93 # One file to install: mt embeds its own static/ tree
94 # (multithreaded/src/static_assets.rs) rather than serving it from a directory
95 # beside the binary, which is what makes it fit a mechanism that ships exactly
96 # one file per companion.
97 #
98 # NOT a `bin_names` entry — that list is the SERVER crate's bin targets.
99 [[companion]]
100 name = "multithreaded"
101 manifest_dir = "multithreaded"
102 bin = "multithreaded"
103
104 # Crates the cargo_test gate runs, in order; the gate stops at the first red one.
105 # This list used to be absent here, which means the default applied — a single
106 # `server` entry — so everything else in the repo shipped ungated, the companions
107 # installed onto prod-1 included. A target with no Cargo.toml in the sha being
108 # built is skipped with a warning rather than failing, so this list can describe
109 # the tip and still bisect.
110 #
111 # scratch_db exports DATABASE_URL/TEST_DATABASE_URL. Only crates whose sqlx
112 # macros type-check against a live DB need it; the rest ship offline `.sqlx` data
113 # and are left in offline mode.
114 [[test_target]]
115 dir = "server"
116 features = ["fast-tests"]
117 scratch_db = true
118
119 # Companion: ships to prod-1, so it is gated first among the rest.
120 [[test_target]]
121 dir = "mnw-cli"
122
123 # Companion: ships to testnot-1 and prod-1 (see sando.toml).
124 [[test_target]]
125 dir = "multithreaded"
126 scratch_db = true
127
128 [[test_target]]
129 dir = "pom"
130
131 [[test_target]]
132 dir = "wam"
133
134 # docengine lives in its own repo since 2026-07-30 and reaches the build through
135 # the [[aux_repo]] checkout, which sits beside the worktree rather than under it.
136 # `aux_repo` resolves `dir` against that checkout instead; `dir` is empty because
137 # the crate is at the repo root. Gated because the checkout is at branch HEAD and
138 # is compiled into these binaries — a break there breaks this build.
139 [[test_target]]
140 aux_repo = "docengine"
141 all_features = true
142
143 # shared/* — every app and service in the repo links these.
144 [[test_target]]
145 dir = "shared/egui-updater"
146
147 [[test_target]]
148 dir = "shared/kberg"
149 all_features = true
150
151 [[test_target]]
152 dir = "shared/livechat"
153 all_features = true
154
155 [[test_target]]
156 dir = "shared/ops-core"
157
158 [[test_target]]
159 dir = "shared/ops-exec"
160 all_features = true
161
162 [[test_target]]
163 dir = "shared/pom-contract"
164
165 [[test_target]]
166 dir = "shared/s3-storage"
167
168 [[test_target]]
169 dir = "shared/synckit-client"
170 all_features = true
171
172 [[test_target]]
173 dir = "shared/tagtree"
174
175 # Non-binary content shipped as part of each release. Multiple entries can
176 # target the same `dst` (additive merge — used to build `docs/` from three
177 # worktree sources). Sources are relative to the worktree root; dsts are
178 # relative to the bundle root (`<release_root>/releases/<digest16>/` once the
179 # bundle is published; release dirs are named for their content digest, not the
180 # version).
181 #
182 # error-pages is now only load-bearing for 502.html: the 404 and 500 pages are
183 # embedded in the server binary and served at /__errors/, which Caddy proxies to
184 # (server/deploy/Caddyfile). 502 is the app-is-down page, so it cannot come from
185 # the app, and Caddy keeps reading it off disk.
186 [[release_contents]]
187 src = "server/deploy/error-pages"
188 dst = "error-pages"
189
190 [[release_contents]]
191 src = "server/static"
192 dst = "static"
193 required = true
194
195 [[release_contents]]
196 src = "server/site-docs/public"
197 dst = "docs/public"
198 required = true
199
200 [[release_contents]]
201 src = "server/site-docs/examples"
202 dst = "docs/examples"
203
204 [[release_contents]]
205 src = "server/docs/business/assumptions.toml"
206 dst = "docs/assumptions.toml"
207 required = true
208
209 # Migrations ride in the bundle, which is what puts them inside the digest.
210 #
211 # `migration_dry_run` used to read them out of the worktree. That proved
212 # something about a checkout sitting next to the artifact rather than about the
213 # artifact, and the checkout can be edited between the dry run and the deploy.
214 # The gate now resolves `[[migration_check]].dir` against the bundle first and
215 # falls back to the worktree, so these two entries are what move the guarantee
216 # from "the source we had" to "the bytes that ship".
217 #
218 # It is also what lets the gate run at all against an artifact Sando did not
219 # build: an accepted bundle has no worktree to fall back to, and a builder that
220 # does not ship its migrations gets told the gate has nothing to dry-run rather
221 # than a green run over nothing.
222 [[release_contents]]
223 src = "server/migrations"
224 dst = "server/migrations"
225 required = true
226
227 [[release_contents]]
228 src = "multithreaded/migrations"
229 dst = "multithreaded/migrations"
230 required = true
231