fix(marmot-interop): parse post-v0.2 wn --json shape in interactive harness

The `.result` wrapper fix landed in lib.sh's pollers and the headless tests
back in f08b010f, but the 8 inline `jq` reads in marmot-interop.sh were
missed — which silently returned empty against current `wn` and made every
UI-verification test look like "Amethyst didn't propagate X" when in fact
the underlying wn state was correct and the script just couldn't see it.

All 8 reads now peel `(.result // .)` the same way the lib.sh helpers do,
staying backwards-compatible with the pre-v0.2 flat shape:
  * test 02, 04 member lists
  * test 06 member-removed check
  * test 07 group-name poll
  * test 08 admin list (promote + demote)
  * test 09 anchor message lookup
  * test 11 leave-group member check

Also split the configure_relays sanity check into three relay-level
surfaces so a broken relay set points at the specific kind it can't
handle, instead of 10 later tests all timing out with the same "no
invite" symptom:

  * kind:30443  (KeyPackage)       — both sides publish + symmetric discover
  * kind:10050  (Inbox advertise)  — C reachable as giftwrap target
  * kind:1059   (Gift wrap)        — B->C welcome delivery
  * kind:445    (MLS commit/msg)   — real group-message round-trip

And drop the orphan whitenoise-mdk-plaintext-policy.patch: it lived in
`headless/patches/` but was never referenced by setup.sh's patch array,
and if it ever were applied it would flip mdk-core's MLS wire-format
from MIXED_CIPHERTEXT to MIXED_PLAINTEXT — a protocol-breaking
divergence from every stock whitenoise-rs / White Noise build. Removing
it eliminates the trap of a future contributor "enabling" it.

https://claude.ai/code/session_018kSBco5VVfctkW6vAm7NzA
This commit is contained in:
Claude
2026-04-22 14:59:44 +00:00
parent 4499114ab2
commit d8d094db48
2 changed files with 66 additions and 25 deletions
@@ -1,11 +0,0 @@
--- a/../../../.cargo/git/checkouts/mdk-7d5a3a2420b194f5/8a8d06c/crates/mdk-core/src/groups.rs
+++ b/../../../.cargo/git/checkouts/mdk-7d5a3a2420b194f5/8a8d06c/crates/mdk-core/src/groups.rs
@@ -1215,7 +1215,7 @@
);
let group_config = MlsGroupCreateConfig::builder()
.ciphersuite(self.ciphersuite)
- .wire_format_policy(MIXED_CIPHERTEXT_WIRE_FORMAT_POLICY)
+ .wire_format_policy(MIXED_PLAINTEXT_WIRE_FORMAT_POLICY)
.use_ratchet_tree_extension(true)
.capabilities(capabilities)
.with_group_context_extensions(extensions)
+66 -14
View File
@@ -243,7 +243,19 @@ configure_relays() {
info "B relays: $(printf '%s' "$relay_list" | jq -r '.result[]? | "\(.url) [\(.status)]"' 2>/dev/null | tr '\n' ' ')" info "B relays: $(printf '%s' "$relay_list" | jq -r '.result[]? | "\(.url) [\(.status)]"' 2>/dev/null | tr '\n' ' ')"
printf 'B relay list: %s\n' "$relay_list" >>"$LOG_FILE" printf 'B relay list: %s\n' "$relay_list" >>"$LOG_FILE"
step "sanity-check: B publishes KP, C fetches it" # Sanity check is split across three relay-level surfaces so a failure
# points at the exact kind the relay set can't handle, instead of 10
# later tests all timing out with the same "no invite" symptom:
#
# kind:30443 (KeyPackage) — both sides publish + discover
# kind:10050 (Inbox advertise) — C must be reachable as a giftwrap target
# kind:1059 (Gift wrap) — B->C welcome delivery
# kind:445 (MLS commit/msg) — real group message round-trip
#
# All failures are warnings (not hard fails) so a known-broken relay set
# still lets the harness continue into the 13 tests — they will fail
# anyway but at least the operator will have the diagnostic hint here.
step "sanity-check kind:30443: B+C publish + symmetric discover"
local publish_out local publish_out
if publish_out=$(wn_b keys publish 2>&1); then if publish_out=$(wn_b keys publish 2>&1); then
info "wn_b keys publish: ok" info "wn_b keys publish: ok"
@@ -251,17 +263,57 @@ configure_relays() {
warn "wn_b keys publish failed: $publish_out" warn "wn_b keys publish failed: $publish_out"
printf 'wn_b keys publish: %s\n' "$publish_out" >>"$LOG_FILE" printf 'wn_b keys publish: %s\n' "$publish_out" >>"$LOG_FILE"
fi fi
if publish_out=$(wn_c keys publish 2>&1); then
info "wn_c keys publish: ok"
else
warn "wn_c keys publish failed: $publish_out"
printf 'wn_c keys publish: %s\n' "$publish_out" >>"$LOG_FILE"
fi
sleep 4 sleep 4
local sanity_raw sanity_id local sanity_raw sanity_id
sanity_raw=$(wn_c --json keys check "$B_NPUB" 2>>"$LOG_FILE" || true) sanity_raw=$(wn_c --json keys check "$B_NPUB" 2>>"$LOG_FILE" || true)
sanity_id=$(printf '%s' "$sanity_raw" | jq -r '.result.event_id // .event_id // empty' 2>/dev/null || true) sanity_id=$(printf '%s' "$sanity_raw" | jq -r '.result.event_id // .event_id // empty' 2>/dev/null || true)
if [[ -n "$sanity_id" && "$sanity_id" != "null" ]]; then if [[ -n "$sanity_id" && "$sanity_id" != "null" ]]; then
info "sanity OK — relay round-trip works (event_id: $sanity_id)" info "kind:30443 C->B ok (event_id: $sanity_id)"
else else
warn "sanity-check failed — public relays may be rejecting kind 30443." warn "kind:30443 C->B failed — relays may be rejecting KeyPackages"
warn "Consider rerunning with --local-relays (requires 'just docker-up' in whitenoise-rs)." printf 'sanity keys check B raw: %s\n' "$sanity_raw" >>"$LOG_FILE"
info "raw keys check response: $sanity_raw" fi
printf 'sanity keys check raw: %s\n' "$sanity_raw" >>"$LOG_FILE" sanity_raw=$(wn_b --json keys check "$C_NPUB" 2>>"$LOG_FILE" || true)
sanity_id=$(printf '%s' "$sanity_raw" | jq -r '.result.event_id // .event_id // empty' 2>/dev/null || true)
if [[ -n "$sanity_id" && "$sanity_id" != "null" ]]; then
info "kind:30443 B->C ok (event_id: $sanity_id)"
else
warn "kind:30443 B->C failed — relays may be rejecting KeyPackages"
printf 'sanity keys check C raw: %s\n' "$sanity_raw" >>"$LOG_FILE"
fi
step "sanity-check kinds 10050/1059/445: B creates group + invites C + exchanges a message"
local sanity_gid sanity_c_gid sanity_create
sanity_create=$(wn_b --json groups create "sanity-check" "$C_NPUB" 2>>"$LOG_FILE" || true)
sanity_gid=$(printf '%s' "$sanity_create" | jq_group_id)
printf 'sanity groups create raw: %s\n' "$sanity_create" >>"$LOG_FILE"
if [[ -z "$sanity_gid" ]]; then
warn "sanity group create failed — see $LOG_FILE (stale account state? rerun with 'rm -rf state/')"
else
info "sanity group id: $sanity_gid"
if sanity_c_gid=$(wait_for_invite C 30); then
info "kind:10050+1059 ok — C received welcome (gid: $sanity_c_gid)"
wn_c groups accept "$sanity_c_gid" >/dev/null 2>&1 || true
wn_b messages send "$sanity_gid" "sanity-ping" >/dev/null 2>&1 || true
if wait_for_message C "$sanity_c_gid" "sanity-ping" 30; then
info "kind:445 ok — C decrypted sanity-ping"
else
warn "kind:445 failed — C never decrypted sanity-ping (relays may be dropping group messages)"
warn "Consider rerunning with --local-relays."
fi
# best-effort cleanup so re-runs don't accumulate dead sanity groups
wn_c groups leave "$sanity_c_gid" >/dev/null 2>&1 || true
wn_b groups leave "$sanity_gid" >/dev/null 2>&1 || true
else
warn "kind:10050/1059 failed — C never received welcome; relays likely dropping gift wraps or inbox lists"
warn "Consider rerunning with --local-relays (requires 'just docker-up' in whitenoise-rs)."
fi
fi fi
} }
@@ -357,7 +409,7 @@ that's the bug."
step "verifying member list on B" step "verifying member list on B"
local members local members
members=$(wn_b --json groups members "$gid" 2>/dev/null | jq -r '.[].pubkey // .[].public_key' 2>/dev/null | sort | tr '\n' ' ') members=$(wn_b --json groups members "$gid" 2>/dev/null | jq -r '(.result // .) | .[].pubkey // .[].public_key' 2>/dev/null | sort | tr '\n' ' ')
if ! expect_contains "$members" "$A_HEX" "member list" \ if ! expect_contains "$members" "$A_HEX" "member list" \
|| ! expect_contains "$members" "$B_HEX" "member list"; then || ! expect_contains "$members" "$B_HEX" "member list"; then
record_result "02 Amethyst->B create+invite" fail "member list mismatch" record_result "02 Amethyst->B create+invite" fail "member list mismatch"
@@ -465,7 +517,7 @@ test_04_three_member_group() {
step "verifying all three members on all three clients" step "verifying all three members on all three clients"
local members_b local members_b
members_b=$(wn_b --json groups members "$gid" 2>/dev/null | jq -r '.[].pubkey // .[].public_key' | tr '\n' ' ') members_b=$(wn_b --json groups members "$gid" 2>/dev/null | jq -r '(.result // .) | .[].pubkey // .[].public_key' | tr '\n' ' ')
expect_contains "$members_b" "$A_HEX" "B's member list" || : expect_contains "$members_b" "$A_HEX" "B's member list" || :
expect_contains "$members_b" "$B_HEX" "B's member list" || : expect_contains "$members_b" "$B_HEX" "B's member list" || :
expect_contains "$members_b" "$C_HEX" "B's member list" || : expect_contains "$members_b" "$C_HEX" "B's member list" || :
@@ -536,7 +588,7 @@ test_06_member_removal() {
local deadline=$(( $(date +%s) + 60 )) removed=0 local deadline=$(( $(date +%s) + 60 )) removed=0
while [[ $(date +%s) -lt $deadline ]]; do while [[ $(date +%s) -lt $deadline ]]; do
if ! wn_c --json groups members "$gid" 2>/dev/null \ if ! wn_c --json groups members "$gid" 2>/dev/null \
| jq -e --arg p "$C_HEX" '.[]? | select((.pubkey // .public_key) == $p)' >/dev/null 2>&1; then | jq -e --arg p "$C_HEX" '(.result // .) | .[]? | select((.pubkey // .public_key) == $p)' >/dev/null 2>&1; then
removed=1; break removed=1; break
fi fi
sleep 3 sleep 3
@@ -581,7 +633,7 @@ test_07_metadata_rename() {
step "polling B for name change (60s)" step "polling B for name change (60s)"
local deadline=$(( $(date +%s) + 60 )) name="" local deadline=$(( $(date +%s) + 60 )) name=""
while [[ $(date +%s) -lt $deadline ]]; do while [[ $(date +%s) -lt $deadline ]]; do
name=$(wn_b --json groups show "$gid" 2>/dev/null | jq -r '.name // empty') name=$(wn_b --json groups show "$gid" 2>/dev/null | jq -r '(.result // .) | .name // empty')
[[ "$name" == "Interop-02-renamed" ]] && break [[ "$name" == "Interop-02-renamed" ]] && break
sleep 3 sleep 3
done done
@@ -627,7 +679,7 @@ test_08_admin_promote_demote() {
step "verifying admin list contains both B and A" step "verifying admin list contains both B and A"
local admins local admins
admins=$(wn_b --json groups admins "$gid" 2>/dev/null | jq -r '.[].pubkey // .[].public_key // .[]' | tr '\n' ' ') admins=$(wn_b --json groups admins "$gid" 2>/dev/null | jq -r '(.result // .) | .[].pubkey // .[].public_key // .[]' | tr '\n' ' ')
if expect_contains "$admins" "$A_HEX" "admin list" && expect_contains "$admins" "$B_HEX" "admin list"; then if expect_contains "$admins" "$A_HEX" "admin list" && expect_contains "$admins" "$B_HEX" "admin list"; then
pass_msg "admin promote worked" pass_msg "admin promote worked"
else else
@@ -637,7 +689,7 @@ test_08_admin_promote_demote() {
step "B demotes A" step "B demotes A"
wn_b groups demote "$gid" "$A_NPUB" >/dev/null 2>&1 || warn "demote returned nonzero" wn_b groups demote "$gid" "$A_NPUB" >/dev/null 2>&1 || warn "demote returned nonzero"
sleep 5 sleep 5
admins=$(wn_b --json groups admins "$gid" 2>/dev/null | jq -r '.[].pubkey // .[].public_key // .[]' | tr '\n' ' ') admins=$(wn_b --json groups admins "$gid" 2>/dev/null | jq -r '(.result // .) | .[].pubkey // .[].public_key // .[]' | tr '\n' ' ')
if [[ "$admins" != *"$A_HEX"* ]]; then if [[ "$admins" != *"$A_HEX"* ]]; then
pass_msg "demote removed A" pass_msg "demote removed A"
record_result "08 admin promote/demote" pass record_result "08 admin promote/demote" pass
@@ -660,7 +712,7 @@ test_09_reply_react_unreact() {
sleep 3 sleep 3
local msg_id local msg_id
msg_id=$(wn_b --json messages list "$gid" --limit 10 2>/dev/null \ msg_id=$(wn_b --json messages list "$gid" --limit 10 2>/dev/null \
| jq -r '[.[]? | select((.content // .text // "") == "anchor for reactions")][0].id // .[0].event_id // empty' 2>/dev/null || true) | jq -r '(.result // .) | [.[]? | select((.content // .text // "") == "anchor for reactions")][0].id // .[0].event_id // empty' 2>/dev/null || true)
if [[ -z "$msg_id" || "$msg_id" == "null" ]]; then if [[ -z "$msg_id" || "$msg_id" == "null" ]]; then
fail_msg "could not find anchor message id" fail_msg "could not find anchor message id"
record_result "09 reply/react" fail "anchor id missing"; return record_result "09 reply/react" fail "anchor id missing"; return
@@ -747,7 +799,7 @@ test_11_leave_group() {
local deadline=$(( $(date +%s) + 60 )) gone=0 local deadline=$(( $(date +%s) + 60 )) gone=0
while [[ $(date +%s) -lt $deadline ]]; do while [[ $(date +%s) -lt $deadline ]]; do
if ! wn_b --json groups members "$gid" 2>/dev/null \ if ! wn_b --json groups members "$gid" 2>/dev/null \
| jq -e --arg p "$A_HEX" '.[]? | select((.pubkey // .public_key) == $p)' >/dev/null 2>&1; then | jq -e --arg p "$A_HEX" '(.result // .) | .[]? | select((.pubkey // .public_key) == $p)' >/dev/null 2>&1; then
gone=1; break gone=1; break
fi fi
sleep 3 sleep 3