Structural decision (OQ-09 resolved): alkgit follows the alktty/ alktunnels template — a single published protocol crate on alkcall channels, no binary, no front doors. - ADR-010 supersedes ADR-001 (crate decomposition) and ADR-006 (http router factory); both marked Superseded - Single crate at repo root: Cargo.toml with gix feature (default-on backend implementations; wire layer compiles without it — gix-hash always-on with sha1 per the compile-time-rejected invariant), crates/ workspace deleted, src/lib.rs stub in place - doors.md replaces http.md/ssh.md/alkgitd.md: alkhttp git-feature sequencing (after first publish), alkssh requirement (fixed-grammar exec dispatch), native alk/git path, downstream assembly - backend.md replaces storage.md: GitRegistry/GitRefs/GitPackGen/ GitPackIngest traits (ingest validates, refs commits — single CAS home), gix feature encodes POC-2 prerequisites - transport.md reframed for the single crate; backend traits replace hook traits in the public API - OQ-09 resolved (all five sub-decisions in ADR-010), OQ-01 resolved (subsumed), OQ-03 narrowed to publish-freeze, OQ-08 narrowed to registry identity + vault placement, OQ-07 rescoped to the gix feature's registry impl - vision.md v2: single-binary/monorepo framing corrected as init-agent artifact; POC checklist marked complete - AGENTS.md + .opencode agent specs updated to the new shape Verification: cargo build (default + no-default-features), cargo test --all-features, clippy --all-features -D warnings, fmt --check all pass. Third review round: zero critical, all warnings/suggestions addressed (GitPackGen signature amended in ADR-004, stale anchors fixed, ADR-006 body tense normalized, CAS split stated, vision residuals cleaned).
7.7 KiB
alkgit Phase 0: Vision and Guiding Principles
Status: draft v2 — 2026-09-21 (v1 2026-09-19; v2 amends the delivery shape — see "Sub-crate shape") Phase: 0 (exploration) — this document captures WHAT we are building and WHY before architecture (phase 1) commits to HOW.
Vision
A git payload service for the alk family, in Rust: alkgit implements the
git smart protocol as a pure protocol crate on alkcall channels (the
alk/git ALPN) — storage behind backend traits (gitoxide implementation
behind a feature), producer/consumer halves, no binary, no front doors.
Doors are family infrastructure: alkhttp exposes smart-http, alkssh
(planned) will expose git-over-ssh, the alknet rewrite carries the native
path; downstream consumers assemble what they want. It exists because
self-hosted git platforms (gitea/gitlab) are large multi-component
applications with a long-tail of exposed APIs, plaintext secret storage,
and web-UI attack surface — and because CVE-2026-59774 (gitea)
demonstrated that a single logic bug in an internally-exposed API is
enough for full compromise of the host. Our blast-radius and exposure model
is designed from day one, not retrofitted.
The problem, precisely
- Exposure model: mainstream self-hosted git servers expose a large
HTTP API surface regardless of auth (openapi describes everything;
enforcement is somewhere else). alkcall inverts this: only operations the
caller has privileges for are visible on the wire, and
Visibility::Internalops are structurally unreachable. alkgit inherits that property by using alkcall as the transport/protocol substrate. - Secret hygiene: gitea stores secrets plaintext in its DB. alkgit uses alkvault for anything credential-shaped; the metadata store holds vault references, never plaintext secrets.
- Footprint: a git server is a small program (storage + smart protocol + thin doors); the platform features (issues, PRs, CI) are where the CVEs live. alkgit v1 is deliberately just the git service as a protocol crate; everything else stays out (doors live in the door crates — alkhttp, alkssh — per ADR-010).
- Language: the whole serving path is Rust (memory-safe, no C deps in the packet path).
Guiding principles (architecture must honor)
- Authenticated by default — no unauthenticated endpoint exists unless a repo is explicitly marked public; even then, advertisement is the only anonymous surface, and push is always authenticated.
- Visible-surface = authorized-surface — the alkcall model end to end; no endpoint exists on the wire that a caller cannot see themselves authorized for; internal/admin ops are never wire-reachable.
- No plaintext secrets at rest — alkvault or nothing.
- Thin interfaces, one core — http and ssh are adapters that authenticate, resolve a repo, and hand a duplex stream to the transport layer. Policy lives in exactly one place. The core never knows which front door is talking (see "ALPN as a service" below).
- Honest capability advertisement — the git protocol advertises only what we actually serve (this is both protocol correctness and the security pattern: promise/enforce in the same place).
- gitoxide for storage/wire primitives — never shell out to the
gitbinary (no GPL dependency, no process injection surface); own the smart protocol server layer ourselves on gitoxide primitives. - Bounded resources — every protocol session carries wall-clock, size, and round limits; git servers are internet-facing by definition.
Non-goals for v1
- Web UI of any kind.
- Issues/PR/review features.
- Git LFS (later phase, separate decision).
- federation/replication between alkgit instances (later phase).
- Serving as a general sshd (alkgit carries no ssh surface at all; alkssh is the door).
- Windows as a serving platform (linux first; keep code portable-ish but don't test it).
Sub-crate shape (amended 2026-09-21 by ADR-010)
The v1 draft's table below was an init-agent artifact (monorepo + binary +
own doors); the corrected shape is the alktty/alktunnels pattern — see
docs/architecture/decisions/010-pure-protocol-crate.md:
| Piece | Role |
|---|---|
alkgit (single crate) |
wire layer (substrates, V2 state machines) + producer/consumer halves + backend traits |
gix feature (default on) |
gitoxide-backed implementation of the backend traits |
alkhttp git feature (future) |
smart-http mounting of the stateless substrate |
| alkssh (future family crate) | git-over-ssh door |
| downstream assembly | the actual deployment (config, listeners, TLS/ACME, vault) |
Composability: "ALPN as a service"
alkgit is the git member of the alk "ALPN as a service" family — alktty, alktunnels, and alksocks (socks5) follow the same pattern, and the alknet mono-repo is being decomposed into exactly these pieces for rewrite. The pattern's load-bearing rule: alkgit never knows which front door is talking. The protocol crate consumes (identity, repo id, duplex stream, limits) and speaks git; everything above the stream is the door's problem. That is what keeps alkgit composable for downstream use:
- A future gitea/gitlab-like application embeds
alkgit(wire layer, with its own backend implementation via the traits or the gix feature) and adds its own UI/issues/PR layer without forking anything here. - Registry management ops, if the gix feature ships any, are a set of alkcall ops, not an embedded web framework — a downstream app can either use them or replace them (OQ-07).
- Nothing in the crate may reach upward into alkhttp/alkssh concerns (no http types, no channel types below the transport boundary).
The v1 reduction follows from this: wire layer + backend traits + one gix implementation. A simple static/template web UI for the public repo listing is explicitly out of scope here (would be a separate downstream thing on top).
Primary deployment target
Our own use case is the design anchor: public self-hosted repos with anonymous clone over http, authenticated push, no gitea-style app features in use. So:
- Anonymous fetch (clone/fetch advertisement + pack) on explicitly-public repos is a first-class path, not an afterthought.
- Push is always authenticated, on every repo, no exceptions.
- ACL must be simple enough to reason about completely: repo visibility (public/private) + identity-based read/write, nothing richer in v1.
What phase 0 must still produce before phase 1
- gitoxide capability + version research (
gitoxide.md) - alk stack fit + integration surface (
alk-stack.md) - server-side protocol inventory (
git-protocol.md) - license/reference policy (
reference-policy.md) - POC-1: real
git cloneover alkcall BiStream using gix-packetline (validates BiStream fit + packetline async codec end-to-end) - POC-2: server-side pack generation composition (bundle-write vs entries-to-bytes) for a small want/have set
- POC-3: http smart-endpoint streaming shape through alkhttp (chunked pack response, unbuffered receive-pack POST ingestion)
- Convergence: recommended approach summary feeding phase 1 architecture
Immediate threat-model notes carried into architecture
- Registry management ops, if the gix feature ships any, are alkcall
Visibility::Internalops over an admin-only listener; they are never part of the git traffic surface (OQ-07). - Repo names arriving on the wire are registry IDs, never paths; storage roots are configured server-side only.
- The advertisement phase runs ACL before the first ref line is emitted.
- receive-pack applies ref updates via CAS transactions; hooks/plugins do not exist in v1 (no arbitrary code execution surface at all).