Skip to content

fix(mcp): scope GITTENSORY_MCP_TOKEN read access to the operator allowlist, not just write/manage #2455

Description

@JSONbored

Parent: #1936

Problem

#2274 scoped the static-token GITTENSORY_MCP_TOKEN write/manage MCP tool paths (requireRepoManageAccess, requireRepoApprovalQueueAccess) to an operator-configured repo allowlist. The read-access guards were left unscoped:

canAccessRepo/requireRepoAccess, requireContributorAccess, requireOperatorAccess, and requireWatchableRepo (src/mcp/server.ts ~line 2033 and surrounding) all unconditionally trust the shared static mcp identity — canAccessRepo returns true immediately whenever this.identity.kind !== "session", so the maintainer/owner/operator permission check (canLoginAccessRepo) is never invoked for a static-token caller.

GITTENSORY_MCP_TOKEN is an ordinary, end-user-obtainable CLI credential (see env.d.ts ~lines 141-146 and the #2274 commit message itself, which states this explicitly). As things stand, any holder of that token can:

  • call gittensory_get_repo_context / gittensory_get_issue_quality / gittensory_preflight_pr / gittensory_get_outcome_calibration / gittensory_validate_linked_issue / gittensory_get_maintainer_noise / gittensory_get_label_audit against a private repo they have no GitHub collaborator access to,
  • call gittensory_get_decision_pack / gittensory_get_contributor_profile / gittensory_monitor_open_prs for an arbitrary other login to pull that contributor's private decision pack (requireContributorAccess, ~lines 1769-1773, same session-only guard),
  • call gittensory_get_fleet_analytics (requireOperatorAccess, ~lines 2069-2074) to pull cross-instance operator-only fleet calibration data — the code comment there literally says "private-token / static identities are trusted," which is the opposite of the posture fix(mcp): scope the static MCP token to an operator-configured repo allowlist #2274 just established for the write path.

Fix

Extend the same allowlist-scoping pattern #2274 applied to requireRepoManageAccess/requireRepoApprovalQueueAccess to canAccessRepo/requireRepoAccess, requireContributorAccess, requireOperatorAccess, and requireWatchableRepo for the static mcp identity: deny by default, require an explicit operator opt-in — matching the rationale already documented at server.ts ~lines 1780-1784 and 1811.

Regression tests

  • A static-token call to each of the read-access tools listed above against a repo NOT on the allowlist is denied.
  • A static-token call against an allowlisted repo still succeeds (no regression for the intended broker/CLI use case).
  • Operator/fleet-analytics tools reject the static identity unless explicitly opted in, matching the write-path posture.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions