extract_line_offset split on : from the left, so names like
HEAD:.quire/config.fnl broke the parser. Use regex-lite to match
the first :LINE:COLUMN: run instead, which is unambiguous.
Embed Fennel compiler and implement load_string round-trip
Vendor fennel.lua 1.5.1 and wrap it behind a Fennel struct that owns
a Lua VM. Uses mlua with lua54 + serde features so fennel.eval results
deserialize directly into typed Rust structs. Uses unsafe_new because
Fennel needs the debug standard library internally.
Extract Quire struct to replace Repo and Config threading
Repo was a thin validated-name wrapper that required callers to pass
repos_dir alongside it at every call site. Quire holds the config and
provides repo() -> PathBuf and repos() -> Iterator, collapsing two
arguments into one at every command handler.
All repo name validation now goes through Repo::from_name(). The exec
command strips the SSH leading slash before calling it, keeping the
Repo type focused on name rules only. Removed the duplicate
validate_repo_path function from exec.rs.
New `quire repo` subcommand group with new/list/rm. Name validation
rejects traversal, deep nesting, missing .git suffix, and reserved
segments (.git). The exec allowlist dispatches `quire repo` to the
binary. Post-receive hook is configured system-wide via gitconfig
instead of per-repo.
Trixie ships newer packages overall. Git still needs building from
source (trixie has 2.47, we need 2.54+) but trixie is a better
foundation going forward.
Build git 2.54 from source and add hook subcommand
Debian bookworm ships git 2.39 but we need 2.54+ for
hook.<name>.command config support, which lets quire register
hooks via git config instead of writing shim scripts to disk.
The hook subcommand is a no-op that logs invocations — enough to
verify the dispatch path works end-to-end.
Bind-mounted repos under /var/quire are owned by the host's git user;
baking a quire user with a different uid into the image triggered
git's safe.directory "dubious ownership" check. Setting the user at
docker run time keeps ownership aligned end-to-end.
Clippy and miette conventions are already enforced by tooling.
Use "just all" instead of "cargo test" since the justfile is
the canonical check runner.
Simplify Config to Default and use miette bail/ensure macros
Config::load() with env var parsing was premature. Default impl is
enough for now. Switch exec.rs from if/return Err(miette!) to
ensure! and bail! for idiomatic miette usage.
Switch from color-eyre to miette for error reporting
Miette provides better diagnostic output and integrates with thiserror
via the Diagnostic derive. Library errors now derive both Error and
Diagnostic. Binary uses miette::Result with into_diagnostic() for
third-party errors.
Implement quire exec dispatch with git command allowlist
Parses SSH_ORIGINAL_COMMAND, validates git commands against an
allowlist (receive-pack, upload-pack, upload-archive), sanitizes
repo paths, and execs the git subprocess. Removes the separate
quire-dispatch shell script — the binary handles dispatch directly.
Updates host reference configs to use quire exec in ForceCommand.
Replace binary release with Docker image build and push
Multi-stage Dockerfile builds the Rust binary then copies it into a
slim runtime image with git and ca-certificates. CI workflow follows
the ketchup pattern: single ci.yml with test, zizmor, and build jobs.
Build pushes to GHCR on green main, tags with YYYYMMDD-<short-sha>,
and creates a GitHub release. Removes the old release workflow and
dotslash config.
sshd_config Match block, quire-dispatch script with repo path
validation and git-command allowlist, and a README covering setup
steps. These are reference configs versioned with the repo — the
dispatch script will be replaced by quire exec in step 2.
Minimal image: debian bookworm, git, quire user, bare test repo
at /var/quire/repos/foo.git. Entrypoint passes through to docker
exec invocations. No sshd, no quire binary yet.
Scaffold Rust binary project with clap, CI, and tooling
Restructure from a minimal lib+main into a proper binary project
layout: library target with error types, separate binary target
under src/bin/quire/ with clap subcommands (serve, exec), CalVer
versioning via build.rs, integration tests, justfile, clippy config,
mutation testing config, and GitHub Actions CI/release workflows.