feat(updates): seamless release flow — push-notify, VERSION copy, robust mirror
- self-updater: per-instance notify secret (auto-generated), notifyAndApply() triggers an immediate check+apply for the publishing host - routes: POST /api/system/update-notify (X-DashCaddy-Notify-Secret gated, added to public-routes allowlist so TOTP doesn't block machine-to-machine) - dashcaddy-update.sh: include VERSION in backup/deploy/rollback copy lists; belt-and-suspenders write trigger.json commit to VERSION post-deploy. Fixes drift where /app/VERSION stayed at the old commit after self-update. - release.sh: mirror failures are non-fatal+loud; HTTP-verify get2 after rsync; auto-notify co-located instance via /opt/dashcaddy/updates/notify-secret (or honour DASHCADDY_NOTIFY_TARGETS for multi-instance setups).
This commit is contained in:
@@ -116,6 +116,28 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
|
||||
});
|
||||
}, 'system-update-apply'));
|
||||
|
||||
// Notify endpoint — the publishing host POSTs here when a new release is
|
||||
// out so the instance can update within seconds instead of waiting for the
|
||||
// next 30-min poll. Auth is a shared secret in X-DashCaddy-Notify-Secret
|
||||
// (per-instance, generated on first start, lives at
|
||||
// <updatesDir>/notify-secret). This route is in the public-routes allowlist
|
||||
// because TOTP would block machine-to-machine notifies.
|
||||
router.post('/system/update-notify', asyncHandler(async (req, res) => {
|
||||
const presented = req.get('X-DashCaddy-Notify-Secret') || '';
|
||||
const expected = selfUpdater.getNotifySecret() || '';
|
||||
// constant-time compare to avoid timing leaks
|
||||
const presentedBuf = Buffer.from(presented);
|
||||
const expectedBuf = Buffer.from(expected);
|
||||
const ok = presentedBuf.length === expectedBuf.length &&
|
||||
presentedBuf.length > 0 &&
|
||||
require('crypto').timingSafeEqual(presentedBuf, expectedBuf);
|
||||
if (!ok) {
|
||||
return res.status(401).json({ success: false, error: 'Invalid notify secret' });
|
||||
}
|
||||
const result = selfUpdater.notifyAndApply('http-notify');
|
||||
res.json({ success: true, ...result });
|
||||
}, 'system-update-notify'));
|
||||
|
||||
// Get update status
|
||||
router.get('/system/update-status', asyncHandler(async (req, res) => {
|
||||
res.json({
|
||||
|
||||
Reference in New Issue
Block a user