Hub stage 8: settings drift, webhook notices, profiles
CI / check (push) Successful in 4m27s
Hub / check (push) Successful in 1m17s
CI / image (push) Successful in 1m54s
Hub / image (push) Successful in 1m56s

The drift check now also covers the settings baseline and the Blocked
and Allowed lists baseline; the drift dialog offers Open compare,
Accept as baseline and Revert to baseline for them. Old drift.json
files still load.

HUB_WEBHOOK_URL (and an optional HUB_WEBHOOK_SECRET for an HMAC
signature) receives drift.found, drift.cleared and write.failed
notices, only on change, without values, never blocking a request and
never logging the address beyond its host. Admins see the webhook
status and can send a test from About and from the drift dialog.

Profiles bundle the hub's app, settings and lists baselines. Applying
one to a server runs install, app configs, settings and lists in order
after a preview; a failed step stops that server's later steps and
Retry failed resumes from it. Profiles export and import as a file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DenozordecandClaude Opus 5.5 committed 2026-11-01 02:11:19 +07:00
1 parent 392b644faa
commit 9742f0fe69
32 files changed
+3123 -106

No files matched your search

+12
View File
@@ -150,6 +150,17 @@ export const ROUTES: Record<string, Route> = {
'hub/apps/history/rollback': writeAll('apps.write'),
'hub/apps/baseline/restore': writeAll('apps.write'),
'hub/apps/drift/accept': writeAll('apps.write'),
// Profiles (profiles.ts): bundles of apps, settings and lists. They hold settings secrets, so everything needs admin.
'hub/profiles/list': read('admin'),
'hub/profiles/get': read('admin'),
'hub/profiles/export': read('admin'),
'hub/profiles/preview': read('admin'),
'hub/profiles/snapshot': writeAll('admin'),
'hub/profiles/delete': writeAll('admin'),
'hub/profiles/import': writeAll('admin'),
'hub/profiles/apply': writeAll('admin'),
'hub/webhook/status': read('admin'),
'hub/webhook/test': writeAll('admin'),
'hub/drift/get': read(),
'hub/drift/check': writeAll('apps.write'),
// Configs can hold secrets, so the file of all baselines needs apps.write even to read.
@@ -220,6 +231,7 @@ const LARGE_BODIES: Record<string, number> = {
'dhcp/scopes/set': 2 * MB,
'hub/settings/baseline/save': 2 * MB,
'hub/settings/overrides/save': 2 * MB,
'hub/profiles/import': 5 * MB,
'allowed/import': 5 * MB,
'blocked/import': 5 * MB,
}