Some checks failed
Dependency security audit / rustsec (push) Has been cancelled
133 lines
7.8 KiB
Markdown
133 lines
7.8 KiB
Markdown
# Embedded Git and synchronization
|
|
|
|
All Git behavior is implemented in `crates/storage`. IronStorage never launches
|
|
`git`, a credential helper, an SSH client, a hook, a filter, or a merge driver.
|
|
Repositories are opened with isolated configuration and environment access;
|
|
repository-local configuration that can affect an operation is rejected.
|
|
Upstream `pass git init` deliberately writes `diff.gpg.binary` and a
|
|
`diff.gpg.textconv` GnuPG command. IronStorage preserves these passive keys for
|
|
compatibility but never evaluates them: it reads Git blobs and renders decrypted
|
|
diffs through Rust storage APIs. Frontends cannot add or change diff drivers.
|
|
This behavior follows the
|
|
[upstream password-store initialization](https://git.zx2c4.com/password-store/tree/src/password-store.sh)
|
|
while keeping runtime helper execution disabled.
|
|
|
|
`GitRepository` initializes and opens password-store worktrees, selects the
|
|
innermost repository for a nested entry, and implements status, log, diff, add,
|
|
commit, remote, and local-config operations. Successful insert, edit, generate,
|
|
recipient-policy, remove, move, and copy transactions use the same concrete
|
|
committer. Only their affected paths are staged, unrelated index state is
|
|
preserved, no-op mutations create no commit, and commit failures restore the
|
|
index so the storage transaction can roll back its files.
|
|
|
|
## Remote endpoint contract
|
|
|
|
Storage parses credential-free HTTPS URLs plus feature-gated `ssh://` and
|
|
scp-like SSH URLs into one typed endpoint contract. Local paths, `git://`,
|
|
`file://`, helper transports, URL rewrites, separate push URLs, embedded
|
|
credentials, and unknown schemes are rejected before transport. A build
|
|
without the `ssh` feature reports SSH as unsupported before connection or
|
|
repository mutation instead of treating its configuration as malformed.
|
|
|
|
## HTTPS transport
|
|
|
|
HTTPS credentials are requested with the configured server ID and application
|
|
ID and remain outside Git configuration. macOS resolves them solely through
|
|
the standard Internet-password credential for the same HTTPS endpoint.
|
|
|
|
Fetch uses the embedded Rust smart-HTTP client with an explicit credential
|
|
callback, so Git's credential cascade is never entered. Push implements the
|
|
receive-pack protocol directly: it validates the advertisement, checks the
|
|
remote tip is an ancestor, creates a complete Git pack with a SHA-1 trailer,
|
|
requests `report-status`, and accepts the update only after both unpack and ref
|
|
status succeed. HTTP redirects are disabled so authorization cannot cross an
|
|
origin boundary.
|
|
|
|
## SSH authentication
|
|
|
|
With the optional `ssh` feature, storage opens an in-process Russh client and
|
|
verifies the server key before any authentication or command. Known-host files
|
|
are read with size and line bounds; exact, hashed, and bracketed non-default
|
|
port entries are supported. Unknown keys require an explicit call to persist
|
|
the confirmed key atomically. Changed keys always fail and are never replaced.
|
|
|
|
Desktop applications take remote names and URLs from the password-store's
|
|
`.git/config`. Authentication uses the matching `~/.ssh/config` identity or an
|
|
explicit OpenSSH private-key file (Ed25519, ECDSA, or RSA), or one exact SHA-256
|
|
fingerprint from an already-running SSH agent.
|
|
Encrypted-key passphrases come from `SecretBytes` in the operating-system
|
|
secret store. Identity attempts are bounded and deterministic; IronStorage
|
|
does not spray keys, use passwords or keyboard-interactive authentication,
|
|
start/probe an agent process or run proxy/helper commands. The in-process
|
|
client reads `Host`, `HostName`, `User`, `Port`, and `IdentityFile`; executable
|
|
OpenSSH directives remain disabled. The explicit client allowlist excludes SHA-1 key exchange/MAC,
|
|
RSA/SHA-1 signatures, DSA, CBC, `none`, compression, and host certificates.
|
|
Cancellation interrupts connection and authentication without changing Git,
|
|
known hosts, or secure storage.
|
|
|
|
The standard CLI, TUI, and desktop applications compile this transport and pass
|
|
their Git actions through storage's typed endpoint selection. They display both
|
|
SSH URL forms without reparsing them. An unknown key opens an explicit native
|
|
confirmation showing the host, port, algorithm, and fingerprint; a changed key
|
|
is a non-bypassable error. Encrypted-key prompts use hidden or masked input and
|
|
retain a supplied passphrase only after SSH authentication and the requested Git
|
|
operation succeed. Cancelling either prompt leaves the repository, known hosts,
|
|
and secure storage unchanged.
|
|
|
|
## SSH upload-pack
|
|
|
|
With the same feature enabled, branch discovery, clone, fetch, and pull open a
|
|
session channel without a PTY and request only `git-upload-pack '<path>'`.
|
|
Storage single-quotes the repository as one shell argument, preserving the
|
|
absolute, account-relative, and tilde path semantics of the two supported SSH
|
|
URL forms while preventing whitespace, quotes, metacharacters, environment
|
|
assignments, or options from selecting another command. No local Git, SSH,
|
|
shell, transport helper, or fetch-pack process is involved.
|
|
|
|
The channel is a bounded adapter into gix's existing pack-protocol client.
|
|
Stdout carries only protocol bytes; stderr is retained only as a bounded,
|
|
single-line remote-service diagnostic. Storage requires a zero exit status and
|
|
clean channel completion, distinguishes malformed advertisements and packs from
|
|
network, trust, authentication, service, and cancellation failures, and closes
|
|
the channel promptly when cancellation is requested. Gix continues to own pack
|
|
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
|
|
prevalidates tree entries, rejects links and submodules, writes private files
|
|
atomically, updates the real Git index, and rolls the worktree/index back if the
|
|
reference update fails. `sync` performs pull before push, while clone builds in
|
|
a private sibling directory and installs the completed vault with a rename.
|
|
|
|
Commit signing is optional. The embedded OpenPGP key store signs the canonical
|
|
unsigned commit bytes and adds an ASCII-armored `gpgsig` header compatible with
|
|
Git/GPG without invoking `gpg`.
|
|
|
|
The transport boundary is injectable for deterministic compatibility tests.
|
|
HTTPS tests inspect credentials, advertisements, receive-pack commands, object
|
|
counts, pack checksums, non-fast-forward behavior, and server status. SSH tests
|
|
use a pure-Rust in-process Russh server and upload-pack fixture to exercise
|
|
chunked reference and pack streams, end-to-end clone/fetch/pull, command
|
|
quoting, cancellation, and rollback without an external Git or SSH executable.
|
|
Frontend tests cover typed transport display, prompt masking and cancellation,
|
|
retry routing, conflicts, authentication failures, and successful HTTPS
|
|
regression paths without duplicating protocol logic.
|
|
|
|
The final two-URL lifecycle, adversarial failure, dependency, target, and
|
|
artifact matrix is maintained in `ssh-transport-audit.md`.
|