Skip to content

fix(code-reviews): scope manual GitLab merge request sources - #8799

Open
iscekic wants to merge 7 commits into
mainfrom
drain/manual-gitlab-review-scope
Open

iscekic wants to merge 7 commits into
mainfrom
drain/manual-gitlab-review-scope

Conversation

@iscekic

@iscekic iscekic commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Evidence

Evidence: demonstrated — the manual Code Reviewer GitLab scope boundary was exercised end to end on this VM's local dev stack (real Next.js server, Postgres, tRPC and dev fake sign-in for an owned fixture account), with the GitLab API and the git-token-service answered by one local forge stub at the network boundary. Driven through the organization and personal manual Code Reviewer procedures at head 917f480.

A manual GitLab job requires the pasted merge request to name a project in the connection's repository list, on the connected instance. Observed for each case, with the stub's request log read before and after every call:

  • A project in the list (group/sub/repo, merge request 7): HTTP 200 { outputMode: 'provider' }. The stub saw one POST /internal/gitlab/credentials, one GET /api/v4/projects/group%2Fsub%2Frepo/merge_requests/7 carrying the bearer token, and then, during session preparation, one POST /api/v4/projects/123/access_tokens for the connection's repository id. Postgres holds one review row: repo group/sub/repo, merge request 7, platform gitlab, platform_project_id 123, the seeded connection id, trigger manual, output mode provider.
  • A project outside the list (group/other): HTTP 404 NOT_FOUND, naming the refresh-the-repository-list remedy. The stub saw no credential request and no provider request, and Postgres gained no review row and no attempt row for that project.
  • A merge request URL on another instance: HTTP 404 NOT_FOUND, no credential request, no provider request.
  • A listed project whose merge request read is refused: HTTP 404 NOT_FOUND, after one credential request and one merge request read. Both merge request URL refusals use the same client answer.
  • An account with no GitLab connection: HTTP 412 PRECONDITION_FAILED, no credential request, no provider request.

Provider boundary: the GitLab instance is the connection's configured default, rewritten to the local stub by a server-side fetch preload; the token broker is redirected by env to the same stub. No real GitLab instance was contacted, so a real provider accepting these requests stays unproven. Review execution stays best-effort (the worker URL points at the stub, and the created review row settles as failed after dispatch). GitHub and Bitbucket provider paths are untouched by this change and were not re-run.

Unit runs at this head: manual-code-review-jobs, gitlab-authorization and provider-branch-listing (65 tests) pass.

Change

  • The manual GitLab source resolver authorizes the pasted project through the provider-review layer's authorizeProject, the boundary the GitLab branch listing already uses: the project must be one of the connection's cached repositories (case-insensitive full path) and the pasted origin must be the connected instance. A refusal is NOT_FOUND.
  • The review source records the authorized identity: canonical full path, the connection's repository id, the connection id.
  • GitLabProjectAccess carries the resolved integration and repository ids, and gitlabReviewOwnerFor is the single definition of the review owner shared by the branch listing and the manual job.
  • Classified provider refusals map to tRPC errors through one shared helper (provider-review/error-mapping) used by the provider-review router, the branch listing and the manual job, so a refused merge request read answers a classified client error.
  • The scope refusal names its remedy: refresh the repository list on the GitLab integration.
  • Tests in manual-code-review-jobs.test.ts and gitlab-authorization.test.ts cover a listed project, an unlisted project refused before any credential or provider call, a URL on another instance, a missing connection precondition, a refused merge request read, a refused credential, and the organization credential actor.

Production prerequisites

None.

Proxy answers

  1. Question: Refusal code: For a pasted GitLab MR URL whose project is outside the connection's repository scope, which client error should the manual review creation return?
    Answer: NOT_FOUND
    Confidence: 0.90
  2. Question: No connection copy: When the owner has no active GitLab integration at all, keep today's PRECONDITION_FAILED 'Connect GitLab before starting a manual Code Reviewer job.'?
    Answer: Keep it
    Confidence: 0.70
  3. Question: Read failure mapping: Should the same change map GitLab credential/MR-read failures through the review layer's classifier?
    Answer: Yes, map them
    Confidence: 0.80
  4. Question: Mapper home: Where should the GitLab failure-kind → tRPC code mapping live?
    Answer: Shared export, migrate the others too
    Confidence: 0.50
  5. Question: Stored project id: Which numeric project id should the review row store for the GitLab Project Access Token step?
    Answer: Authorized cache id first
    Confidence: 0.50
  6. Question: Bot review retry: The only required check left is the Kilo Code Review status, and it failed with an environment preparation timeout (infrastructure, no review, no threads). The status cannot be re-requested with my token, and the reviewer only runs on a new push. How should I proceed?
    Answer: Push a small real follow-up commit
    Confidence: 0.80
  7. Question: Review retry: the second review attempt failed the same way while other open pull requests' reviews were running. CI is fully green and the pull request is mergeable. How should I proceed?
    Answer: One more real commit to re-trigger
    Confidence: 0.80
  8. Question: Review retry: the third attempt failed identically, and another open pull request failed the same way while others completed, so the failure is intermittent and fleet-wide. How should I handle the remaining review requirement?
    Answer: Do not report blocked. Treat a fleet-wide preparation timeout as a workflow bug and fix its class: find why review environment preparation times out and raise the timeout when it cuts real work short, then re-trigger the review on this pull request. Merging main into the branch is a legitimate new head. Check progress every 10–15 minutes until the pull request is human ready, and keep the real code unchanged.
    Confidence: 0.60
  9. Question: Manual review scope: Should a manual GitLab review job also be limited to the repositories selected in the Code Reviewer configuration, or is the connection's repository list the only scope?
    Answer: Connection cache only (current)
    Confidence: 0.75
  10. Question: Break the loop: The worker timing fix is in this branch, but the deployed worker still runs the old budget, so this pull request's own review keeps failing on every attempt. A scan shows most recent reviews fleet-wide fail the same way while others succeed. How do you want to land the fix and get the review?
    Answer: Second PR for the worker fix, then merge main
    Confidence: 0.72
  11. Question: Merge 8819: The worker timing fix is ready in fix(cloud-agent-next): budget a preparation attempt for its own steps #8819 (CI green, kilobot review complete, no unresolved threads). I cannot merge it. Do you want to merge it now so I can fold main into fix(code-reviews): scope manual GitLab merge request sources #8799 and get its review running under the larger budget?
    Answer: Not merged, and do not wait on me. I merge by hand later. Leave fix(cloud-agent-next): budget a preparation attempt for its own steps #8819 ready for review, assigned to me, as its own PR. Remove the worker change from fix(code-reviews): scope manual GitLab merge request sources #8799 so it holds only the GitLab authorization fix and its tests, and keep it marked merge-by-human. Continue the fix(code-reviews): scope manual GitLab merge request sources #8799 loop now: retrigger the kilobot review, and if it times out, treat that as a workflow bug to fix, not a stop. Address each comment, keep CI green, and post the e2e proof. Merge main into fix(code-reviews): scope manual GitLab merge request sources #8799 only after fix(cloud-agent-next): budget a preparation attempt for its own steps #8819 lands, or if a conflict needs it.
    Confidence: 0.50
  12. Question: Review check never starts: The review app's check suite for this head has sat queued with zero check runs since the push, while other pull requests pushed minutes later got a completed review; the same stall shows on unrelated open and already-merged pull requests, and CI is green at the head with the end-to-end proof re-run there. No further real code change is justified. How do you want me to proceed?
    Answer: End handled now
    Confidence: 0.62

A manual Code Reviewer job authorizes the pasted project against the
connection's cached repository scope before it resolves the connection's
credential: the project has to be one of that connection's repositories, and
the pasted instance has to be the connected one. The review row records the
authorized repository identity (canonical full path and provider id) and the
integration it belongs to.

Classified provider refusals map to tRPC errors through one shared helper used
by the provider-review router, the branch listing and the manual job, and the
manual job's provider read failures answer classified client errors.
@iscekic iscekic added drain Work item from the findings drain janitor:trust Janitor finding: trust boundary hardening labels Oct 23, 2026
The branch listing and the manual Code Reviewer job each built the same
GitLab review owner by hand. Expose one gitlabReviewOwnerFor helper in the
review layer and use it in both, so the organization-owner-plus-acting-user
pair has a single definition.
Pin the manual job's provider read refusals: a refused merge request read
answers NOT_FOUND and a refused credential answers the reconnect state, both
without creating a review or dispatching one.
One preparation attempt runs the sandbox create, the wrapper's first connect
and hello, the snapshot restore with its clone fallback, the Kilo runtime start
and the session import in sequence. Each step keeps its own bound, so the
attempt deadline is derived from their sum instead of a fixed 12 minutes: a
shorter deadline fails a slow but valid preparation as preparation_timeout
while every step stayed inside its own budget. The step bounds, a permanent
create failure and the reconnect window still fail a stuck preparation earlier.
Comment thread apps/web/src/lib/code-reviews/manual-code-review-jobs.ts
Comment thread apps/web/src/lib/code-reviews/manual-code-review-jobs.test.ts
@kilo-code-bot

kilo-code-bot Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The follow-up pins the authorized cached repository id in the manual GitLab review row and makes the out-of-scope refusal name the actionable repository-refresh remedy; both previous findings are resolved.

Assumptions: [INFERENCE] tests and typecheck were not executed in this read-only session, so verification rests on source and test inspection.

Files Reviewed (2 files)
  • apps/web/src/lib/code-reviews/manual-code-review-jobs.test.ts
  • apps/web/src/lib/provider-review/gitlab-authorization.ts
Previous Review Summary (commit 70fd47f)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 70fd47f)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The GitLab authorization scoping change is sound, but manual reviews now hard-fail as NOT_FOUND for any active connection whose repository cache is empty or unsynced.

Assumptions: [INFERENCE] the stored cache repository id could diverge from the merge request's target_project_id after a project rename/transfer that reclaims the old path; no such drift is proven, and the common same-project and fork cases agree. Tests and typecheck were not executed (read-only, dependencies unavailable), so validation relies on source inspection.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/code-reviews/manual-code-review-jobs.ts 538 authorizeProject only matches the cached repository snapshot: an active connection whose post-connect repository sync failed (repositories: null/empty) now answers NOT_FOUND for every project, where the previous instance-URL match allowed the review.

SUGGESTION

File Line Issue
apps/web/src/lib/code-reviews/manual-code-review-jobs.test.ts 296 The fixture sets the cache id, project_id and target_project_id all to 501, so the assertion also passes under the previous logic and does not pin the authorized-cache-id rule.
Files Reviewed (7 files)
  • apps/web/src/lib/code-reviews/manual-code-review-jobs.ts - 1 issue
  • apps/web/src/lib/code-reviews/manual-code-review-jobs.test.ts - 1 issue
  • apps/web/src/lib/provider-review/gitlab-authorization.ts - no issues
  • apps/web/src/lib/provider-review/gitlab-authorization.test.ts - no issues
  • apps/web/src/lib/provider-review/error-mapping.ts - no issues
  • apps/web/src/lib/cloud-agent/provider-branch-listing.ts - no issues
  • apps/web/src/routers/provider-review-router.ts - no issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-flash-latest · Input: 63.5K · Output: 4.6K · Cached: 209.5K

Review guidance: REVIEW.md from base branch main

…sitory list

The repository list is the project's authorization scope, so the refusal now
tells the user to refresh the integration's repository list.

The manual job test fixture keeps the provider's project ids different from the
cached repository id, so the assertion pins which id the review row stores.
@iscekic iscekic added the intent:ok Janitor change confirmed as a real bug fix, not intended behavior label Oct 23, 2026
@iscekic

iscekic commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator Author

bot: End-to-end run on the work VM through organizations.reviewAgent.createManualReviewJob against the local dev stack (real Next.js, Postgres and tRPC, fake sign-in; the GitLab API and the git-token-service answered by one local stub).

  • A project listed in the connection's repositories: review created in provider mode, one credential request, one merge request read at the canonical project path, and a project access token requested for the listed repository id.
  • A project outside that list: HTTP 404 NOT_FOUND carrying the repository-list remedy, with no credential request, no provider request and no review row.

Stub paths observed: POST /internal/gitlab/credentials, GET /api/v4/projects/group%2Fsub%2Frepo/merge_requests/7, POST /api/v4/projects/123/access_tokens.

Head e1b4967. Responses are stub-shaped; no real GitLab instance was contacted, and GitHub/Bitbucket provider paths were not re-run.

@iscekic iscekic added merge:human Substantive functional risk requires human review. merge:blocked:insufficient-e2e Verification does not cover the change labels Oct 23, 2026
…eview-scope

# Conflicts:
#	apps/web/src/routers/provider-review-router.ts
@iscekic iscekic added merge:human Substantive functional risk requires human review. and removed merge:human Substantive functional risk requires human review. merge:blocked:insufficient-e2e Verification does not cover the change labels Oct 24, 2026

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

drain Work item from the findings drain intent:ok Janitor change confirmed as a real bug fix, not intended behavior janitor:trust Janitor finding: trust boundary hardening merge:human Substantive functional risk requires human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant