Skip to content

fix: move read-only lookup routes (regions, brand-presence stats) to capability-gated access#2819

Merged
ravverma merged 5 commits into
mainfrom
read-only-org-end-point
Jul 15, 2026
Merged

fix: move read-only lookup routes (regions, brand-presence stats) to capability-gated access#2819
ravverma merged 5 commits into
mainfrom
read-only-org-end-point

Conversation

@ravverma

@ravverma ravverma commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

fix: move read-only lookup routes from INTERNAL_ROUTES to capability-gated access

Problem

Several read-only lookup endpoints were listed in INTERNAL_ROUTES, so they were only reachable through the internal/session-token path and did not go through the standard required-capability check. As a result, callers on the read-only admin org charter (RO-admin), who are granted the relevant read capabilities, could not reach these harmless reads.

Change

Move the following routes out of INTERNAL_ROUTES and into routeRequiredCapabilities (src/routes/required-capabilities.js), each gated behind the lowest read capability that fits:

Route Capability
GET /v2/regions organization:read
GET /org/:spaceCatId/brands/all/brand-presence/stats brand:read
GET /org/:spaceCatId/brands/:brandId/brand-presence/stats brand:read

The two brand-presence stats routes join their sibling brand-presence routes (filter-dimensions, weeks, sentiment-overview, etc.), which are already brand:read. GET /v2/regions is a global lookup table with no org scope, so organization:read is the appropriate least-privilege gate.

Why this is safe / low-risk

  • Read-only - all three are GETs on lookup/stats data. No writes, no new endpoints, no response-shape change.
  • Least-privilege reads - gated behind the minimal read capability (organization:read / brand:read) rather than left internal-only.
  • Consistent with existing routes - the brand-presence stats routes now match every other brand-presence endpoint's capability; /v2/regions uses the same organization:read pattern as other global reads.
  • No behavior change for existing internal callers - they already satisfy these read capabilities.

Note on access model

routeRequiredCapabilities is the shared map the S2S wrapper also consumes, so once a route has a capability, any consumer (session-token or S2S) holding that capability can call it. This is intended for these non-sensitive reads. The comments carried over from INTERNAL_ROUTES are updated/removed so they no longer claim "not for S2S consumers."

Testing

  • All modified lines covered (Codecov); eslint passes.
  • Only the authorization path for these routes changes; responses are unchanged.

@ravverma ravverma requested a review from MysticatBot July 15, 2026 07:12
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@MysticatBot MysticatBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ravverma,

⚠ Degraded review - no spec document was found for this change (searched the PR links, the touched repos' docs, the architecture/guidelines docs, and linked Jira). This review covers code-level quality but could not validate the change against an agreed design, so confidence is reduced. Add a spec link (PR template section 4) and re-request review for a full-confidence pass.

Verdict: Request changes - the carried-over comment contradicts the route's new access model.
Complexity: LOW - trivial diff; API surface signal.
Changes: Moves GET /v2/regions from INTERNAL_ROUTES to routeRequiredCapabilities with organization:read capability (1 file).
Note: Recommend a human read before merge - possible divergence from the documented design (heuristic, flagged by the conventions reviewer). The bot review is a complement to, not a replacement for, a human read here.

Must fix before merge

  1. [Important] Stale comment contradicts new access model - src/routes/required-capabilities.js:~256 (details inline)
Non-blocking (1): minor issues and suggestions
  • nit: PR title says "region" (singular) but the actual route is GET /v2/regions (plural) - may affect commit-history searchability.

Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 1m 51s | Cost: $2.69 | Commit: 355740ee8c824eac72e452ca7f11d02e9e18695a
If this code review was useful, please react with 👍. Otherwise, react with 👎.

Comment thread src/routes/required-capabilities.js
@MysticatBot MysticatBot added ai-reviewed Reviewed by AI complexity:low AI-assessed PR complexity: LOW needs-human-review AI reviewer recommends a human read before merge labels Jul 15, 2026
@ravverma ravverma changed the title fix: moving region end point to required capability with read fix: move GET /v2/regions to organization:read for the read-only admin charter Jul 15, 2026
@ravverma ravverma requested a review from MysticatBot July 15, 2026 07:26
The route now lives in routeRequiredCapabilities, which the S2S wrapper also
consumes, so it is reachable by any consumer holding organization:read. The
carried-over 'not for S2S consumers' note was stale and misleading.
@github-actions

Copy link
Copy Markdown

This PR will trigger a patch release when merged.

@ravverma ravverma requested review from MysticatBot and removed request for MysticatBot July 15, 2026 08:24

@MysticatBot MysticatBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ravverma,

⚠ Degraded review - no spec document was found for this change (searched the PR links, the touched repos' docs, the architecture/guidelines docs, and linked Jira). This review covers code-level quality but could not validate the change against an agreed design, so confidence is reduced. Add a spec link (PR template section 4) and re-request review for a full-confidence pass.

Verdict: Approve - prior finding addressed, change is clean and correctly scoped.
Complexity: LOW - trivial diff; API surface signal.
Changes: Moves GET /v2/regions from INTERNAL_ROUTES to routeRequiredCapabilities with organization:read capability (1 file).

Previously flagged, now resolved

  • Stale comment ("session-token authenticated, not for S2S consumers") now correctly describes the new access model.
  • PR title alignment with route path.

Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 0m 59s | Cost: $2.19 | Commit: 15455c85a9974d7736e1a2207aba460675f7d5a8
If this code review was useful, please react with 👍. Otherwise, react with 👎.

@MysticatBot MysticatBot removed the needs-human-review AI reviewer recommends a human read before merge label Jul 15, 2026
Move 'GET /org/:spaceCatId/brands/all/brand-presence/stats' and
'GET /org/:spaceCatId/brands/:brandId/brand-presence/stats' out of
INTERNAL_ROUTES into routeRequiredCapabilities with brand:read, matching the
sibling brand-presence routes (filter-dimensions, weeks, etc.).
@ravverma ravverma changed the title fix: move GET /v2/regions to organization:read for the read-only admin charter fix: move read-only lookup routes (regions, brand-presence stats) to capability-gated access Jul 15, 2026
@ravverma ravverma merged commit 312180b into main Jul 15, 2026
23 of 28 checks passed
@ravverma ravverma deleted the read-only-org-end-point branch July 15, 2026 08:54
solaris007 pushed a commit that referenced this pull request Jul 15, 2026
# [1.653.0](v1.652.1...v1.653.0) (2026-07-15)

### Bug Fixes

* move read-only lookup routes (regions, brand-presence stats) to capability-gated access ([#2819](#2819)) ([312180b](312180b))

### Features

* **prompts:** source-aware upsertPrompts + reject unregistered sources ([#2810](#2810)) ([04e9fc8](04e9fc8)), closes [#793](#793) [#793](#793) [#793](#793) [#793](#793) [#2692](#2692)
@solaris007

Copy link
Copy Markdown
Member

🎉 This PR is included in version 1.653.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-reviewed Reviewed by AI complexity:low AI-assessed PR complexity: LOW released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants