summaryrefslogtreecommitdiff
path: root/bin
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 /bin
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.
Diffstat (limited to 'bin')
-rwxr-xr-xbin/dot-request85
1 files changed, 85 insertions, 0 deletions
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