From: Alpha Chen Date: Mon, 27 Apr 2026 02:53:07 +0000 (-0700) Subject: Add docs/config.md for the Fennel config schemas X-Git-Url: http://quire.kejadlen.dev/?a=commitdiff_plain;h=2eaac4018daa5fde73f145788b4abb0768f90c8f;p=quire.git Add docs/config.md for the Fennel config schemas Assisted-by: Claude Opus 4.7 via Claude Code --- diff --git a/README.md b/README.md index ada3cb9..324ea77 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,10 @@ Quire's data lives under one volume: /var/quire/ repos/ bare git repos; per-repo config lives in-tree at .quire/config.fnl runs/ CI run metadata, artifacts, and logs; retention-policied - config.fnl global config (GitHub PAT, SMTP creds, etc.) + config.fnl global config; see docs/config.md for the schema ``` -Host-side config (sshd_config block, Caddyfile, docker-compose file) lives on the host, version-controlled separately. See `PLAN.md` for the reference layout. +Host-side config (sshd_config block, Caddyfile, docker-compose file) lives on the host, version-controlled separately. See `PLAN.md` for the reference layout, `docs/config.md` for the global and per-repo Fennel schemas. ## Status diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000..cadae50 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,71 @@ +# Config files + +Quire reads two Fennel config files. Both are pure data — a single +top-level table — loaded via the embedding described in +[`fennel.md`](fennel.md). + +## Global config + +Lives at `/var/quire/config.fnl` on the bind-mounted volume. +Operator-created. Re-read on every call (no caching today). + +| Key | Type | Required | Purpose | +|------------------|----------------|----------|----------------------------------------------------------| +| `:github :token` | `SecretString` | yes | GitHub PAT used for `http.extraHeader` on mirror pushes. | +| `:sentry :dsn` | `SecretString` | no | Sentry DSN for error reporting. Omit to disable. | + +Minimal: + +```fennel +{:github {:token "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"}} +``` + +With Sentry, and the token sourced from a Docker secret: + +```fennel +{:github {:token {:file "/run/secrets/github_token"}} + :sentry {:dsn "https://key@o0.ingest.sentry.io/0"}} +``` + +A missing file is a typed error (`Error::ConfigNotFound`). A malformed +file surfaces as a Fennel parse or eval error with source labels. + +## Per-repo config + +Lives at `.quire/config.fnl` *checked into the repo* — quire reads it +from `HEAD` of the bare repo via `git show HEAD:.quire/config.fnl` +whenever a hook needs it. Repos without the file (or without a given +key) get defaults; this is a no-op for the post-receive hook, not an +error. + +| Key | Type | Required | Purpose | +|----------------|----------|----------|-------------------------------------------------------------------------------| +| `:mirror :url` | `String` | no | HTTPS URL of the mirror remote. URLs with embedded `user:pass@` are rejected. | + +Example: + +```fennel +{:mirror {:url "https://github.com/owner/repo.git"}} +``` + +## SecretString values + +Any field typed as `SecretString` accepts two shapes: + +- A plain string: `"hunter2"`. +- A file reference: `{:file "/run/secrets/github_token"}`. + +File references are resolved on first call to `.reveal()` and cached +for the lifetime of the parsed value. A single trailing newline is +stripped (Docker secrets convention); additional trailing newlines are +preserved. + +The `Debug` impl redacts the value, so a config struct slipping into a +`tracing::debug!` call won't leak the secret. Calling `.reveal()` and +logging the result bypasses this — don't. + +## See also + +- [`fennel.md`](fennel.md) — how Fennel files are loaded into Rust structs. +- `src/quire.rs` — `GlobalConfig`, `RepoConfig`, `MirrorConfig` definitions. +- `src/secret.rs` — `SecretString` implementation and tests.