Fix MCP tools enumeration leak via non-uniform not-found errors
What does this MR do and why?
MCP tools leaked whether a private project or group exists. The shared ResourceFinder looked resources up without current_user scoping, and callers raised an "Access denied" message that differed from the "not found" one, so a caller could tell "exists but forbidden" from "does not exist" by comparing error strings. This folds authorization into the finders behind an ability: keyword so a missing record and a forbidden one raise the same "not found or inaccessible" error, applies the same treatment to merge request and work-item resolution, and standardizes every MCP tool's not-found message to that wording.
Details
ResourceFinder:find_project!/find_group!take anability:keyword (default:read_project/:read_group); after the DB lookup,Ability.allowed?is checked, and if the record is missing or the check fails, the sameStandardError "… not found or inaccessible"is raised.find_work_item_in_parent!is made uniform the same way.find_parent_by_id_or_path!delegates straight to the finders, and the now-redundantauthorize_parent_access!/can_read_parent?helpers are removed.- Merge request tools (
MergeRequestResolution): use the non-authorizingfind_projectand letMergeRequestsFinderscope bycurrent_user, so a missing project, an inaccessible project, and a missing or inaccessible merge request all raise the same error. - Analytics tracking scope (EE
CallTool): resolves its project/group with plain, non-authorizing lookups — the scope only feeds internal telemetry, never a response, so there is nothing to gate — and is memoized so a tool call's start and finish events share a single lookup. - Wording: all MCP tools (labels, wikis, jobs, pipelines, merge requests, commits) now use
"<resource> not found or inaccessible"for one consistent, non-leaking message.
References
- Closes https://gitlab.com/gitlab-org/gitlab/-/work_items/612800
- Related: !248744 (merged) (fixed
get_repository_file_tool.rbwith the same approach)
Screenshots or screen recordings
No UI changes - backend only.
How to set up and validate locally
- In a Rails console, create a private project and a user who is not a member.
- As that user, call a project-scoped MCP tool (or
find_project!(private_project.id.to_s)). - Observe the error is
"Project '<id>' not found or inaccessible"- identical to the error for a genuinely non-existent project ID, so the two cases cannot be told apart.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.