Skip to content

fix(orb): session allowlist is missing 3 routes that explicitly document themselves as maintainer-session routes #8653

Description

@JSONbored

⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.

Context

src/api/routes.ts's canSessionAccessPath (lines 6097-6124) is a global pre-route allowlist that
runs in middleware (line 1207) for every non-operator browser session, before any route handler
executes. Three routes call requireRepoMaintainer/requireRepoWriteAccess internally (implying
they're meant to be reachable by a maintainer's browser session) and each carries a doc comment
claiming parity with an already-allowlisted sibling route — but none of the three has a matching
predicate in canSessionAccessPath:

  • automation-state (line 2874) — comment says "Maintainer-gated like /settings" (line 2872);
    /settings has isRepoSettingsPath in the allowlist, automation-state does not.
  • ams-miner-cohort (line 3133) — comment says "mirrors maintainer-noise above" (line 3131);
    maintainer-noise has isRepoMaintainerNoisePath in the allowlist, ams-miner-cohort does not.
  • pulls/:number/chat-qa (line 3331) — comment explicitly says it "exposes ... to
    apps/loopover-ui's maintainer panel" (line 3323). Confirmed live:
    apps/loopover-ui/src/components/site/app-panels/chat-qa-panel.tsx:59-67 calls this exact
    endpoint with credentials: "include" — real browser-session usage, not just a doc claim.

All three routes carry a /* v8 ignore next -- unauthorized requests are rejected by the auth middleware before reaching the handler. */ comment (lines 2877, 3136) asserting the
gate instanceof Response branch is unreachable — but for a real non-operator maintainer session,
it's the opposite branch (the coarse 403 from the missing allowlist entry) that fires, so the route
handler is never reached at all.

Verified untested: test/integration/api.test.ts:989-991 only exercises automation-state via a
static bearer token, never a session cookie. test/unit/maintainer-chat-qa.test.ts uses
createSessionForGitHubUser but only against /v1/app/maintainer-dashboard, never against the
chat-qa POST route itself. test/unit/access-boundary.test.ts — the exact regression-test file
for this class of bug (its own comment: "Before the fix this returned 403 insufficient_role at the
session allowlist" for validate-linked-issue/agent/pending-actions) — has no case for any of
these 3 routes.

Consequence: a logged-in maintainer using a real browser session (not the internal operator bearer
token) gets 403 insufficient_role on automation-state and ams-miner-cohort, and — critically —
using the Chat Q&A panel in the actual web dashboard fails outright for every maintainer.

Requirements

  • Add a matching predicate for each of the 3 routes to canSessionAccessPath, mirroring the pattern
    already used for isRepoSettingsPath (for /settings) and isRepoMaintainerNoisePath (for
    maintainer-noise).
  • Do not weaken the existing allowlist for any other route while making this change.

Deliverables

  • canSessionAccessPath allows a maintainer session to reach automation-state.
  • canSessionAccessPath allows a maintainer session to reach ams-miner-cohort.
  • canSessionAccessPath allows a maintainer session to reach pulls/:number/chat-qa.
  • New test cases added to test/unit/access-boundary.test.ts, following its own established
    template (session cookie via createSessionForGitHubUser, asserting 200 for a maintainer's
    own repo and 403 forbidden_repo for a different maintainer's repo), for all 3 routes.

All four Deliverables are required in the same PR.

Test Coverage Requirements

src/** is measured by codecov/patch (99%+ target, branch-counted). Each new test must exercise
both the "own repo" (allowed) and "other repo" (still rejected) branches for all 3 routes, matching
access-boundary.test.ts's existing template exactly.

Expected Outcome

A maintainer using a real browser session (not an internal operator token) can reach
automation-state, ams-miner-cohort, and the Chat Q&A panel for their own repo, matching what each
route's own doc comment already claims should work.

Links & Resources

  • src/api/routes.ts:6097-6124 (canSessionAccessPath), :1207 (middleware call site)
  • src/api/routes.ts:2872-2877 (automation-state), :3131-3136 (ams-miner-cohort), :3323-3331
    (pulls/:number/chat-qa)
  • apps/loopover-ui/src/components/site/app-panels/chat-qa-panel.tsx:59-67 (real browser call site)
  • test/unit/access-boundary.test.ts (existing regression-test file and template for this exact bug
    class)
  • See the related issue filed alongside this one for registration-readiness and
    gittensor-config-recommendation (a lower-confidence variant of the same root cause)

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions