Implement SSH upload-pack for branch discovery, clone, fetch, and pull #115

Closed
opened 2026-08-24 20:17:07 +00:00 by hugo · 1 comment
Owner

Goal

Carry every read-side Git remote operation over a verified and authenticated SSH channel while reusing IronStorage's existing embedded Git object, checkout, and merge logic.

Scope

  • Open a russh session channel without a PTY and execute the server-side git-upload-pack service for the validated repository path.
  • Construct the remote command with correct Git SSH path semantics and robust quoting. Repository text must never inject a second command, shell operator, environment assignment, option, or alternate service.
  • Adapt the channel byte stream to the existing gix/IronStorage fetch boundary or the smallest equivalent pure-Rust pack-protocol adapter; do not run local git fetch-pack, ssh, or a shell.
  • Support reference advertisement, protocol negotiation, branch discovery, clone, fetch, remote-tracking updates, fast-forward pull, merge pull, and the existing typed conflict behavior for both SSH URL spellings.
  • Preserve clone staging and atomic installation, dirty-worktree refusal, safe checkout, ref validation, object limits, rollback, progress phases, and cancellation semantics already enforced for HTTPS.
  • Read stdout as protocol bytes, treat bounded stderr as diagnostic-only, require successful channel/service completion, and map network, host trust, authentication, protocol, remote-service, cancellation, and malformed-pack failures distinctly.
  • Cancellation must close the channel/session promptly and must not extend the authentication lease.
  • Do not assume shell access beyond the Git server accepting the standard git-upload-pack '<path>' exec request.

Tests and verification

  • Use an in-process russh server and pure-Rust upload-pack fixture; application tests must not require an installed ssh or git executable.
  • Cover empty and populated repositories, branch discovery, initial clone, incremental fetch, fast-forward, merge, conflict, tags/advertised refs, both URL spellings, absolute/relative/tilde paths, slow/chunked I/O, malformed advertisements/packs, remote non-zero exit, disconnect, and cancellation.
  • Add command-injection regressions for quotes, whitespace, newlines, shell metacharacters, and leading options in repository paths.
  • Prove failure leaves destination, object database, refs, index, and worktree in the same valid state required by the HTTPS path.
  • Run all repository-required Rust gates.

Acceptance criteria

  • Branch discovery, clone, fetch, and pull work end to end over both requested SSH URL forms.
  • No local process or helper is launched.
  • Existing storage-owned merge, conflict, progress, cancellation, and rollback guarantees apply equally to SSH.
  • Untrusted hosts and unauthenticated sessions cannot reach git-upload-pack.

Depends on the remote-model and SSH authentication/host-verification issues in this milestone.

Protocol reference: https://git-scm.com/docs/pack-protocol#_ssh_transport

## Goal Carry every read-side Git remote operation over a verified and authenticated SSH channel while reusing IronStorage's existing embedded Git object, checkout, and merge logic. ## Scope - Open a `russh` session channel without a PTY and execute the server-side `git-upload-pack` service for the validated repository path. - Construct the remote command with correct Git SSH path semantics and robust quoting. Repository text must never inject a second command, shell operator, environment assignment, option, or alternate service. - Adapt the channel byte stream to the existing `gix`/IronStorage fetch boundary or the smallest equivalent pure-Rust pack-protocol adapter; do not run local `git fetch-pack`, `ssh`, or a shell. - Support reference advertisement, protocol negotiation, branch discovery, clone, fetch, remote-tracking updates, fast-forward pull, merge pull, and the existing typed conflict behavior for both SSH URL spellings. - Preserve clone staging and atomic installation, dirty-worktree refusal, safe checkout, ref validation, object limits, rollback, progress phases, and cancellation semantics already enforced for HTTPS. - Read stdout as protocol bytes, treat bounded stderr as diagnostic-only, require successful channel/service completion, and map network, host trust, authentication, protocol, remote-service, cancellation, and malformed-pack failures distinctly. - Cancellation must close the channel/session promptly and must not extend the authentication lease. - Do not assume shell access beyond the Git server accepting the standard `git-upload-pack '<path>'` exec request. ## Tests and verification - Use an in-process `russh` server and pure-Rust upload-pack fixture; application tests must not require an installed `ssh` or `git` executable. - Cover empty and populated repositories, branch discovery, initial clone, incremental fetch, fast-forward, merge, conflict, tags/advertised refs, both URL spellings, absolute/relative/tilde paths, slow/chunked I/O, malformed advertisements/packs, remote non-zero exit, disconnect, and cancellation. - Add command-injection regressions for quotes, whitespace, newlines, shell metacharacters, and leading options in repository paths. - Prove failure leaves destination, object database, refs, index, and worktree in the same valid state required by the HTTPS path. - Run all repository-required Rust gates. ## Acceptance criteria - Branch discovery, clone, fetch, and pull work end to end over both requested SSH URL forms. - No local process or helper is launched. - Existing storage-owned merge, conflict, progress, cancellation, and rollback guarantees apply equally to SSH. - Untrusted hosts and unauthenticated sessions cannot reach `git-upload-pack`. Depends on the remote-model and SSH authentication/host-verification issues in this milestone. Protocol reference: https://git-scm.com/docs/pack-protocol#_ssh_transport
hugo added this to the 07 - Pure-Rust Git-over-SSH remotes milestone 2026-08-24 20:17:07 +00:00
hugo added the enhancement label 2026-08-24 20:17:07 +00:00
Author
Owner

Implemented and pushed in 051e14235f.

Implementation:

  • Added a bounded Russh session-channel adapter for gix upload-pack with no PTY, process, shell, helper, or unsafe Rust.
  • Added single-argument repository quoting, stdout-only protocol handling, bounded/sanitized stderr diagnostics, successful-exit enforcement, cancellation, and distinct network/trust/authentication/Git-protocol/SSH-service/malformed-pack errors.
  • Routed discovery, clone, fetch, pull, remote tracking, fast-forward, merge, and typed conflicts through the existing storage-owned gix and rollback paths for ssh:// and scp-like remotes. SSH passphrase retrieval uses the active authentication handle without extending its lease.
  • Added pure-Rust in-process Russh/upload-pack tests for populated and empty repositories, both URL spellings, branches/tags, clone/incremental fetch/pull/merge/conflict, slow/chunked I/O, malformed advertisement/pack, nonzero exit, disconnect, cancellation, hostile paths, unchanged repositories/destinations, and trust/auth rejection before upload-pack.

Verification:

  • cargo fmt --all -- --check
  • RUSTFLAGS=-D warnings cargo check --workspace --all-targets
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
  • SSH-feature check, clippy, and complete test suite all pass (50 storage unit tests plus integration suites).
  • Release macOS bundle built and validated with Computer Use: existing vault loaded; Git Synchronization showed HTTPS origin main, 0 ahead / 0 behind, clean worktree. No Apple/iPhone sources changed.
  • cargo audit: 2 medium RUSTSEC-2023-0071 RSA instances remain with no fixed upgrade; 15 allowed transitive maintenance/unsoundness warnings were also reported. No audit finding was suppressed or mixed into this issue.
Implemented and pushed in 051e14235f3a711411b5121f929403dba6d1bc0c. Implementation: - Added a bounded Russh session-channel adapter for gix upload-pack with no PTY, process, shell, helper, or unsafe Rust. - Added single-argument repository quoting, stdout-only protocol handling, bounded/sanitized stderr diagnostics, successful-exit enforcement, cancellation, and distinct network/trust/authentication/Git-protocol/SSH-service/malformed-pack errors. - Routed discovery, clone, fetch, pull, remote tracking, fast-forward, merge, and typed conflicts through the existing storage-owned gix and rollback paths for ssh:// and scp-like remotes. SSH passphrase retrieval uses the active authentication handle without extending its lease. - Added pure-Rust in-process Russh/upload-pack tests for populated and empty repositories, both URL spellings, branches/tags, clone/incremental fetch/pull/merge/conflict, slow/chunked I/O, malformed advertisement/pack, nonzero exit, disconnect, cancellation, hostile paths, unchanged repositories/destinations, and trust/auth rejection before upload-pack. Verification: - cargo fmt --all -- --check - RUSTFLAGS=-D warnings cargo check --workspace --all-targets - cargo clippy --workspace --all-targets -- -D warnings - cargo test --workspace - SSH-feature check, clippy, and complete test suite all pass (50 storage unit tests plus integration suites). - Release macOS bundle built and validated with Computer Use: existing vault loaded; Git Synchronization showed HTTPS origin main, 0 ahead / 0 behind, clean worktree. No Apple/iPhone sources changed. - cargo audit: 2 medium RUSTSEC-2023-0071 RSA instances remain with no fixed upgrade; 15 allowed transitive maintenance/unsoundness warnings were also reported. No audit finding was suppressed or mixed into this issue.
hugo closed this issue 2026-08-25 18:31:38 +00:00
Sign in to join this conversation.