Apply AI file exclusions to add_commit MCP partial-edit reads

What does this MR do and why?

This is the second follow-up hardening the add_commit MCP server tool's partial-edit path (old_str/new_str).

Related to #622860 (closed).

Problem

Partial edits read the target file's full content through an internal helper, BlobsTool. BlobsTool reused the get_repository_file GraphQL query, but not GetRepositoryFileTool, so it skipped that tool's file_excluded? check. In EE, that check delegates to Ai::FileExclusionService, which enforces a project's Duo context-exclusion rules (files an admin has excluded from AI processing).

As a result, the partial-edit path could read the content of an excluded file server-side (to expand the edit), even though get_repository_file refuses to read it directly. GraphQL still enforced read_code, so this was not a raw permission escalation, but it defeated the AI context-exclusion control specifically.

Fix

BlobsTool#execute now checks the requested paths against exclusion rules before reading, via a new excluded_paths hook:

  • CE has no exclusions (returns none).
  • The EE override calls Ai::FileExclusionService — the same service GetRepositoryFileTool uses.
  • If any requested path is excluded, BlobsTool returns an error response naming the excluded path(s), and AddCommitService surfaces that as a partial-edit error instead of reading and committing the file.

The exclusion applies only to the partial-edit read path. Full-content commits (content) are unchanged — they overwrite without reading, so they were never in scope.

Scope of changes

  • app/services/mcp/tools/repositories/blobs_tool.rb — exclusion gate in execute, CE stub excluded_paths, prepend_mod
  • ee/app/services/ee/mcp/tools/repositories/blobs_tool.rb — EE excluded_paths override using Ai::FileExclusionService
  • ee/spec/services/ee/mcp/tools/repositories/blobs_tool_spec.rb — exclusion behavior (no rules, matched rule, negation re-include, partial match of multiple paths)
  • ee/spec/services/ee/mcp/tools/repositories/add_commit_service_spec.rb — end-to-end: partial edit on an excluded file does not commit and returns an error

How to set up and validate locally

  1. Configure a Duo context-exclusion rule for a file path in a project.
  2. Call add_commit with a partial edit (old_str/new_str) targeting that path.
  3. Confirm the tool returns an error and no commit is created.

30 examples pass across the CE/EE blobs and add_commit specs.

🤖 Generated with Claude Code

Edited by Jessie Young

Merge request reports

Loading
Loading