Files
claude-plugin-nixbuild/bin/nb-substituters
T
Oleks cbcf122422 Initial commit: nixbuild.net operator plugin
Haiku ops agent + 3 tools (nbshell expect+PTY admin-shell driver, nbapi
read-only HTTP client, nb-substituters guarded cache manager) + 2 skills
(nixbuild-settings, nixbuild-usage). Encodes the two-control-surface model
and the path-style-substituter-URL gotcha.
2026-06-01 11:17:40 +03:00

109 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# nb-substituters — manage nixbuild.net account binary-cache substituters and
# their trusted public keys, with a guard for nixbuild's URL rules.
#
# WHY a wrapper: nixbuild's `settings substituters --add` REJECTS path-style
# URLs (e.g. https://host/cache-name → "invalid substituter", trailing slash
# doesn't help). It accepts only host-root HTTPS (https://host), s3://bucket/
# prefix, or cachix://name. An Attic/nix-serve cache served at a sub-path must
# therefore be reached path-LESS — e.g. front it at a host root with a reverse
# proxy that rewrites `/<hash>.narinfo` and `/nar/*` into the cache namespace
# (the oleks fleet does this for Attic at https://nix-cache-custom.oleks.space
# via a Caddy root-rewrite). This wrapper catches the path-style mistake before
# it hits the shell and explains the fix.
#
# Also: `builders-use-substitutes = true` on the CLIENT does NOT forward the
# client's substituter list to nixbuild — it tells the remote to use ITS OWN
# (these, account-side) substituters. So caches must be registered here to take
# effect during remote builds.
#
# Usage:
# nb-substituters list # show substituters + trusted keys
# nb-substituters add-cache <url> [public-key] # add substituter (+ key if given)
# nb-substituters add-key <public-key> # add a trusted public key only
# nb-substituters remove <url> # remove a substituter
# nb-substituters remove-key <public-key> # remove a trusted public key
# nb-substituters reset # reset both back to defaults
#
# Delegates the actual shell I/O to nbshell (sibling script).
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
NBSHELL="${HERE}/nbshell"
valid_substituter() {
# Accept: https://host (no path), s3://bucket[/prefix], cachix://name.
# Reject: https://host/path (the nixbuild gotcha), http (warn), bare host.
local u="$1"
case "$u" in
https://*/*/* | https://*/?* )
# has a path component after the host
return 1 ;;
https://*/ )
return 1 ;;
https://* )
return 0 ;;
s3://* | cachix://* )
return 0 ;;
*)
return 1 ;;
esac
}
case "${1:-}" in
list)
"$NBSHELL" 'settings substituters --show' 'settings trusted-public-keys --show'
;;
add-cache)
url="${2:-}"; key="${3:-}"
[ -n "$url" ] || { echo "add-cache: need a URL" >&2; exit 2; }
if ! valid_substituter "$url"; then
cat >&2 <<EOF
nb-substituters: '$url' is not an acceptable nixbuild substituter.
nixbuild accepts only host-root HTTPS (https://host, NO path), s3://bucket/prefix,
or cachix://name. A cache served at a sub-path (Attic, nix-serve) must be exposed
path-less — e.g. front it at a host root with a reverse-proxy rewrite of
/<hash>.narinfo and /nar/* into the cache namespace, then add that bare host here.
EOF
exit 1
fi
if [ -n "$key" ]; then
"$NBSHELL" \
"settings substituters --add ${url}" \
"settings trusted-public-keys --add ${key}" \
'settings substituters --show' \
'settings trusted-public-keys --show'
else
echo "note: no public key given — content from $url will only validate if its signing key is already trusted." >&2
"$NBSHELL" "settings substituters --add ${url}" 'settings substituters --show'
fi
;;
add-key)
key="${2:-}"; [ -n "$key" ] || { echo "add-key: need a public key" >&2; exit 2; }
"$NBSHELL" "settings trusted-public-keys --add ${key}" 'settings trusted-public-keys --show'
;;
remove)
url="${2:-}"; [ -n "$url" ] || { echo "remove: need a URL" >&2; exit 2; }
"$NBSHELL" "settings substituters --remove ${url}" 'settings substituters --show'
;;
remove-key)
key="${2:-}"; [ -n "$key" ] || { echo "remove-key: need a public key" >&2; exit 2; }
"$NBSHELL" "settings trusted-public-keys --remove ${key}" 'settings trusted-public-keys --show'
;;
reset)
"$NBSHELL" \
'settings substituters --reset' \
'settings trusted-public-keys --reset' \
'settings substituters --show' \
'settings trusted-public-keys --show'
;;
""|-h|--help|help)
sed -n '2,32p' "$0"
;;
*)
echo "nb-substituters: unknown command '${1}'" >&2
exit 2
;;
esac