API: ai_workflows scope refuses the blobs/batch read, breaking no-clone repository access
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
Problem
API::Repositories admits the ai_workflows scope on GET and HEAD only:
# lib/api/repositories.rb:19
allow_access_with_scope :ai_workflows, if: ->(request) { request.get? || request.head? }POST :id/repository/blobs/batch is a read — the file list travels in the request
body because it does not fit in a query string — so a Duo workflow token is
refused with insufficient_scope on content the same scope can already read one
file at a time through GET files/:path/raw.
Evidence
Found while running the Duo developer flow with no working tree, reaching the
repository through the ws CLI instead of a clone. ws performed the whole task
— grep, cat x12, replace x5, diff — then both ws materialize and
ws checkpoint failed here:
POST .../repository/blobs/batch: 403 {error: insufficient_scope},
{error_description: The request requires higher privileges than provided by the
access token.}, {scope: ai_workflows api read_api}The agent then fell back to git clone, reapplied the same change by hand, and
opened the merge request that way. The run scored mr_created = 1 while the
no-clone write path was entirely broken — a false positive that is invisible
unless you read the tool calls.
Proposed fix
Admit the batch endpoint by path rather than widening the gate to POST in general, so no write route is affected:
allow_access_with_scope :ai_workflows, if: ->(request) do
request.get? || request.head? ||
(request.post? && request.path.end_with?('/repository/blobs/batch'))
endVerified: with this change ws checkpoint succeeded and returned a real commit
(20a3c40d, 3 files, +3/-3) with no clone anywhere in the run.
Context
Surfaced while measuring no-clone repository access for gitlab-org#23427