DC-010: convert res.json({success:true,...}) → ok() in updates/notifications/tailscale
CI / Test & Lint (push) Has been cancelled
CI / Security audit (push) Has been cancelled

Routes converted: updates.js (17), notifications.js (8), tailscale.js (12).
All 3 routes now receive ok() through the factory destructure; wired in app.js.

notifications.js: kept 2 res.json() calls for genuine partial-failure semantics
  - POST /test with ?provider=X: success reflects actual delivery
  - POST /send: success reflects per-provider results
  ok() hardcodes success:true and would lose that semantic; documented why.

tailscale.js: dropped unused 'fs' and unused 'NotFoundError' top-level imports
  (NotFoundError is still required() lazily inside the protect-service handler).
  Net change: 12 calls cleaned up, 2 lint warnings fixed.

750/750 tests still pass.
This commit is contained in:
Hermes
2026-06-25 14:29:27 -07:00
parent bf515e5415
commit c509f6ff10
4 changed files with 62 additions and 64 deletions
+22 -23
View File
@@ -9,9 +9,10 @@ const { ValidationError } = require('../errors');
* @param {Object} deps.selfUpdater - DashCaddy self-update manager
* @param {Function} deps.asyncHandler - Async route handler wrapper
* @param {Function} deps.logError - Error logging function
* @param {Function} deps.ok - Success response helper
* @returns {express.Router}
*/
module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }) {
module.exports = function({ updateManager, selfUpdater, asyncHandler, logError, ok }) {
const router = express.Router();
// ===== UPDATE MANAGEMENT ENDPOINTS =====
@@ -20,7 +21,7 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
router.post('/updates/check', asyncHandler(async (req, res) => {
await updateManager.checkForUpdates();
const updates = updateManager.getAvailableUpdates();
res.json({ success: true, updates, count: updates.length });
ok(res, { updates, count: updates.length });
}, 'updates-check'));
// Get available updates
@@ -28,19 +29,19 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
const updates = updateManager.getAvailableUpdates();
const paginationParams = parsePaginationParams(req.query);
const result = paginate(updates, paginationParams);
res.json({ success: true, updates: result.data, count: updates.length, ...(result.pagination && { pagination: result.pagination }) });
ok(res, { updates: result.data, count: updates.length, ...(result.pagination && { pagination: result.pagination }) });
}, 'updates-available'));
// Update a container
router.post('/updates/update/:containerId', asyncHandler(async (req, res) => {
const result = await updateManager.updateContainer(req.params.containerId, req.body);
res.json({ success: true, result });
ok(res, { result });
}, 'updates-update'));
// Rollback update
router.post('/updates/rollback/:containerId', asyncHandler(async (req, res) => {
await updateManager.rollbackUpdate(req.params.containerId);
res.json({ success: true, message: 'Rollback completed' });
ok(res, { message: 'Rollback completed' });
}, 'updates-rollback'));
// Get update history
@@ -50,19 +51,19 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
const fetchLimit = paginationParams ? Number.MAX_SAFE_INTEGER : (parseInt(req.query.limit) || 50);
const history = updateManager.getHistory(fetchLimit);
const result = paginate(history, paginationParams);
res.json({ success: true, history: result.data, ...(result.pagination && { pagination: result.pagination }) });
ok(res, { history: result.data, ...(result.pagination && { pagination: result.pagination }) });
}, 'updates-history'));
// Configure auto-update
router.post('/updates/auto-update/:containerId', asyncHandler(async (req, res) => {
updateManager.configureAutoUpdate(req.params.containerId, req.body);
res.json({ success: true, message: 'Auto-update configured' });
ok(res, { message: 'Auto-update configured' });
}, 'updates-auto-update'));
// Get auto-update configuration
router.get('/updates/auto-update', asyncHandler(async (req, res) => {
const config = updateManager.getAutoUpdateConfig();
res.json({ success: true, config });
ok(res, { config });
}, 'updates-auto-update-config'));
// Schedule update
@@ -72,7 +73,7 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
throw new ValidationError('scheduledTime is required');
}
updateManager.scheduleUpdate(req.params.containerId, scheduledTime);
res.json({ success: true, message: 'Update scheduled', scheduledTime });
ok(res, { message: 'Update scheduled', scheduledTime });
}, 'updates-schedule'));
// ===== DASHCADDY SELF-UPDATE ENDPOINTS =====
@@ -80,20 +81,20 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
// Get current version
router.get('/system/version', asyncHandler(async (req, res) => {
const local = selfUpdater.getLocalVersion();
res.json({ success: true, name: 'DashCaddy', version: local.version, commit: local.commit });
ok(res, { name: 'DashCaddy', version: local.version, commit: local.commit });
}, 'system-version'));
// Check for DashCaddy update
router.get('/system/update-check', asyncHandler(async (req, res) => {
const result = await selfUpdater.checkForUpdate();
res.json({ success: true, ...result });
ok(res, { ...result });
}, 'system-update-check'));
// Apply available update
router.post('/system/update-apply', asyncHandler(async (req, res) => {
const check = await selfUpdater.checkForUpdate();
if (!check.available) {
return res.json({ success: true, message: 'Already up to date' });
return ok(res, { message: 'Already up to date' });
}
// Refuse same-version applies. The check.available flag can theoretically be
// true with equal versions (commit-mismatch path); applying anyway just
@@ -102,14 +103,13 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
const localV = check.local && check.local.version;
const remoteV = check.remote && check.remote.version;
if (localV && remoteV && localV === remoteV) {
return res.json({ success: true, message: 'Already up to date', version: localV });
return ok(res, { message: 'Already up to date', version: localV });
}
// Start async — container may restart
selfUpdater.applyUpdate(check.remote).catch(err => {
logError('self-update', err);
});
res.json({
success: true,
ok(res, {
message: 'Update initiated',
fromVersion: localV,
toVersion: remoteV,
@@ -128,20 +128,19 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
// constant-time compare to avoid timing leaks
const presentedBuf = Buffer.from(presented);
const expectedBuf = Buffer.from(expected);
const ok = presentedBuf.length === expectedBuf.length &&
const secretOk = presentedBuf.length === expectedBuf.length &&
presentedBuf.length > 0 &&
require('crypto').timingSafeEqual(presentedBuf, expectedBuf);
if (!ok) {
if (!secretOk) {
return res.status(401).json({ success: false, error: 'Invalid notify secret' });
}
const result = selfUpdater.notifyAndApply('http-notify');
res.json({ success: true, ...result });
ok(res, { ...result });
}, 'system-update-notify'));
// Get update status
router.get('/system/update-status', asyncHandler(async (req, res) => {
res.json({
success: true,
ok(res, {
status: selfUpdater.getStatus(),
lastCheck: selfUpdater.lastCheckTime,
lastResult: selfUpdater.lastCheckResult,
@@ -151,13 +150,13 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
// Get self-update history
router.get('/system/update-history', asyncHandler(async (req, res) => {
const history = selfUpdater.getUpdateHistory();
res.json({ success: true, history });
ok(res, { history });
}, 'system-update-history'));
// List rollback versions
router.get('/system/rollback-versions', asyncHandler(async (req, res) => {
const versions = selfUpdater.getAvailableRollbacks();
res.json({ success: true, versions });
ok(res, { versions });
}, 'system-rollback-versions'));
// Rollback to a previous version
@@ -167,7 +166,7 @@ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }
selfUpdater.rollbackToVersion(version).catch(err => {
logError('self-rollback', err);
});
res.json({ success: true, message: `Rollback to ${version} initiated` });
ok(res, { message: `Rollback to ${version} initiated` });
}, 'system-rollback'));
return router;