trails/apps/journal/app/lib
Ullrich Schäfer 57696286e4
feat(journal): federation instance blocklist
Task group 3 of federation-hardening. There was no blocklist of any kind;
the only lever against a hostile instance was an IP/host block in Caddy.

- New `federation_blocked_instances` table (domain PK, reason,
  created_at). Additive → created by drizzle-kit push.
- `federation-blocklist.server.ts`: exact-host matching —
  `isBlockedDomain`, `isBlockedIri` (unparseable IRI ⇒ treated as
  blocked), and `filterBlockedDomains` for batch recipient filtering.
- Enforced at all three boundaries (spec: federation-operations
  "Instance blocklist"):
  - inbox — each of the 4 listeners silently drops a blocked actor's
    activity (202, no error oracle) before dedup/side effects;
  - delivery enqueue — `enqueueActivityDeliveries` filters blocked
    recipients in one batch query;
  - outbox poll / actor fetch — `pollRemoteActor` refuses a blocked host
    up front (`skipped: "blocked instance"`), before any network.
- Operator procedure (SQL insert/list/delete) documented in the
  deployment runbook's federation section.
- Tests: unit (hostOfIri) + integration against real Postgres covering
  the helper and the delivery + outbox boundaries; inbox uses the same
  tested isBlockedIri primitive.

Note: the inbox-drop *counter* (federation_inbox_dropped_total{reason})
lands with the other metrics in task 4.2; this commit is the enforcement.

Verified: db + journal typecheck + lint clean; drizzle-kit push creates
the table; blocklist integration tests green against real Postgres;
journal unit suite 357 passing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 22:59:11 +02:00
..
auth fix(journal): fail loud in production when secrets are unset 2026-05-24 11:37:20 +02:00
connected-services security: log redaction, magic-link enumeration, federation doc cap 2026-06-11 07:52:34 +02:00
notifications Merge /follows/requests into /notifications as a tabbed inbox 2026-04-26 08:24:59 +02:00
sync activity-sport-type: schema, contract, write/read paths, federation 2026-06-12 14:11:41 +02:00
activities.server.ts route-surface-breakdown (Phase 2): async Overpass backfill + SSE 2026-06-14 19:18:03 +02:00
actor-iri.ts fix(journal): architectural audit omnibus 2026-05-24 10:28:33 +02:00
api-guard.server.test.ts fix: enforce Terms gate on bearer-token API requests 2026-05-08 01:59:28 +02:00
api-guard.server.ts one source of truth for Route/Activity shapes; enforce api contracts 2026-06-10 07:39:50 +02:00
auth.server.ts security: log redaction, magic-link enumeration, federation doc cap 2026-06-11 07:52:34 +02:00
boss.server.ts feat(journal): durable Fedify message queue over pg-boss 2026-07-13 21:46:46 +02:00
canView.test.ts Apply public-content-visibility: visibility flag + public profile 2026-04-19 09:11:39 +02:00
config.server.test.ts fix(journal): fail loud in production when secrets are unset 2026-05-24 11:37:20 +02:00
config.server.ts fix: add E2E opt-out for fail-loud secret/DB-URL guards 2026-05-24 11:45:09 +02:00
crypto.server.test.ts Add Komoot import with public (bio verification) and authenticated modes 2026-05-23 10:18:46 +02:00
crypto.server.ts feat(journal): federation schema + per-user signing keypairs 2026-06-06 14:15:51 +02:00
db.ts Deepen three architectural seams: FIT consolidation, host election extraction, injectable db 2026-05-10 15:52:31 +02:00
demo-bot.integration.test.ts ci: wire integration tests into the CI E2E job 2026-05-25 23:27:44 +02:00
demo-bot.server.ts journal: gpx-save owns the validate-and-derive step (processGpx) 2026-06-10 03:28:13 +02:00
demo-bot.test.ts Apply configurable-demo-persona: per-instance demo identity + voice 2026-04-19 10:30:32 +02:00
email.server.test.ts Add observability: health endpoints, structured logging, metrics, Grafana stack 2026-03-26 22:59:44 +01:00
email.server.ts fix: extensionless server-side imports + lint rule to catch them 2026-05-26 08:08:19 +02:00
events.server.ts Implement notifications + supporting fixes 2026-04-26 01:28:55 +02:00
explore.integration.test.ts Include the demo persona on /explore so users can follow it 2026-04-26 11:43:24 +02:00
explore.server.ts Include the demo persona on /explore so users can follow it 2026-04-26 11:43:24 +02:00
federation-blocklist.integration.test.ts feat(journal): federation instance blocklist 2026-07-13 22:59:11 +02:00
federation-blocklist.server.test.ts feat(journal): federation instance blocklist 2026-07-13 22:59:11 +02:00
federation-blocklist.server.ts feat(journal): federation instance blocklist 2026-07-13 22:59:11 +02:00
federation-delivery.server.test.ts fix(journal): retract federated activities only on public→non-public 2026-06-07 08:52:23 +02:00
federation-delivery.server.ts feat(journal): federation instance blocklist 2026-07-13 22:59:11 +02:00
federation-inbox.integration.test.ts fix(journal): show remote followers in follower/following lists 2026-06-07 09:13:44 +02:00
federation-inbox.server.ts feat(journal): federation inbox — Mastodon follows land here 2026-06-06 14:33:43 +02:00
federation-ingest.integration.test.ts feat(journal): honor 429/Retry-After in outbox polling (§7.4) 2026-06-07 12:35:59 +02:00
federation-ingest.server.test.ts security: log redaction, magic-link enumeration, federation doc cap 2026-06-11 07:52:34 +02:00
federation-ingest.server.ts feat(journal): federation instance blocklist 2026-07-13 22:59:11 +02:00
federation-keys.server.test.ts feat(journal): federation schema + per-user signing keypairs 2026-06-06 14:15:51 +02:00
federation-keys.server.ts feat(journal): federation schema + per-user signing keypairs 2026-06-06 14:15:51 +02:00
federation-kv.integration.test.ts feat(journal): federation inbox — Mastodon follows land here 2026-06-06 14:33:43 +02:00
federation-kv.server.ts feat(journal): federation inbox — Mastodon follows land here 2026-06-06 14:33:43 +02:00
federation-objects.server.test.ts activity-sport-type: schema, contract, write/read paths, federation 2026-06-12 14:11:41 +02:00
federation-objects.server.ts activity-sport-type: schema, contract, write/read paths, federation 2026-06-12 14:11:41 +02:00
federation-outbound.integration.test.ts feat(journal): outbound trails-to-trails follows (social-federation §6) 2026-06-07 11:50:35 +02:00
federation-outbound.server.test.ts feat(journal): outbound trails-to-trails follows (social-federation §6) 2026-06-07 11:50:35 +02:00
federation-outbound.server.ts feat(journal): outbound trails-to-trails follows (social-federation §6) 2026-06-07 11:50:35 +02:00
federation-outbox.integration.test.ts feat(journal): dereferenceable Note objects at /activities/:id 2026-06-06 23:18:30 +02:00
federation-outbox.server.ts activity-sport-type: schema, contract, write/read paths, federation 2026-06-12 14:11:41 +02:00
federation-queue.server.test.ts feat(journal): durable Fedify message queue over pg-boss 2026-07-13 21:46:46 +02:00
federation-queue.server.ts feat(journal): durable Fedify message queue over pg-boss 2026-07-13 21:46:46 +02:00
federation-replay.integration.test.ts feat(journal): inbound federation replay defense 2026-07-13 22:07:30 +02:00
federation-replay.server.ts feat(journal): inbound federation replay defense 2026-07-13 22:07:30 +02:00
federation-two-instance.integration.test.ts feat(journal): two-instance federation harness + trails↔trails Accept fix (§11) 2026-06-07 13:36:35 +02:00
federation.server.test.ts fix(journal): actor profile fields must serialize as a JSON array 2026-06-07 08:43:03 +02:00
federation.server.ts feat(journal): federation instance blocklist 2026-07-13 22:59:11 +02:00
follow.integration.test.ts Locked-account profiles: private = stub + Pending follow flow 2026-04-25 23:38:26 +02:00
follow.server.ts feat(journal): outbound trails-to-trails follows (social-federation §6) 2026-06-07 11:50:35 +02:00
gpx-save.server.test.ts journal: gpx-save owns the validate-and-derive step (processGpx) 2026-06-10 03:28:13 +02:00
gpx-save.server.ts journal: gpx-save owns the validate-and-derive step (processGpx) 2026-06-10 03:28:13 +02:00
http.server.test.ts fix(journal): architectural audit omnibus 2026-05-24 10:28:33 +02:00
http.server.ts fix(journal): architectural audit omnibus 2026-05-24 10:28:33 +02:00
jwt.server.ts fix(journal): single-use JWT enforcement for route callback tokens (#2 Phase B) 2026-05-26 00:38:08 +02:00
komoot-bulk-import.server.ts activity-sport-type: schema, contract, write/read paths, federation 2026-06-12 14:11:41 +02:00
komoot.server.test.ts Add Komoot import with public (bio verification) and authenticated modes 2026-05-23 10:18:46 +02:00
komoot.server.ts fix(journal): architectural audit omnibus 2026-05-24 10:28:33 +02:00
legal.ts docs(journal): federation privacy manifest + runbook + honest home blurb (§10) 2026-06-07 12:21:51 +02:00
logger.server.test.ts feat(journal): per-request requestId propagated through logs 2026-05-24 12:31:30 +02:00
logger.server.ts feat(journal): per-request requestId propagated through logs 2026-05-24 12:31:30 +02:00
metrics.server.test.ts fix(journal): match metric route label against known templates 2026-06-19 11:00:03 +02:00
metrics.server.ts fix(journal): match metric route label against known templates 2026-06-19 11:00:03 +02:00
notifications.integration.test.ts Cursor-based pagination for /notifications 2026-04-26 01:42:32 +02:00
notifications.server.ts Cursor-based pagination for /notifications 2026-04-26 01:42:32 +02:00
oauth.server.test.ts Implement OAuth2 PKCE auth, discovery, and mobile API client 2026-04-13 00:41:40 +02:00
oauth.server.ts Drop auth.server.ts re-exports + rename to .server.ts convention (task 5.2) 2026-05-08 03:01:30 +02:00
operator.ts Add legal pages, ToS acceptance, and alpha banner 2026-04-18 00:08:48 +02:00
overpass-ways.server.ts route-surface-breakdown (Phase 2): async Overpass backfill + SSE 2026-06-14 19:18:03 +02:00
ownership.server.test.ts journal: branded ownership loading for routes and activities 2026-06-10 02:35:00 +02:00
ownership.server.ts journal: branded ownership loading for routes and activities 2026-06-10 02:35:00 +02:00
rate-limit.server.test.ts fix(journal): rate-limit auth endpoints 2026-05-24 11:51:43 +02:00
rate-limit.server.ts fix: bypass rate limiter when E2E=true 2026-05-24 11:57:01 +02:00
routes.server.ts route-surface-breakdown (Phase 1): Planner-path surface/waytype bars 2026-06-14 18:46:49 +02:00
sentry.client.ts fix(sentry): remove hardcoded DSN fallbacks; supply via env in CI 2026-05-25 23:07:07 +02:00
social-feed.integration.test.ts feat(journal): audience-aware social feed with remote activities (§8+§9) 2026-06-07 12:32:11 +02:00
sport-type.test.ts activity-sport-type: schema, contract, write/read paths, federation 2026-06-12 14:11:41 +02:00
sport-type.ts activity-sport-type: schema, contract, write/read paths, federation 2026-06-12 14:11:41 +02:00
stats.test.ts activity-stats: shared StatRow + canonical metrics across surfaces 2026-06-12 14:48:36 +02:00
stats.ts activity-stats: shared StatRow + canonical metrics across surfaces 2026-06-12 14:48:36 +02:00
surface-match.server.test.ts route-surface-breakdown (Phase 2): async Overpass backfill + SSE 2026-06-14 19:18:03 +02:00
surface-match.server.ts route-surface-breakdown (Phase 2): async Overpass backfill + SSE 2026-06-14 19:18:03 +02:00