Skip to content

fix(server): normalize full repository URLs in GitLab lookups - #7862

Open
Exotic209093 wants to merge 1 commit into
pingdotgg:mainfrom
Exotic209093:fix/glab-full-url-lookup
Open

fix(server): normalize full repository URLs in GitLab lookups#7862
Exotic209093 wants to merge 1 commit into
pingdotgg:mainfrom
Exotic209093:fix/glab-full-url-lookup

Conversation

@Exotic209093

@Exotic209093 Exotic209093 commented Aug 22, 2026

Copy link
Copy Markdown

New-project GitLab lookup sent the entire pasted URL to \glab api projects/\ whenever the host wasn't a known one like gitlab.com, so self-hosted instances (e.g. sourcecontrol.example.com) failed on full URLs while bare \group/project\ worked.

This adds
ormalizeGitLabRepositoryPath, which parses any http(s) URL and extracts the owner/repo path generically instead of sniffing hostnames. It handles trailing slashes, .git\ suffixes, nested groups (GitLab supports them), and strips /-/...\ web UI sections, then encodes the result exactly as the bare-path case does.

Fixes #7849

ox-alpha via opencode


Note

Medium Risk
Touches orchestration interrupt handling (synthetic cancel events) and GitLab project-path parsing used for clone lookups. Logic is localized and covered by tests, but a bad parse or missed pending request could leave prompts stuck or look up the wrong project.

Overview
Two independent server fixes.

Turn interrupt now closes open user-input prompts after a successful provider interrupt. Some providers drop callbacks without a matching resolution event; the reactor scans thread activities for pending user-input.requested items and appends user-input.resolved with cancelled: true.

GitLab clone lookup no longer sends a full pasted URL to glab api projects/.... normalizeGitLabRepositoryPath extracts namespace/project from any http(s) host (self-hosted included), stripping .git, trailing slashes, nested groups, and /-/... web UI paths.

Reviewed by Cursor Bugbot for commit 64c0661. Configure here.

Note

Normalize full repository URLs in GitLabCli.getRepositoryCloneUrls

  • Adds normalizeGitLabRepositoryPath in GitLabCli.ts: trims input, parses HTTP(S) URLs, drops UI sections (segments starting with -), strips case-insensitive .git suffix, and returns the namespace/project path. Bare paths pass through unchanged.
  • GitLabCli.make.service.getRepositoryCloneUrls now encodes the normalized path instead of input.repository directly, so pasted clone URLs (including self-hosted) resolve correctly via glab api projects/<encoded path>.
  • Adds tests in GitLabCli.test.ts covering URL extraction, .git stripping, nested groups, UI subpaths, and bare-path passthrough.
  • Risk: callers passing repository inputs that previously relied on direct encoding of raw URLs will now hit the correct projects API path; malformed URLs that fail parsing fall back to the trimmed input.

Macroscope summarized 6133897.

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ba5addbd-f87b-4269-aa50-ce2c68947b09

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 22, 2026
yield* providerService.interruptTurn({ threadId: event.payload.threadId });
// Some providers discard their callbacks without emitting a matching
// resolution event. Close those requests after the interrupt succeeds.
yield* Effect.forEach(pendingUserInputRequests(thread.activities), ({ requestId, turnId }) =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium Layers/ProviderCommandReactor.ts:1267

Interrupts can produce duplicate terminal activities for the same user-input requestId: thread.activities is the pre-interrupt snapshot, while the provider may emit user-input.resolved during interruptTurn, so this loop still appends a synthetic cancellation for an already-resolved request. Re-read the thread after interruption and append cancellations only for requests that remain unresolved, or make the completion idempotent.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/Layers/ProviderCommandReactor.ts around line 1267:

Interrupts can produce duplicate terminal activities for the same user-input `requestId`: `thread.activities` is the pre-interrupt snapshot, while the provider may emit `user-input.resolved` during `interruptTurn`, so this loop still appends a synthetic cancellation for an already-resolved request. Re-read the thread after interruption and append cancellations only for requests that remain unresolved, or make the completion idempotent.


try {
const url = new URL(trimmed);
const segments = url.pathname.split("/").filter((segment) => segment.length > 0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High sourceControl/GitLabCli.ts:406

For a relative-root GitLab installation, normalizeGitLabRepositoryPath includes the instance base path in the project identifier: https://example.com/gitlab/group/project becomes gitlab/group/project instead of group/project, so getRepositoryCloneUrls queries the wrong project. Remove the host's configured GitLab base path before extracting the namespace/project path.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/sourceControl/GitLabCli.ts around line 406:

For a relative-root GitLab installation, `normalizeGitLabRepositoryPath` includes the instance base path in the project identifier: `https://example.com/gitlab/group/project` becomes `gitlab/group/project` instead of `group/project`, so `getRepositoryCloneUrls` queries the wrong project. Remove the host's configured GitLab base path before extracting the namespace/project path.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64c066175f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +405 to +406
const url = new URL(trimmed);
const segments = url.pathname.split("/").filter((segment) => segment.length > 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the pasted GitLab host during lookup

When a user is authenticated to multiple GitLab instances and pastes a URL whose host is not the host selected by glab for the current directory, this discards url.host, so URLs such as https://gitlab.example.com/group/project and https://gitlab.com/group/project invoke the same API command and can query the wrong instance. The lookup must carry the pasted host through to the glab invocation rather than using only the pathname.

Useful? React with 👍 / 👎.

Comment on lines +405 to +406
const url = new URL(trimmed);
const segments = url.pathname.split("/").filter((segment) => segment.length > 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for GitLab installations hosted below an origin path

For a self-hosted instance configured under a relative URL root, such as https://example.com/gitlab, the valid project URL https://example.com/gitlab/group/project is normalized to gitlab/group/project; the API project identifier is actually group/project, so the lookup still fails for this supported self-hosted layout. The installation prefix needs to be distinguished from the repository namespace instead of treating every pathname segment as part of the project ID.

Useful? React with 👍 / 👎.

Comment on lines +1264 to +1267
yield* providerService.interruptTurn({ threadId: event.payload.threadId });
// Some providers discard their callbacks without emitting a matching
// resolution event. Close those requests after the interrupt succeeds.
yield* Effect.forEach(pendingUserInputRequests(thread.activities), ({ requestId, turnId }) =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Split the provider interruption behavior from this GitLab fix

These lines introduce a separate production behavior change for every provider interruption, including synthetic user-input resolution and a dedicated reactor test, even though the stated change concerns GitLab repository URL lookup. Move this lifecycle change into its own focused change so it can be reviewed, tested, and reverted independently, as required by the repository's one-concern rule.

AGENTS.md reference: AGENTS.md:L119-L119

Useful? React with 👍 / 👎.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 64c0661. Configure here.

turnId,
createdAt: event.payload.createdAt,
}),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale interrupt cancels open prompts

Medium Severity

processTurnInterruptRequested loads thread activities once, then runs interruptTurn, then cancels every request still present in that snapshot. Providers that do emit a resolution during interrupt can already close the prompt, so this path still appends a later user-input.resolved with cancelled: true, producing a spurious cancellation after a real resolution.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 64c0661. Configure here.

@macroscopeapp

macroscopeapp Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — Adds GitLab URL normalization with tests. Unresolved comments identify design limitations: discarding the URL hostname could route multi-host users to the wrong GitLab instance, and relative-root installations produce incorrect paths. These behavioral concerns warrant human review.

Not approved because:

  • 2 blocking correctness issues found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@Exotic209093
Exotic209093 force-pushed the fix/glab-full-url-lookup branch from 64c0661 to 6133897 Compare August 22, 2026 01:38
@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

1 participant