]> quire.kejadlen.dev Git - quire.git/commitdiff
Add host-side reference configs for SSH dispatch
authorAlpha Chen <alpha@kejadlen.dev>
Thu, 23 Apr 2026 23:57:07 +0000 (23:57 +0000)
committerAlpha Chen <alpha@kejadlen.dev>
Fri, 24 Apr 2026 14:30:31 +0000 (07:30 -0700)
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.

Assisted-by: GLM-5.1 via pi
docs/host/README.md [new file with mode: 0644]
docs/host/quire-dispatch [new file with mode: 0644]
docs/host/sshd_config [new file with mode: 0644]

diff --git a/docs/host/README.md b/docs/host/README.md
new file mode 100644 (file)
index 0000000..9863c5d
--- /dev/null
@@ -0,0 +1,52 @@
+# Host setup for quire
+
+Reference configs for dispatching SSH connections into the quire container.
+
+## Files
+
+- `sshd_config` — drop into `/etc/ssh/sshd_config.d/` on the host
+- `quire-dispatch` — copy to `/usr/local/bin/quire-dispatch` and `chmod +x`
+
+## Setup
+
+1. Create the git user on the host:
+
+       sudo useradd --system --create-home git
+
+2. Add your public key:
+
+       sudo mkdir -p /home/git/.ssh
+       sudo cp ~/.ssh/id_ed25519.pub /home/git/.ssh/authorized_keys
+       sudo chown -R git:git /home/git/.ssh
+       sudo chmod 700 /home/git/.ssh
+       sudo chmod 600 /home/git/.ssh/authorized_keys
+
+3. Install the dispatch script:
+
+       sudo cp quire-dispatch /usr/local/bin/quire-dispatch
+       sudo chmod +x /usr/local/bin/quire-dispatch
+
+4. Install the sshd config:
+
+       sudo cp sshd_config /etc/ssh/sshd_config.d/quire.conf
+       sudo systemctl reload sshd
+
+5. Start the quire container:
+
+       docker run -d --name quire-container quire
+
+6. Test:
+
+       git clone git@localhost:foo.git /tmp/test-clone
+
+## Notes
+
+The dispatch script is the security boundary between the host and the container.
+It only allows `git-receive-pack`, `git-upload-pack`, and `git-upload-archive`.
+Repo paths are validated: no `..` traversal, must end in `.git`, no double slashes.
+
+When `quire exec` is built (step 2), the ForceCommand will change to:
+
+    ForceCommand docker exec -i quire-container quire exec "$SSH_ORIGINAL_COMMAND"
+
+and this dispatch script will be replaced by the quire binary's own allowlist.
diff --git a/docs/host/quire-dispatch b/docs/host/quire-dispatch
new file mode 100644 (file)
index 0000000..f169014
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# /usr/local/bin/quire-dispatch
+#
+# Invoked by sshd ForceCommand for the git user.
+# Parses $SSH_ORIGINAL_COMMAND to extract the repo path and git command,
+# then dispatches into the quire container via docker exec.
+#
+# $SSH_ORIGINAL_COMMAND examples:
+#   git-receive-pack '/foo.git'
+#   git-upload-pack '/foo.git'
+#   git-upload-archive '/foo.git'
+
+set -euo pipefail
+
+# shellcheck disable=SC2154
+cmd="${SSH_ORIGINAL_COMMAND:-}"
+
+if [[ -z "$cmd" ]]; then
+    echo "quire: interactive sessions are not supported" >&2
+    exit 1
+fi
+
+# Extract the git subcommand (git-receive-pack, git-upload-pack, etc).
+git_cmd="${cmd%% *}"
+
+# Extract the repo path argument. Git sends it as a quoted string,
+# e.g. git-receive-pack '/foo.git'. Strip the leading command and
+# surrounding quotes.
+repo="${cmd#* }"
+repo="${repo#\'}"
+repo="${repo%\'}"
+repo="${repo#/}"
+
+case "$git_cmd" in
+    git-receive-pack|git-upload-pack|git-upload-archive)
+        ;;
+    *)
+        echo "quire: unsupported command: $git_cmd" >&2
+        exit 1
+        ;;
+esac
+
+# Validate repo path: no .., must end in .git, no double slashes.
+if [[ "$repo" == *".."* ]] || [[ "$repo" != *.git ]] || [[ "$repo" == *//* ]]; then
+    echo "quire: invalid repository: $repo" >&2
+    exit 1
+fi
+
+exec docker exec -i quire-container \
+    /bin/sh -c "cd /var/quire/repos/${repo} && ${git_cmd} ."
diff --git a/docs/host/sshd_config b/docs/host/sshd_config
new file mode 100644 (file)
index 0000000..cefd73d
--- /dev/null
@@ -0,0 +1,14 @@
+# /etc/ssh/sshd_config.d/quire.conf
+#
+# Drop this file into sshd_config.d (or append to sshd_config).
+# Forces all connections as the git user through the quire dispatch script.
+# No port forwarding, agent forwarding, X11, or PTY — these are git/quire
+# connections, not interactive shells.
+
+Match User git
+    AuthorizedKeysFile /home/git/.ssh/authorized_keys
+    ForceCommand /usr/local/bin/quire-dispatch
+    AllowTcpForwarding no
+    AllowAgentForwarding no
+    X11Forwarding no
+    PermitTTY no