From e4c52a5553a9acfd8455a93b2d68bb005ce146e6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Jul 2026 01:21:40 +0000 Subject: [PATCH] test(marmot): refresh interop harness for restructured whitenoise-rs whitenoise-rs became a workspace (core `whitenoise` crate at root, wn/wnd moved to crates/whitenoise-cli) and grew native --discovery-relays / --default-account-relays flags, which broke the headless harness's patch/build assumptions. - Repath the mock-keyring patch to crates/whitenoise-cli/src/bin/wnd.rs and match the new main() (env-gated Whitenoise::initialize_mock_keyring_store(); the fn is pub under the integration-tests feature). - Drop the discovery-env / defaults-env patches: start_daemon now passes the native --discovery-relays / --default-account-relays flags instead. - Build wn/wnd via `cargo build -p whitenoise-cli --features whitenoise/integration-tests` (the binaries left the root crate; integration-tests brings in the mock keyring). - The skip-unprocessable-retry patch still applies (root crate, 19-line offset). Enables the end-to-end test_17_group_image_commit (amy sets a group icon -> whitenoise must still process the commit) added in the previous commit to actually run. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01JL3GXW1fmHa3xWfQjLLqfp --- .../patches/whitenoise-defaults-env.patch | 24 ------- .../patches/whitenoise-discovery-env.patch | 23 ------- .../patches/whitenoise-mock-keyring.patch | 21 +++--- cli/tests/marmot/setup.sh | 64 +++++++++---------- 4 files changed, 40 insertions(+), 92 deletions(-) delete mode 100644 cli/tests/marmot/patches/whitenoise-defaults-env.patch delete mode 100644 cli/tests/marmot/patches/whitenoise-discovery-env.patch diff --git a/cli/tests/marmot/patches/whitenoise-defaults-env.patch b/cli/tests/marmot/patches/whitenoise-defaults-env.patch deleted file mode 100644 index 57cc16cd4f..0000000000 --- a/cli/tests/marmot/patches/whitenoise-defaults-env.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/src/whitenoise/relays.rs -+++ b/src/whitenoise/relays.rs -@@ -98,6 +98,21 @@ - } - - pub(crate) fn defaults() -> Vec { -+ // marmot-interop-headless patch: honour $WHITENOISE_DISCOVERY_RELAYS -+ // (comma-separated list) when present so newly created accounts only -+ // ever get our loopback relay baked into their NIP-65 / inbox / -+ // key-package lists. Without this override, `create-identity` stamps -+ // the hard-coded public set into the account's relay lists, and every -+ // later activate / publish burns connection budget on unreachable -+ // sockets — enough to break inbox-plane activation and drop kind:1059. -+ if let Ok(from_env) = std::env::var("WHITENOISE_DISCOVERY_RELAYS") { -+ let parsed: Vec = from_env -+ .split(',').map(str::trim).filter(|s| !s.is_empty()) -+ .filter_map(|u| RelayUrl::parse(u).ok()) -+ .map(|url| Relay::new(&url)) -+ .collect(); -+ if !parsed.is_empty() { return parsed; } -+ } - let urls: &[&str] = if cfg!(debug_assertions) { - &["ws://localhost:8080", "ws://localhost:7777"] - } else { diff --git a/cli/tests/marmot/patches/whitenoise-discovery-env.patch b/cli/tests/marmot/patches/whitenoise-discovery-env.patch deleted file mode 100644 index 8fb0fec0aa..0000000000 --- a/cli/tests/marmot/patches/whitenoise-discovery-env.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/src/relay_control/discovery.rs -+++ b/src/relay_control/discovery.rs -@@ -87,6 +87,20 @@ - - /// Initial curated relay set from the planning doc. - pub(crate) fn curated_default_relays() -> Vec { -+ // marmot-interop-headless patch: honour $WHITENOISE_DISCOVERY_RELAYS -+ // (comma-separated list) when present, so the harness can force wnd -+ // to use a loopback relay instead of the baked-in public set. -+ if let Ok(from_env) = std::env::var("WHITENOISE_DISCOVERY_RELAYS") { -+ let parsed: Vec = from_env -+ .split(',') -+ .map(str::trim) -+ .filter(|s| !s.is_empty()) -+ .filter_map(|u| RelayUrl::parse(u).ok()) -+ .collect(); -+ if !parsed.is_empty() { -+ return parsed; -+ } -+ } - [ - "wss://index.hzrd149.com", - "wss://indexer.coracle.social", diff --git a/cli/tests/marmot/patches/whitenoise-mock-keyring.patch b/cli/tests/marmot/patches/whitenoise-mock-keyring.patch index f346b43520..ed729fcf91 100644 --- a/cli/tests/marmot/patches/whitenoise-mock-keyring.patch +++ b/cli/tests/marmot/patches/whitenoise-mock-keyring.patch @@ -1,18 +1,17 @@ ---- a/src/bin/wnd.rs -+++ b/src/bin/wnd.rs -@@ -22,6 +22,15 @@ +--- a/crates/whitenoise-cli/src/bin/wnd.rs ++++ b/crates/whitenoise-cli/src/bin/wnd.rs +@@ -44,6 +44,14 @@ async fn main() -> whitenoise_cli::Result<()> { let args = Args::parse(); let config = Config::resolve(args.data_dir.as_ref(), args.logs_dir.as_ref()); -+ // marmot-interop-headless patch: allow sandboxes/CI without a real -+ // kernel keyring to fall back to the integration-tests mock keyring -+ // by setting $WHITENOISE_MOCK_KEYRING=1. Requires the daemon to be -+ // built with --features cli,integration-tests. No effect otherwise. -+ #[cfg(feature = "integration-tests")] ++ // marmot-interop-headless patch: allow sandboxes / CI without a real kernel ++ // keyring to fall back to the integration-tests mock keyring store by setting ++ // $WHITENOISE_MOCK_KEYRING=1. Requires building the binaries with ++ // `--features whitenoise/integration-tests` (the harness does). + if std::env::var("WHITENOISE_MOCK_KEYRING").is_ok() { + Whitenoise::initialize_mock_keyring_store(); + } + - let wn_config = WhitenoiseConfig::new(&config.data_dir, &config.logs_dir, KEYRING_SERVICE_ID); - Whitenoise::initialize_whitenoise(wn_config).await?; - + let mut wn_config = + WhitenoiseConfig::new(&config.data_dir, &config.logs_dir, KEYRING_SERVICE_ID); + if !args.discovery_relays.is_empty() { diff --git a/cli/tests/marmot/setup.sh b/cli/tests/marmot/setup.sh index 386a2bf3f1..6d03eb44fd 100644 --- a/cli/tests/marmot/setup.sh +++ b/cli/tests/marmot/setup.sh @@ -52,32 +52,27 @@ preflight() { 2>&1 | tee -a "$LOG_FILE" fi - # Four harness-only patches to wnd so it runs fully offline / in - # sandboxes that block outbound + kernel keyring: - # 1. discovery-env: honour $WHITENOISE_DISCOVERY_RELAYS so we can - # point wnd at our loopback relay instead of the baked-in public - # set. Without it wnd exits with NoRelayConnections. - # 2. mock-keyring: honour $WHITENOISE_MOCK_KEYRING so wnd uses the + # Two harness-only patches to whitenoise-rs so it runs in sandboxes that + # block the kernel keyring: + # 1. mock-keyring: honour $WHITENOISE_MOCK_KEYRING so wnd uses the # integration-tests mock keyring store when the kernel keyutils - # syscalls are blocked (common in containers / CI). - # 3. defaults-env: reuse the same env var so `Relay::defaults()` - # (what `create-identity` stamps into the new account's NIP-65 / - # inbox / key-package lists) points at the loopback relay too. - # Without it every account wnd creates carries damus.io / - # primal.net / nos.lol, and every later activate / publish burns - # connection budget on unreachable sockets — enough to break the - # account-inbox subscription plane and drop kind:1059 delivery. - # 4. skip-unprocessable-retry: when mdk-core returns - # `MlsMessageUnprocessable` (pre-membership commit, too-old epoch) - # the message is provably undecryptable — retrying it ten times - # with exponential backoff (total ~17 min) just blocks later - # decryptable commits behind a queue of doomed retries, which in - # the harness manifests as "A already left" / "name unchanged" - # timeouts. The patch treats that error as terminal. + # syscalls are blocked (common in containers / CI). Compiled in via + # `--features whitenoise/integration-tests` on the build below. + # 2. skip-unprocessable-retry: when mdk-core returns a terminal MLS + # error (MlsMessageUnprocessable / PreviouslyFailed / MdkCoreError) + # the message is provably undecryptable — retrying it ten times with + # exponential backoff (~17 min) just blocks later decryptable commits + # behind a queue of doomed retries, which in the harness manifests as + # "A already left" / "name unchanged" timeouts. The patch treats those + # errors as terminal. + # + # The relay-override patches this harness used to carry (discovery-env / + # defaults-env) are gone: upstream wnd now takes native --discovery-relays + # and --default-account-relays flags (passed in start_daemon), which do the + # same job without patching. wn/wnd also moved into the crates/whitenoise-cli + # workspace member — the mock-keyring patch targets that path. local -a patches=( - "whitenoise-discovery-env.patch" "whitenoise-mock-keyring.patch" - "whitenoise-defaults-env.patch" "whitenoise-skip-unprocessable-retry.patch" ) # Apply each patch with a real exit-code check. The previous version @@ -114,7 +109,8 @@ preflight() { for attempt in $(seq 1 $max); do step "building wn + wnd (attempt $attempt/$max, ~5 min first run)" ( cd "$WN_REPO" && \ - cargo build --release --features cli,integration-tests --bin wn --bin wnd ) \ + cargo build --release -p whitenoise-cli \ + --features whitenoise/integration-tests --bin wn --bin wnd ) \ 2>&1 | tee -a "$LOG_FILE" [[ -x "$WN_BIN" && -x "$WND_BIN" ]] && break [[ "$attempt" -lt "$max" ]] && warn "wn/wnd build failed (likely transient 503 from rustup or crates.io) — retrying" @@ -243,17 +239,17 @@ start_daemon() { -exec rm -rf {} + 2>/dev/null || true fi mkdir -p "$data_dir/logs" "$data_dir/release" - # Env vars consumed by the two harness-only wnd patches applied in - # preflight: - # WHITENOISE_DISCOVERY_RELAYS — forces the discovery plane at our - # loopback relay (kills the "can't reach nos.lol" exit path). - # WHITENOISE_MOCK_KEYRING — swaps in the integration-tests mock - # secret store so wnd doesn't fall over when the kernel blocks - # keyutils syscalls. - # Both are harmless on a real host with connectivity + a real keyring. - WHITENOISE_DISCOVERY_RELAYS="$RELAY_URL" \ - WHITENOISE_MOCK_KEYRING=1 \ + # --discovery-relays / --default-account-relays are native wnd flags that + # force both the discovery plane and freshly-created accounts' NIP-65 / inbox + # / key-package lists onto our loopback relay (kills the "can't reach nos.lol" + # exit path and stops accounts from carrying unreachable public relays). + # + # WHITENOISE_MOCK_KEYRING=1 is consumed by the mock-keyring patch: it swaps in + # the integration-tests mock secret store so wnd doesn't fall over when the + # kernel blocks keyutils syscalls. Harmless on a real host with a real keyring. + WHITENOISE_MOCK_KEYRING=1 \ nohup "$WND_BIN" --data-dir "$data_dir" --logs-dir "$data_dir/logs" \ + --discovery-relays "$RELAY_URL" --default-account-relays "$RELAY_URL" \ >"$data_dir/logs/stdout.log" 2>"$data_dir/logs/stderr.log" & local pid=$! echo "$pid" > "$data_dir/pid"