bastion 0.61.0
ci / personal-data (push) Successful in 8s
ci / test (push) Successful in 7m17s
ci / fuzz (push) Successful in 6m33s

This commit is contained in:
Privatae
2026-11-02 06:20:42 +00:00
parent 4f8285ef18
commit 1176f7fd0b
47 changed files with 3574 additions and 294 deletions
+1 -1
View File
@@ -1 +1 @@
0.60.0
0.61.0
+41
View File
@@ -24,8 +24,49 @@
# reads a `go test -json` run instead and names every cited test that
# skipped in it, with the reason it gave. It exits non-zero if any did: a CI job
# that runs a claim's test where it cannot run proves nothing about the claim.
#
# deploy/check-claims.sh --failed <go test -json output>
#
# names every test that failed in such a run, with the last lines it printed,
# and the package's own lines when the package failed outside any test (a
# panic, a build error, a timeout), so a failed CI job says why. It exits
# non-zero if anything failed.
set -euo pipefail
HERE="$(cd "$(dirname "$0")/.." && pwd)"
if [ "${1:-}" = "--failed" ]; then
python3 - "${2:?usage: deploy/check-claims.sh --failed <go test -json output>}" <<'PY'
import json, sys
out, failed, pkg_out, pkg_failed = {}, [], [], False
for line in open(sys.argv[1], encoding="utf-8", errors="replace"):
try:
e = json.loads(line)
except ValueError:
pkg_out.append(line.rstrip("\n")) # what go itself printed: a build error
continue
t, a = e.get("Test"), e.get("Action")
if a == "output":
(out.setdefault(t, []) if t else pkg_out).append(e.get("Output", "").rstrip("\n"))
elif a == "fail":
if t:
failed.append(t)
else:
pkg_failed = True
for t in failed[:40]:
print("FAILED " + t)
for l in out.get(t, [])[-60:]:
print(" " + l)
if len(failed) > 40:
print("... and %d more failed tests" % (len(failed) - 40))
if pkg_failed and not failed:
print("the package failed outside any test:")
for l in pkg_out[-80:]:
print(" " + l)
print("%d tests failed" % len(failed))
sys.exit(1 if failed or pkg_failed else 0)
PY
exit $?
fi
if [ "${1:-}" = "--skipped" ]; then
RUN="$(cd "$(dirname "${2:?usage: deploy/check-claims.sh --skipped <go test -json output> [repo root]}")" && pwd)/$(basename "$2")"
ROOT="${3:-$HERE}"
+85 -2
View File
@@ -466,11 +466,11 @@ if [ "$networked" = 1 ] && [ "$root" != 1 ]; then
fi
key="$os-$arch"
tmp=$(mktemp); man=$(mktemp)
tmp=$(mktemp); man=$(mktemp); vdir=$(mktemp -d)
# Any exit before the final mv must leave nothing behind and install nothing:
# this script is piped to `sudo sh`, so a partial run is a root-privileged
# partial install.
trap 'rm -f "$tmp" "$man"' EXIT INT TERM
trap 'rm -f "$tmp" "$man"; rm -rf "$vdir"' EXIT INT TERM
die() { echo "ERROR: $*" >&2; exit 1; }
@@ -485,8 +485,91 @@ else die "no sha256sum or shasum on this system — cannot verify the download,
fi
sha_of() { $SHACMD "$1" | cut -d' ' -f1; }
# ── the release signature ──────────────────────────────────────────────────
#
# The manifest names each binary's digest, and the download is checked against
# it. The manifest itself is signed with a release key whose public half is
# pinned here, the same keys a running bastion checks every update with
# (client-go/release_sign.go productionReleaseKeys; install_sig_sh_test.go
# holds the two to each other). So a copy of this script read on GitHub and run
# from there as root, or with --just-me, installs only a release we signed
# (possibly an older one), whatever the download host serves. Run without
# sudo, the copy does not install for the whole machine itself: its root step
# fetches this installer from the website again (whole_machine_script) and
# runs that. The signature is over one statement, as verifyReleaseSignature
# builds it: privatae-release-signature-v1, the kind, the version, and the
# manifest's sha256, a line each; it sits beside the manifest at
# version.json.<the first 16 hex of that sha256>.sig, in base64.
#
# Checked with an openssl that does Ed25519 (OpenSSL 3, on most Linux; the
# openssl@3 Homebrew installs on a Mac). A probe signature made for this tells
# "this openssl cannot check" from "the signature is wrong": the first prints a
# note and keeps the digest check alone, which is what the script did before;
# the second refuses to install.
RELEASE_KEYS='MCowBQYDK2VwAyEAtWOyZm38DwTwbawSnvExQG/CQsVJBKYWc46arCBZj9E= MCowBQYDK2VwAyEACKL+J0VSdqrfY4AmxChvylJ1ha4e8GvcrYF2o17Ah+g='
SIG_PROBE_KEY='MCowBQYDK2VwAyEA1TRy5NeI2n7tieFf6cHe5VE69SV0XL7Vx4k6EwFlFFk='
SIG_PROBE_SIG='Do3fnwjyv8QgR+9sJcc0A3Sr0XzSKqBW8DK8kzaJL29tS8KxuStc2tp+HheJvoGwXmrH2kg7YN+yDLKVDnDqDQ=='
# release_signature_check <manifest> <empty scratch dir>: returns when the
# manifest's signature verifies, or when no openssl here can check one (said);
# exits when it does not verify.
release_signature_check() {
rs_man=$1 rs_dir=$2
rs_pem() { printf -- '-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n' "$1" > "$2"; }
rs_ssl=""
rs_pem "$SIG_PROBE_KEY" "$rs_dir/probe.pem"
printf 'privatae-installer-probe-v1\n' > "$rs_dir/probe.msg"
printf 'privatae-installer-probe-v0\n' > "$rs_dir/probe.other"
# The probe signature must verify over its message and not over another: an
# openssl that passes every signature is no check, and is set aside like one
# that cannot check, never taken for one.
for c in openssl /opt/homebrew/opt/openssl@3/bin/openssl /usr/local/opt/openssl@3/bin/openssl; do
command -v "$c" >/dev/null 2>&1 || continue
printf '%s' "$SIG_PROBE_SIG" | "$c" base64 -d -A -out "$rs_dir/probe.sig" 2>/dev/null || continue
if "$c" pkeyutl -verify -pubin -inkey "$rs_dir/probe.pem" -rawin -in "$rs_dir/probe.msg" \
-sigfile "$rs_dir/probe.sig" >/dev/null 2>&1 &&
! "$c" pkeyutl -verify -pubin -inkey "$rs_dir/probe.pem" -rawin -in "$rs_dir/probe.other" \
-sigfile "$rs_dir/probe.sig" >/dev/null 2>&1; then
rs_ssl=$c; break
fi
done
if [ -z "$rs_ssl" ]; then
echo "NOTE: no openssl here can check an Ed25519 signature, so the release's signature is not checked;"
echo " the download is still checked against the manifest's digest, fetched over HTTPS."
if [ "$os" = darwin ]; then
echo " To check the signature too, install OpenSSL 3 (brew install openssl@3) and run this again."
else
echo " To check the signature too, install OpenSSL 3 from your distribution and run this again."
fi
return 0
fi
rs_sum=$(sha_of "$rs_man")
case "$rs_sum" in *[!0-9a-f]* | "") die "cannot take the manifest's digest — refusing to install unverified" ;; esac
rs_ver=$(sed -n 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$rs_man" | head -n 1)
case "$rs_ver" in
"" | *[!0-9A-Za-z.+-]*) die "the manifest names no usable version — refusing to install unverified" ;;
esac
rs_short=$(printf '%s' "$rs_sum" | cut -c1-16)
curl -fsSL --max-filesize 4096 "$base/version.json.$rs_short.sig" -o "$rs_dir/sig.b64" \
|| die "cannot fetch the release's signature ($base/version.json.$rs_short.sig) — refusing to install unverified"
tr -d ' \r\n' < "$rs_dir/sig.b64" | "$rs_ssl" base64 -d -A -out "$rs_dir/sig" 2>/dev/null \
|| die "the release's signature is malformed — refusing to install"
[ "$(wc -c < "$rs_dir/sig" | tr -d ' ')" = 64 ] || die "the release's signature is malformed — refusing to install"
printf 'privatae-release-signature-v1\nbastion\n%s\n%s\n' "$rs_ver" "$rs_sum" > "$rs_dir/statement"
for k in $RELEASE_KEYS; do
rs_pem "$k" "$rs_dir/key.pem"
if "$rs_ssl" pkeyutl -verify -pubin -inkey "$rs_dir/key.pem" -rawin -in "$rs_dir/statement" \
-sigfile "$rs_dir/sig" >/dev/null 2>&1; then
echo "Release signature verified (version $rs_ver)."
return 0
fi
done
die "the release's signature does not verify against the pinned release keys — refusing to install"
}
echo "Fetching manifest..."
curl -fsSL "$base/version.json" -o "$man" || die "cannot fetch $base/version.json — refusing to install unverified"
release_signature_check "$man" "$vdir"
# Pull this platform's expected digest out of version.json without needing jq or
# python (neither is guaranteed on a clean macOS or a minimal container): find the