Relay (X23, X27): the intake key is its own tier (upload and file drops only, RELAY_INTAKE_COMPAT=0 closes it);
a run task needs an Ed25519 signature by the Mac run key over {to, nonce, body sha256, flags} (RELAY_RUN_PUB,
401 without) and an HMAC tag with the target's machine secret that the agent verifies before anything runs;
results and registration are bound to the machine the secret proves (403 on a forged from).
X24: every client and Mac tool sends x-relay-token as a header to /api/relay?fn=; the path token stays for the
phone page only. X25: the agent arms the logon task only for a restart a task asked for and disarms on start
and exit. X26: 30-day retention with blob deletion, feed capped at 100, the dl base as RELAY_DL_BASE held by the
agent, never in a body. X28: GET inbox never acks (POST inbox does), RELAY-REBOOT on its own line and only with a
reboot flag, 120/min and 10 failed auths/min per IP, no username or folder on register, WSL sudo scoped to
apt-get and dpkg with SETENV, no password on a command line. X29: the intake key reaches curl through -K in
upload.sh and both upload-log.bat; tools/ci/curl-header-check.sh fails the class. G14: TZ=UTC in ship-app.mjs
and publish-jobs.sh; tools/ci/commit-tz-check.sh fails the class; history-rewrite.md names the .old-2026-10-05
files as the values in the history. The handler moved to relay/lib/handler.mjs with injected sql and blobs
(relay/lib/blob.mjs holds @vercel/blob) so relay/test/handler.test.mjs drives it without a database:
47 tests across 6 suites, all green.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
31 lines
2.1 KiB
Bash
Executable file
31 lines
2.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# No secret header on a curl command line (review round 4, ledger X29 and X24): a key passed as `-H "x-igneum-key: ..."`
|
|
# is readable by every local user in the process list for the length of the upload. Scripts pass secret headers through
|
|
# a config file (`curl -K <file>` with `header = "..."` lines) or a header file (`-H @file`). The class check (standing
|
|
# rule, 5 October 2026): any .sh, .bat, .cmd or .ps1 line that invokes curl with x-igneum-key, x-relay-token or
|
|
# x-machine-secret as a -H argument fails this.
|
|
#
|
|
# bash tools/ci/curl-header-check.sh [--self-test]
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
PAT='curl[^|]*-H[[:space:]]+"?[^"]*x-(igneum-key|relay-token|machine-secret):'
|
|
check_tree() { # <root> -> 0 when clean; prints offenders
|
|
local root="$1" bad=0
|
|
while IFS= read -r hit; do echo "secret header on a curl command line: ${hit#$root/}"; bad=1; done \
|
|
< <(grep -rnE --include='*.sh' --include='*.bat' --include='*.cmd' --include='*.ps1' "$PAT" "$root" 2>/dev/null | grep -v '/node_modules/' | grep -v '/vendor/' | grep -v '/fixtures/' | grep -v 'tools/ci/curl-header-check.sh' | grep -vE '^[^:]+:[0-9]+:[[:space:]]*(printf|echo) ' || true) # fixture writers in the other checks
|
|
return $bad
|
|
}
|
|
if [ "${1:-}" = "--self-test" ]; then
|
|
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
|
mkdir -p "$T/a"
|
|
printf 'curl -sS -K "$cfg" -X POST "$url" -H "Content-Type: application/json" --data-binary @body\n' > "$T/a/good.sh"
|
|
check_tree "$T" >/dev/null || { echo "self-test: the clean tree failed"; exit 1; }
|
|
printf 'curl -sS -X POST "$url" -H "x-igneum-key: $KEY" --data-binary @body\n' > "$T/a/bad.sh"
|
|
if check_tree "$T" >/dev/null; then echo "self-test: the bad tree passed"; exit 1; fi
|
|
rm "$T/a/bad.sh"
|
|
printf 'curl.exe -sS -X POST "%%URL%%" -H "x-igneum-key: %%KEY%%" --data-binary "@%%OUT%%"\n' > "$T/a/bad.bat"
|
|
if check_tree "$T" >/dev/null; then echo "self-test: the bad .bat passed"; exit 1; fi
|
|
echo "curl-header-check self-test: fires on the bad cases, passes the good one"
|
|
exit 0
|
|
fi
|
|
if check_tree "$ROOT"; then echo "curl-header-check: no secret header on any curl command line"; else exit 1; fi
|