hub v0.133.0 (R-859 test approvals end with the test; R-840 bundle on the System page, manifest, alarm); installer 1.31.0 (root files from the config bundle); bundle bootstrap script; golden 0.293.0 evidence; rulings 96–99; drill-r50 removed (evidence)
gates / gates (push) Successful in 29s
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
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
#!/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."
|
||||
Reference in New Issue
Block a user