Skip to content

[Fix] Brain proxy bypasses per-tool approval policies on the task path - #3089

Draft
roomote-roomote[bot] wants to merge 1 commit into
developfrom
fix/native-mcp-tool-approval-enforcement-0ljg5i4jowksz
Draft

roomote-roomote[bot] wants to merge 1 commit into
developfrom
fix/native-mcp-tool-approval-enforcement-0ljg5i4jowksz

Conversation

@roomote-roomote

@roomote-roomote roomote-roomote Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

​Opened on behalf of @mrubens. Follow up by mentioning @roomote-roomote, in the web UI, or in Slack.

Related issue

Raised by an internal security review of the per-tool integration approval work (#3069 / #3072 / #3076 / #3078); no separate tracking issue.

Why this PR exists

  • A maintainer explicitly invited this PR in the linked issue or discussion
  • I am a maintainer / this is internal Roomote work

What changed

The native-handler enforcement gap from that review was largely closed by #3103; this PR covers what remained after it landed.

  • Brain proxy opt-in. The Brain (gbrain) runs through createMcpProxy but never set toolApprovalIntegrationId, so per-tool ask / reject policies keyed to gbrain were still unenforced on the task execution path: a task sandbox holding a run token could call /api/mcp/gbrain directly and run a tool an admin had disabled. It now opts in through credential resolution, exactly the way linear.ts does, so the proxy's existing enforcement hook (including the Auto/shadow behavior from [Feat] Automatic approvals: a decision model risk-assesses tool calls nobody has made a choice about #3084) applies.
  • End-to-end coverage for the native guard. notion-tool-approvals.test.ts exercises the native-handler guard from [Improve] Consolidate MCP tool availability into approval modes #3103 through the real Notion handler: a reject policy refuses a task run's call with a 403 before any Notion API contact, an ask-first tool is held until the Session owner's approval claim succeeds, an unreadable claim fails closed, rejected tools disappear from tools/list, batch requests are refused while a block is in force, and the experiment-off path reads nothing and blocks nothing. Develop previously had only the guard's unit test.
  • Status preservation. The native guard's tools/list filter now preserves the upstream response status when it re-serializes the filtered payload instead of always returning 200.

How it was tested

  • The new Notion end-to-end suite (6 tests) plus the existing guard unit tests pass.
  • Full MCP handler suite passes: 929 tests, including the pre-existing tool-approval-enforcement tests.
  • pnpm --filter @roomote/api check-types passes; pre-push gates (oxlint, residual ESLint, check-types:fast, knip) pass.

Checklist

  • The PR title follows the repo convention: [Fix], [Feat], [Improve], [Refactor], [Docs], or [Chore] followed by a user-facing description
  • This PR is small and scoped to one change
  • pnpm lint and pnpm check-types pass locally
  • I added tests or included a clear manual validation note above
  • I removed secrets, tokens, private keys, and customer data from code, logs, and screenshots
  • If this change should appear in the changelog, I ran pnpm changeset

@roomote-community

roomote-community Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

No code issues found. See task

Reviewed dadad21

@roomote-roomote
roomote-roomote Bot marked this pull request as ready for review September 22, 2026 04:08
…ive enforcement end to end

The Brain proxy runs through createMcpProxy but never set
toolApprovalIntegrationId, so per-tool ask/reject policies keyed to gbrain
were unenforced on the task path. Opt in through credential resolution, the
same way linear does.

Also cover the native-handler guard end to end through the Notion handler
(reject refused before any upstream contact, ask held until the approval
claim succeeds, claim errors fail closed, rejected tools hidden from
tools/list, batch refused, experiment-off inert), and preserve the upstream
status when filtering a native tools/list response.
@roomote-roomote
roomote-roomote Bot force-pushed the fix/native-mcp-tool-approval-enforcement-0ljg5i4jowksz branch from 492c0d1 to dadad21 Compare September 22, 2026 19:11
@roomote-roomote roomote-roomote Bot changed the title [Fix] Per-tool approval policies are unenforced for native MCP integrations on the task path [Fix] Brain proxy bypasses per-tool approval policies on the task path Sep 22, 2026
@roomote-roomote roomote-roomote Bot assigned daniel-lxs and unassigned mrubens Sep 22, 2026
@daniel-lxs
daniel-lxs marked this pull request as draft September 23, 2026 16:53

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants