Files
buzz/docs/admin/README.md
T
Jordan Mecom b747feddb3 Require credentials for deployment admin access
Co-authored-by: Jordan Mecom <jm@squareup.com>
Signed-off-by: Jordan Mecom <jm@squareup.com>
2026-08-03 13:44:05 -07:00

77 lines
3.5 KiB
Markdown

# Read-only deployment moderation dashboard
Buzz can expose a private, deployment-wide read-only dashboard from the existing
relay process. It shows open moderation reports and recent product feedback.
Configure `BUZZ_ADMIN_HOST` and a strong password to activate the dashboard. A
private ingress should also limit access to the operator VPN or approved source
IPs.
Required configuration:
```text
BUZZ_ADMIN_HOST=admin.example.com
BUZZ_ADMIN_USERNAME=admin
BUZZ_ADMIN_PASSWORD=<random password with at least 16 bytes>
BUZZ_ADMIN_WEB_DIR=/srv/buzz/admin-web
```
The relay requires HTTP Basic credentials before it serves the dashboard, its
assets, any admin API, or an attachment. `BUZZ_ADMIN_USERNAME` defaults to
`admin`; the password has no default,
must be at least 16 bytes, and is retained by the relay only as a digest. The
configured host and matching browser origin remain defense-in-depth checks.
Requests and responses are bounded and uncached. Use HTTPS so the credentials
are not exposed in transit, and route admin traffic through the private ingress.
When the UI runs in a separate pod, proxy `/api/admin/v1/*` to the relay while
preserving the admin `Host` header. A `NetworkPolicy` grants the admin pod access
to that relay path.
Read routes:
- `GET /api/admin/v1/reports`
- `GET /api/admin/v1/reports/:id`
- `GET /api/admin/v1/feedback`
- `GET /api/admin/v1/feedback/:id`
Report reads accept optional `communityId`, `status`, `reportType`, `targetKind`,
`after`, `before`, and `limit` parameters. Limits are capped at 200. Feedback is
a bounded newest-first summary from the existing product-feedback repository.
For local review, run `just admin-seed` before `just admin`. The seed command
also uploads real image and diagnostic fixtures to local MinIO. Feedback search
and filters run over the bounded browser result set; the **Acted on** checkbox is
stored in that browser's local storage.
## Feedback attachment boundary
Feedback attachment bytes are available only through the feedback-scoped read
route:
- `GET /api/admin/v1/feedback/:id/attachments/:sha256`
The route uses the same private-ingress, exact admin `Host`, and same-origin
boundary as the JSON API. It is not a generic media endpoint. The relay loads
the feedback row, derives its community from server-owned provenance, verifies
that host resolution still maps to the row's `community_id`, and requires the
requested SHA-256 to match both the `x` field and source-community `/media/` URL
in that row's persisted `imeta` tag. It then reads the tenant-scoped media
sidecar before accessing the shared content-addressed blob. Unknown feedback,
unreferenced hashes, malformed paths, and cross-community substitutions all
collapse to `404`.
Only `GET` and `HEAD` are routed. Existing community `/media/*` authorization is
unchanged, including `BUZZ_REQUIRE_MEDIA_GET_AUTH`; the browser receives no
Blossom credential or reusable signed URL. Responses are uncached, `nosniff`,
governed by a restrictive CSP, streamed from object storage, and non-previewable
content retains attachment disposition. Successful reads produce a structured
trace containing feedback ID, community ID, and attachment hash, but no feedback
body or attachment URL.
The deployment credential identifies administrators as a group, not as
individual people. Anyone with that credential can read attachments for
feedback records they can access. Rotate the password when an administrator
loses access. Per-person attribution requires identity-aware authentication at
the ingress or application layer.