Skip to content

fix(api,sync): Delimit positional arguments in git clone mirror invocations - #463

Open
cairn-intern wants to merge 6 commits into
Twigpine:mainfrom
cairn-intern:recreate-376-fix-git-clone-positional-delimiter
Open

cairn-intern wants to merge 6 commits into
Twigpine:mainfrom
cairn-intern:recreate-376-fix-git-clone-positional-delimiter

Conversation

@cairn-intern

Copy link
Copy Markdown

Summary

Passes -- before positional path and URL arguments in git clone --mirror subprocess invocations to ensure positional inputs cannot be interpreted as command-line flags.

Changes

  • crates/gitlawb-node/src/api/repos.rs: Add -- before positional arguments in fork_repo.
  • crates/gitlawb-node/src/sync.rs: Add -- before positional arguments in clone_repo.
  • crates/gl/src/mirror.rs: Add -- before positional arguments in gl mirror.

Test plan

  • cargo check --workspace
  • git diff HEAD --check

Fixes #374

Summary by CodeRabbit

  • Bug Fixes

    • Improved cloning, mirroring, forking, and synchronization reliability for repository paths or URLs beginning with a hyphen.
    • Prevented Git from misinterpreting repository inputs as command-line options.
    • Improved recovery behavior when refreshing repository data or processing failed blob and manifest sources.
    • Improved handling of overloaded repository write operations and disconnected push processes.
    • Sanitized warning output for safer error reporting.
  • Tests

    • Added regression coverage for safe repository inputs, recovery failures, stalled operations, and write-operation handling.

Recreated from closed PR #376 by @euxaristia (approved but unmerged). Original branch: euxaristia/node:fix/git-clone-positional-delimiter

…ations

Pass "--" before positional path/URL arguments in Command invocations
for "git clone --mirror" across repos.rs, sync.rs, and gl mirror.rs.

Fixes Twigpine#374
Fix cargo fmt line-length break for git clone --mirror arguments.

Refs Twigpine#376
The delimiter change had no test, so nothing stopped it being reverted as
cosmetic. What it guards is real: git parses a remote beginning with a
dash as an option, and --upload-pack=<cmd> is one git hands to a shell.

No path reaches that today. Peer URLs are gated by is_public_http_url, so
the origin clone_repo composes can only begin with http:// or https://;
fork paths are joins under repos_dir; and clap rejects a leading-dash
positional in gl mirror. The delimiter is what removes git's dependence
on those three unrelated gates staying correct.

Assert git reports the whole argument as a repository it cannot find,
which is only true once the delimiter forces it to be a path.
Undelimited, git consumes it as an option and fails against the
destination instead, never naming the injected string, so the assertion
is red before the fix and green after.

Refs Twigpine#374
Carry the positional argument delimiter into fetch_repo when setting the
remote origin URL and into setup_partial_clone across all clone branches.
Correct the error string quoted in the clone regression test docstring.

Refs Twigpine#374
The delimiter contract is duplicated across five direct `git` argv
constructions, but only `sync::clone_repo` had a test that went red when
`--` was deleted. Removing or misplacing the delimiter in any other sink
left the suite green, so the hardening rested on review rather than on
the tests.

Each changed sink now has a subprocess-facing regression driven through
real git: the three `setup_partial_clone` shapes (plain, `--branch`, and
the sparse/promisor arm), `fetch_repo`'s `remote set-url`, `gl mirror`,
and the fork clone.

Two of these could not carry the obvious assertion:

- `git_global` and `git_run` both format failures as
  `git {args:?} failed: {stderr}`, so the injected value is already in
  the message via the debug-printed argv. Asserting that the error
  merely contains it passes with `--` deleted. The clone tests assert on
  git's own single-quoted `repository '<value>'` instead, which only
  appears when git read the value as a repository.
- `remote set-url` does not fail on a delimited option-shaped value, it
  stores it. The `fetch_repo` test asserts the stored URL rather than an
  error: undelimited, git exits 129 with `unknown option` and leaves the
  previous URL in place.

`gl mirror` and `fork_repo` needed their argv extracted to be testable.
`mirror::run` loads a keypair and contacts a node before reaching the
clone, and bails with a message that interpolates the source whether or
not the delimiter is present. The extraction keeps the production
`.status()` call, so a large mirror clone still streams git's progress
to the terminal instead of being captured.

Every one of the five was confirmed red with its delimiter removed and
green with it restored.

Refs Twigpine#374
`emit_warning` sanitizes a line before writing it, which strips ANSI
escape and bidi characters from untrusted text. Three warning sites in
the blob-recovery paths still used a bare `eprintln!` while interpolating
`oid`, which comes from node JSON or an Arweave gateway manifest, so
those escapes reached the user's terminal raw.

Refs Twigpine#374

@greptile-apps greptile-apps 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Only developers with an assigned seat can use this organization's usage-based review budget, and seats here are assigned manually. Ask an admin to assign a seat, or change the review continuation mode in Billing.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 6199b103-dff1-4f44-b6c0-4f9cf6d9be7c

📥 Commits

Reviewing files that changed from the base of the PR and between bfc44f9 and 23e7a07.

📒 Files selected for processing (4)
  • crates/gitlawb-node/src/api/repos.rs
  • crates/gitlawb-node/src/sync.rs
  • crates/gl/src/clone.rs
  • crates/gl/src/mirror.rs

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

@beardthelion beardthelion added crate:gl gl — the contributor CLI crate:node gitlawb-node — the serving node and REST API kind:bug Defect fix — wrong or unsafe behavior subsystem:api Node REST API request/response surface subsystem:replication Mirror, replica, and cross-node sync labels Sep 24, 2026

@beardthelion beardthelion left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified on 23e7a07c against real git, both directions. Removing each new -- reddens its paired test on the assertion it names, across the clone_repo, set-url, and all three setup_partial_clone argv shapes, plus the extracted fork and mirror helpers. git remote set-url origin -- --upload-pack=false stores the value verbatim where the undelimited form exits 129 on unknown option, and the promisor arm's option ordering is pinned by the existing positive-path test (a misplaced -- turns the filter into a positional and fails the clone outright).

On reachability: peer URLs are built from is_public_http_url-validated origins and the fork paths are server-derived, so nothing stored can be option-shaped today. This lands as sink-side hardening and is framed that way. The three eprintln! reroutes through emit_warning do strip control and bidi characters via sanitize_node_msg.

Not asks, recorded only. gl mirror's create-repo error path (crates/gl/src/mirror.rs:123) still prints the node's message verbatim on failure, the one sanitize_node_msg outlier among the touched files; same class as the warnings rerouted here, worth a follow-up. The remote-derived default-branch name reaches git checkout -q undelimited at crates/gl/src/clone.rs:222; if that is ever worth hardening it wants a leading-dash reject, not --, which would reinterpret the name as a pathspec. And the mirror clone still inherits the terminal via .status() (crates/gl/src/mirror.rs:95), so a source server the user points it at can write sideband and progress bytes to stderr unfiltered, the same as running git clone by hand; deliberate for progress streaming, but a quiet or sanitized mode would pay off for hostile-source runs. All three predate this PR. The fork and mirror tests pin the extracted argv helpers rather than the fork_repo/run call sites, so a future inline refactor would drop that coverage silently; the doc comments already say as much.

One process note, not a finding: the PR body's Changes list is a commit behind the diff (it omits fetch_repo, clone.rs, and the warning reroutes), worth a refresh so the description matches what lands. PR Checks reads action_required on this fork head; that is mine to approve, not yours.

@euxaristia euxaristia 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.

Re-submission of the closed #376 (argument delimiting in the git clone mirror invocations). The closed round's approach was correct; this needs the same rebase onto current sync.rs plus tests proving the delimiter actually lands in the argv (the closed round lacked them, which is why it stalled).

@euxaristia euxaristia 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.

LGTM. Re-review of head 23e7a07 confirms positional argument delimiting with -- across clone, fork, and mirror invocations is fully verified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crate:gl gl — the contributor CLI crate:node gitlawb-node — the serving node and REST API kind:bug Defect fix — wrong or unsafe behavior subsystem:api Node REST API request/response surface subsystem:replication Mirror, replica, and cross-node sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(api,sync): Delimit positional arguments in git clone mirror invocations

3 participants