From 23df6a8b5296638a600d8e6fcefd096c3a06b156 Mon Sep 17 00:00:00 2001 From: bunker-admin Date: Wed, 15 Apr 2026 11:57:50 -0600 Subject: [PATCH] Fresh-install + upgrade-path hardening bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six independent fixes surfaced during the v2.9.1 → v2.9.2 admin-UI upgrade validation today. Together they make a clean install on a new box work end-to-end without in-session patching. - Fix 1: scripts/validate-compose-parity.sh + build-release.sh hook — fail release builds when api/admin/media-api/nginx healthcheck blocks drift between docker-compose.yml and docker-compose.prod.yml. Previous boot-race fix had to be applied to both files manually. - Fix 2: scripts/systemd/install.sh chowns logs/ to the install user (the API container creates subdirs there as root, locking the host-side watcher out), pre-creates logs/upgrade-watcher.log, and changemaker-upgrade.service adds StartLimitIntervalSec=0 so a single transient failure can't wedge the .path unit permanently. - Fix 3: /api/upgrade/status now returns a `watcher` sub-object that flags the host systemd watcher as stalled when trigger.json has been pending >30s. Admin SettingsPage SystemUpgradeTab renders a warning Alert with the systemctl recovery command when unhealthy. - Fix 4: scripts/upgrade.sh write_result() — prefer head -1 VERSION over `git rev-parse HEAD` so release-mode upgrades report the new tag in result.json instead of "unknown". - Fix 5: admin container healthcheck start_period 20s → 60s in both compose files, same class as the earlier api fix. Matches Gancio convention. - Fix 7: /api/pangolin/sync now detects resources bound to a stale siteId (common after --pangolin-site new rotations), deletes and recreates them against the current site, and reports them under a new `reassigned` response field. Bunker Admin --- admin/src/pages/SettingsPage.tsx | 24 +++++- admin/src/types/api.ts | 7 ++ api/src/modules/pangolin/pangolin.routes.ts | 90 +++++++++++++-------- api/src/modules/upgrade/upgrade.routes.ts | 3 +- api/src/modules/upgrade/upgrade.service.ts | 32 ++++++++ docker-compose.prod.yml | 2 +- docker-compose.yml | 2 +- scripts/build-release.sh | 11 +++ scripts/systemd/changemaker-upgrade.service | 1 + scripts/systemd/install.sh | 8 ++ scripts/upgrade.sh | 4 +- scripts/validate-compose-parity.sh | 78 ++++++++++++++++++ 12 files changed, 223 insertions(+), 39 deletions(-) create mode 100755 scripts/validate-compose-parity.sh diff --git a/admin/src/pages/SettingsPage.tsx b/admin/src/pages/SettingsPage.tsx index 9abab2d7..0c459f66 100644 --- a/admin/src/pages/SettingsPage.tsx +++ b/admin/src/pages/SettingsPage.tsx @@ -62,7 +62,7 @@ import { api } from '@/lib/api'; import { useMobile } from '@/hooks/useMobile'; import { PageTour } from '@/components/tour/PageTour'; import type { AppOutletContext } from '@/components/AppLayout'; -import type { SmtpTestResult, SmtpSendTestResult, UpgradeStatusResponse, UpgradeStatus, UpgradeProgress, UpgradeResult, UpgradeHistoryResponse } from '@/types/api'; +import type { SmtpTestResult, SmtpSendTestResult, UpgradeStatusResponse, UpgradeStatus, UpgradeProgress, UpgradeResult, UpgradeHistoryResponse, WatcherHealth } from '@/types/api'; const { Text, Paragraph } = Typography; @@ -742,6 +742,7 @@ function SystemUpgradeTab() { const [progress, setProgress] = useState(null); const [result, setResult] = useState(null); const [running, setRunning] = useState(false); + const [watcher, setWatcher] = useState(null); const [checking, setChecking] = useState(false); const [upgrading, setUpgrading] = useState(false); const [apiOffline, setApiOffline] = useState(false); @@ -760,6 +761,7 @@ function SystemUpgradeTab() { setProgress(data.progress); setResult(data.result); setRunning(data.running); + setWatcher(data.watcher ?? null); setApiOffline(false); return data; } catch { @@ -996,6 +998,26 @@ function SystemUpgradeTab() { /> )} + {watcher && !watcher.healthy && ( + +
{watcher.reason || 'Host systemd watcher is not processing upgrade triggers.'}
+
+ Recovery:{' '} + + sudo systemctl reset-failed changemaker-upgrade.path changemaker-upgrade.service && sudo systemctl restart changemaker-upgrade.path + +
+ + } + showIcon + style={{ marginBottom: 16 }} + /> + )} + {/* Actions */}