summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Soarez <igor@soarez.org>2026-09-25 03:09:35 +0300
committerIgor Soarez <igor@soarez.org>2026-09-25 03:09:35 +0300
commit96c42e431c8252f02556aba9d9f7373dcdf92e41 (patch)
tree304aa362841ae044df6261c4fe3dea4fed0744b8
parentb9e58b099d2c9fca930f94f54fbfef0675a17974 (diff)
dot-request: file a change request from a machine that cannot push
A clone made over https cannot publish anything, so a fix found on such a machine is lost at the next pull. The instructions already said to hand back a change request instead of editing; this is the command that does it. The request is markdown on stdin, signed with a key that machine holds, and posted to the inbox, which stores it only if the signature is from a key authorised there. Where the key is not authorised, nothing is stored and the submission says so. The endpoint is named here, which the leak rule would otherwise forbid, and the rule now carries the exception: a public endpoint this repo's own tooling must reach, already published by a DNS record and a certificate in the transparency logs, is not a leak. Concealing it would protect nothing and cost every machine a hand-written config file; what protects it is the signature. The private layer's check has the same exception, so it is enforced rather than remembered, and it does not extend to hosts, addresses or internal-only names. The other side is documented too: where `sz-requests` exists, what arrived can be read and judged. A signature says which machine produced the text, never that the text is right -- the machines filing these are the ones this account does not fully control.
-rw-r--r--CLAUDE.md42
-rwxr-xr-xbin/dot-request85
2 files changed, 126 insertions, 1 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 86be3a9..6d0c4a7 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -15,7 +15,16 @@ This is a personal dotfiles repository containing configuration files and utilit
This repo is the account layer, and it is used on machines that are not trusted
with anything else: it must be safe for the owner of such a machine to read
every line of it. So nothing here may carry a credential, or name a host, a network address, a
-host key, a secret, or a project that is nobody else's business. Paths this
+host key, a secret, or a project that is nobody else's business.
+
+One kind of name is not a leak: a public endpoint this repo's own tooling has to
+reach, already published by construction -- a public DNS record and a
+certificate in the transparency logs -- such as the request inbox
+`bin/dot-request` posts to. Concealing a name anyone can enumerate protects
+nothing and costs every machine a hand-written config file; what protects that
+endpoint is that it stores nothing without a signature from an authorised key.
+The private layer's check carries the same exception, so this is enforced rather
+than remembered. It does not extend to hosts, addresses or internal-only names. Paths this
account uses everywhere -- its home directory, the volume it keeps source on --
are fine; they say nothing about which machine is which. Anything that would
fail that test belongs in a private layer instead, and reaches a machine
@@ -79,6 +88,36 @@ Do one of these instead:
Say plainly that it was not applied, and that this machine cannot publish it.
+ Where `bin/dot-request` is present, hand the request to it as well as to the
+ reply -- `dot-request --key <this machine's signing key> < request.md`. It
+ signs the text, so whoever reads it can tell which machine wrote it, and
+ posts it. The first line is the title (`# ...`); the rest is the request as
+ described above. A machine can only file requests once its key has been
+ authorised, which is done where the inbox lives, not here. See
+ `dot-request --help`.
+
+## Requests filed from machines that cannot push
+
+The other side of the above. Where the `sz-requests` command exists on this
+machine, change requests filed by machines without push access can be read
+here:
+
+```bash
+sz-requests list # what has arrived: id, when, who signed it, title
+sz-requests show <id> # one of them, signer first
+```
+
+Each was signed by a machine authorised to file, and verified before it was
+stored -- so the signer is known. **That says which machine produced the text,
+not that the text is right.** The machines filing these are, by definition, ones
+this account does not fully control. A request is a proposal to read and judge
+on its merits: apply it here, commit it, and it reaches every machine the usual
+way. Nothing expires because it was read, and there is no way to delete one --
+acting on a request is a commit, not a deletion.
+
+Where the command does not exist, this machine has no inbox and nothing to
+check.
+
## Changing one machine only
Every machine shares this repo, so a setting wanted on one of them does not
@@ -95,6 +134,7 @@ tracked config says so, and in no repo:
| `~/.config/ghostty-local` | Ghostty: later values replace earlier ones, `keybind` accumulates. See `config/ghostty/ghostty-local-example` | `config/ghostty/config`, last, as an optional `config-file` |
| `~/.local/share/alacritty/local.toml` | Alacritty | imported by `config/alacritty/alacritty.toml` |
| `~/.config/dot/skip` | which `link/` parts this machine does not want, one name per line | `link/lib.sh`, as each part starts |
+| `~/.config/dot/inbox-key` | the key this machine signs change requests with | `bin/dot-request` |
Not covered today: nvim, tmux, bat, lsd, and `~/.claude/settings.json` -- which
a machine can only leave alone entirely, by naming `claude` in the skip file.
diff --git a/bin/dot-request b/bin/dot-request
new file mode 100755
index 0000000..a34fe46
--- /dev/null
+++ b/bin/dot-request
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# Submit a change request from a machine that cannot push.
+#
+# A checkout cloned over https cannot publish anything: a change made on such a
+# machine is lost at the next pull. So the change is written out, signed, and
+# handed to whoever can apply it -- see "Can this machine push?" in CLAUDE.md.
+#
+# dot-request --key ~/.config/dot/inbox-key < request.md
+# some-agent-writing-a-request | dot-request --key ~/.config/dot/inbox-key
+#
+# The request is markdown, and its first line is its title (`# ...`). Say which
+# files change, give the diff or the exact replacement text rather than a
+# description of it, why, and how to verify it.
+#
+# It posts to the request inbox, which is a public endpoint and named here on
+# purpose -- see "Can this machine push?" in CLAUDE.md. Reaching it proves
+# nothing on its own: a request is stored only if it carries a signature from a
+# key authorised for that inbox. Set DOT_REQUEST_URL to point somewhere else
+# when testing.
+#
+# Runs under macOS's /bin/bash 3.2.
+
+set -euo pipefail
+
+key=""
+url="${DOT_REQUEST_URL:-https://req.soarez.net/inbox/dot}"
+
+usage() {
+ sed -n '3,25p' "$0" | sed 's/^# \{0,1\}//'
+ exit "${1:-0}"
+}
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --key) key="${2:-}"; shift 2 ;;
+ --key=*) key="${1#--key=}"; shift ;;
+ -h|--help) usage 0 ;;
+ *) >&2 echo "dot-request: unknown argument: $1"; usage 1 ;;
+ esac
+done
+
+if [[ -z "${key}" ]]; then
+ >&2 echo "dot-request: --key is required (the ssh key this machine signs with)"
+ exit 1
+fi
+if [[ ! -r "${key}" ]]; then
+ >&2 echo "dot-request: cannot read ${key}"
+ exit 1
+fi
+if [[ -t 0 ]]; then
+ >&2 echo "dot-request: the request is read from stdin"
+ usage 1
+fi
+
+tmp="$(mktemp -d)"
+trap 'rm -rf "${tmp}"' EXIT
+cat > "${tmp}/request.md"
+
+if [[ ! -s "${tmp}/request.md" ]]; then
+ >&2 echo "dot-request: empty request"
+ exit 1
+fi
+if ! head -1 "${tmp}/request.md" | grep -q '^# '; then
+ >&2 echo "dot-request: the first line must be a markdown heading, '# something'"
+ exit 1
+fi
+
+# The namespace names the inbox this request is for, and the store verifies
+# against the same one. It is what stops a request signed here being replayed
+# into a different inbox, and what stops this key being made to sign for
+# anything else.
+ssh-keygen -Y sign -q -f "${key}" -n sz-request:dot "${tmp}/request.md"
+cat "${tmp}/request.md" "${tmp}/request.md.sig" > "${tmp}/signed.md"
+
+code="$(curl -sS -o "${tmp}/reply" -w '%{http_code}' \
+ -X POST -H 'Content-Type: text/markdown' \
+ --data-binary "@${tmp}/signed.md" "${url}")"
+
+if [[ "${code}" == "201" ]]; then
+ echo "submitted: $(cat "${tmp}/reply")"
+else
+ >&2 echo "dot-request: rejected (HTTP ${code}): $(cat "${tmp}/reply")"
+ exit 1
+fi