Repository navigation
fix(server): end clone options before the repository URL - #14781
Conversation
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a narrowly scoped Git argument-handling bug fix that preserves normal clone behavior and adds regression coverage for option-like local repository paths. It changes no schemas, defaults, deployment configuration, or sensitive code. You can add or adjust custom eligibility rules. Learn more. |
Dismissing prior approval to re-evaluate 75883b3
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review. 📝 WalkthroughWalkthrough
ChangesGit clone argument handling
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable merge-blocking risk is identified for this change. It is ready to merge after normal checks. Architecture SummaryArchitecture risk: 🔵 Low · up to The change affects 1 system. Changed systems: Architecture concerns Review detailsSystems and components
Before / after behavior
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
75883b3 to
bd5567c
Compare
Dismissing prior approval to re-evaluate bd5567c
bd5567c to
c7043ff
Compare
|
Review requested
Logged so this PR shows when a maintainer was asked to review it. |
Fork's SSH clone test expects upstream's `--` before the repository URL (pingdotgg#14781); upstream's JetBrains launcher tests used the pre-rename testLayer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
## What's Changed * refactor(server,relay): webhook capabilities live in services, not handlers by @juliusmarminge in pingdotgg/t3code#16232 * fix(server): a T3 Connect preferences save finishes even if the client disconnects by @juliusmarminge in pingdotgg/t3code#16266 * refactor(server): import service modules as namespaces, not aliased layers by @juliusmarminge in pingdotgg/t3code#16267 * feat(server): log how long PR watches stay quiet before they end by @t3dotgg in pingdotgg/t3code#16262 * feat(server,web): choose where new worktrees are created by @juliusmarminge in pingdotgg/t3code#16231 * perf(server): idle status polls and PR sweeps start fewer git processes by @t3dotgg in pingdotgg/t3code#16272 * perf(server): PR watches spend ~90% fewer GitHub points by checking a 1-point fingerprint first by @t3dotgg in pingdotgg/t3code#16270 * fix(pull-requests): PR detail reads no longer drain the GitHub quota by @t3dotgg in pingdotgg/t3code#16280 * refactor: layer variables are named layer or layerXyz by @juliusmarminge in pingdotgg/t3code#16282 * refactor(server): T3 Connect link capabilities live in a CloudLink service by @juliusmarminge in pingdotgg/t3code#16265 * fix(web): sidebar drag and drop no longer snaps back by @t3dotgg in pingdotgg/t3code#16291 * fix(web): inline HTML renders no longer trap the thread's scroll by @t3dotgg in pingdotgg/t3code#16283 * refactor(server): one module per service instead of Services/ and Layers/ folders by @juliusmarminge in pingdotgg/t3code#16295 * chore(review): configure CodeRabbit in TypeScript by @esthor in pingdotgg/t3code#16281 * docs: put the Effect and web UI review rules in the docs by @esthor in pingdotgg/t3code#16286 * chore(lint): require a reason on every lint and type-checker suppression by @esthor in pingdotgg/t3code#16294 * refactor(relay): import HookInboxObject once, as a namespace by @juliusmarminge in pingdotgg/t3code#16307 * fix(web): a rejected desktop-local credential is not retried every poll by @juliusmarminge in pingdotgg/t3code#16273 * feat(desktop): the renderer's bootstrap token rotates every 12 hours by @juliusmarminge in pingdotgg/t3code#16275 * fix(web): recover from a closed IndexedDB connection by @juliusmarminge in pingdotgg/t3code#16311 * fix(relay): stop forcing manual relay deploys by default by @juliusmarminge in pingdotgg/t3code#13563 * feat(relay): measure the managed tunnel backlog by @juliusmarminge in pingdotgg/t3code#13564 * feat(relay): clean up tunnels of hosts that never registered recovery by @juliusmarminge in pingdotgg/t3code#13565 * perf(relay): delete expired tunnels four at a time within a time budget by @juliusmarminge in pingdotgg/t3code#13566 * feat(connect): tell users when an idle tunnel was removed by @juliusmarminge in pingdotgg/t3code#13567 * docs(relay): add the legacy tunnel cleanup rollout runbook by @juliusmarminge in pingdotgg/t3code#13568 * chore(review): point CodeRabbit at the web UI conventions by @esthor in pingdotgg/t3code#16324 * chore(review): turn off CodeRabbit's docstring coverage check by @esthor in pingdotgg/t3code#16328 * refactor(server): CloudLink keeps only the link lifecycle; pure checks live beside it by @juliusmarminge in pingdotgg/t3code#16340 * refactor(server): CloudLink fails with its own errors; the connect routes map them to HTTP by @juliusmarminge in pingdotgg/t3code#16341 * refactor(server): replay guards stay in CloudLink by @juliusmarminge in pingdotgg/t3code#16349 * fix(server): forks no longer merge into their upstream repo's project group by @t3dotgg in pingdotgg/t3code#16353 * fix(server): stop the startup project sync from delaying the app window by @Mnigos in pingdotgg/t3code#14912 * fix(web): avoid blocking image preparation conversions by @Bil0000 in pingdotgg/t3code#13342 * fix(server): return partial workspace index on timeout by @Michel-Liao in pingdotgg/t3code#11500 * fix(server): probe project favicon candidates concurrently by @ishaanko in pingdotgg/t3code#12543 * fix(observability): a failing trace disk no longer stalls the server by @t3dotgg in pingdotgg/t3code#13758 * fix(server): status polling no longer locks the git index by @ahalekelly in pingdotgg/t3code#14718 * perf(shared): scan PATH once per command before spawning, not on every spawn by @SkiTee3000 in pingdotgg/t3code#12600 * fix(server): main's startup auto-pull test compiles again by @t3dotgg in pingdotgg/t3code#16357 * fix(server): project favicons stop being rescanned every minute by @t3dotgg in pingdotgg/t3code#16206 * fix(server): Claude limits load again for users with large transcript histories by @t3dotgg in pingdotgg/t3code#16358 * fix(server): caches and ids are written atomically by @juliusmarminge in pingdotgg/t3code#16242 * fix(server): one-shot initializers no longer race by @juliusmarminge in pingdotgg/t3code#16260 * fix(server): the PR cache sweep only removes real entry files by @juliusmarminge in pingdotgg/t3code#16285 * chore: keep one copy each of undici 8 and ws 8 by @juliusmarminge in pingdotgg/t3code#16211 * fix(shared): DrainableWorker keeps running after a failed item by @juliusmarminge in pingdotgg/t3code#16223 * fix(server): metrics count interrupted work on the monotonic clock by @juliusmarminge in pingdotgg/t3code#16207 * refactor(web): import connection storage as a namespace in its test by @juliusmarminge in pingdotgg/t3code#16315 * fix(contracts): trimmed IDs round-trip by @juliusmarminge in pingdotgg/t3code#16300 * fix(server): main's settings, keybindings and session tests compile again by @juliusmarminge in pingdotgg/t3code#16363 * chore(lint): catch known tags with Effect.catchTags by @esthor in pingdotgg/t3code#16361 * fix(observability): T3 Connect tracing stops at the relay boundary by @juliusmarminge in pingdotgg/t3code#16314 * fix(relay): error and deadline responses carry CORS headers by @juliusmarminge in pingdotgg/t3code#16253 * fix(web): bring back the live shimmer on work log rows by @juliusmarminge in pingdotgg/t3code#16372 * refactor: Effect code gets UUIDs and SHA-256 from Effect's Crypto by @esthor in pingdotgg/t3code#16377 * fix(relay): export traces through one tracer, one request span each by @juliusmarminge in pingdotgg/t3code#16382 * fix(server): Pi thread titles use linked PR context by @juliusmarminge in pingdotgg/t3code#16210 * fix(desktop): retry transient bearer bootstrap and degrade on session fetch failure by @jamesvillarrubia in pingdotgg/t3code#12919 * fix(server): avoid scanning completed history for pending secrets by @Yash-Singh1 in pingdotgg/t3code#16409 * fix(orchestration-v2): let Stop recover stalled runs by @Yash-Singh1 in pingdotgg/t3code#15442 * fix(release): resolve version-qualified catalog overrides by @Yash-Singh1 in pingdotgg/t3code#16411 * fix(web): type in front of bold that starts a composer line by @saphid in pingdotgg/t3code#13217 * fix(desktop): prevent browser screenshot filename collisions by @saphid in pingdotgg/t3code#14784 * fix(server): end clone options before the repository URL by @saphid in pingdotgg/t3code#14781 * fix(web): queued messages no longer split the composer notice stack by @tristanmanchester in pingdotgg/t3code#16400 * fix(server): reject invalid explicit Bitbucket repositories by @aravhawk in pingdotgg/t3code#15876 * fix: restore desktop and server typechecks on main by @Yash-Singh1 in pingdotgg/t3code#16415 * fix(shared): find versioned JetBrains macOS app bundles by @Sypher760-gif in pingdotgg/t3code#16246 * fix(server): OpenCode 2 threads get T3 Code's MCP tools by @nkoynov in pingdotgg/t3code#16142 * feat(preview): run the browser on the environment server by @maria-rcks in pingdotgg/t3code#15328 * fix: restore service references breaking ci by @maria-rcks in pingdotgg/t3code#16495 * fix(mcp): mark declared tool failures as errors by @maria-rcks in pingdotgg/t3code#15617 * fix(release): unblock nightly browser tests and cli builds by @maria-rcks in pingdotgg/t3code#16515 ## New Contributors * @esthor made their first contribution in pingdotgg/t3code#16281 * @ahalekelly made their first contribution in pingdotgg/t3code#14718 * @SkiTee3000 made their first contribution in pingdotgg/t3code#12600 * @jamesvillarrubia made their first contribution in pingdotgg/t3code#12919 * @Sypher760-gif made their first contribution in pingdotgg/t3code#16246 * @nkoynov made their first contribution in pingdotgg/t3code#16142 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261005.2702...v0.0.46-nightly.20261006.2735 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261006.2735
## What's Changed * refactor(server,relay): webhook capabilities live in services, not handlers by @juliusmarminge in pingdotgg/t3code#16232 * fix(server): a T3 Connect preferences save finishes even if the client disconnects by @juliusmarminge in pingdotgg/t3code#16266 * refactor(server): import service modules as namespaces, not aliased layers by @juliusmarminge in pingdotgg/t3code#16267 * feat(server): log how long PR watches stay quiet before they end by @t3dotgg in pingdotgg/t3code#16262 * feat(server,web): choose where new worktrees are created by @juliusmarminge in pingdotgg/t3code#16231 * perf(server): idle status polls and PR sweeps start fewer git processes by @t3dotgg in pingdotgg/t3code#16272 * perf(server): PR watches spend ~90% fewer GitHub points by checking a 1-point fingerprint first by @t3dotgg in pingdotgg/t3code#16270 * fix(pull-requests): PR detail reads no longer drain the GitHub quota by @t3dotgg in pingdotgg/t3code#16280 * refactor: layer variables are named layer or layerXyz by @juliusmarminge in pingdotgg/t3code#16282 * refactor(server): T3 Connect link capabilities live in a CloudLink service by @juliusmarminge in pingdotgg/t3code#16265 * fix(web): sidebar drag and drop no longer snaps back by @t3dotgg in pingdotgg/t3code#16291 * fix(web): inline HTML renders no longer trap the thread's scroll by @t3dotgg in pingdotgg/t3code#16283 * refactor(server): one module per service instead of Services/ and Layers/ folders by @juliusmarminge in pingdotgg/t3code#16295 * chore(review): configure CodeRabbit in TypeScript by @esthor in pingdotgg/t3code#16281 * docs: put the Effect and web UI review rules in the docs by @esthor in pingdotgg/t3code#16286 * chore(lint): require a reason on every lint and type-checker suppression by @esthor in pingdotgg/t3code#16294 * refactor(relay): import HookInboxObject once, as a namespace by @juliusmarminge in pingdotgg/t3code#16307 * fix(web): a rejected desktop-local credential is not retried every poll by @juliusmarminge in pingdotgg/t3code#16273 * feat(desktop): the renderer's bootstrap token rotates every 12 hours by @juliusmarminge in pingdotgg/t3code#16275 * fix(web): recover from a closed IndexedDB connection by @juliusmarminge in pingdotgg/t3code#16311 * fix(relay): stop forcing manual relay deploys by default by @juliusmarminge in pingdotgg/t3code#13563 * feat(relay): measure the managed tunnel backlog by @juliusmarminge in pingdotgg/t3code#13564 * feat(relay): clean up tunnels of hosts that never registered recovery by @juliusmarminge in pingdotgg/t3code#13565 * perf(relay): delete expired tunnels four at a time within a time budget by @juliusmarminge in pingdotgg/t3code#13566 * feat(connect): tell users when an idle tunnel was removed by @juliusmarminge in pingdotgg/t3code#13567 * docs(relay): add the legacy tunnel cleanup rollout runbook by @juliusmarminge in pingdotgg/t3code#13568 * chore(review): point CodeRabbit at the web UI conventions by @esthor in pingdotgg/t3code#16324 * chore(review): turn off CodeRabbit's docstring coverage check by @esthor in pingdotgg/t3code#16328 * refactor(server): CloudLink keeps only the link lifecycle; pure checks live beside it by @juliusmarminge in pingdotgg/t3code#16340 * refactor(server): CloudLink fails with its own errors; the connect routes map them to HTTP by @juliusmarminge in pingdotgg/t3code#16341 * refactor(server): replay guards stay in CloudLink by @juliusmarminge in pingdotgg/t3code#16349 * fix(server): forks no longer merge into their upstream repo's project group by @t3dotgg in pingdotgg/t3code#16353 * fix(server): stop the startup project sync from delaying the app window by @Mnigos in pingdotgg/t3code#14912 * fix(web): avoid blocking image preparation conversions by @Bil0000 in pingdotgg/t3code#13342 * fix(server): return partial workspace index on timeout by @Michel-Liao in pingdotgg/t3code#11500 * fix(server): probe project favicon candidates concurrently by @ishaanko in pingdotgg/t3code#12543 * fix(observability): a failing trace disk no longer stalls the server by @t3dotgg in pingdotgg/t3code#13758 * fix(server): status polling no longer locks the git index by @ahalekelly in pingdotgg/t3code#14718 * perf(shared): scan PATH once per command before spawning, not on every spawn by @SkiTee3000 in pingdotgg/t3code#12600 * fix(server): main's startup auto-pull test compiles again by @t3dotgg in pingdotgg/t3code#16357 * fix(server): project favicons stop being rescanned every minute by @t3dotgg in pingdotgg/t3code#16206 * fix(server): Claude limits load again for users with large transcript histories by @t3dotgg in pingdotgg/t3code#16358 * fix(server): caches and ids are written atomically by @juliusmarminge in pingdotgg/t3code#16242 * fix(server): one-shot initializers no longer race by @juliusmarminge in pingdotgg/t3code#16260 * fix(server): the PR cache sweep only removes real entry files by @juliusmarminge in pingdotgg/t3code#16285 * chore: keep one copy each of undici 8 and ws 8 by @juliusmarminge in pingdotgg/t3code#16211 * fix(shared): DrainableWorker keeps running after a failed item by @juliusmarminge in pingdotgg/t3code#16223 * fix(server): metrics count interrupted work on the monotonic clock by @juliusmarminge in pingdotgg/t3code#16207 * refactor(web): import connection storage as a namespace in its test by @juliusmarminge in pingdotgg/t3code#16315 * fix(contracts): trimmed IDs round-trip by @juliusmarminge in pingdotgg/t3code#16300 * fix(server): main's settings, keybindings and session tests compile again by @juliusmarminge in pingdotgg/t3code#16363 * chore(lint): catch known tags with Effect.catchTags by @esthor in pingdotgg/t3code#16361 * fix(observability): T3 Connect tracing stops at the relay boundary by @juliusmarminge in pingdotgg/t3code#16314 * fix(relay): error and deadline responses carry CORS headers by @juliusmarminge in pingdotgg/t3code#16253 * fix(web): bring back the live shimmer on work log rows by @juliusmarminge in pingdotgg/t3code#16372 * refactor: Effect code gets UUIDs and SHA-256 from Effect's Crypto by @esthor in pingdotgg/t3code#16377 * fix(relay): export traces through one tracer, one request span each by @juliusmarminge in pingdotgg/t3code#16382 * fix(server): Pi thread titles use linked PR context by @juliusmarminge in pingdotgg/t3code#16210 * fix(desktop): retry transient bearer bootstrap and degrade on session fetch failure by @jamesvillarrubia in pingdotgg/t3code#12919 * fix(server): avoid scanning completed history for pending secrets by @Yash-Singh1 in pingdotgg/t3code#16409 * fix(orchestration-v2): let Stop recover stalled runs by @Yash-Singh1 in pingdotgg/t3code#15442 * fix(release): resolve version-qualified catalog overrides by @Yash-Singh1 in pingdotgg/t3code#16411 * fix(web): type in front of bold that starts a composer line by @saphid in pingdotgg/t3code#13217 * fix(desktop): prevent browser screenshot filename collisions by @saphid in pingdotgg/t3code#14784 * fix(server): end clone options before the repository URL by @saphid in pingdotgg/t3code#14781 * fix(web): queued messages no longer split the composer notice stack by @tristanmanchester in pingdotgg/t3code#16400 * fix(server): reject invalid explicit Bitbucket repositories by @aravhawk in pingdotgg/t3code#15876 * fix: restore desktop and server typechecks on main by @Yash-Singh1 in pingdotgg/t3code#16415 * fix(shared): find versioned JetBrains macOS app bundles by @Sypher760-gif in pingdotgg/t3code#16246 * fix(server): OpenCode 2 threads get T3 Code's MCP tools by @nkoynov in pingdotgg/t3code#16142 * feat(preview): run the browser on the environment server by @maria-rcks in pingdotgg/t3code#15328 * fix: restore service references breaking ci by @maria-rcks in pingdotgg/t3code#16495 * fix(mcp): mark declared tool failures as errors by @maria-rcks in pingdotgg/t3code#15617 * fix(release): unblock nightly browser tests and cli builds by @maria-rcks in pingdotgg/t3code#16515 ## New Contributors * @esthor made their first contribution in pingdotgg/t3code#16281 * @ahalekelly made their first contribution in pingdotgg/t3code#14718 * @SkiTee3000 made their first contribution in pingdotgg/t3code#12600 * @jamesvillarrubia made their first contribution in pingdotgg/t3code#12919 * @Sypher760-gif made their first contribution in pingdotgg/t3code#16246 * @nkoynov made their first contribution in pingdotgg/t3code#16142 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261005.2702...v0.0.46-nightly.20261006.2735 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261006.2735
Problem
When you clone a repository whose URL or local path starts with
-, the server passes that value to Git, which parses it as agit cloneoption. This affects Add Project → clone on web, desktop and mobile, and thet3_project_clonetool. For example, cloning a local repository named--barefails withfatal: repository 'checkout' does not existinstead of creating the checkout.Why this qualifies
This is the CONTRIBUTING "small, obvious bug" route. It is a one-line fix for a positional-argument bug at the only
git clonecall site, and it uses Git's standard--option terminator. Normal clone URLs and existing flows do not change. There is no linked issue and no prior maintainer discussion.Fix
SourceControlRepositoryService.cloneRepositorynow passes--after the clone options. That puts the repository URL or path and the destination directory after the terminator, so Git always treats them as positional arguments. This also covers a destination directory name that starts with-.The same parsing means an option-like operand can do more than fail. For example, a destination named
--upload-pack=<command>makes Git run that command during the clone. Only a client that is already allowed to clone can supply that value, and standard paired clients can already run terminal commands. So this closes argument injection at the Git process boundary; it does not fix a privilege escalation.Tests:
--bare, and an ordinarysource.gitas a control. Each must produce a working tree at the requested destination.Evidence
Environment: macOS 26.5.2 (arm64), Git 2.50.1 (Apple Git-155), Node 24.12.0. Verified on upstream main f870c419fc. This branch is that commit plus this one change.
Reproduction (real server process). I ran each step against a server built from upstream main, then against one built from this branch:
t3 serve) on a fresh, isolated data directory, withGIT_TRACEpointing at a file.t3 auth session issue./wssocket. Call the samesourceControl.cloneRepositoryRPC the clients use, withremoteUrl: "--bare"(a local bare repository) and the destinationcheckoutin the same directory.Observed before (upstream main):
Observed after (this branch):
Focused checks, run at this head:
vp test run src/sourceControl/SourceControlRepositoryService.test.ts(fromapps/server), with main'sSourceControlRepositoryService.tsswapped in--barecase fails withfatal: repository 'checkout' does not exist, and the argument assertion fails.source.gitcontrol.vp run --filter t3 typecheckvp lint --report-unused-disable-directiveson both changed filesvp fmt --checkon both changed filesvp run --filter t3 build:bundlenode scripts/release-smoke.tsThere is no UI change, so there are no screenshots. The evidence is the server trace above.
Surfaces
projectClone.start/sourceControl.cloneRepositoryRPCs.t3_project_clone: fixed. It calls the same service method.Not checked
provider+repository) feeds the same argument list.--barecase.GPT-6.1 Sol and Claude Opus 5.5 via T3 Code
🤖 Generated with Claude Code