Implement SSH receive-pack pushes

This commit is contained in:
2026-08-25 20:56:06 +02:00
parent 051e14235f
commit 76e707f645
5 changed files with 1370 additions and 67 deletions

View File

@@ -97,7 +97,8 @@ configuration, try additional keys, prompt for passwords or
keyboard-interactive authentication, launch an agent, or invoke proxy/helper
commands. In builds with the `ssh` feature, the same configuration drives
branch discovery, clone, fetch, and pull over the embedded upload-pack channel;
push support is enabled separately when receive-pack is available.
push and full pull-then-push synchronization use the matching embedded
receive-pack channel.
The typed endpoint model is always available so an SSH remote remains readable
through the Rust API even when the binary was built without SSH. Such a build

View File

@@ -80,6 +80,18 @@ verification, object limits, and atomic ref updates, while the existing
IronStorage code continues to own clone staging, checkout, merge, conflict, and
rollback behavior.
SSH push opens the same verified and authenticated session-channel boundary for
`git-receive-pack '<path>'`. Storage validates the advertisement, rejects
non-fast-forward updates before sending, constructs the complete reachable
object pack, then half-closes channel input and drains the status and bounded
stderr streams. The remote-tracking ref advances only after `unpack ok`, an
`ok` for the selected ref, a zero service exit, and clean channel completion.
Unpack and ref-policy rejections remain typed failures; a malformed response,
disconnect, or cancellation after sending is an unknown outcome that requires
a fresh fetch before retrying and is never replayed automatically. Synchronize
always completes pull first and cannot open receive-pack after a failed,
cancelled, or conflicted pull.
Pull refuses a dirty worktree. It fast-forwards when possible and otherwise
uses the embedded three-way tree merge. Unresolved paths are returned as typed
`MergeConflicts`; no conflict markers or partial checkout are written. Checkout