Skip to main content

max / makenotwork

Give code_smoke the CDN_BASE_URL the server has required since 3e3b1d15 code_smoke failed its first run on the host with MissingCdnBaseUrl, buried under the summary "migrate+seed run failed: exit 101". It is gate drift, not a server bug. CDN_BASE_URL became unconditionally required on 2026-07-30 (server 3e3b1d15, so no cover URL could fall back to a 24-hour presigned link written into a durable column). code_smoke_env was written 2026-07-17 and never learned about it. Nothing failed in between because the gate was configured in the repo and absent from /etc/sando until 2026-08-03, so it had never run. Fixed on the gate side, where the other synthetic values already live: SIGNING_SECRET, HOST_URL, INSECURE_COOKIES and SCAN_ENABLED are all invented for the same reason. CDN_BASE_URL now points at the smoke server's own origin, and nothing ever requests it. Relaxing the requirement for --seed-examples was the alternative and is worse: the requirement is unconditional precisely so nothing can boot without it, and the seed writes durable rows that embed media URLs. Checked the rest of Config::from_env while there. CDN_BASE_URL was the only gap: the other secrets are Option, their Weak* checks only fire when the var is set, and MissingPublicBucket cannot trigger because the gate's loopback HOST_URL keeps is_production false. The new test is the point. code_smoke is the ONLY gate that reaches Config::from_env — boot_smoke and MNW_CHECK_DOCS both short-circuit in main before config loads — so every mandatory server var has to be answered in this one function, and nothing connects the two lists. The test asserts the keys are present and non-empty, that HOST_URL stays loopback (or is_production flips and the gate trips MissingPublicBucket), and that the dummy signing secret clears the server's 32-char floor. The next required var now fails here rather than in a promote. Verified by reproducing the gate's exact invocation: migrate + seed against a throwaway DB with this env exits 0.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-03 17:38 UTC
Signed with PGP, not checked
Commit: d4d162e7bb2c53d83963892d78efc94fa84f3aa1
Parent: 5586c50
2 files changed, +87 insertions, -4 deletions
@@ -2965,3 +2965,31 @@
2965 2965 version = "1.0.21"
2966 2966 source = "registry+https://github.com/rust-lang/crates.io-index"
2967 2967 checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
2968 +
2969 + [[patch.unused]]
2970 + name = "synckit-client"
2971 + version = "0.6.0"
2972 +
2973 + [[patch.unused]]
2974 + name = "synckit-config"
2975 + version = "0.1.2"
2976 +
2977 + [[patch.unused]]
2978 + name = "kberg"
2979 + version = "0.1.0"
2980 +
2981 + [[patch.unused]]
2982 + name = "painhours"
2983 + version = "0.1.0"
2984 +
2985 + [[patch.unused]]
2986 + name = "tagtree"
2987 + version = "0.4.0"
2988 +
2989 + [[patch.unused]]
2990 + name = "docengine"
2991 + version = "0.4.0"
2992 +
2993 + [[patch.unused]]
2994 + name = "supernote-push"
2995 + version = "0.1.0"
@@ -1729,14 +1729,33 @@
1729 1729 /// hand it a dummy signing secret, and disable file scanning (no AV/YARA on the
1730 1730 /// build host). The worktree is a clean git checkout, so no stray `.env` shadows
1731 1731 /// these (and dotenvy never overrides already-set vars).
1732 + ///
1733 + /// This list has to carry EVERY var the server's `Config::from_env` treats as
1734 + /// mandatory, because `code_smoke` is the only gate that reaches that function
1735 + /// at all: `boot_smoke` and the docs check both short-circuit in `main` before
1736 + /// config is loaded. So when the server makes a new var required, this is where
1737 + /// it has to be answered, and nothing connects the two lists automatically.
1738 + ///
1739 + /// That has already bitten once. `CDN_BASE_URL` became mandatory on 2026-07-30
1740 + /// (server 3e3b1d15, closing a cover URL that could expire), 13 days after this
1741 + /// function was written, and `code_smoke` failed with `MissingCdnBaseUrl` the
1742 + /// first time it ran on the host — which was 2026-08-03, because the gate was
1743 + /// configured in the repo and absent from `/etc/sando` in between.
1744 + ///
1745 + /// The values are deliberately throwaway. The gate asks whether this code can
1746 + /// migrate, seed, boot and serve; whether a given deployment's env is complete
1747 + /// is the `config_check_env_file` guard's job, on the node, against that node's
1748 + /// real env file.
1732 1749 fn code_smoke_env(cmd: &mut tokio::process::Command, ctx: &GateCtx, db_url: &str) {
1750 + let origin = format!("http://127.0.0.1:{}", ctx.cfg.code_smoke_port);
1733 1751 cmd.env("DATABASE_URL", db_url)
1734 1752 .env("HOST", "127.0.0.1")
1735 1753 .env("PORT", ctx.cfg.code_smoke_port.to_string())
1736 - .env(
1737 - "HOST_URL",
1738 - format!("http://127.0.0.1:{}", ctx.cfg.code_smoke_port),
1739 - )
1754 + .env("HOST_URL", &origin)
1755 + // Required unconditionally by Config::from_env. Pointing it at the smoke
1756 + // server's own origin keeps every rendered media URL resolvable within
1757 + // the gate; no request is ever made to it.
1758 + .env("CDN_BASE_URL", &origin)
1740 1759 .env("SIGNING_SECRET", CODE_SMOKE_SIGNING_SECRET)
1741 1760 .env("SCAN_ENABLED", "false")
1742 1761 .env("INSECURE_COOKIES", "1");
@@ -3534,6 +3553,42 @@
3534 3553 assert!(!bytes_contain(b"", b"listening"));
3535 3554 }
3536 3555
3556 + #[tokio::test]
3557 + async fn code_smoke_env_supplies_every_mandatory_server_var() {
3558 + // code_smoke is the only gate that reaches the server's Config::from_env
3559 + // (boot_smoke and the docs check short-circuit before it), so anything
3560 + // that function requires has to be answered here. CDN_BASE_URL became
3561 + // mandatory 13 days after this env was written and went unnoticed until
3562 + // the gate first ran on the host; this test is what makes the next one
3563 + // fail here instead of in a promote.
3564 + let ctx = resolving_ctx("/w/abc", &[]);
3565 + let mut cmd = tokio::process::Command::new("true");
3566 + code_smoke_env(&mut cmd, &ctx, "postgres:///throwaway");
3567 + let set: std::collections::HashMap<String, String> = cmd
3568 + .as_std()
3569 + .get_envs()
3570 + .filter_map(|(k, v)| Some((k.to_str()?.to_string(), v?.to_str()?.to_string())))
3571 + .collect();
3572 + for key in [
3573 + "DATABASE_URL",
3574 + "HOST",
3575 + "PORT",
3576 + "HOST_URL",
3577 + "CDN_BASE_URL",
3578 + "SIGNING_SECRET",
3579 + ] {
3580 + assert!(set.contains_key(key), "code_smoke_env must set {key}");
3581 + assert!(!set[key].is_empty(), "{key} must not be empty");
3582 + }
3583 + // Loopback, so Config::from_env's is_production branch stays false and
3584 + // the gate never trips MissingPublicBucket for want of an S3 bucket.
3585 + assert!(set["HOST_URL"].starts_with("http://127.0.0.1"));
3586 + assert_eq!(set["HOST"], "127.0.0.1");
3587 + // The signing secret has to clear the server's 32-char floor, or the
3588 + // gate fails with WeakSigningSecret instead of testing anything.
3589 + assert!(set["SIGNING_SECRET"].len() >= 32);
3590 + }
3591 +
3537 3592 #[test]
3538 3593 fn code_smoke_db_name_sanitizes_and_caps() {
3539 3594 assert_eq!(