Files
alkgit/docs/architecture/ssh.md
T
glm-5.3-flash 8f73da5d12 docs(architecture): phase 1 bootstrap — specs, 9 ADRs, OQ tracker
Architecture documentation structure per sdd_process phase 1:

- README index (doc table, ADR table, lifecycle), overview with crate
  map, dependency rules, and security invariants
- Component specs: storage, transport, http, ssh, alkgitd (all draft)
- ADRs 001-009: crate decomposition, front-door-blind core, V2-first
  protocol, pack pipeline (data::output generation / data::input
  ingestion), session substrate types, http adapter composition
  (proposed, OQ-01), ACL-before-advertisement, registry-resolved repo
  identity, bounded-resources budgets
- open-questions.md: OQ-01..08 with two deferred(scope), one
  deferred(unclear), door-type definitions, blocker tracker tasks in
  tasks/architecture/
- v1 ssh-door decision recorded: russh terminates wire SSH in alkgitd;
  alkcall channels stay the internal substrate (OQ-03 partially
  resolved)

Two review rounds (fresh-context subagent): 4 critical + 17 warnings
fixed in round one; zero critical + 4 warnings + 5 suggestions fixed in
round two. All ADR/OQ cross-references verified resolving.
2026-09-21 03:55:33 +00:00

4.6 KiB

status, last_updated
status last_updated
draft 2026-09-21

alkgit-ssh: SSH Front Door

What it is

The ssh adapter: serves the git command surface over ssh. Unlike http, ssh is session-shaped, so it maps directly onto the transport duplex session (ADR-002).

Client compatibility (v1 decision): stock git clients (git clone ssh://git@host/repo) speak the SSH wire protocol — an exec request over an SSH connection. alkcall channels are not that protocol; they are alkgit's internal session layer. v1 therefore terminates real SSH wire protocol (russh is the candidate); the vision's "not a general sshd" non-goal is untouched — only the git command surface is served. Concretely:

  • alkgitd terminates SSH (russh under the ssh door) and hands the adapter the post-auth exec request + stream.
  • alkcall channels remain the internal substrate identity/ACL flows through (alk-stack.md §"Interfaces in alkcall terms"); the adapter's dispatch output is the same duplex session either way.
  • A pure-alkcall-channels ssh door (no wire SSH) is a downstream-embedding variant only — OQ-03 territory, not v1.
  • Manifest note: the pre-phase-1 workspace skeleton pins only alkcall in crates/alkgit-ssh/Cargo.toml; the russh dependency (and where it sits — alkgitd vs alkgit-ssh) is set when this spec implements.

What we serve

Exactly the git command surface, not a general sshd (vision non-goals):

Command Serves
git-upload-pack '<repo>' fetch/clone (duplex V2 session)
git-receive-pack '<repo>' push (duplex receive-pack; OQ-04)
git-upload-archive not served (declined explicitly —
docs/research/git-protocol.md §security notes; honest refusal, not
silence)

Session flow

  1. Command dispatch: parse the exec request string (git-upload-pack / git-receive-pack + quoted repo argument). Reject other commands with a clear error on stderr (no shell interpretation — the command string is parsed, never executed).
  2. Repo resolution + ACL (ADR-007/008): the quoted repo argument is a registry ID; resolve, authorize (read for upload-pack, write for receive-pack — push always authenticated), all before any protocol byte.
  3. V2 negotiation: GIT_PROTOCOL=version=2 arrives as an ssh env line (git-protocol.md §framing). v1 policy: expect/require V2 per ADR-003 (V0/V1 declined with a clear error).
  4. Handoff: the post-auth stream (from the russh-terminated session) is the duplex substrate; transport runs the duplex session (advertise-once → command loop, sideband packs). The adapter's job ends here — no protocol logic lives in this crate.

Identity

  • With russh terminating SSH (see the v1 decision), peer identity comes from the ssh authentication the terminator performs (public key, typically). How that identity becomes an alkgit/alkcall identity — and where authorized keys live (vault involvement) — is OQ-08, shared with http; one auth session settles both doors.

Relationship to russh

russh terminates the SSH wire protocol for stock git clients (see the v1 decision above). The dispatch + ACL + handoff sequence (§Session flow) is door-agnostic: alkcall-channel and russh inputs converge on the same transport duplex session. Whether alkgit-ssh exports a russh-flavored adapter separately from the alkcall one is an OQ-03 (embedding surface) question — v1 ships the path alkgitd needs (russh termination → this adapter's dispatch).

Limits

The duplex session carries Limits (ADR-009). Channel-level caps (alkcall ADR-041 per-identity channel cap) still apply above us; git sessions consume one channel each (alk-stack.md §"Interfaces in alkcall terms").

Design Decisions

ADR Decision Summary
001 Crate decomposition ssh is a separate replaceable adapter
002 Session boundary duplex session = native ssh shape
003 V2-first V0/V1 declined via env-line check
007 ACL first before advertisement, push always authed
008 Repo identity exec argument = registry ID

Open Questions

  • OQ-08: ssh identity mechanics (open).
  • OQ-03: russh-flavored embedder adapter (deferred(scope)).

References

  • docs/research/poc-1-findings.md (duplex session shape, git:// in-band framing analog — ssh exec is the same resolve-before-emit order)
  • docs/research/alk-stack.md §"Interfaces in alkcall terms"