feat(host-install)+docs: D1 — install self-update artifacts on day-0 + architecture §11 self-update (implemented)
felhom-host-install.sh installs felhom-selfupdate-guarded (sh -n), the rollback unit + the [Unit] start-limit drop-in (daemon-reload) so day-0 boxes get operator-signed self-update from birth; non-fatal on pre-D1 agent repos. 03-host-agent.md §11 updated to the shipped mechanism (signed op, A/B wrapper, OnFailure rollback, tuned start-limit backstop). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -1264,6 +1264,19 @@ step_agent_install() {
|
||||
log_success " installed /usr/local/sbin/felhom-mkfs-guarded (0755, the guarded mkfs path)"
|
||||
fi
|
||||
|
||||
# Self-update guarded wrapper (TASK D1) — the ONLY binary-swap path the sudoers permits. Install
|
||||
# it BEFORE the sudoers (which allowlists it), 0755 root:root under /usr/local/sbin. sh -n first.
|
||||
if $DRY_RUN; then
|
||||
log_dry "fetch configs/felhom-selfupdate-guarded ; sh -n ; install 0755 -> /usr/local/sbin/felhom-selfupdate-guarded"
|
||||
else
|
||||
local sutmp; sutmp=$(mktemp -t felhom-selfupd.XXXXXX)
|
||||
fetch_raw "configs/felhom-selfupdate-guarded" "$sutmp"
|
||||
sh -n "$sutmp" || { rm -f "$sutmp"; die "fetched felhom-selfupdate-guarded failed sh -n — refusing to install"; }
|
||||
install -m 0755 -o root -g root "$sutmp" /usr/local/sbin/felhom-selfupdate-guarded
|
||||
rm -f "$sutmp"
|
||||
log_success " installed /usr/local/sbin/felhom-selfupdate-guarded (0755, the guarded A/B binary-swap path)"
|
||||
fi
|
||||
|
||||
# Sudoers — fetch the canonical file, validate with visudo -cf BEFORE installing (0440 root:root).
|
||||
if $DRY_RUN; then
|
||||
log_dry "fetch configs/felhom-agent.sudoers ; visudo -cf ; install 0440 -> $AGENT_SUDOERS"
|
||||
@@ -1292,6 +1305,32 @@ step_agent_install() {
|
||||
systemctl enable felhom-agent >/dev/null 2>&1 || true
|
||||
log_success " installed $AGENT_UNIT + enabled (started in step 6 after config)"
|
||||
fi
|
||||
|
||||
# Self-update rollback unit + start-limit drop-in (TASK D1). The drop-in gives felhom-agent the
|
||||
# tuned start-limit (SPIKE-agent-selfupdate: [Unit] StartLimitIntervalSec=120 + Burst=4 → a
|
||||
# crash-looping update reaches terminal `failed` in ~20s instead of looping forever) and the
|
||||
# OnFailure= that auto-reverts. Both are idempotent installs (+ daemon-reload). Non-fatal on a
|
||||
# box whose agent repo predates them (the raw fetch would 404) — self-update just stays manual.
|
||||
if $DRY_RUN; then
|
||||
log_dry "fetch configs/felhom-agent-rollback.service -> /etc/systemd/system/ ; fetch configs/felhom-agent-limits.conf -> $AGENT_UNIT.d/ ; daemon-reload"
|
||||
else
|
||||
local rbtmp; rbtmp=$(mktemp -t felhom-rollback.XXXXXX)
|
||||
if fetch_raw "configs/felhom-agent-rollback.service" "$rbtmp" 2>/dev/null; then
|
||||
install -m 0644 -o root -g root "$rbtmp" /etc/systemd/system/felhom-agent-rollback.service
|
||||
local ddir="${AGENT_UNIT}.d"; mkdir -p "$ddir"
|
||||
local lmtmp; lmtmp=$(mktemp -t felhom-limits.XXXXXX)
|
||||
fetch_raw "configs/felhom-agent-limits.conf" "$lmtmp"
|
||||
# [SF-3] the keys MUST be in [Unit] — refuse a drop-in that would half-apply in [Service].
|
||||
grep -q '^\[Unit\]' "$lmtmp" || { rm -f "$lmtmp" "$rbtmp"; die "self-update limits drop-in missing [Unit] section — refusing"; }
|
||||
install -m 0644 -o root -g root "$lmtmp" "$ddir/felhom-agent-limits.conf"
|
||||
rm -f "$lmtmp"
|
||||
systemctl daemon-reload
|
||||
log_success " installed self-update rollback unit + start-limit drop-in (auto-rollback armed)"
|
||||
else
|
||||
log_skip " self-update rollback artifacts not in the agent repo yet — self-update stays manual"
|
||||
fi
|
||||
rm -f "$rbtmp"
|
||||
fi
|
||||
_state_mark agent_install
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user