| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
|
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
|
| 32 |
|
| 33 |
|
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
|
| 38 |
|
| 39 |
|
| 40 |
|
| 41 |
|
| 42 |
|
| 43 |
|
| 44 |
|
| 45 |
|
| 46 |
set -euo pipefail |
| 47 |
|
| 48 |
SHA="${1:-}" |
| 49 |
if [[ ! "$SHA" =~ ^[0-9a-f]{7,40}$ ]]; then |
| 50 |
echo "sando-self-update: refusing non-hex sha: '$SHA'" >&2 |
| 51 |
exit 2 |
| 52 |
fi |
| 53 |
|
| 54 |
SELF_DIR="${SANDO_SELF_UPDATE_DIR:-/srv/sando/self-update}" |
| 55 |
UPSTREAM_URL="${SANDO_UPSTREAM_URL:-/srv/sando/mnw.git}" |
| 56 |
BUILD_USER="${SANDO_BUILD_USER:-sando}" |
| 57 |
BIN="${SANDO_BIN:-/usr/local/bin/sandod}" |
| 58 |
DEPLOY_BRANCH="${SANDO_DEPLOY_BRANCH:-main}" |
| 59 |
DAEMON_CONFIG="${SANDO_DAEMON_CONFIG:-/etc/sando/sando-daemon.toml}" |
| 60 |
REPO_DIR="$SELF_DIR/MNW" |
| 61 |
BUILD_HOME="$(getent passwd "$BUILD_USER" | cut -d: -f6)" |
| 62 |
|
| 63 |
echo "sando-self-update: building sandod @ $SHA as $BUILD_USER (provenance: origin/$DEPLOY_BRANCH)" |
| 64 |
|
| 65 |
|
| 66 |
|
| 67 |
|
| 68 |
install -d -o "$BUILD_USER" -g "$BUILD_USER" "$SELF_DIR" |
| 69 |
runuser -u "$BUILD_USER" -- env \ |
| 70 |
HOME="$BUILD_HOME" \ |
| 71 |
PATH="$BUILD_HOME/.cargo/bin:/usr/local/bin:/usr/bin:/bin" \ |
| 72 |
bash -euo pipefail -c " |
| 73 |
if [[ ! -d '$REPO_DIR/.git' ]]; then |
| 74 |
git clone '$UPSTREAM_URL' '$REPO_DIR' |
| 75 |
fi |
| 76 |
cd '$REPO_DIR' |
| 77 |
# Pin origin to the configured source every run, so switching |
| 78 |
# SANDO_UPSTREAM_URL (e.g. remote -> local bare repo) takes effect on an |
| 79 |
# already-cloned checkout instead of silently keeping the old remote. |
| 80 |
git remote set-url origin '$UPSTREAM_URL' |
| 81 |
git fetch --prune origin |
| 82 |
# Provenance seal: the sha must be reachable from the deploy branch in the |
| 83 |
# source repo. --is-ancestor exits 1 for a non-ancestor and >1 for a |
| 84 |
# bad/unresolvable ref, so any non-deploy-branch sha is refused fail-closed |
| 85 |
# before a single line is built or installed. |
| 86 |
if ! git merge-base --is-ancestor '$SHA' 'origin/$DEPLOY_BRANCH'; then |
| 87 |
echo \"sando-self-update: refusing sha '$SHA' — not an ancestor of origin/$DEPLOY_BRANCH\" >&2 |
| 88 |
exit 4 |
| 89 |
fi |
| 90 |
git checkout --detach '$SHA' |
| 91 |
cd sando |
| 92 |
# Clean build: wipe the workspace target so no stale incremental object |
| 93 |
# survives across shas. A reused pre-node_health Gate enum object once |
| 94 |
# produced a sandod that crash-looped on the current config (postmortem |
| 95 |
# #6). Self-updates are rare, so a full recompile is a cheap insurance. |
| 96 |
cargo clean |
| 97 |
cargo build --release --locked -p sando-daemon |
| 98 |
" |
| 99 |
|
| 100 |
|
| 101 |
|
| 102 |
NEW_BIN="$REPO_DIR/sando/target/release/sandod" |
| 103 |
[[ -x "$NEW_BIN" ]] || { echo "sando-self-update: build produced no binary at $NEW_BIN" >&2; exit 3; } |
| 104 |
|
| 105 |
|
| 106 |
|
| 107 |
|
| 108 |
|
| 109 |
|
| 110 |
echo "sando-self-update: self-testing $NEW_BIN against $DAEMON_CONFIG" |
| 111 |
if ! runuser -u "$BUILD_USER" -- env SANDO_CONFIG="$DAEMON_CONFIG" "$NEW_BIN" --check-config; then |
| 112 |
echo "sando-self-update: new binary FAILED --check-config against $DAEMON_CONFIG; refusing to install (sandod left running on the current binary)" >&2 |
| 113 |
exit 5 |
| 114 |
fi |
| 115 |
|
| 116 |
|
| 117 |
|
| 118 |
echo "sando-self-update: installing $NEW_BIN -> $BIN and restarting sandod" |
| 119 |
install -m 0755 "$NEW_BIN" "$BIN" |
| 120 |
systemctl restart sandod |
| 121 |
echo "sando-self-update: done ($SHA live)" |
| 122 |
|