refactor(relay): extract NIP-29 membership authorization (#7285)

## Why

NIP-29 membership authorization for kinds 9000, 9001, and 9022 was
embedded in a large async handler, requiring Postgres and Redis to test
and repeating the last-owner rule across five call sites. This addresses
[TheSentinel454/buzz#24](https://github.com/TheSentinel454/buzz/issues/24)
without adding the broader state/repository abstraction suggested there
because HTTP and WebSocket writes already share ingestion.

## What

- Extract pure, typed membership authorization decisions while leaving
database reads and mutations in `validate_admin_event`.
- Preserve existing client-visible errors and independent database
last-owner safeguards.
- Collapse five last-owner policy restatements into one predicate and
share the identical self-departure policy.
- Include the relay decision modules in `just test-unit`, so these tests
execute in CI.

## Risk Assessment

Medium-low. This touches production relay authorization, but
intentionally preserves wire behavior and database defense in depth;
exhaustive decision tables and relay-backed tests cover the affected
paths.

## Simplification

This removes repeated policy from the orchestration path and makes the
rule set directly testable without introducing a repository trait or
second transport path.

## Verification

Verified at `15255a090797f85874921120003c645962fefaed`:

- `just test-unit` — all 10 package summaries passed. An initial run hit
two unrelated timing-sensitive `buzz-acp` failures; the complete retry
passed 905/905 in that package.
- `cargo fmt --all -- --check`
- `cargo clippy --workspace --all-targets -- -D warnings`
- `just file-size-check` — 10/10 policy tests passed.
- `just security-review-check` — 13/13 tests passed.
- Push preflight — `push-head-scope`, `branch-skew`, `file-size-check`,
`rust-tests`, and `desktop-tauri-checks` passed.
- Blox Postgres relay lane — 84/84 at the byte-identical source patch;
full live `e2e_relay` behavior matched the clean base (45 pass and the
same pre-existing kind:9002 failure on each).

Generated with Claude Code

---------

Signed-off-by: tornquist <tornquist@squareup.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Luke Tornquist
2026-09-04 10:46:55 -04:00
committed by GitHub
parent 01bacb8df3
commit cd02b693aa
8 changed files with 916 additions and 134 deletions

View File

@@ -37,6 +37,7 @@ clients_call=$(extract_job clients "$orchestrator")
mobile_swift_call=$(extract_job mobile-swift-domain "$orchestrator")
desktop_gate=$(extract_job desktop "$orchestrator")
macos_gate=$(extract_job desktop-build-macos "$orchestrator")
relay_e2e_job=$(extract_job relay-e2e "$relay_workflow")
[[ "$desktop_call" == *'uses: ./.github/workflows/_ci-desktop.yml'* ]] ||
fail "Desktop Domain must call _ci-desktop.yml"
@@ -68,6 +69,8 @@ grep -Fq "inputs.lane == 'postgres'" "$relay_workflow" ||
fail "PostgreSQL tests must be selected by their isolated lane"
grep -Fq "inputs.lane == 'artifacts'" "$relay_workflow" ||
fail "relay artifacts must be selected by their isolated lane"
[[ "$relay_e2e_job" == *'cargo test -p buzz-test-client --test e2e_relay nip29_departure_wire -- --ignored --nocapture'* ]] ||
fail "Relay E2E must select the NIP-29 departure wire tests"
grep -Fq "inputs.lane == 'mobile-swift'" "$clients_workflow" ||
fail "Mobile Swift must be selected by its isolated lane"