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.
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:
alkgitdterminates SSH (russh under thesshdoor) 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
alkcallincrates/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
- 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). - 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.
- V2 negotiation:
GIT_PROTOCOL=version=2arrives as an ssh env line (git-protocol.md§framing). v1 policy: expect/require V2 per ADR-003 (V0/V1 declined with a clear error). - 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"