Overview global 24h rollup + BRIN tuning runbook (#333) #814

Merged
PlasticDigits merged 4 commits from cursor/gitlab-issue-workflow-2834 into main 2026-06-05 14:45:56 +00:00
PlasticDigits commented 2026-06-05 13:57:55 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #333 — follow-up to #281 for bounded /api/v1/overview cache-miss latency.

Changes

  • global_stats_24h rollup table (migration 20260605120000_global_stats_24h_rollup.sql) — single-row materialized global 24h stats (SUM(offer_amount), SUM(volume_usd), COUNT(*)).
  • refresh_global_stats — refreshed every ~5 min by volume_aggregator and once at indexer startup (poller.rs), same cadence as pair_volume_24h.
  • get_global_stats — reads rollup on cache miss; optional live swap_events aggregate via OVERVIEW_GLOBAL_STATS_LIVE=1 for debug/parity.
  • 60s whole-response cache unchanged in overview.rs.
  • BRIN ops runbook — docs/runbooks/overview-global-stats-brin.md with production tuning guidance (pages_per_range, autosummarize, brin_summarize_new_values) and before/after EXPLAIN workflow.
  • Docs/skills — docs/indexer-invariants.md, skills/AGENTS_INDEXER_VOLUME_PAGINATION.md updated for V5 rollup path.

Acceptance checklist

Criterion Verification Result
Cache miss on /overview reads rollup — no swap_events scan cargo test --test indexer_overview_global_stats overview_cache_miss_reads_rollup_not_swap_events PASS
Rollup values match live aggregate within refresh interval cargo test --test indexer_overview_global_stats global_stats_rollup_matches_live_query PASS
BRIN tuning documented with EXPLAIN evidence workflow docs/runbooks/overview-global-stats-brin.md PASS
indexer_overview_global_stats tests extended 7 tests green PASS
docs/indexer-invariants.md updated — overview uses rollup doc diff PASS

Verification checklist (third parties)

docker compose up -d postgres
./scripts/setup-postgres-dev-databases.sh
cd indexer && cargo test --test indexer_overview_global_stats --test api_overview -j 1 -- --test-threads=1

Optional parity check with live aggregate:

OVERVIEW_GLOBAL_STATS_LIVE=1 cargo test --test indexer_overview_global_stats global_stats_rollup_matches_live_query -j 1 -- --test-threads=1

Notes

  • Issue #333 left open until deploy verification; #281 closable after production deploy confirms rollup freshness.
  • pair_count still computed live from pairs on each cache miss (unchanged semantics).
  • Max rollup staleness: one volume-aggregator interval (~5 min), documented in runbook.

Note

Low Risk
Read-path optimization with documented ~5 min staleness; migration backfills on deploy; startup fallback avoids serving zeros when swaps exist.

Overview
/api/v1/overview no longer runs a live 24h aggregate over swap_events on each 60s cache miss. It reads the materialized global_stats_24h row instead (SUM(offer_amount), SUM(volume_usd), COUNT(*)), refreshed on the same ~5 minute loop as pair_volume_24h (startup in poller.rs + volume_aggregator).

get_global_stats prefers the rollup; OVERVIEW_GLOBAL_STATS_LIVE=1 or a zero rollup with recent swaps still triggers the old live query. pair_count stays a live COUNT(*) from pairs.

Adds migration 20260605120000_global_stats_24h_rollup.sql, operator runbook docs/runbooks/overview-global-stats-brin.md (BRIN as safety net for live fallback), updated invariants/skills, and expanded indexer_overview_global_stats tests.

Reviewed by Cursor Bugbot for commit e817be2ae4. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Implements GitLab [#333](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/333) — follow-up to #281 for bounded `/api/v1/overview` cache-miss latency. ### Changes - **`global_stats_24h` rollup table** (migration `20260605120000_global_stats_24h_rollup.sql`) — single-row materialized global 24h stats (`SUM(offer_amount)`, `SUM(volume_usd)`, `COUNT(*)`). - **`refresh_global_stats`** — refreshed every ~5 min by `volume_aggregator` and once at indexer startup (`poller.rs`), same cadence as `pair_volume_24h`. - **`get_global_stats`** — reads rollup on cache miss; optional live `swap_events` aggregate via `OVERVIEW_GLOBAL_STATS_LIVE=1` for debug/parity. - **60s whole-response cache** unchanged in `overview.rs`. - **BRIN ops runbook** — `docs/runbooks/overview-global-stats-brin.md` with production tuning guidance (`pages_per_range`, `autosummarize`, `brin_summarize_new_values`) and before/after EXPLAIN workflow. - **Docs/skills** — `docs/indexer-invariants.md`, `skills/AGENTS_INDEXER_VOLUME_PAGINATION.md` updated for V5 rollup path. ## Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Cache miss on `/overview` reads rollup — no `swap_events` scan | `cargo test --test indexer_overview_global_stats overview_cache_miss_reads_rollup_not_swap_events` | PASS | | Rollup values match live aggregate within refresh interval | `cargo test --test indexer_overview_global_stats global_stats_rollup_matches_live_query` | PASS | | BRIN tuning documented with EXPLAIN evidence workflow | `docs/runbooks/overview-global-stats-brin.md` | PASS | | `indexer_overview_global_stats` tests extended | 7 tests green | PASS | | `docs/indexer-invariants.md` updated — overview uses rollup | doc diff | PASS | ## Verification checklist (third parties) ```bash docker compose up -d postgres ./scripts/setup-postgres-dev-databases.sh cd indexer && cargo test --test indexer_overview_global_stats --test api_overview -j 1 -- --test-threads=1 ``` Optional parity check with live aggregate: ```bash OVERVIEW_GLOBAL_STATS_LIVE=1 cargo test --test indexer_overview_global_stats global_stats_rollup_matches_live_query -j 1 -- --test-threads=1 ``` ## Notes - Issue **#333** left **open** until deploy verification; **#281** closable after production deploy confirms rollup freshness. - `pair_count` still computed live from `pairs` on each cache miss (unchanged semantics). - Max rollup staleness: one volume-aggregator interval (~5 min), documented in runbook. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Read-path optimization with documented ~5 min staleness; migration backfills on deploy; startup fallback avoids serving zeros when swaps exist. > > **Overview** > **`/api/v1/overview`** no longer runs a live 24h aggregate over **`swap_events`** on each 60s cache miss. It reads the materialized **`global_stats_24h`** row instead (`SUM(offer_amount)`, `SUM(volume_usd)`, `COUNT(*)`), refreshed on the same ~5 minute loop as **`pair_volume_24h`** (startup in **`poller.rs`** + **`volume_aggregator`**). > > **`get_global_stats`** prefers the rollup; **`OVERVIEW_GLOBAL_STATS_LIVE=1`** or a zero rollup with recent swaps still triggers the old live query. **`pair_count`** stays a live **`COUNT(*)`** from **`pairs`**. > > Adds migration **`20260605120000_global_stats_24h_rollup.sql`**, operator runbook **`docs/runbooks/overview-global-stats-brin.md`** (BRIN as safety net for live fallback), updated invariants/skills, and expanded **`indexer_overview_global_stats`** tests. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e817be2ae48b4df4cc38c8aa5e0c9b9fbb103959. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
PlasticDigits commented 2026-06-05 13:58:03 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 13:58:06 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 8fd57cba - test(indexer): fix BigDecimal zero comparison in overview rollup test

Compare with previous version

added 1 commit <ul><li>8fd57cba - test(indexer): fix BigDecimal zero comparison in overview rollup test</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/96/diffs?diff_id=1836859697&start_sha=6899d0f69f0a3e036387b3f69b7405ebf15f7d92)
PlasticDigits commented 2026-06-05 13:58:11 +00:00 (Migrated from gitlab.com)

mentioned in issue #333

mentioned in issue #333
ghost1 commented 2026-06-05 13:58:12 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 13:58:19 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-05 13:59:18 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d (includes 6899d0f feat + 8fd57cb test fix)

Scope: global_stats_24h materialized rollup for GET /api/v1/overview cache-miss path — migration, refresh_global_stats / get_global_stats (rollup + optional OVERVIEW_GLOBAL_STATS_LIVE live fallback), volume-aggregator + poller startup refresh, docs/runbook, integration tests.

Method: Traced /api/v1/overview → volume::get_global_stats; reviewed new SQL (parameterized only), migration constraints, background refresh wiring, and whether any attacker-controlled input reaches a new sink.

Outcome: FINDINGS: 0 medium+

No inline threads — nothing met the bar for a reportable issue on this diff.

Notes (non-findings)

  • DoS: This change reduces cache-miss cost (O(1) PK read on global_stats_24h vs live swap_events aggregate). Existing 60s whole-response cache unchanged.
  • Injection: New queries use bound parameters ($1); no user/query-string input in SQL.
  • OVERVIEW_GLOBAL_STATS_LIVE: Operator env only (not HTTP/config surface); re-enables live scan for debug — misconfiguration risk is ops-side, not a remote exploit path introduced here.
  • Integrity / freshness: Up to ~5 min rollup lag is documented product behavior, not an authz or injection issue. pair_count remains a live COUNT(*) on pairs (unchanged pattern).
  • Auth / disclosure: /overview stays a public read-only stats endpoint; errors still routed via internal_err.
## Security review **Commit reviewed:** `8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d` (includes `6899d0f` feat + `8fd57cb` test fix) **Scope:** `global_stats_24h` materialized rollup for `GET /api/v1/overview` cache-miss path — migration, `refresh_global_stats` / `get_global_stats` (rollup + optional `OVERVIEW_GLOBAL_STATS_LIVE` live fallback), volume-aggregator + poller startup refresh, docs/runbook, integration tests. **Method:** Traced `/api/v1/overview` → `volume::get_global_stats`; reviewed new SQL (parameterized only), migration constraints, background refresh wiring, and whether any attacker-controlled input reaches a new sink. **Outcome:** `FINDINGS: 0` medium+ No inline threads — nothing met the bar for a reportable issue on this diff. ### Notes (non-findings) - **DoS:** This change **reduces** cache-miss cost (O(1) PK read on `global_stats_24h` vs live `swap_events` aggregate). Existing **60s** whole-response cache unchanged. - **Injection:** New queries use bound parameters (`$1`); no user/query-string input in SQL. - **`OVERVIEW_GLOBAL_STATS_LIVE`:** Operator env only (not HTTP/config surface); re-enables live scan for debug — misconfiguration risk is ops-side, not a remote exploit path introduced here. - **Integrity / freshness:** Up to ~5 min rollup lag is documented product behavior, not an authz or injection issue. `pair_count` remains a live `COUNT(*)` on `pairs` (unchanged pattern). - **Auth / disclosure:** `/overview` stays a public read-only stats endpoint; errors still routed via `internal_err`.
PlasticDigits commented 2026-06-05 13:59:22 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d (test(indexer): fix BigDecimal zero comparison in overview rollup test)

Diff scope: e41f61b..8fd57cb (10 files) — global_stats_24h materialized rollup, refresh_global_stats / get_global_stats read path, volume-aggregator + poller refresh, optional OVERVIEW_GLOBAL_STATS_LIVE=1 live aggregate, runbook/docs/tests.

Outcome: FINDINGS: 0 (no medium, high, or critical issues on this diff)

Summary

Security review: no medium+ findings on this diff.

Reviewed attacker-controlled inputs on the changed paths: GET /api/v1/overview still has no query/body parameters; the handler only calls volume::get_global_stats and existing asset/oracle reads. New SQL (refresh_global_stats, rollup SELECT) uses bound parameters only ($1 cutoff); no string concatenation from HTTP.

OVERVIEW_GLOBAL_STATS_LIVE is process environment only (not client-settable). Mis-setting it in production could restore the pre-#333 swap_events aggregate (DoS/perf regression), but that requires operator config access and is documented as debug/parity-only in the runbook.

The change reduces unauthenticated DoS surface on /overview cache miss (O(1) global_stats_24h PK read vs scanning swap_events). Rollup staleness (~5 min) affects public market-stat accuracy, not authn/authz or fund safety.

Inline threads: none (no findings to anchor on diff lines).


Automated security review (MR webhook).

## Security review **Commit reviewed:** `8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d` (`test(indexer): fix BigDecimal zero comparison in overview rollup test`) **Diff scope:** `e41f61b..8fd57cb` (10 files) — `global_stats_24h` materialized rollup, `refresh_global_stats` / `get_global_stats` read path, volume-aggregator + poller refresh, optional `OVERVIEW_GLOBAL_STATS_LIVE=1` live aggregate, runbook/docs/tests. **Outcome:** **FINDINGS: 0** (no medium, high, or critical issues on this diff) ### Summary Security review: **no medium+ findings** on this diff. Reviewed attacker-controlled inputs on the changed paths: `GET /api/v1/overview` still has no query/body parameters; the handler only calls `volume::get_global_stats` and existing asset/oracle reads. New SQL (`refresh_global_stats`, rollup `SELECT`) uses bound parameters only (`$1` cutoff); no string concatenation from HTTP. `OVERVIEW_GLOBAL_STATS_LIVE` is process environment only (not client-settable). Mis-setting it in production could restore the pre-#333 `swap_events` aggregate (DoS/perf regression), but that requires operator config access and is documented as debug/parity-only in the runbook. The change **reduces** unauthenticated DoS surface on `/overview` cache miss (O(1) `global_stats_24h` PK read vs scanning `swap_events`). Rollup staleness (~5 min) affects public market-stat accuracy, not authn/authz or fund safety. **Inline threads:** none (no findings to anchor on diff lines). --- *Automated security review (MR webhook).*
ghost1 commented 2026-06-05 13:59:46 +00:00 (Migrated from gitlab.com)

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Reviewed by Cursor Bugbot for commit 8fd57cbaf6. Configure here.

<!-- BUGBOT_REVIEW --> Cursor Bugbot has reviewed your changes and found 1 potential issue. <!-- BUGBOT_FIX_ALL --> <a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9BTExfSU5fQ1VSU09SIiwiZGF0YSI6eyJyZWRpc0tleSI6ImJ1Z2JvdC1tdWx0aToyMzlmNTExYy1lZWU3LTQ4YzgtYTE4ZS05M2Y5YmU4NmU1OGEiLCJlbmNyeXB0aW9uS2V5IjoiLUl1SVZYeFA4NllCTDFheVZiSi1lU1JfWVpOYjdVMWNKVDR2Rl83bEpObyIsImJyYW5jaCI6ImN1cnNvci9naXRsYWItaXNzdWUtd29ya2Zsb3ctMjgzNCIsInJlcG9Pd25lciI6IlBsYXN0aWNEaWdpdHMiLCJyZXBvTmFtZSI6ImNsOHktZGV4LXRlcnJhY2xhc3NpYyJ9fQ" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix All in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a> <!-- /BUGBOT_FIX_ALL --> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_BEGIN --> <sup>Bugbot Autofix is [ON](https://www.cursor.com/dashboard/bugbot). A cloud agent has been kicked off to fix the reported issue. <!-- BUGBOT_AUTOFIX_AGENT_LINK --></sup> <!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END --> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-05 13:59:49 +00:00 (Migrated from gitlab.com)

Overview zeros before first refresh

Medium Severity

After the new migration, get_global_stats serves the seeded global_stats_24h row (zeros) on /overview cache misses until refresh_global_stats finishes. The API task starts in parallel with the indexer, so early requests—and the 60s overview cache—can show zero volume and trades while swap_events already has data.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8fd57cbaf6. Configure here.

### Overview zeros before first refresh **Medium Severity** <!-- DESCRIPTION START --> After the new migration, `get_global_stats` serves the seeded `global_stats_24h` row (zeros) on `/overview` cache misses until `refresh_global_stats` finishes. The API task starts in parallel with the indexer, so early requests—and the 60s overview cache—can show zero volume and trades while `swap_events` already has data. <!-- DESCRIPTION END --> <!-- BUGBOT_BUG_ID: 49d4120c-3ce8-46dc-8e3a-22d9b9b8a8d2 --> <!-- LOCATIONS START indexer/src/db/queries/volume.rs#L170-L198 indexer/migrations/20260605120000_global_stats_24h_rollup.sql#L4-L13 LOCATIONS END --> <details> <summary>Additional Locations (1)</summary> - [`indexer/migrations/20260605120000_global_stats_24h_rollup.sql#L4-L13`](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-//blob/8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d/indexer/migrations/20260605120000_global_stats_24h_rollup.sql#L4-L13) </details> <div><a href="https://cursor.com/open?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90Ojg1YWM4OGQzLTdmNmYtNGQxMC1iYjI4LTVlM2ZjNzc3ZmQ1NCIsImVuY3J5cHRpb25LZXkiOiI5NHY4b1g2UFU4QjZ4VndBM3hodVRKNE5FQ3YzWk1vWHhXSEh1T3NmbVFFIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0yODM0IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIn19" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-cursor-light.png"><img alt="Fix in Cursor" width="115" height="28" src="https://cursor.com/assets/images/fix-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?link=eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9XRUIiLCJkYXRhIjp7InJlZGlzS2V5IjoiYnVnYm90Ojg1YWM4OGQzLTdmNmYtNGQxMC1iYjI4LTVlM2ZjNzc3ZmQ1NCIsImVuY3J5cHRpb25LZXkiOiI5NHY4b1g2UFU4QjZ4VndBM3hodVRKNE5FQ3YzWk1vWHhXSEh1T3NmbVFFIiwiYnJhbmNoIjoiY3Vyc29yL2dpdGxhYi1pc3N1ZS13b3JrZmxvdy0yODM0IiwicmVwb093bmVyIjoiUGxhc3RpY0RpZ2l0cyIsInJlcG9OYW1lIjoiY2w4eS1kZXgtdGVycmFjbGFzc2ljIiwicHJOdW1iZXIiOjk2LCJjb21taXRTaGEiOiI4ZmQ1N2NiYWY2OGQ5OGNlMjQ1M2UwY2I5NTNjYWQzYzFlYTE4NTlkIiwicHJvdmlkZXIiOiJnaXRsYWIiLCJob3N0bmFtZSI6ImdpdGxhYi5jb20ifX0" target="_blank" rel="noopener noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/fix-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/fix-in-web-light.png"><img alt="Fix in Web" width="99" height="28" src="https://cursor.com/assets/images/fix-in-web-dark.png"></picture></a></div> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
ghost1 commented 2026-06-05 14:06:48 +00:00 (Migrated from gitlab.com)

added 1 commit

  • 91c041a7 - fix(indexer): fall back to live global stats when rollup is uninitialized

Compare with previous version

added 1 commit <ul><li>91c041a7 - fix(indexer): fall back to live global stats when rollup is uninitialized</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/96/diffs?diff_id=1836880551&start_sha=8fd57cbaf68d98ce2453e0cb953cad3c1ea1859d)
PlasticDigits commented 2026-06-05 14:08:41 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 91c041a74063dddbc9ab70153eef9f9450623bc7 (fix(indexer): fall back to live global stats when rollup is uninitialized)

Diff scope: e41f61b..91c041a — global_stats_24h materialized rollup for GET /api/v1/overview cache-miss path; refresh_global_stats / get_global_stats (rollup + uninitialized fallback + optional OVERVIEW_GLOBAL_STATS_LIVE=1 live path); volume-aggregator + poller startup refresh; runbook/docs/tests.

Method: Re-read prior security-review notes on this MR (reviews at 8fd57cb). Traced /api/v1/overview → volume::get_global_stats; reviewed new SQL (parameterized only), migration constraints (CHECK (id = 1)), background refresh wiring, and the new total_trades == 0 + EXISTS fallback added in 91c041a. Verified no HTTP/query/body input reaches SQL or env toggles.

Outcome: FINDINGS: 0 medium+

Security review: no medium+ findings on this diff.

Inline threads: none (no findings to anchor on diff lines).

Notes (non-findings)

  • Prior review still applies: Rollup read path remains O(1) with bound parameters; /overview is unchanged public read-only with 60s whole-response cache and global per-IP rate limiting.
  • 91c041a fallback: When the seeded rollup row still shows total_trades = 0 but swap_events has rows in the 24h window, the handler runs a cheap EXISTS then falls back to get_global_stats_live. This restores pre-rollup accuracy during startup/degraded refresh — not an attacker-controllable sink (global_stats_24h is indexer-written only; swap rows come from chain ingestion, not HTTP).
  • DoS: Steady-state cache misses are cheaper than pre-#333. The fallback can re-enable the live aggregate at most once per 60s cache TTL during the brief uninitialized window (or if refresh_global_stats persistently fails — ops/DB issue). That is not worse than the pre-MR cache-miss path and is bounded by existing rate limits.
  • OVERVIEW_GLOBAL_STATS_LIVE: Process environment only; misconfiguration is operator-side, not a remote exploit path.
  • Integrity / freshness: Up to ~5 min rollup lag and documented staleness affect public market-stat accuracy, not authn/authz or fund safety.

Automated security review (MR webhook).

## Security review **Commit reviewed:** `91c041a74063dddbc9ab70153eef9f9450623bc7` (`fix(indexer): fall back to live global stats when rollup is uninitialized`) **Diff scope:** `e41f61b..91c041a` — `global_stats_24h` materialized rollup for `GET /api/v1/overview` cache-miss path; `refresh_global_stats` / `get_global_stats` (rollup + uninitialized fallback + optional `OVERVIEW_GLOBAL_STATS_LIVE=1` live path); volume-aggregator + poller startup refresh; runbook/docs/tests. **Method:** Re-read prior security-review notes on this MR (reviews at `8fd57cb`). Traced `/api/v1/overview` → `volume::get_global_stats`; reviewed new SQL (parameterized only), migration constraints (`CHECK (id = 1)`), background refresh wiring, and the new `total_trades == 0` + `EXISTS` fallback added in `91c041a`. Verified no HTTP/query/body input reaches SQL or env toggles. **Outcome:** `FINDINGS: 0` medium+ Security review: **no medium+ findings** on this diff. **Inline threads:** none (no findings to anchor on diff lines). ### Notes (non-findings) - **Prior review still applies:** Rollup read path remains O(1) with bound parameters; `/overview` is unchanged public read-only with 60s whole-response cache and global per-IP rate limiting. - **`91c041a` fallback:** When the seeded rollup row still shows `total_trades = 0` but `swap_events` has rows in the 24h window, the handler runs a cheap `EXISTS` then falls back to `get_global_stats_live`. This restores pre-rollup accuracy during startup/degraded refresh — not an attacker-controllable sink (`global_stats_24h` is indexer-written only; swap rows come from chain ingestion, not HTTP). - **DoS:** Steady-state cache misses are cheaper than pre-#333. The fallback can re-enable the live aggregate at most once per 60s cache TTL during the brief uninitialized window (or if `refresh_global_stats` persistently fails — ops/DB issue). That is not worse than the pre-MR cache-miss path and is bounded by existing rate limits. - **`OVERVIEW_GLOBAL_STATS_LIVE`:** Process environment only; misconfiguration is operator-side, not a remote exploit path. - **Integrity / freshness:** Up to ~5 min rollup lag and documented staleness affect public market-stat accuracy, not authn/authz or fund safety. --- *Automated security review (MR webhook).*
ghost1 commented 2026-06-05 14:39:22 +00:00 (Migrated from gitlab.com)

mentioned in commit e817be2ae4

mentioned in commit e817be2ae48b4df4cc38c8aa5e0c9b9fbb103959
ghost1 commented 2026-06-05 14:39:23 +00:00 (Migrated from gitlab.com)

added 1 commit

  • e817be2a - test(indexer): regression for uninitialized global_stats_24h rollup

Compare with previous version

added 1 commit <ul><li>e817be2a - test(indexer): regression for uninitialized global_stats_24h rollup</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/96/diffs?diff_id=1836954424&start_sha=91c041a74063dddbc9ab70153eef9f9450623bc7)
PlasticDigits commented 2026-06-05 14:39:29 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
ghost1 commented 2026-06-05 14:39:36 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-05 14:41:03 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: e817be2ae48b4df4cc38c8aa5e0c9b9fbb103959 (test(indexer): regression for uninitialized global_stats_24h rollup)

Diff scope: e41f61b..e817be2 — global_stats_24h materialized rollup for GET /api/v1/overview cache-miss path; refresh_global_stats / get_global_stats (rollup read + uninitialized fallback + optional OVERVIEW_GLOBAL_STATS_LIVE=1 live path); migration backfill on upgrade; volume-aggregator + poller startup refresh; runbook/docs/tests.

Method: Re-read prior security-review notes on this MR (reviews at 8fd57cb, 91c041a; inline thread on uninitialized rollup zeros — resolved). Traced /api/v1/overview → volume::get_global_stats; reviewed new SQL (parameterized only), migration constraints (CHECK (id = 1)), background refresh wiring, total_trades == 0 + EXISTS fallback (91c041a), and migration backfill (e817be2). Verified no HTTP/query/body input reaches SQL or env toggles.

Outcome: FINDINGS: 0 medium+

Security review: no medium+ findings on this diff.

Inline threads: none (no findings to anchor on diff lines).

Notes (non-findings)

  • Prior inline finding (uninitialized rollup zeros): Addressed by migration backfill (e817be2) and runtime fallback to get_global_stats_live when rollup total_trades = 0 but recent swaps exist (91c041a). Not re-reported.
  • Read path: Steady-state cache misses are O(1) rollup fetch with bound parameters; /overview remains public read-only with 60s whole-response cache and global per-IP rate limiting.
  • DoS: Rollup path is strictly cheaper than pre-#333 live aggregate. Fallback to live query is bounded (startup/degraded refresh window, at most once per 60s cache TTL) and not attacker-controllable (global_stats_24h is indexer-written; swap_events rows come from chain ingestion).
  • OVERVIEW_GLOBAL_STATS_LIVE: Process environment only; misconfiguration is operator-side, not a remote exploit path.
  • Integrity / freshness: Up to ~5 min rollup lag and documented staleness affect public market-stat accuracy, not authn/authz or fund safety.

Automated security review (MR webhook).

## Security review **Commit reviewed:** `e817be2ae48b4df4cc38c8aa5e0c9b9fbb103959` (`test(indexer): regression for uninitialized global_stats_24h rollup`) **Diff scope:** `e41f61b..e817be2` — `global_stats_24h` materialized rollup for `GET /api/v1/overview` cache-miss path; `refresh_global_stats` / `get_global_stats` (rollup read + uninitialized fallback + optional `OVERVIEW_GLOBAL_STATS_LIVE=1` live path); migration backfill on upgrade; volume-aggregator + poller startup refresh; runbook/docs/tests. **Method:** Re-read prior security-review notes on this MR (reviews at `8fd57cb`, `91c041a`; inline thread on uninitialized rollup zeros — resolved). Traced `/api/v1/overview` → `volume::get_global_stats`; reviewed new SQL (parameterized only), migration constraints (`CHECK (id = 1)`), background refresh wiring, `total_trades == 0` + `EXISTS` fallback (`91c041a`), and migration backfill (`e817be2`). Verified no HTTP/query/body input reaches SQL or env toggles. **Outcome:** `FINDINGS: 0` medium+ Security review: **no medium+ findings** on this diff. **Inline threads:** none (no findings to anchor on diff lines). ### Notes (non-findings) - **Prior inline finding (uninitialized rollup zeros):** Addressed by migration backfill (`e817be2`) and runtime fallback to `get_global_stats_live` when rollup `total_trades = 0` but recent swaps exist (`91c041a`). Not re-reported. - **Read path:** Steady-state cache misses are O(1) rollup fetch with bound parameters; `/overview` remains public read-only with 60s whole-response cache and global per-IP rate limiting. - **DoS:** Rollup path is strictly cheaper than pre-#333 live aggregate. Fallback to live query is bounded (startup/degraded refresh window, at most once per 60s cache TTL) and not attacker-controllable (`global_stats_24h` is indexer-written; `swap_events` rows come from chain ingestion). - **`OVERVIEW_GLOBAL_STATS_LIVE`:** Process environment only; misconfiguration is operator-side, not a remote exploit path. - **Integrity / freshness:** Up to ~5 min rollup lag and documented staleness affect public market-stat accuracy, not authn/authz or fund safety. --- *Automated security review (MR webhook).*
PlasticDigits commented 2026-06-05 14:45:56 +00:00 (Migrated from gitlab.com)

mentioned in commit eb48e91095

mentioned in commit eb48e91095cf24a35ea6e78d5d886fa8e3f07d01
PlasticDigits (Migrated from gitlab.com) merged commit eb48e91095 into main 2026-06-05 14:45:56 +00:00
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit c6fa879c2c

mentioned in commit c6fa879c2c9b0f69296a48d38e6c437ae62c2f9e
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 8d74197226

mentioned in commit 8d74197226815c0ead6d5bd94bd338fbc0ccb553
PlasticDigits commented 2026-06-08 13:42:27 +00:00 (Migrated from gitlab.com)

mentioned in commit 76f09228c0

mentioned in commit 76f09228c00e1d825817a42044a387ec3a724345
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit f178056f36

mentioned in commit f178056f36d6ffdfdefa229e22a9331fd93efeec
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!814
No description provided.