Priority: Medium · Area: Observability / exposure · Est. effort: 6–9 h
📌 Problem
src/routes/metrics.ts serves operational data — a MetricsSnapshot (metrics.ts:24) including counts such as "Total registered anchors, active or not" (:25) — plus a snapshot history endpoint returning { snapshots } (:116).
Both apiKeyAuth and rateLimiter guard only mutating methods; their shared MUTATING_METHODS set is POST, PUT, PATCH, DELETE. GET is therefore unauthenticated and unlimited on every route, including these.
Two consequences:
- Unauthenticated business intelligence. Anchor counts, liquidity totals and settlement volumes over time describe the operational state of the network. Whether that should be public is a decision nobody appears to have made explicitly — it is a side effect of the auth middleware only covering writes.
- Unbounded, unlimited history reads. A snapshot history endpoint with no rate limit is a cheap way to generate load, and depending on retention, a large response.
Establish the facts before proposing changes: what exactly the two endpoints return, whether history retention is bounded, and whether any field is sensitive.
🎯 Design decision required
State and defend:
- Public or protected? A metrics endpoint intended for a scraper inside the deployment boundary should not be internet-reachable unauthenticated; one intended as a public network-transparency feed legitimately is. Decide, and make the code reflect it.
- Granularity. If some fields are fine to expose and others are not, is the answer two endpoints, or field filtering by auth level? Argue it.
- Read-path limiting. Should
rateLimiter cover reads — here specifically, or globally? Note this overlaps the rate-limiter issue; coordinate and say which PR owns the change.
🧩 Requirements and context
- Do not change the metrics content without saying why; this is about exposure.
- If you protect the endpoint, provide a documented path for a legitimate scraper — a separate credential or a bound interface — so monitoring does not silently break.
- Any retention bound on snapshot history must be explicit and tested.
src/openapi.ts must reflect whatever auth requirement you land on.
- All 42 test files must pass.
🛠️ Suggested execution
- Document exactly what both endpoints return and whether history is bounded.
- Classify each field as safe-to-expose or not.
- Implement your decision.
- Add tests for the auth behaviour and the retention bound.
- Update the OpenAPI spec and the operator documentation.
✅ Acceptance criteria
🚫 Out of scope
- Adding new metrics.
- Building a monitoring stack.
- The general rate-limiter store work — separate issue.
🧪 Verification
npm ci
npm test src/routes
npm run lint && npm run build && npm test
📤 What your PR must include
- The endpoint response inventory and field classification.
- Your public-vs-protected decision.
- How a legitimate scraper still works.
- The retention-bound test.
Closes #<n>.
🔒 Security notes
The underlying issue is that "authenticate mutating methods only" was applied uniformly without asking what each read endpoint discloses. Aggregate operational metrics over time reveal volume, timing and participant counts — useful to an operator and equally useful to someone probing the network before targeting it. The specific fix matters less than making the exposure decision deliberately rather than inheriting it from middleware defaults.
📋 Guidelines
- Minimum 95% test coverage on changed lines
- Clear documentation
- Timeframe: 96 hours from assignment
- One logical change per commit; no merge commits
💬 Join our community
Working on this, or want to sanity-check your approach before you start? Come and ask — the maintainers are there and happy to help.
Telegram: https://t.me/Grainlify
Priority: Medium · Area: Observability / exposure · Est. effort: 6–9 h
📌 Problem
src/routes/metrics.tsserves operational data — aMetricsSnapshot(metrics.ts:24) including counts such as "Total registered anchors, active or not" (:25) — plus a snapshot history endpoint returning{ snapshots }(:116).Both
apiKeyAuthandrateLimiterguard only mutating methods; their sharedMUTATING_METHODSset isPOST, PUT, PATCH, DELETE.GETis therefore unauthenticated and unlimited on every route, including these.Two consequences:
Establish the facts before proposing changes: what exactly the two endpoints return, whether history retention is bounded, and whether any field is sensitive.
🎯 Design decision required
State and defend:
rateLimitercover reads — here specifically, or globally? Note this overlaps the rate-limiter issue; coordinate and say which PR owns the change.🧩 Requirements and context
src/openapi.tsmust reflect whatever auth requirement you land on.🛠️ Suggested execution
✅ Acceptance criteria
src/openapi.tsreflects the auth requirement.npm run lint,npm run buildandnpm testpass.🚫 Out of scope
🧪 Verification
📤 What your PR must include
Closes #<n>.🔒 Security notes
The underlying issue is that "authenticate mutating methods only" was applied uniformly without asking what each read endpoint discloses. Aggregate operational metrics over time reveal volume, timing and participant counts — useful to an operator and equally useful to someone probing the network before targeting it. The specific fix matters less than making the exposure decision deliberately rather than inheriting it from middleware defaults.
📋 Guidelines
💬 Join our community
Working on this, or want to sanity-check your approach before you start? Come and ask — the maintainers are there and happy to help.
Telegram: https://t.me/Grainlify