jsgit-ssh
v0.1.3
Published
An SSH transport for isomorphic-git: an http-client shim that speaks git-upload-pack/git-receive-pack over an ssh2 exec channel, so git.clone/fetch/push/listServerRefs work over SSH in pure JS
Maintainers
Readme
jsgit-ssh
An SSH transport for isomorphic-git. isomorphic-git only ships HTTP(S) transports out of the box; this package adds the SSH one.
It's an isomorphic-git-compatible http client shim that speaks git-upload-pack/git-receive-pack over an ssh2 exec channel instead of real HTTP. All the git logic (object storage, refs, index/working-tree handling, packing, protocol framing) is delegated to isomorphic-git — this package contributes exactly the SSH connection and wire framing.
Pure JavaScript: no native modules, no git binary required. (ssh2 is pure JS; its optional native helpers are never built.)
Usage
import fs from 'node:fs';
import git from 'isomorphic-git';
import { createSshHttpClient } from 'jsgit-ssh';
const { http, url, dispose } = createSshHttpClient({ url: '[email protected]:org/repo.git' });
await git.clone({ fs, http, url, dir: './repo', depth: 1 }); // closes its own connection when done
await git.push({ fs, http, url, dir: './repo', ref: 'main' }); // same client, a brand-new connection
const refs = await git.listServerRefs({ http, url }); // discover-only: no POST, so...
await dispose(); // ...call this or the connection lingerscreateSshHttpClient() accepts the same connection options as any ssh command: username, identityFile, passphrase, trustNewHosts, knownHostsPath, onProgress. It also accepts robustness/hardening options:
idleTimeoutMs— abort the operation if the server sends or accepts no data for this long (default300000;0disables). Guards against stalled or malicious servers hanging the client forever.algorithms— passed straight through tossh2({ kex, cipher, hmac, serverHostKey }allowlists) if you want to restrict negotiation below ssh2's already-modern defaults.keepaliveInterval/keepaliveCountMax— SSH-level keepalive for dead-connection detection (defaults30000/3).
Server-controlled data is bounded on all paths: ref advertisements are capped at 64 MiB, and remote stderr is tail-capped at 64 KiB for error reporting.
Connection lifecycle
Connections are per-operation, not persistent — deliberately, so nothing needs to be tracked or closed across a whole program's lifetime the way a normal http client's keep-alive connection would be:
git.clone/git.fetch/git.pusheach open a fresh SSH connection and close it automatically once that operation's response has been fully read — success or failure, it doesn't linger.- The same
http/urlpair can be reused for as many separate operations as you like; each one gets its own connection, not a shared/persistent one. - Exception: isomorphic-git's discover-only calls (
git.listServerRefs,getRemoteInfo/getRemoteInfo2) issue a request but never a follow-up, so there's no "operation finished" moment to hook a close onto. Call the client'sdispose()after one of these if no further clone/fetch/push on the same client is coming — otherwise that connection is left open indefinitely. A subsequent GET on the same client (another discover-only call, or the start of a clone/fetch/push) also closes it automatically, so this only matters for the last operation on a client. - Not safe for concurrent operations on one client instance — it tracks a single in-flight connection, and a second concurrent operation will tear down the first's. Create a separate
createSshHttpClient()call per concurrent operation.
Host key verification
Host keys are verified against ~/.ssh/known_hosts (hashed and plaintext entries, [host]:port form supported). By default, an unknown host is refused. Pass trustNewHosts: true for trust-on-first-use: the key is verified and appended to known_hosts. A host whose key changed from what's on record is always a hard failure — trustNewHosts never overrides that, since a changed key on an already-known host is the actual thing TOFU exists to catch.
Auth
Auth precedence: explicit identityFile > ssh-agent (SSH_AUTH_SOCK) > default ~/.ssh/id_rsa.
License
MIT
