CAMPAIGN-3 Task A: agent v0.85.0 boot/recovery plane docs + host-install deployment_mode (--mode gates node self-heal)
network-storage-nas.md gains Boot-ordering (F12), reassert-hardening (F11/F10/F9), F13 limitation, and Node self-heal (appliance) sections. host-install v1.14.0 templates deployment_mode from --mode + byo assert. Live matrix: host reboot x2 = 0 ordering-cycle lines (F12 dead); appliance self-heal recovered attempt 1. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017CDMFpFx84pfviCTVuGGhf
This commit is contained in:
@@ -1,5 +1,15 @@
|
||||
# Felhom scripts — Changelog
|
||||
|
||||
## felhom-host-install v1.14.0 — deployment_mode from --mode (appliance self-heal gate) (2026-07-12)
|
||||
|
||||
- The agent-config writer now templates the top-level **`deployment_mode`** field from `--mode`
|
||||
(`appliance` | `byo`), authoritative even over a `--preserve-from` config. It gates the agent's
|
||||
node self-heal (host networking recovery at boot — F12-class defense in depth, agent v0.85.0):
|
||||
only `deployment_mode:"appliance"` unlocks the remedy; anything else, including a stale preserved
|
||||
value or a typo, is byo (the check runs + WARNs, the remedy is unreachable). The byo config assert
|
||||
additionally refuses `deployment_mode=appliance` (a byo box must never carry a host-service
|
||||
self-heal). Companion to CAMPAIGN-3 Task A (`documentation/audits/CAMPAIGN-3-2026-07-11.md`).
|
||||
|
||||
## felhom-host-install v1.13.0 — systemd-journal group for the agent user (NAS verify) (2026-07-11)
|
||||
|
||||
- The agent-user setup now adds `felhom-agent` to the **`systemd-journal` group** (idempotent
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#===============================================================================
|
||||
# felhom-host-install.sh v1.13.0
|
||||
# felhom-host-install.sh v1.14.0
|
||||
# Day-0 host-bootstrap for a Felhom Proxmox host (operator-deploy model).
|
||||
#
|
||||
# Run by the operator on a FRESHLY-PVE-INSTALLED box (after a manual PVE install
|
||||
@@ -19,6 +19,11 @@
|
||||
# new credential. The checksum trust root is the HUB, not Gitea. This removes the
|
||||
# old prerequisite "install the agent binary + unit manually".
|
||||
#
|
||||
# v1.14.0 (CAMPAIGN-3 Part 6): --mode now also templates the agent's top-level `deployment_mode`
|
||||
# ("appliance" | "byo") — authoritative from --mode, written even over a --preserve-from config, so a
|
||||
# byo box can never inherit an appliance host-service self-heal. Gates the agent's node self-heal
|
||||
# (host networking recovery at boot, F12-class; agent v0.85.0). The byo config assert now also refuses
|
||||
# deployment_mode=appliance. absent/typo → byo (fail-safe).
|
||||
# v1.10.0 (GL-2, go-live G2/G4/G5): explicit --mode appliance|byo install profile — the flag is now
|
||||
# REQUIRED for a fresh install (no default; build-golden v2.0.0 precedent: defaults rot). byo =
|
||||
# BYO-host hardening for a Proxmox host the operator does NOT own: break-glass (step 4b) gated OFF
|
||||
@@ -2002,6 +2007,11 @@ if pf and os.path.exists(pf):
|
||||
except Exception: base = {}
|
||||
# fresh-host defaults for any section not preserved
|
||||
base.setdefault('log_level','info')
|
||||
# CAMPAIGN-3 Part 6: deployment_mode gates the agent's node self-heal (host networking recovery at
|
||||
# boot, F12-class). Authoritative from --mode: "appliance" unlocks the remedy; "byo" (or anything
|
||||
# else, including a stale preserved value) leaves it CHECK-only. Written explicitly so a byo box can
|
||||
# never inherit an appliance self-heal from a --preserve-from config.
|
||||
base['deployment_mode'] = 'appliance' if os.environ.get('INSTALL_MODE') == 'appliance' else 'byo'
|
||||
# privileged.mode = "sudo": the canonical unit runs the agent as the NON-root felhom-agent user, so
|
||||
# every host-root op goes through `sudo -n` against /etc/sudoers.d/felhom-agent. ("direct" was the old
|
||||
# dev/CI shortcut for a root agent.) Force the mode authoritative (a stale preserved "direct" config
|
||||
@@ -2070,18 +2080,19 @@ PY
|
||||
# interpreter pattern as the write above) and refuse to start the daemon on any true value —
|
||||
# a --preserve-from carrying lan_resolver.enable=true is exactly what this catches.
|
||||
if [[ "$MODE" == "byo" ]]; then
|
||||
AGENT_CONFIG="$AGENT_CONFIG" python3 <<'PY' || die "byo config assert FAILED — see the keys above; a byo box must keep lan_resolver/wg_tunnel/oob off (fix the preserved config and re-run with --resume)"
|
||||
AGENT_CONFIG="$AGENT_CONFIG" python3 <<'PY' || die "byo config assert FAILED — see the keys above; a byo box must keep lan_resolver/wg_tunnel/oob off and deployment_mode=byo (fix the preserved config and re-run with --resume)"
|
||||
import json, os, sys
|
||||
d = json.load(open(os.environ['AGENT_CONFIG']))
|
||||
bad = []
|
||||
if d.get('lan_resolver', {}).get('enable'): bad.append('lan_resolver.enable (takes over host DNS on :53)')
|
||||
if d.get('wg_tunnel', {}).get('enabled'): bad.append('wg_tunnel.enabled (opens an outbound WG tunnel)')
|
||||
if d.get('oob', {}).get('enabled'): bad.append('oob.enabled (starts a second operator sshd)')
|
||||
if d.get('deployment_mode') == 'appliance': bad.append('deployment_mode=appliance (unlocks host-service self-heal on a host we do not own)')
|
||||
if bad:
|
||||
print('byo-forbidden config keys are TRUE: ' + '; '.join(bad), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
PY
|
||||
log_success " byo config asserts passed (lan_resolver.enable / wg_tunnel.enabled / oob.enabled all off)"
|
||||
log_success " byo config asserts passed (lan_resolver.enable / wg_tunnel.enabled / oob.enabled off; deployment_mode=byo)"
|
||||
fi
|
||||
|
||||
# health: read-only selftest (proxmox) must pass before provisioning
|
||||
|
||||
Reference in New Issue
Block a user