#!/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
