Document the reputation query API
docker-build-push / build-push (push) Successful in 5s

README gets the full contract (request/response shape, the cost ceiling and
why it exists, the block-width cap and expiry, and the two new tables).
CLAUDE.md gets the two rules that are easy to undo by accident: the endpoint
must never serve unauthenticated, and the width cap and expiry are policy
decisions rather than tuning knobs.
This commit is contained in:
pmb committed 2026-09-13 16:24:48 -07:00
1 parent 6952fbadf6
commit 47e92ca10f
2 files changed
+135 -1

No files matched your search

+27
View File
@@ -19,6 +19,18 @@ A FastAPI webhook server. One Mastodon admin webhook delivers `account.created`,
and auto-**silence** young/dormant accounts past the threshold — lowered for
accounts with a flagged signup IP (see README).
Alongside the webhook it serves a **reputation query API** — `POST
/api/reputation` — which is the pre-emptive counterpart to all of the above.
Mastodon calls it during signup, immediately before its own IpBlock /
EmailDomainBlock lookups; it classifies the IP/email domain, records it,
registers the block, and only then returns, so the lookup that follows
rejects the signup outright. It **writes**, so it is authenticated
(`X-Reputation-Key`) and 404s unless `REPUTATION_API_ENABLED` *and*
`REPUTATION_API_KEY` are both set. The caller is the
`call-welcomebot-reputation-api` patch on the Mastodon fork — see
`~/secondbrain/yttrx-documentation/mastodon-fork-patches.md`. README.md's
"Reputation query API" section has the full contract.
Alongside the webhook it serves an optional read-only **blocklist API** —
`GET /api/blocks`, `/api/blocks/ip-ranges`, `/api/blocks/email-domains` —
publishing the IP ranges and email domains the bot has auto-blocked. It is
@@ -62,6 +74,17 @@ user-memory note `project_welcomebot` has the current state.
check-mail.org's disposable/risk fields back into the response — that would
be redistributing a paid reputation feed's data. Account identifiers
(handles, ids, emails, raw signup IPs) are out for the usual reasons.
- **The reputation API must never serve unauthenticated.** It installs IP
blocks; an open endpoint that does that is a denial-of-service lever. An
empty `REPUTATION_API_KEY` disables the route rather than opening it, and
that behaviour is asserted in `test_local.py` — don't "fix" it into a
permissive default.
- **Don't remove the block-width cap or the block expiry.** `IP_SCRUTINY_MAX_
BLOCK_PREFIX_V4`/`_V6` (24/48) and `IP_SCRUTINY_IPBLOCK_EXPIRES_IN` (24h)
exist because ipapi.is reports whole ASN routes: without the cap a single
`abuser` flag on a consumer address blocks its entire ISP route (routes of
/8–/11 are routine, and `197.211.32.0/19` was already registered against a
Benin mobile carrier). Raising them is a policy decision, not a tuning knob.
- **`admin.yttrx.com`'s `/root/yttrx-welcomebot/` is not a git repo any more**
(cleaned up 2026-07-06). Don't `git init`/clone it back into place — the
registry image + `docker-compose.yml`/`.env` is the whole deploy surface now.
@@ -217,6 +240,10 @@ needed. Without these scopes the reconcile 403s and exits having changed
nothing, which is the deliberate failure mode: never read an outage as "every
block was removed".
The reputation API needs no scopes beyond those above — it registers the same
`Admin::IpBlock` / `EmailDomainBlock` records as the webhook path, so
`admin:write:ip_blocks` + `admin:write:email_domain_blocks` cover it.
**The suspicious-signup sweep (`app/suspicious_sweep.py`) needs another scope,
`admin:read:accounts`**, to `GET /api/v1/admin/accounts/:id` (fetches current
post/follow counts + role/suspended state to decide whether to suspend) —