scripts/ferry-up.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env sh
# Get Ferryman current and this repository attached, in one command.
#
# curl -fsSL https://raw.githubusercontent.com/estejosh/ferryman/main/scripts/ferry-up.sh | sh
# ferry-up.sh # from a checkout
#
# # What this is for
#
# The first outside upgrade report said it plainly: there is no documented upgrade path
# for a channel-mode worker. `docs/UPGRADING.md` describes a SQLite server with a
# `/healthz` endpoint that does not exist in this mode, and `docs/UPDATES.md` describes
# an updater that does not apply. The agent had to read the source of
# `ferryman-channel` to convince itself its signing key would survive before it dared
# upgrade. A real user will not do that.
#
# So: one command, safe to run repeatedly, in any repository. It installs or updates
# `ferry`, attaches the repository if it is not attached, and then tells you where you
# stand - including the one fact a fleet actually needs, which is whether this machine
# is on the same build as the others.
#
# # What it will not do
#
# It does not touch your signing keys, your channel, or your work. Upgrading has never
# rotated a key - that is deliberate, and the reason is in `ferryman-channel`: rotating
# on upgrade would invalidate every signature that machine has already published. This
# script prints the key fingerprint before and after so you can see that for yourself
# rather than take it on faith.
set -eu
say() { printf 'ferry-up: %s\n' "$1"; }
warn() { printf 'ferry-up: %s\n' "$1" >&2; }
die() { printf 'ferry-up: %s\n' "$1" >&2; exit 1; }
EMAIL="${FERRYMAN_EMAIL:-}"
ENABLE=1
for arg in "$@"; do
case "$arg" in
--email=*) EMAIL="${arg#--email=}" ;;
--no-enable) ENABLE=0 ;;
--help|-h)
cat <<'USAGE'
ferry-up: install or update ferry, attach this repository, and report status.
--email=you@example.com contact email for `ferry enable` (or set FERRYMAN_EMAIL)
--no-enable update the binary only; do not attach this repository
Safe to run twice. Never rotates a signing key.
USAGE
exit 0 ;;
*) die "unknown option: $arg (try --help)" ;;
esac
done
# ---------------------------------------------------------------- before
# Recorded BEFORE anything changes, because "did my identity survive?" is the question
# an upgrade has to be able to answer, and it cannot be answered afterwards from memory.
BEFORE_VERSION="$(ferry --version 2>/dev/null || echo 'not installed')"
BEFORE_KEYS=""
if [ -d .ferryman/keys ]; then
# Fingerprints only. The key never leaves the machine and must not appear in a log.
if command -v sha256sum >/dev/null 2>&1; then
BEFORE_KEYS="$(sha256sum .ferryman/keys/*.key 2>/dev/null | cut -c1-16 || true)"
elif command -v shasum >/dev/null 2>&1; then
BEFORE_KEYS="$(shasum -a 256 .ferryman/keys/*.key 2>/dev/null | cut -c1-16 || true)"
fi
fi
say "before: $BEFORE_VERSION"
# ---------------------------------------------------------------- install
say 'installing or updating ferry...'
if command -v curl >/dev/null 2>&1; then
curl -fsSL https://raw.githubusercontent.com/estejosh/ferryman/main/scripts/install.sh | sh
elif command -v wget >/dev/null 2>&1; then
wget -qO- https://raw.githubusercontent.com/estejosh/ferryman/main/scripts/install.sh | sh
else
die 'need curl or wget'
fi
command -v ferry >/dev/null 2>&1 || die 'ferry is still not on PATH; add the install directory to PATH and re-run'
AFTER_VERSION="$(ferry --version 2>&1)"
say "after: $AFTER_VERSION"
if [ "$BEFORE_VERSION" = "$AFTER_VERSION" ] && [ "$BEFORE_VERSION" != 'not installed' ]; then
# Not an error. Worth saying out loud, because the previous release reported an
# identical version string before and after a day of changes, and "nothing appears to
# have happened" was indistinguishable from "nothing happened".
say 'the version and commit are unchanged, so this machine was already current'
fi
# ---------------------------------------------------------------- attach
if [ "$ENABLE" -eq 1 ]; then
if [ -f .ferryman/bridge.toml ]; then
say 'this repository is already attached; leaving its configuration alone'
elif [ -z "$EMAIL" ]; then
warn 'this repository is not attached, and no email was given'
warn 'run: ferry-up.sh --email=you@example.com (or FERRYMAN_EMAIL=...)'
else
say "attaching this repository as $(basename "$(pwd)")..."
# `enable` never prompts and is safe to run twice; it is built to be run by an agent
# with nobody watching.
ferry enable --email "$EMAIL"
fi
fi
# ---------------------------------------------------------------- after
printf '\n'
if [ -f .ferryman/bridge.toml ]; then
say 'where this repository stands:'
ferry channel status 2>&1 || true
printf '\n'
ferry channel agents 2>&1 || true
printf '\n'
# The one that matters after an upgrade: every artifact should still read `Valid`. A
# new binary that cannot verify signatures written by the old one is the failure this
# whole check exists to catch.
say 'signature check on every artifact (all should read Valid):'
ferry channel tasks 2>&1 || true
printf '\n'
fi
AFTER_KEYS=""
if [ -d .ferryman/keys ]; then
if command -v sha256sum >/dev/null 2>&1; then
AFTER_KEYS="$(sha256sum .ferryman/keys/*.key 2>/dev/null | cut -c1-16 || true)"
elif command -v shasum >/dev/null 2>&1; then
AFTER_KEYS="$(shasum -a 256 .ferryman/keys/*.key 2>/dev/null | cut -c1-16 || true)"
fi
fi
if [ -n "$BEFORE_KEYS" ]; then
if [ "$BEFORE_KEYS" = "$AFTER_KEYS" ]; then
say 'signing key unchanged (upgrading never rotates one)'
else
# Loud, and stop. A changed key means every artifact this machine has published
# stops verifying for every other machine, and the roster will treat its next
# registration as an impostor. Recovering is a restore, not a retry.
warn ''
warn '*** THE SIGNING KEY CHANGED. STOP. ***'
warn 'Every artifact this machine published will now fail to verify elsewhere.'
warn 'Restore .ferryman/keys from a backup before running anything else, and'
warn 'please report this: https://github.com/estejosh/ferryman/issues'
exit 1
fi
fi
cat <<'NEXT'
next:
ferry agent run # this machine does work
ferry agent review # this machine judges results
ferry soak # a report to paste into an issue while we soak-test
Run this same command on every machine in the fleet, then compare the commit in
`ferry --version`. If they differ, they are not running the same Ferryman.
NEXT