Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8c3faf7
feat(relay): require a bearer token on the admin moderation API
Jul 30, 2026
e8e2b4c
fix(relay): lock the admin dashboard down with a response CSP
Jul 30, 2026
3904e76
docs(admin): document the admin dashboard CSP
Jul 30, 2026
d8735af
fix(relay): serve the admin favicon and scope the CSP doc claim
Jul 30, 2026
348d1dc
feat(relay): add BUZZ_ADMIN_INSECURE_NO_AUTH bypass for network-layer…
Jul 30, 2026
910f04e
docs(admin-web): fix probeAuthRequired() return-value comment
Jul 30, 2026
75277f3
refactor(relay): replace AdminConfig bool pair with AdminAuth enum
Jul 31, 2026
e93d5be
feat(admin): three-mode auth — BUZZ_ADMIN_AUTH enum + NIP-98 pubkey a…
Aug 3, 2026
1682a5e
fix(admin): pass path-and-query to NIP-98 auth, add bounded retry, fi…
Aug 3, 2026
a4380f1
Merge remote-tracking branch 'origin/main' into wpfleger/admin-api-be…
Aug 5, 2026
49547fa
feat(relay): Phase 1 — NIP-98 admin auth with OPERATOR/MODERATOR role…
Aug 7, 2026
56befa5
chore: merge origin/main into wpfleger/admin-api-bearer-auth
Aug 7, 2026
fa1f46f
feat(relay): Phase 2 — enforcement state machine, report resolution o…
Aug 7, 2026
0d2b17d
test(relay): mark two admin DB-dependent tests as ignored
Aug 7, 2026
eaa38d7
fix(relay): wire v4 §6a state machine — outbox in claim txn, lease wo…
Aug 7, 2026
6e0dfcf
test(relay): fix DB test fixtures — 32-byte event IDs, valid enum val…
Aug 7, 2026
e17add0
chore: merge origin/main into wpfleger/admin-api-bearer-auth
Aug 7, 2026
1046232
test(relay): add 6 e2e state-machine tests through production driver/…
Aug 7, 2026
9a95cbe
fix(relay): fence action lease + outbox claim tokens at every commit …
Aug 8, 2026
f1b4a44
test(relay): expire action lease before re-driving in kick-provenance…
Aug 8, 2026
9d8c2c8
chore: merge origin/main into wpfleger/admin-api-bearer-auth
Aug 8, 2026
0dbbf48
fix(buzz-db): bump embedded migrator count to 32 for 0032 migration
Aug 8, 2026
e2ad308
Merge remote-tracking branch 'origin/main' into wpfleger/admin-api-be…
Aug 8, 2026
b4b3ea0
fix(relay): address pass-4 review findings: notice idempotency, lease…
Aug 8, 2026
5527704
test(relay): address pass-5 review findings: session-local GUC, real …
Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,40 @@ RELAY_URL=ws://localhost:3000
# (use `just web` for Vite HMR instead).
# BUZZ_WEB_DIR=./web/dist

# -----------------------------------------------------------------------------
# Admin Dashboard (private moderation surface)
# -----------------------------------------------------------------------------
# Host name that serves the read-only moderation dashboard and its
# /api/admin/v1 endpoints. Leave unset to keep the admin surface absent.
# Setting it requires one of the two authentication variables below.
# BUZZ_ADMIN_HOST=admin.localhost:3000
#
# Authentication mode. Accepted values: token (default), disabled, nip98.
# Any other value is a startup error.
# BUZZ_ADMIN_AUTH=token
#
# Option A — BUZZ_ADMIN_AUTH=token (default when unset):
# Exactly 64 hex characters (32 bytes); generate with `openssl rand -hex 32`.
# `just admin` generates a throwaway one per run and prints it.
# BUZZ_ADMIN_TOKEN=<64 hex characters>
#
# Option B — BUZZ_ADMIN_AUTH=disabled (network-layer auth only):
# Set only when the admin API is already protected at the network layer
# (VPN, private ingress). The relay logs a WARN on every startup.
# BUZZ_ADMIN_TOKEN must NOT also be set.
#
# Option C — BUZZ_ADMIN_AUTH=nip98 (Nostr pubkey-based auth):
# NIP-98 HTTP Auth. Each request must carry an Authorization: Nostr header
# with a signed kind-27235 event. Authorized principals are resolved from:
# 1. RELAY_OPERATOR_PUBKEYS — comma-separated 64-char hex pubkeys (config Operators).
# 2. RELAY_OWNER_PUBKEY — implicit Operator fallback when RELAY_OPERATOR_PUBKEYS is unset.
# 3. relay_operators table — DB-managed Operator/Moderator roster.
# The dashboard requires a NIP-07 browser extension.
# RELAY_OPERATOR_PUBKEYS=<64-char hex pubkey>[,<64-char hex pubkey>...]
#
# Directory holding the built dashboard assets (`pnpm -C admin-web build`).
# BUZZ_ADMIN_WEB_DIR=./admin-web/dist

# Shared Redis-backed admission limits. Defaults shown below; each value must
# be a positive integer.
# BUZZ_RATE_LIMIT_HUMAN_MESSAGES_PER_MIN=60
Expand Down
28 changes: 27 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Changelog

## Unreleased

- **Breaking:** the relay admin moderation API (`/api/admin/v1`) now requires
explicit authentication configuration when `BUZZ_ADMIN_HOST` is set. Choose
one mode via `BUZZ_ADMIN_AUTH` (unset defaults to `token`):
- **`BUZZ_ADMIN_AUTH=token` (default):** set `BUZZ_ADMIN_TOKEN` to exactly
64 hex characters (`openssl rand -hex 32`). Every request requires
`Authorization: Bearer`. The dashboard prompts for the token on first load.
- **`BUZZ_ADMIN_AUTH=disabled`:** admin API is unauthenticated. Use only when
the admin API is already protected by a VPN or private ingress. The relay
logs a `WARN` on every startup. The dashboard skips the token prompt.
- **`BUZZ_ADMIN_AUTH=nip98`:** NIP-98 HTTP Auth. Every request must carry an
`Authorization: Nostr <base64 event>` header containing a signed kind-27235
event. Authorized principals resolve from `RELAY_OPERATOR_PUBKEYS`
(comma-separated 64-char hex pubkeys for config-backed Operators),
`RELAY_OWNER_PUBKEY` (implicit Operator fallback when `RELAY_OPERATOR_PUBKEYS`
is unset), and the `relay_operators` table (DB-managed Operator/Moderator
roster). The dashboard requires a NIP-07 browser extension (nos2x or Alby);
without one it shows an installation screen. Individual operator access is
revocable without rotating a shared secret.
- Any unrecognised value for `BUZZ_ADMIN_AUTH` is a startup error
(typo-proofing). `BUZZ_ADMIN_TOKEN` set alongside `disabled` or `nip98` is
also a startup error.
- `Host`/`Origin` matching is retained in all modes as defense-in-depth.
- **Migration from the previous `BUZZ_ADMIN_INSECURE_NO_AUTH=true`:** replace
with `BUZZ_ADMIN_AUTH=disabled`. The behavior is identical.

## v0.5.8

### Desktop and shared changes
Expand All @@ -13,7 +40,6 @@
- infra: bind development services to loopback ([#4871](https://github.com/block/buzz/pull/4871)) ([`65834d68d0d3441c4e628540d6d5c8b0a2e757c9`](https://github.com/block/buzz/commit/65834d68d0d3441c4e628540d6d5c8b0a2e757c9))

[Compare desktop-v0.5.7...desktop-v0.5.8](https://github.com/block/buzz/compare/desktop-v0.5.7...desktop-v0.5.8)

## v0.5.7

### Desktop and shared changes
Expand Down
6 changes: 5 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,11 @@ admin: bootstrap _ensure-migrations
pnpm -C admin-web build
export BUZZ_ADMIN_HOST="${BUZZ_ADMIN_HOST:-admin.localhost:3000}"
export BUZZ_ADMIN_WEB_DIR="${BUZZ_ADMIN_WEB_DIR:-{{justfile_directory()}}/admin-web/dist}"
# The relay refuses to start without a token, and never logs one. Mint a
# throwaway per run so no dev secret is ever committed or reused.
export BUZZ_ADMIN_TOKEN="${BUZZ_ADMIN_TOKEN:-$(openssl rand -hex 32)}"
echo "Admin dashboard: http://${BUZZ_ADMIN_HOST}/reports"
echo "Admin token (paste into dashboard prompt): ${BUZZ_ADMIN_TOKEN}"
cargo run -p buzz-relay

# Seed deterministic reports and product feedback for local admin dashboard review
Expand All @@ -429,7 +433,7 @@ admin-check: fmt-check
cargo test -p buzz-relay api::admin
cargo test -p buzz-relay router::tests
pnpm -C admin-web check
pnpm -C admin-web exec playwright test
pnpm -C admin-web test:e2e

# Start the relay server in release mode
relay-release: _ensure-migrations
Expand Down
Loading
Loading