diff --git a/dashcaddy-api/__tests__/input-validator.test.js b/dashcaddy-api/__tests__/input-validator.test.js index 48f3af6..309748c 100644 --- a/dashcaddy-api/__tests__/input-validator.test.js +++ b/dashcaddy-api/__tests__/input-validator.test.js @@ -14,6 +14,9 @@ const { } = require('../input-validator'); describe('Input Validator', () => { + function fail(message) { + throw new Error(message); + } describe('ValidationError', () => { it('has correct name, message, field, and statusCode', () => { diff --git a/dashcaddy-api/__tests__/routes/health.routes.test.js b/dashcaddy-api/__tests__/routes/health.routes.test.js index ecd6521..558e381 100644 --- a/dashcaddy-api/__tests__/routes/health.routes.test.js +++ b/dashcaddy-api/__tests__/routes/health.routes.test.js @@ -524,9 +524,7 @@ describe('Health Routes', () => { it('returns error when no url parameter provided', async () => { const { app } = createApp(); const res = await request(app).get('/api/health/probe'); - // ValidationError is not imported at module scope, so this throws a ReferenceError - // which the error handler catches as a 500 - expect(res.status).toBe(500); + expect(res.status).toBe(400); }); }); diff --git a/dashcaddy-api/routes/apps/compose.js b/dashcaddy-api/routes/apps/compose.js index 128439b..9473bf7 100644 --- a/dashcaddy-api/routes/apps/compose.js +++ b/dashcaddy-api/routes/apps/compose.js @@ -256,7 +256,9 @@ module.exports = function({ docker, caddy, servicesStateManager, portLockManager const existing = docker.client.getContainer(containerName); await existing.remove({ force: true }); await new Promise(r => setTimeout(r, 1000)); - } catch (_) {} + } catch (_) { + // No stale container to remove + } const container = await docker.client.createContainer(containerConfig); await container.start(); diff --git a/dashcaddy-api/routes/exec.js b/dashcaddy-api/routes/exec.js index 983478c..1a3e69a 100644 --- a/dashcaddy-api/routes/exec.js +++ b/dashcaddy-api/routes/exec.js @@ -55,7 +55,9 @@ async function handleExec(ws, containerId, log) { if (chunks.length > 0 && Buffer.concat(chunks).toString().includes('/bash')) { shell = '/bin/bash'; } - } catch (_) {} + } catch (_) { + // Fall back to /bin/sh when bash detection fails + } execInstance = await container.exec({ Cmd: [shell], @@ -96,21 +98,27 @@ async function handleExec(ws, containerId, log) { return; } } - } catch (_) {} + } catch (_) { + // Treat message as raw terminal input if JSON parsing fails + } // Regular terminal input execStream.write(data); }); ws.on('close', () => { if (execStream) { - try { execStream.destroy(); } catch (_) {} + try { execStream.destroy(); } catch (_) { + // Ignore stream teardown errors on socket close + } } }); ws.on('error', (err) => { log.warn('exec', 'WebSocket error', { containerId, error: err.message }); if (execStream) { - try { execStream.destroy(); } catch (_) {} + try { execStream.destroy(); } catch (_) { + // Ignore stream teardown errors after websocket errors + } } }); diff --git a/dashcaddy-api/routes/services.js b/dashcaddy-api/routes/services.js index 314f7ef..726214d 100644 --- a/dashcaddy-api/routes/services.js +++ b/dashcaddy-api/routes/services.js @@ -8,10 +8,9 @@ const { APP, REGEX, TIMEOUTS } = require('../constants'); const { validateServiceConfig, isValidPort } = require('../input-validator'); const { exists } = require('../fs-helpers'); const { paginate, parsePaginationParams } = require('../pagination'); -const { ValidationError, NotFoundError } = require('../errors'); +const { ValidationError, NotFoundError, ConflictError } = require('../errors'); const { resolveServiceUrl } = require('../url-resolver'); const { success, error: errorResponse } = require('../response-helpers'); -const { ConflictError, ValidationError, NotFoundError } = require('../errors'); /** * Services route factory