mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
## What `BUZZ_AUTH_TAG` stored in the **raw Nostr tag form** `[auth,hex,,hex]` (unquoted, comma-delimited — how an `auth` tag serializes inside a Nostr event and how `.env` files commonly store it) was rejected by the CLI: ``` BUZZ_AUTH_TAG is malformed: invalid JSON: expected value at line 1 column 2 ``` …and even when the CLI *could* parse it, it forwarded the raw string as the `x-auth-tag` header, so the relay's `verify_auth_tag` (which expects JSON) rejected it with `403 relay_membership_required`. Two commits close both gaps. ## Commits ### 1. `fix(nip-oa): accept raw Nostr tag form in parse_json_array` `parse_json_array` (`crates/buzz-sdk/src/nip_oa.rs`) only accepted well-formed JSON arrays. Added a fallback: when strict JSON parsing fails *and* the trimmed input is bracket-delimited, split on `,` and treat each field as a string (empty field `,,` → empty string, matching `["auth","hex","","hex"]`). All consumers (`parse_auth_tag`, `verify_auth_tag`, the CLI, `buzz-acp`) benefit from one change at the lowest layer. ### 2. `fix(cli): canonicalize BUZZ_AUTH_TAG to JSON before sending x-auth-tag header` The CLI stored the raw input string and sent it verbatim as the `x-auth-tag` header (`client.rs:618`). Added `canonicalize_auth_tag` in `buzz-sdk`: parse either form, re-serialize to canonical JSON. The CLI now canonicalizes before storing as `auth_tag_json`, so the header is always valid JSON regardless of input form. Together: local parse + wire canonicalization means the raw form works end-to-end. ## Why The raw form `[auth,hex,,hex]` is exactly how an `auth` tag serializes inside a Nostr event. That shape leaks into `.env` files and shell variables because there's no canonical "stored form" outside an event. The SDK + CLI should accept it rather than push quoting/conversion logic onto every consumer (harnesses, agent shells, external tools). ## Security Both changes are purely syntactic — they only change how a 4-element string array is extracted and containerized. All downstream validation is unchanged: - `parse_auth_tag`: still checks exactly 4 elements, `"auth"` label, 64-char lowercase-hex pubkey, 128-char signature. - `verify_auth_tag`: still reconstructs the preimage and verifies the BIP-340 Schnorr signature against the owner pubkey. No new attack surface — a malformed or forged tag is still rejected at the same validation points. ## Tests 4 new tests in `nip_oa::tests`: - `test_parse_auth_tag_raw_nostr_form` — raw form with conditions + empty conditions - `test_parse_auth_tag_raw_form_with_whitespace` — raw form with surrounding whitespace - `test_canonicalize_auth_tag_raw_to_json` — raw→JSON and JSON→JSON normalization All 25 `nip_oa` tests pass (21 existing + 4 new). `cargo fmt --check` and `cargo clippy -p buzz-sdk -p buzz-cli` clean. ## Verification Confirmed end-to-end against a live community relay (`wss://hermesagent.communities.buzz.xyz`): - **Before:** raw `BUZZ_AUTH_TAG` → CLI parse error, or `403 relay_membership_required` if somehow parsed. - **After:** raw `BUZZ_AUTH_TAG` → CLI parses it, canonicalizes to JSON for the header, relay accepts via NIP-OA owner delegation, `buzz channels members` returns the full roster. ## Context Originated from a community investigation where agent-side relay access was failing because the harness-exported `BUZZ_AUTH_TAG` (raw Nostr form) was rejected by the CLI (expecting JSON). This removes the impedance mismatch at the source. --------- Signed-off-by: amanning3390 <adam.manning@pro-serveinc.com> Signed-off-by: Tyler <109685178+tlongwell-block@users.noreply.github.com> Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Tyler <109685178+tlongwell-block@users.noreply.github.com>