Files
alkgit/docs/architecture/decisions/007-acl-before-advertisement.md
T
glm-5.3-flash 86bf5a0cf0 refactor(architecture): ADR-010 — pure protocol crate (alktty template)
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).
2026-09-21 10:54:03 +00:00

64 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-007: ACL runs before any advertisement or ref line
## Status
Accepted
## Context
Ref names leak repository existence (and structure). The advertisement is
the first thing a client sees; if ACL runs after advertisement begins, a
denied caller has already learned that a repo (or a ref within it) exists.
The vision's visible-surface = authorized-surface invariant requires the
check to run before the first byte of git protocol content.
POC-1 observed the natural enforcement point on the git:// path: the repo
name arrives in-band in the first request line, *before* any ref data — so
the resolve-then-authorize step sits structurally ahead of the first
emitted line. POC-3 noted the http extra-routes are registered permissive
by default (the gateway bearer layer does not cover them) — making the
http-side check an explicit door responsibility (alkhttp `git` feature), not an inherited
one.
## Decision
Every session/request performs, in order, before any protocol output:
1. Extract the wire repo name (git:// first-request line; ssh exec command
string; http path segment).
2. Resolve it against the registry to (repo id, storage root) — reject
unknown repos with the same error as unauthorized ones (no existence
oracle) (ADR-008).
3. Run alkcall `AccessControl::check(peer_identity)` against the repo's
required access. Read access covers the *whole fetch surface*:
advertisement, ref listing, and pack transfer alike — anonymous access
on explicitly-public repos grants the same full read path
(vision §"Primary deployment target" makes anonymous clone first-class;
the "advertisement is the only anonymous surface" line in the same
doc's principle 1 is read as the *minimum* boundary, and this decision
sets the operative rule).
4. Only then hand the session to transport.
Adapters embed this sequence; transport asserts it (the session entry
points take an authorized-repo marker — a type the adapter constructs only
after step 3 passes — so skipping the check is a type error, not a runtime
log) but does not re-check — authorization evaluation lives in one place,
alkcall, and invocation/wiring lives in one place, the adapter.
Push is always authenticated on every repo, no exceptions (vision §
"Primary deployment target").
## Consequences
- No ref/capability line is ever emitted for a repo a caller cannot see;
the gitea-class "enforcement elsewhere" bug is structurally excluded.
- Unknown-repo and unauthorized errors are indistinguishable to callers.
- The check is cheap (registry lookup + ACL check) and runs before any
expensive protocol work.
- http adapters must wire ACL explicitly for their routes (POC-3 showed
alkhttp extra routes default permissive) — doors.md encodes this.
## References
- `docs/research/vision.md` §"Guiding principles" 1–2, §"Immediate threat-model notes"
- `docs/research/poc-1-findings.md` follow-up 4; `docs/research/poc3-findings.md` §"does NOT settle" (auth)
- alkcall ADR-017 (privilege model)
- ADR-008 (repo identity), doors.md (door auth mechanics)