diff options
| author | Igor Soarez <igor@soarez.org> | 2026-09-25 03:09:35 +0300 |
|---|---|---|
| committer | Igor Soarez <igor@soarez.org> | 2026-09-25 03:09:35 +0300 |
| commit | 96c42e431c8252f02556aba9d9f7373dcdf92e41 (patch) | |
| tree | 304aa362841ae044df6261c4fe3dea4fed0744b8 /bin | |
| parent | b9e58b099d2c9fca930f94f54fbfef0675a17974 (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-x | bin/dot-request | 85 |
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 |
