DC-011: fix credential route paths + undefined ctx reference error

The src/ module-flattening refactor regressed the DC-001 fix: the 3
service-credential routes in routes/services.js used '/:serviceId/credentials'
instead of '/services/:serviceId/credentials', causing 4 test failures
(services.routes.test.js → 404 instead of 200) — every other route in the
file uses the '/services' prefix.

Also fixed a latent ReferenceError in the same validation branches: they
called ctx.errorResponse() but ctx is never defined in this module's scope
(the factory destructures its deps). Replaced with the imported errorResponse
helper so invalid serviceIds now return a clean 400 instead of crashing 500.

Tests: 4 failed → 0 failed (750 pass). ESLint: no new warnings.
This commit is contained in:
Hermes
2026-06-21 05:54:00 -07:00
parent 3b412bff3b
commit 16276c62fc
+6 -6
View File
@@ -196,12 +196,12 @@ module.exports = function({
// ===== SERVICE CREDENTIAL ENDPOINTS ===== // ===== SERVICE CREDENTIAL ENDPOINTS =====
// Store credentials for a service // Store credentials for a service
router.post('/:serviceId/credentials', asyncHandler(async (req, res) => { router.post('/services/:serviceId/credentials', asyncHandler(async (req, res) => {
const { serviceId } = req.params; const { serviceId } = req.params;
// Validate serviceId to prevent path traversal in credential keys // Validate serviceId to prevent path traversal in credential keys
if (!serviceId || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}$/.test(serviceId)) { if (!serviceId || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}$/.test(serviceId)) {
return ctx.errorResponse(res, 400, 'Invalid service ID'); return errorResponse(res, 400, 'Invalid service ID');
} }
const { apiKey, username, password } = req.body; const { apiKey, username, password } = req.body;
@@ -220,12 +220,12 @@ module.exports = function({
}, 'store-service-creds')); }, 'store-service-creds'));
// Delete credentials for a service // Delete credentials for a service
router.delete('/:serviceId/credentials', asyncHandler(async (req, res) => { router.delete('/services/:serviceId/credentials', asyncHandler(async (req, res) => {
const { serviceId } = req.params; const { serviceId } = req.params;
// Validate serviceId to prevent path traversal in credential keys // Validate serviceId to prevent path traversal in credential keys
if (!serviceId || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}$/.test(serviceId)) { if (!serviceId || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}$/.test(serviceId)) {
return ctx.errorResponse(res, 400, 'Invalid service ID'); return errorResponse(res, 400, 'Invalid service ID');
} }
await credentialManager.delete(`service.${serviceId}.apikey`); await credentialManager.delete(`service.${serviceId}.apikey`);
@@ -235,12 +235,12 @@ module.exports = function({
}, 'delete-service-creds')); }, 'delete-service-creds'));
// Check credential status for a service (what's stored) // Check credential status for a service (what's stored)
router.get('/:serviceId/credentials', asyncHandler(async (req, res) => { router.get('/services/:serviceId/credentials', asyncHandler(async (req, res) => {
const { serviceId } = req.params; const { serviceId } = req.params;
// Validate serviceId to prevent path traversal in credential keys // Validate serviceId to prevent path traversal in credential keys
if (!serviceId || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}$/.test(serviceId)) { if (!serviceId || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}$/.test(serviceId)) {
return ctx.errorResponse(res, 400, 'Invalid service ID'); return errorResponse(res, 400, 'Invalid service ID');
} }
const arrKey = await credentialManager.retrieve(`arr.${serviceId}.apikey`).catch(() => null); const arrKey = await credentialManager.retrieve(`arr.${serviceId}.apikey`).catch(() => null);
const svcKey = await credentialManager.retrieve(`service.${serviceId}.apikey`).catch(() => null); const svcKey = await credentialManager.retrieve(`service.${serviceId}.apikey`).catch(() => null);