Cap indexer API4 per-request cost on GT events, progress, and blacklist-check (#694) #1193

Merged
PlasticDigits merged 1 commit from feat/694-api4-per-request-caps into main 2026-08-28 10:51:40 +00:00
PlasticDigits commented 2026-08-28 09:48:47 +00:00 (Migrated from gitlab.com)

Closes #694

Summary

OWASP API4 per-request caps (audit INTERNAL_GROK46_1787908099 RE-01 / RE-02 / RE-03). Request-count governors stay; each HTTP hit is now bounded.

  • RE-01: GET /gt/events COUNTs swap+liq with the same gem-exclusion WHERE, then 400 event count exceeds 5000 when over MAX_GT_EVENT_ROWS (5000). No truncation. GET still does not SELECT pair_reserves (post-#684 event columns).
  • RE-02: GET /api/v1/route/solve/progress is on lcd_heavy_router (10 RPS). GetDiscount is cached 12s per (trader, sender). Optional progress-only discount_bps is ignored by solve quote math.
  • RE-03: blacklist-check tokens ≤ 16, pairs ≤ 8 (trim/empty-drop). Oversize 400 (fail-closed). Route is on lcd_heavy_router. Factory errors stay sanitized 502.
  • Frontend: omit trader when the parent quote already has discount_bps; exponential backoff after consecutive progress failures. Quote math / refetchIntervals unchanged.

Playbook: skills/AGENTS_INDEXER_API4_PER_REQUEST.md (A694-1–A694-8). QA: make verify-issue-694.

Test plan

  • make verify-issue-694 (twice: 5/5, real test counts)
  • Lib: row-cap / discount cache / progress discount parse / list caps
  • security.rs: 429 on progress + /best + blacklist-check; tokens 17 / pairs 9 → 400; at-cap + empty → 200; LCD down → 502
  • api_gt.rs: 5001 rows → 400; 5000 rows → 200
  • api_route_solve.rs: 3 progress polls, 1 LCD GetDiscount
  • Frontend Vitest: omit-trader + backoff + discount_bps query param (45 tests)
  • Coolify/prod: after deploy, max-span /gt/events stays bounded; progress with trader is not 1:1 LCD
  • Live Swap page: progress still advisory; Place / Swap still works

Acceptance criteria

  • /gt/events never returns more than 5000; over-cap is 400 (documented message, no truncation)
  • /gt/events does not SELECT all of pair_reserves (already true post-#684; grep-guarded)
  • Progress and blacklist-check are on the LCD-heavy governor
  • Progress with trader does not LCD GetDiscount on every poll within the 12s TTL
  • Blacklist tokens/pairs over cap → 400; at-cap still queries factory; factory error still sanitized 502
  • GT gem exclusion, solve cache, CORS, prod RPS clamp, and Peer-IP extractor unchanged
  • security.rs covers 429 on progress + blacklist-check + /best and the new 400s
  • make verify-issue-694 exists and is wired in Makefile / AGENTS.md
  • docs/indexer-invariants.md records the caps and LCD-heavy routes

Not in this MR

  • Coolify/prod curl after deploy (operator)
  • Audit-note close in INTERNAL_GROK46_1787908099 (follow-up when this lands)
  • Live Swap-page browser QA (progress stays advisory; no quote-math change)
  • Scoped pair_reserves WHERE pair_id = ANY — GET never reads that table after #684
  • Per-swap FoT math, new write APIs, XFF trust, prod RPS clamp changes
Closes #694 ## Summary OWASP API4 per-request caps (audit `INTERNAL_GROK46_1787908099` **RE-01 / RE-02 / RE-03**). Request-count governors stay; each HTTP hit is now bounded. - **RE-01:** `GET /gt/events` COUNTs swap+liq with the same gem-exclusion WHERE, then **400** `event count exceeds 5000` when over `MAX_GT_EVENT_ROWS` (5000). No truncation. GET still does not `SELECT` `pair_reserves` (post-#684 event columns). - **RE-02:** `GET /api/v1/route/solve/progress` is on `lcd_heavy_router` (10 RPS). `GetDiscount` is cached 12s per `(trader, sender)`. Optional progress-only `discount_bps` is ignored by solve quote math. - **RE-03:** `blacklist-check` `tokens` ≤ 16, `pairs` ≤ 8 (trim/empty-drop). Oversize **400** (fail-closed). Route is on `lcd_heavy_router`. Factory errors stay sanitized **502**. - **Frontend:** omit `trader` when the parent quote already has `discount_bps`; exponential backoff after consecutive progress failures. Quote math / `refetchInterval`s unchanged. Playbook: `skills/AGENTS_INDEXER_API4_PER_REQUEST.md` (**A694-1–A694-8**). QA: `make verify-issue-694`. ## Test plan - [x] `make verify-issue-694` (twice: 5/5, real test counts) - [x] Lib: row-cap / discount cache / progress discount parse / list caps - [x] `security.rs`: 429 on progress + `/best` + blacklist-check; tokens 17 / pairs 9 → 400; at-cap + empty → 200; LCD down → 502 - [x] `api_gt.rs`: 5001 rows → 400; 5000 rows → 200 - [x] `api_route_solve.rs`: 3 progress polls, 1 LCD `GetDiscount` - [x] Frontend Vitest: omit-trader + backoff + `discount_bps` query param (45 tests) - [ ] Coolify/prod: after deploy, max-span `/gt/events` stays bounded; progress with trader is not 1:1 LCD - [ ] Live Swap page: progress still advisory; Place / Swap still works ## Acceptance criteria - [x] `/gt/events` never returns more than 5000; over-cap is **400** (documented message, no truncation) - [x] `/gt/events` does not `SELECT` all of `pair_reserves` (already true post-#684; grep-guarded) - [x] Progress and blacklist-check are on the LCD-heavy governor - [x] Progress with `trader` does not LCD `GetDiscount` on every poll within the 12s TTL - [x] Blacklist `tokens`/`pairs` over cap → 400; at-cap still queries factory; factory error still sanitized 502 - [x] GT gem exclusion, solve cache, CORS, prod RPS clamp, and Peer-IP extractor unchanged - [x] `security.rs` covers 429 on progress + blacklist-check + `/best` and the new 400s - [x] `make verify-issue-694` exists and is wired in Makefile / AGENTS.md - [x] `docs/indexer-invariants.md` records the caps and LCD-heavy routes ## Not in this MR - Coolify/prod curl after deploy (operator) - Audit-note close in `INTERNAL_GROK46_1787908099` (follow-up when this lands) - Live Swap-page browser QA (progress stays advisory; no quote-math change) - Scoped `pair_reserves` `WHERE pair_id = ANY` — GET never reads that table after #684 - Per-swap FoT math, new write APIs, XFF trust, prod RPS clamp changes
PlasticDigits commented 2026-08-28 10:51:40 +00:00 (Migrated from gitlab.com)

mentioned in commit 3c4060aba0

mentioned in commit 3c4060aba03c2091565c13616cb39296fdf3bc2b
PlasticDigits (Migrated from gitlab.com) merged commit 3c4060aba0 into main 2026-08-28 10:51:41 +00:00
PlasticDigits commented 2026-08-28 11:07:02 +00:00 (Migrated from gitlab.com)

mentioned in issue #694

mentioned in issue #694
PlasticDigits commented 2026-08-28 11:07:04 +00:00 (Migrated from gitlab.com)

mentioned in issue #695

mentioned in issue #695
PlasticDigits commented 2026-08-28 11:07:54 +00:00 (Migrated from gitlab.com)

mentioned in issue #698

mentioned in issue #698
PlasticDigits commented 2026-08-28 11:13:04 +00:00 (Migrated from gitlab.com)

mentioned in issue #699

mentioned in issue #699
PlasticDigits commented 2026-08-28 11:16:00 +00:00 (Migrated from gitlab.com)

mentioned in issue #700

mentioned in issue #700
PlasticDigits commented 2026-08-28 11:17:10 +00:00 (Migrated from gitlab.com)

mentioned in commit ba1d41bfd5

mentioned in commit ba1d41bfd5021e63f6f847726e76d7b6109e96ca
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic!1193
No description provided.