From 8163163120f5a04b6c21fac3d2e1c1e21d4b945f Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Sun, 26 Apr 2026 21:52:47 +0000 Subject: [PATCH] Align docs with code after accuracy audit The audit found docs claiming `quire new` (CLI is `quire repo new`), git 2.36+ (Dockerfile builds 2.54), and a stale fennel.md describing a once-per-process Fennel that the code constructs per-call. README's "Design phase" status also undersold actual progress. Assisted-by: Claude Opus 4.7 via Claude Code --- README.md | 4 ++-- docs/PLAN.md | 2 +- docs/fennel.md | 30 ++++++++++++++++-------------- docs/host/README.md | 7 ++++++- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 4b2f823..e5fef31 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Named after the old bookbinding term: a gathering of folded leaves, sewn togethe A Rust binary that runs in a Docker container, fronted by the host's sshd and a TLS-terminating reverse proxy. It gives you: -- **Git hosting over SSH**, via the host's sshd dispatching into the container. Explicit repo creation (`ssh git@host quire new `). +- **Git hosting over SSH**, via the host's sshd dispatching into the container. Explicit repo creation (`ssh git@host quire repo new `). - **A read-only web view** for browsing README, tree, history, blame, diffs, and refs. - **Automatic mirroring to GitHub** on push, when configured per-repo. Each repo carries its own deploy key — no agent socket to plumb across the host/container boundary. - **Fennel-based CI** (Fennel is a Lisp that compiles to Lua), with pipelines defined in `.quire/ci.fnl`. Unsandboxed by default since every pipeline is code I've written; a bubblewrap-based opt-in is available for the day quire ever runs code I haven't. @@ -45,4 +45,4 @@ Host-side config (sshd_config block, Caddyfile, docker-compose file) lives on th ## Status -Design phase. See `PLAN.md` for the build sequence and open questions. +Early development. SSH dispatch, repo management, and Fennel config loading work; web view, CI, mirroring, and notifications are still ahead. See `PLAN.md` for the build sequence and open questions. diff --git a/docs/PLAN.md b/docs/PLAN.md index 1b8f860..6d21d75 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -204,7 +204,7 @@ Keyboard navigation in the web UI. Atom feeds for recent commits (public, subjec - **Web visibility: public by default, per-repo opt-outs.** Repos are public (they go to GitHub anyway); CI logs require auth. Per-repo `(private true)` and `(public_runs true)` flags cover the exceptions. - **Trust the proxy-injected identity header.** `Remote-User` is trusted because the reverse proxy is the only ingress. Proxy must strip any client-supplied version before injecting its own — this is the security-critical invariant. - **Explicit repo creation, not implicit on first push.** `ssh git@host quire new `. No magic, no shims parsing first pushes. -- **Hooks via `hook..command` config.** Git 2.36+. No shim scripts on disk; `hook..command = /usr/local/bin/quire hook `. Set at creation time. +- **Hooks via `hook..command` config.** Git 2.54+ (the version we build into the container image). No shim scripts on disk; `hook..command = /usr/local/bin/quire hook `. Set at creation time. - **Mirror push is synchronous in post-receive.** Slow GitHub = slow push. Worth it; silent drift is the worst outcome. - **No reverse-direction mirroring.** quire is the source of truth; GitHub is the replica. - **CI pipelines are Fennel macros, not data tables.** The whole point is real code. Shared steps can be factored into `.quire/lib/*.fnl` and `require`'d. diff --git a/docs/fennel.md b/docs/fennel.md index a3b7283..abc193d 100644 --- a/docs/fennel.md +++ b/docs/fennel.md @@ -15,9 +15,9 @@ machinery later, but its design is out of scope here. - **Vendored Fennel compiler** — `fennel.lua` from upstream (BSD-3, single Lua file). Bundled via `include_str!`, registered into the VM as a module at construction. -- **`Fennel` struct** — owns the `Lua` instance and a reference to the - loaded `fennel` module. Constructed once per process; `load_file` and - `load_string` are methods. +- **`Fennel` struct** — owns a `Lua` instance with the Fennel compiler + registered as a Lua global. `load_file` and `load_string` are methods + that look the global up on each call. ## Decisions @@ -34,9 +34,10 @@ A representative per-repo config: :on [:ci-failed :mirror-failed]}} ``` -One `Fennel` per process, reused across loads. Hooks load 1–2 files; -`quire serve` loads many. Avoids re-loading the compiler on each -call. Cheap enough that tests construct freely. +Today each call site (`Quire::global_config`, `Repo::config`) +constructs a fresh `Fennel`. Cheap enough at current call volume. +Reusing a single instance across loads is a planned optimization for +when `quire serve` lands and starts loading per-request. `load_string` is the primitive; `load_file` wraps it. Per-repo config comes from `git show` stdout, not a path on disk, so the string form is @@ -47,8 +48,9 @@ Errors flow through miette. Wrap `mlua::Error` with the source name and any line/column info Lua surfaces. Hook log lines should point at the offending file and line, not just "syntax error." -New top-level `src/fennel.rs`. Used by the still-to-come -`src/config/global.rs` and `src/config/repo.rs`. +Lives in `src/fennel.rs`. Used by `Quire::global_config` and +`Repo::config` in `src/quire.rs`, which also define the `GlobalConfig` +and `RepoConfig` schemas. ## Contracts @@ -65,13 +67,13 @@ impl Fennel { Errors: file-not-found, parse error, eval error, type mismatch — all `miette::Result` with named source labels where Lua provides them. -## Out of scope +## Related modules -- `SecretString` / `!cmd` resolution — chunk 2. Fennel produces plain - strings; `SecretString` is a `serde` newtype that resolves on access. -- `git show HEAD:.quire/config.fnl` plumbing — chunk 3. -- Any `mirror`/`notifications`/`private` schema — defined when chunks 2 - and 3 land. +- `src/secret.rs` — `SecretString` wraps Fennel-loaded strings that + resolve from a file or shell command on access. +- `src/quire.rs` — `Repo::config` reads per-repo Fennel via `git show + HEAD:.quire/config.fnl`; `Quire::global_config` reads the global + config from disk. Both define the schema structs they parse into. ## Test plan diff --git a/docs/host/README.md b/docs/host/README.md index ce3f1bd..1f56d8f 100644 --- a/docs/host/README.md +++ b/docs/host/README.md @@ -33,6 +33,7 @@ Reference configs for dispatching SSH connections into the quire container. --user "$(id -u git):$(id -g git)" \ -e HOME=/tmp \ -v /var/quire:/var/quire \ + -p 127.0.0.1:3000:3000 \ quire In a compose file, the equivalent is `user: "${QUIRE_UID}:${QUIRE_GID}"` @@ -41,7 +42,7 @@ Reference configs for dispatching SSH connections into the quire container. 5. Create a test repo inside the container: - docker exec quire-container quire new foo.git + docker exec quire-container quire repo new foo.git 6. Test the dispatch path: @@ -61,3 +62,7 @@ errors from git when the bind-mounted repo dir's host uid wouldn't otherwise match a container user. `HOME=/tmp` is set because the host uid has no `/etc/passwd` entry inside the container, and git needs a writable `HOME` for its config probing. + +The HTTP port (3000) is published to host loopback only. A reverse proxy +on the host terminates TLS and reverse-proxies to it; nothing else +should reach it directly. -- 2.54.0