Deploy Oikos Console to apps (105); fix missing-directory crash

Console is live: cloned to /opt/oikos-console, deploy.sh ran clean,
webhook secret written to /etc/oikos-console-deploy/secret from the
pre-registered SOPS secret (never printed — decrypted and piped
straight into the target file in one command), both systemd units
enabled and active. Verified locally (127.0.0.1:8091 -> 200) and
end-to-end (https://oikos.hubris.network/ -> 302, the Authentik gate
firing correctly).

Found a real bug during first boot: oikos-console.service's
ReadWritePaths listed /opt/homelab-context/signals and .../approvals,
but neither existed yet on apps' clone — git doesn't track empty
directories, and nothing had ever written a signal/approval from that
host. ProtectSystem=strict + a missing ReadWritePaths target is a hard
226/NAMESPACE crash, not a graceful degradation. Fixed two ways:
the unit now marks those paths optional (`-` prefix) so a fresh deploy
never crash-loops on this again, and deploy.sh now mkdir -p's them
explicitly so the console has real write access from the first boot,
not just a non-crashing-but-broken start.

This is also the first real exercise of the auto-deploy pipeline: this
push should land via Gitea webhook 14 -> oikos-console-deploy.service
on apps, same as homelab-mcp/secrets-issuance already work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 13:57:50 +02:00
parent 610b096840
commit 7610e5394c
3 changed files with 14 additions and 1 deletions

View File

@@ -32,6 +32,13 @@ if [ ! -d /opt/homelab-context/.git ]; then
exit 1
fi
# signals/ and approvals/ are untracked-when-empty (git doesn't version
# empty directories), so a fresh clone won't have them. The systemd unit's
# ReadWritePaths need these to exist before the process starts (confirmed
# the hard way on first deploy, 2026-07-06 — a missing dir here is a
# 226/NAMESPACE crash-loop, not a graceful degradation).
mkdir -p /opt/homelab-context/signals /opt/homelab-context/approvals
systemctl daemon-reload
if systemctl is-active --quiet oikos-console.service; then
systemctl restart oikos-console.service

View File

@@ -21,7 +21,12 @@ ProtectHome=true
PrivateTmp=true
NoNewPrivileges=true
ReadOnlyPaths=/opt/homelab-context /opt/oikos-console
ReadWritePaths=/opt/homelab-context/signals /opt/homelab-context/approvals /opt/homelab-context/ledger /opt/homelab-context/oikos
# "-" prefix marks each path optional — signals/ and approvals/ are
# untracked-when-empty (git doesn't version empty dirs), so a fresh
# /opt/homelab-context clone won't have them yet. Without "-", systemd
# refuses to start at all (226/NAMESPACE) until something else creates
# them first — confirmed the hard way on first deploy (2026-07-06).
ReadWritePaths=-/opt/homelab-context/signals -/opt/homelab-context/approvals -/opt/homelab-context/ledger -/opt/homelab-context/oikos
[Install]
WantedBy=multi-user.target