ff1db11db4
gates / gates (push) Successful in 29s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
55 lines
3.0 KiB
Bash
55 lines
3.0 KiB
Bash
#!/bin/bash
|
|
# felhom-bundle-bootstrap.sh — the ONE by-hand act that lets an installed box take config bundles (R-840, `11` §5.4.2).
|
|
#
|
|
# Why it exists: a signed agent_config_update is installed by the box's ROOT-OWNED felhom-os-apply. A box installed
|
|
# before agent v0.143.0 has an older felhom-os-apply that has no bundle mode, and no signed job can write a root file
|
|
# on such a box (that gap IS R-840). So the first bundle needs this one step, as root, once per box. After it, every
|
|
# later change to the box's root files arrives by the signed route.
|
|
#
|
|
# What it does: downloads the config bundle of AGENT_VERSION, checks its sha256 against the one you pass (the vouched
|
|
# one — the hub's Configuration page or the release output), takes out felhom-os-apply, checks it against the bundle's
|
|
# own entry and that it parses, installs it (0755 root:root, the old copy kept beside it), and runs its self-check.
|
|
# It changes NOTHING else: no sudoers, no unit, no restart, no app, no Docker.
|
|
#
|
|
# Usage (as root on the Proxmox host): bash felhom-bundle-bootstrap.sh <agent-version> <bundle-sha256>
|
|
set -euo pipefail
|
|
VER="${1:-}"; SHA="${2:-}"
|
|
[[ "$VER" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "usage: $0 <agent-version> <bundle-sha256>" >&2; exit 2; }
|
|
[[ "$SHA" =~ ^[0-9a-f]{64}$ ]] || { echo "the bundle sha256 must be 64 lowercase hex characters" >&2; exit 2; }
|
|
[[ $EUID -eq 0 ]] || { echo "run as root" >&2; exit 2; }
|
|
URL="https://gitea.dooplex.hu/api/packages/admin/generic/felhom-agent/$VER/felhom-config-bundle.json"
|
|
DST=/usr/local/sbin/felhom-os-apply
|
|
T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
|
|
|
|
echo "1/4 download $URL"
|
|
curl -fsS -o "$T/bundle.json" "$URL"
|
|
got=$(sha256sum "$T/bundle.json" | awk '{print $1}')
|
|
[[ "$got" == "$SHA" ]] || { echo "STOP: the bundle's sha256 is $got, not $SHA — nothing changed" >&2; exit 1; }
|
|
echo " sha256 OK ($SHA)"
|
|
|
|
echo "2/4 take felhom-os-apply out of the bundle and check it"
|
|
python3 - "$T/bundle.json" "$T/os-apply" "$VER" <<'PY'
|
|
import ast, base64, hashlib, json, sys
|
|
b = json.load(open(sys.argv[1]))
|
|
assert b.get("agent_version") == sys.argv[3], f"the bundle is for {b.get('agent_version')}, not {sys.argv[3]}"
|
|
e = [f for f in b["files"] if f["path"] == "/usr/local/sbin/felhom-os-apply"][0]
|
|
data = base64.b64decode(e["content_b64"])
|
|
assert hashlib.sha256(data).hexdigest() == e["sha256"], "felhom-os-apply does not match its own sha in the bundle"
|
|
text = data.decode()
|
|
ast.parse(text)
|
|
assert 'BUNDLE_OP = "agent_config_update"' in text, "this felhom-os-apply has no bundle mode"
|
|
open(sys.argv[2], "wb").write(data)
|
|
print(" felhom-os-apply sha256", e["sha256"])
|
|
PY
|
|
|
|
echo "3/4 install it (the previous copy is kept as $DST.pre-bundle)"
|
|
[[ -f "$DST" ]] && cp -p "$DST" "$DST.pre-bundle"
|
|
install -m 0755 -o root -g root "$T/os-apply" "$DST.new.$$"
|
|
mv "$DST.new.$$" "$DST"
|
|
|
|
echo "4/4 self-check"
|
|
out=$(python3 "$DST" --self-check)
|
|
echo " $out"
|
|
[[ "$out" == *"bundle-format=1"* ]] || { echo "STOP: the self-check failed — put the old copy back: mv $DST.pre-bundle $DST" >&2; exit 1; }
|
|
echo "DONE. This box can now take signed config bundles. Nothing else was changed."
|