From 82f5405f01c3f36aea2e2bc5c3660766b33a19c5 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 18 Apr 2026 14:15:56 +0000 Subject: [PATCH] fix(marmot-interop): robust pubkey extraction from wn output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wn prints either JSON (with --json) or a yaml-ish "key: value" pretty form depending on the command and build. On the user's macOS run, create-identity printed yaml ("pubkey: npub1..."), the subsequent wn --json whoami didn't return the expected JSON shape, and ensure_identity bailed with "could not determine npub for B". Add a shared extract_pubkey helper in lib.sh that tries, in order: 1. JSON object .pubkey / .npub / .public_key 2. JSON array .[0].pubkey / .[0].npub / .[0].public_key 3. yaml-ish "pubkey: ..." via sed 4. yaml-ish "npub: ..." via sed ensure_identity and prompt_for_a_npub now use it, and also fall back to the non-JSON whoami output if --json returns nothing. On total failure, the raw output is echoed to the log for diagnosis. Also made npub_to_hex best-effort with the same double-try approach. When hex lookup fails, it returns the npub unchanged — downstream expect_contains assertions work against either form since wn's own group listings may use either encoding. https://claude.ai/code/session_01PacmbE1KKWMSRmDw3bnCNo --- tools/marmot-interop/lib.sh | 44 +++++++++++++++++++----- tools/marmot-interop/marmot-interop.sh | 46 ++++++++++++++++++-------- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/tools/marmot-interop/lib.sh b/tools/marmot-interop/lib.sh index 2be815505..eb4bc46d6 100644 --- a/tools/marmot-interop/lib.sh +++ b/tools/marmot-interop/lib.sh @@ -212,16 +212,42 @@ wait_for_member() { return 1 } -# ------- npub <-> hex conversion helpers ------------------------------------- -# whitenoise's `wn` accepts both, but we use hex internally for JSON comparisons. -# We rely on `wn debug` (or fall back to a python one-liner) — but to keep zero -# extra deps we do the conversion via wn itself by round-tripping through -# `wn users show ` which prints both forms. +# ------- output parsing ------------------------------------------------------ +# `wn` prints either JSON (with --json) or a yaml-ish "key: value" pretty form. +# This helper extracts the pubkey (npub) from whichever form we got. +extract_pubkey() { + local raw="$1" v="" + # JSON: single object + v=$(printf '%s' "$raw" | jq -r '.pubkey // .npub // .public_key // empty' 2>/dev/null || true) + if [[ -n "$v" && "$v" != "null" ]]; then printf '%s' "$v"; return; fi + # JSON: array of accounts (whoami may return a list) + v=$(printf '%s' "$raw" | jq -r '.[0].pubkey // .[0].npub // .[0].public_key // empty' 2>/dev/null || true) + if [[ -n "$v" && "$v" != "null" ]]; then printf '%s' "$v"; return; fi + # yaml-ish "pubkey: npub1..." + v=$(printf '%s\n' "$raw" | sed -n 's/^[[:space:]]*pubkey[[:space:]]*:[[:space:]]*//p' | head -n1) + if [[ -n "$v" ]]; then printf '%s' "$v"; return; fi + # yaml-ish "npub: npub1..." (alternative key) + v=$(printf '%s\n' "$raw" | sed -n 's/^[[:space:]]*npub[[:space:]]*:[[:space:]]*//p' | head -n1) + if [[ -n "$v" ]]; then printf '%s' "$v"; return; fi +} + +# Best-effort npub -> hex conversion via `wn users show`. If the lookup fails +# (e.g. --json not supported or user not resolvable), returns the input +# unchanged — downstream comparisons tolerate either form. npub_to_hex() { - local npub="$1" - wn_b --json users show "$npub" 2>/dev/null \ - | jq -r '.pubkey // .public_key // empty' 2>/dev/null \ - || printf '%s' "$npub" + local npub="$1" raw hex + raw=$(wn_b --json users show "$npub" 2>/dev/null || true) + hex=$(printf '%s' "$raw" | jq -r '.pubkey // .public_key // .hex // empty' 2>/dev/null || true) + if [[ -z "$hex" || "$hex" == "null" ]]; then + # fallback to yaml-ish output + raw=$(wn_b users show "$npub" 2>/dev/null || true) + hex=$(printf '%s\n' "$raw" | sed -n 's/^[[:space:]]*\(public_key\|hex\)[[:space:]]*:[[:space:]]*//p' | head -n1) + fi + if [[ -n "$hex" && "$hex" != "null" ]]; then + printf '%s' "$hex" + else + printf '%s' "$npub" + fi } # ------- state file ---------------------------------------------------------- diff --git a/tools/marmot-interop/marmot-interop.sh b/tools/marmot-interop/marmot-interop.sh index 1230d4b3f..3750fd050 100755 --- a/tools/marmot-interop/marmot-interop.sh +++ b/tools/marmot-interop/marmot-interop.sh @@ -145,24 +145,43 @@ ensure_identity() { local who="$1" cmd if [[ "$who" == "B" ]]; then cmd=wn_b; else cmd=wn_c; fi step "ensuring Identity $who" - local npub - npub=$("$cmd" --json whoami 2>/dev/null | jq -r '.pubkey // .npub // empty' 2>/dev/null || true) - if [[ -z "${npub:-}" || "$npub" == "null" ]]; then - info "creating new identity for $who" - "$cmd" create-identity 2>&1 | tee -a "$LOG_FILE" >&2 - npub=$("$cmd" --json whoami 2>/dev/null | jq -r '.pubkey // .npub // empty' || true) - fi + + # First try whoami (will be empty if no account yet). Try --json, then the + # yaml-ish pretty form as a fallback. + local out npub="" + out=$("$cmd" --json whoami 2>/dev/null || true) + npub=$(extract_pubkey "$out") if [[ -z "${npub:-}" ]]; then - fail_msg "could not determine npub for $who"; exit 1 + out=$("$cmd" whoami 2>/dev/null || true) + npub=$(extract_pubkey "$out") fi + + if [[ -z "${npub:-}" ]]; then + info "creating new identity for $who" + out=$("$cmd" create-identity 2>&1 | tee -a "$LOG_FILE") + npub=$(extract_pubkey "$out") + # Some builds only print the npub on whoami after create, not on + # create-identity itself — re-query as a last resort. + if [[ -z "${npub:-}" ]]; then + out=$("$cmd" whoami 2>/dev/null || true) + npub=$(extract_pubkey "$out") + fi + fi + + if [[ -z "${npub:-}" ]]; then + fail_msg "could not determine npub for $who — raw output below:" + printf '%s\n' "$out" | tee -a "$LOG_FILE" >&2 + exit 1 + fi + local hex - hex=$("$cmd" --json users show "$npub" 2>/dev/null | jq -r '.pubkey // .public_key // .hex // empty' 2>/dev/null || true) - [[ -z "$hex" ]] && hex="$npub" + hex=$(npub_to_hex "$npub") if [[ "$who" == "B" ]]; then B_NPUB="$npub"; B_HEX="$hex" else C_NPUB="$npub"; C_HEX="$hex"; fi save_state "${who}_NPUB" "$npub" save_state "${who}_HEX" "$hex" info "$who npub: $npub" + [[ "$hex" != "$npub" ]] && info "$who hex: $hex" } prompt_for_a_npub() { @@ -174,11 +193,10 @@ prompt_for_a_npub() { read -r A_NPUB save_state "A_NPUB" "$A_NPUB" fi - A_HEX=$(wn_b --json users show "$A_NPUB" 2>/dev/null \ - | jq -r '.pubkey // .public_key // .hex // empty' 2>/dev/null || true) - [[ -z "$A_HEX" ]] && A_HEX="$A_NPUB" + A_HEX=$(npub_to_hex "$A_NPUB") save_state "A_HEX" "$A_HEX" - info "A hex: $A_HEX" + info "A npub: $A_NPUB" + [[ "$A_HEX" != "$A_NPUB" ]] && info "A hex: $A_HEX" } # --- relays ------------------------------------------------------------------