Fix DC-005 depth-2 route path bugs: 67 broken requires across 21 files
The DC-005 src/ refactor left depth-2 route files (routes/auth/*, routes/recipes/*, routes/apps/*, routes/arr/*, routes/config/*) with broken require() paths. A filesystem-resolving scanner found 67 broken requires across 21 files — three distinct bug classes: A) '../../../src/...' (3 levels up, above package root) — Bug 7, ~49 occurrences B) '../src/utils/...' (1 level up, resolves to nonexistent routes/src/) — ~15 occurrences C) routes/apps/restore.js:5 used utilities/responses (wrong dir) — should be utils/responses All fixed to '../../src/...' (or '../../src/utils/responses' for class C). routes/auth/totp.js was already fixed in the DC-006 commit. Post-fix: 922/922 tests pass, zero new ESLint warnings. No logic changes — purely mechanical require() path corrections.
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@
|
||||
- **owner:** krystie
|
||||
- **details:** 40+ JS files at `dashcaddy-api/` root level (auth-manager.js, credential-manager.js, etc.). Move into organized subdirs under `src/` (e.g., `src/managers/`, `src/security/`, `src/docker/`). Update all require() paths. This is a big refactor — run tests after.
|
||||
- **result:** Refactor complete on `krystie-improvements` branch (879/879 tests passing on branch). Merged into main via commit `283121e` after resolving 24 conflicts. Post-merge regression check surfaced one additional latent path bug from DC-005: `src/monitoring/health-checker.js` still had `require('./platform-paths')` (relative to `src/monitoring/`), but `platform-paths.js` lives at top level — fixed in commit `9688e64` to `require('../../platform-paths')`. Without that fix, 59 cascading test failures in `health-checker.test.js`. Final post-merge state: 921/922 tests passing.
|
||||
- **remaining latent bugs (tracked, NOT yet fixed):** The DC-005 path-rewrite script left depth-2 route files (`routes/auth/*.js`, `routes/recipes/*.js`, `routes/apps/*.js`, `routes/arr/*.js`, `routes/config/*.js`) with `'../../../src/...'` — **3 levels up instead of 2**, which goes above `dashcaddy-api/` entirely. Required path should be `'../../src/...'` for depth-2 routes. Tests didn't catch this because no test previously imported any depth-2 route (only depth-1 routes like `routes/services.js` were tested). Confirmed-broken imports (with file → offending line): `routes/auth/totp.js:2` (FIXED in DC-006 commit), `routes/auth/keys.js:2`, `routes/auth/sso-gate.js:2-3`, `routes/auth/session-handlers.js:2-3`, `routes/recipes/manage.js:2-3`, `routes/recipes/deploy.js:2-3`, `routes/recipes/index.js:2-3`, `routes/config/assets.js:2-4`, `routes/config/settings.js:2-4`, `routes/config/backup.js:2-4`, `routes/apps/restore.js:2`, `routes/apps/compose.js:2-3`, `routes/apps/deploy.js:2-5`, `routes/apps/helpers.js:2-3`, `routes/apps/templates.js:2-3`, `routes/apps/removal.js:2-3`, `routes/arr/detect.js:2`, `routes/arr/smart-connect.js:2`, `routes/arr/credentials.js:2-3`, `routes/arr/helpers.js:2`, `routes/arr/config.js:2-5`, `routes/arr/plex.js:2`. The fix is mechanical (3 → 2 levels) but touches ~22 files — should be its own PR/commit for clean review.
|
||||
- **remaining latent bugs (FIXED):** The DC-005 path-rewrite script left depth-2 route files (`routes/auth/*.js`, `routes/recipes/*.js`, `routes/apps/*.js`, `routes/arr/*.js`, `routes/config/*.js`) with broken require() paths. A filesystem-resolving scanner found **67 broken requires across 21 files** — three distinct bug classes: (A) `'../../../src/...'` (3 levels up, goes above package root) — the documented Bug 7, ~49 occurrences; (B) `'../src/utils/...'` (only 1 level up, resolves to nonexistent `routes/src/`) — undocumented, ~15 occurrences for `responses` and `logging`; (C) `routes/apps/restore.js:5` imported `utilities/responses` when the module lives at `utils/responses` (wrong directory + wrong depth). All 67 fixed to `'../../src/...'` (or `'../../src/utils/responses'` for the class-C case). `routes/auth/totp.js` was already fixed in the DC-006 commit. Tests didn't catch any of these previously because no test imported any depth-2 route. Post-fix: 922/922 tests pass, zero new ESLint warnings.
|
||||
|
||||
### DC-006: Add integration test for TOTP auth flow
|
||||
- **status:** done
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const express = require('express');
|
||||
const yaml = require('js-yaml');
|
||||
const { DOCKER, REGEX } = require('../../../src/utilities/constants');
|
||||
const { ValidationError } = require('../../../src/utilities/errors');
|
||||
const { DOCKER, REGEX } = require('../../src/utilities/constants');
|
||||
const { ValidationError } = require('../../src/utilities/errors');
|
||||
const platformPaths = require('../../platform-paths');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Docker Compose import routes
|
||||
|
||||
@@ -2,13 +2,13 @@ const express = require('express');
|
||||
const fsp = require('fs').promises;
|
||||
const path = require('path');
|
||||
const validatorLib = require('validator');
|
||||
const { REGEX, DOCKER } = require('../../../src/utilities/constants');
|
||||
const { isValidPort } = require('../../../src/security/input-validator');
|
||||
const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
const { REGEX, DOCKER } = require('../../src/utilities/constants');
|
||||
const { isValidPort } = require('../../src/security/input-validator');
|
||||
const { exists } = require('../../src/utilities/fs-helpers');
|
||||
const platformPaths = require('../../platform-paths');
|
||||
const { ValidationError } = require('../../../src/utilities/errors');
|
||||
const { logError } = require('../src/utils/logging');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { ValidationError } = require('../../src/utilities/errors');
|
||||
const { logError } = require('../../src/utils/logging');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
/**
|
||||
* Apps deployment routes factory
|
||||
* @param {Object} deps - Explicit dependencies
|
||||
|
||||
@@ -2,8 +2,8 @@ const fs = require('fs');
|
||||
const fsp = require('fs').promises;
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const { REGEX, DOCKER } = require('../../../src/utilities/constants');
|
||||
const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
const { REGEX, DOCKER } = require('../../src/utilities/constants');
|
||||
const { exists } = require('../../src/utilities/fs-helpers');
|
||||
const platformPaths = require('../../platform-paths');
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const express = require('express');
|
||||
const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
const { logError } = require('../src/utils/logging');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { exists } = require('../../src/utilities/fs-helpers');
|
||||
const { logError } = require('../../src/utils/logging');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
module.exports = function({
|
||||
docker, caddy, servicesStateManager, asyncHandler, log, helpers,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { DOCKER } = require('../../../src/utilities/constants');
|
||||
const { ok, validationError, notFound, errorResponse } = require('../../../src/utilities/responses');
|
||||
const { DOCKER } = require('../../src/utilities/constants');
|
||||
const { ok, validationError, notFound, errorResponse } = require('../../src/utils/responses');
|
||||
|
||||
const DEFAULT_BACKUP_DIR = process.env.BACKUP_DIR || path.join(__dirname, '..', 'backups');
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const express = require('express');
|
||||
const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
const { exists } = require('../../src/utilities/fs-helpers');
|
||||
/**
|
||||
* Apps templates routes factory
|
||||
* @param {Object} deps - Explicit dependencies
|
||||
@@ -19,8 +19,8 @@ const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
* @param {string} deps.SERVICES_FILE - Services file path
|
||||
* @returns {express.Router}
|
||||
*/
|
||||
const { REGEX } = require('../../../src/utilities/constants');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { REGEX } = require('../../src/utilities/constants');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
module.exports = function({
|
||||
servicesStateManager, asyncHandler, helpers,
|
||||
@@ -55,7 +55,7 @@ module.exports = function({
|
||||
const { appId } = req.params;
|
||||
const template = ctx.APP_TEMPLATES[appId];
|
||||
if (!template) {
|
||||
const { NotFoundError } = require('../../../src/utilities/errors');
|
||||
const { NotFoundError } = require('../../src/utilities/errors');
|
||||
throw new NotFoundError('App template');
|
||||
}
|
||||
ok(res, { template });
|
||||
@@ -90,7 +90,7 @@ module.exports = function({
|
||||
// Update subdomain for deployed app
|
||||
router.post('/update-subdomain', asyncHandler(async (req, res) => {
|
||||
const { serviceId, oldSubdomain, newSubdomain, containerId, ip } = req.body;
|
||||
const { ValidationError } = require('../../../src/utilities/errors');
|
||||
const { ValidationError } = require('../../src/utilities/errors');
|
||||
|
||||
if (!oldSubdomain || typeof oldSubdomain !== 'string') {
|
||||
throw new ValidationError('oldSubdomain is required');
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const express = require('express');
|
||||
const { APP_PORTS, ARR_SERVICES } = require('../../../src/utilities/constants');
|
||||
const { validateURL, validateToken } = require('../../../src/security/input-validator');
|
||||
const { ValidationError, AuthenticationError, NotFoundError } = require('../../../src/utilities/errors');
|
||||
const { logError } = require('../src/utils/logging');
|
||||
const { ok, successMessage } = require('../src/utils/responses');
|
||||
const { APP_PORTS, ARR_SERVICES } = require('../../src/utilities/constants');
|
||||
const { validateURL, validateToken } = require('../../src/security/input-validator');
|
||||
const { ValidationError, AuthenticationError, NotFoundError } = require('../../src/utilities/errors');
|
||||
const { logError } = require('../../src/utils/logging');
|
||||
const { ok, successMessage } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Arr configuration routes factory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const express = require('express');
|
||||
const { validateURL, validateToken } = require('../../../src/security/input-validator');
|
||||
const { ValidationError } = require('../../../src/utilities/errors');
|
||||
const { ok, successMessage } = require('../src/utils/responses');
|
||||
const { validateURL, validateToken } = require('../../src/security/input-validator');
|
||||
const { ValidationError } = require('../../src/utilities/errors');
|
||||
const { ok, successMessage } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Arr credentials routes factory
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const express = require('express');
|
||||
const { APP_PORTS, ARR_SERVICES } = require('../../../src/utilities/constants');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { APP_PORTS, ARR_SERVICES } = require('../../src/utilities/constants');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Arr service detection routes factory
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { APP_PORTS } = require('../../../src/utilities/constants');
|
||||
const { APP_PORTS } = require('../../src/utilities/constants');
|
||||
|
||||
/**
|
||||
* Arr helpers factory
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const express = require('express');
|
||||
const { APP_PORTS } = require('../../../src/utilities/constants');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { APP_PORTS } = require('../../src/utilities/constants');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Plex routes factory
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const express = require('express');
|
||||
const { APP_PORTS } = require('../../../src/utilities/constants');
|
||||
const { APP_PORTS } = require('../../src/utilities/constants');
|
||||
|
||||
/**
|
||||
* Arr smart-connect routes factory
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const express = require('express');
|
||||
const { ValidationError, ForbiddenError, NotFoundError } = require('../../../src/utilities/errors');
|
||||
const { ok, successMessage } = require('../src/utils/responses');
|
||||
const { ValidationError, ForbiddenError, NotFoundError } = require('../../src/utilities/errors');
|
||||
const { ok, successMessage } = require('../../src/utils/responses');
|
||||
/**
|
||||
* Auth API keys routes factory
|
||||
* @param {Object} deps - Explicit dependencies
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { SESSION_TTL, APP, PLEX, TIMEOUTS, buildMediaAuth } = require('../../../src/utilities/constants');
|
||||
const { createCache, CACHE_CONFIGS } = require('../../../src/utilities/cache-config');
|
||||
const { SESSION_TTL, APP, PLEX, TIMEOUTS, buildMediaAuth } = require('../../src/utilities/constants');
|
||||
const { createCache, CACHE_CONFIGS } = require('../../src/utilities/cache-config');
|
||||
|
||||
/**
|
||||
* Auth session handlers routes factory
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const express = require('express');
|
||||
const { SESSION_TTL, APP, PLEX, TIMEOUTS, buildMediaAuth } = require('../../../src/utilities/constants');
|
||||
const { AuthenticationError, NotFoundError } = require('../../../src/utilities/errors');
|
||||
const { SESSION_TTL, APP, PLEX, TIMEOUTS, buildMediaAuth } = require('../../src/utilities/constants');
|
||||
const { AuthenticationError, NotFoundError } = require('../../src/utilities/errors');
|
||||
|
||||
/**
|
||||
* Auth SSO gate routes factory
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const express = require('express');
|
||||
const fsp = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { LIMITS } = require('../../../src/utilities/constants');
|
||||
const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
const { ValidationError } = require('../../../src/utilities/errors');
|
||||
const { LIMITS } = require('../../src/utilities/constants');
|
||||
const { exists } = require('../../src/utilities/fs-helpers');
|
||||
const { ValidationError } = require('../../src/utilities/errors');
|
||||
const platformPaths = require('../../platform-paths');
|
||||
const { ok, successMessage } = require('../src/utils/responses');
|
||||
const { ok, successMessage } = require('../../src/utils/responses');
|
||||
/**
|
||||
* Config assets routes factory
|
||||
* @param {Object} deps - Explicit dependencies
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const fsp = require('fs').promises;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { CADDY } = require('../../../src/utilities/constants');
|
||||
const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
const { ValidationError, AuthenticationError } = require('../../../src/utilities/errors');
|
||||
const { CADDY } = require('../../src/utilities/constants');
|
||||
const { exists } = require('../../src/utilities/fs-helpers');
|
||||
const { ValidationError, AuthenticationError } = require('../../src/utilities/errors');
|
||||
const platformPaths = require('../../platform-paths');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Config backup routes factory
|
||||
@@ -380,7 +380,7 @@ module.exports = function(deps) {
|
||||
if (results.restored.includes('encryptionKey')) {
|
||||
try {
|
||||
// Clear the cached key so crypto-utils reloads from the new file on next use
|
||||
const cryptoUtils = require('../../../src/security/crypto-utils');
|
||||
const cryptoUtils = require('../../src/security/crypto-utils');
|
||||
if (typeof cryptoUtils.clearCachedKey === 'function') {
|
||||
cryptoUtils.clearCachedKey();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const fsp = require('fs').promises;
|
||||
const { validateConfig } = require('../../../src/utilities/config-schema');
|
||||
const { exists } = require('../../../src/utilities/fs-helpers');
|
||||
const { ValidationError } = require('../../../src/utilities/errors');
|
||||
const { ok, successMessage } = require('../src/utils/responses');
|
||||
const { validateConfig } = require('../../src/utilities/config-schema');
|
||||
const { exists } = require('../../src/utilities/fs-helpers');
|
||||
const { ValidationError } = require('../../src/utilities/errors');
|
||||
const { ok, successMessage } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Config settings routes factory
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const express = require('express');
|
||||
const { ValidationError } = require('../../../src/utilities/errors');
|
||||
const { ValidationError } = require('../../src/utilities/errors');
|
||||
const crypto = require('crypto');
|
||||
const { DOCKER } = require('../../../src/utilities/constants');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { DOCKER } = require('../../src/utilities/constants');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Recipes deployment routes factory
|
||||
@@ -28,7 +28,7 @@ module.exports = function({ docker, credentialManager: _credentialManager, servi
|
||||
// eslint-disable-next-line complexity
|
||||
router.post('/deploy', asyncHandler(async (req, res) => {
|
||||
const { recipeId, config } = req.body;
|
||||
const { RECIPE_TEMPLATES } = require('../../../src/recipes/recipe-templates');
|
||||
const { RECIPE_TEMPLATES } = require('../../src/recipes/recipe-templates');
|
||||
|
||||
const recipe = RECIPE_TEMPLATES[recipeId];
|
||||
if (!recipe) throw new ValidationError('Invalid recipe template', 'recipeId');
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const express = require('express');
|
||||
const deployRoutes = require('./deploy');
|
||||
const manageRoutes = require('./manage');
|
||||
const { NotFoundError } = require('../../../src/utilities/errors');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { NotFoundError } = require('../../src/utilities/errors');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
/**
|
||||
* Recipes routes aggregator
|
||||
@@ -32,7 +32,7 @@ module.exports = function(ctx) {
|
||||
|
||||
// GET /api/recipes/templates — list all recipe templates
|
||||
router.get('/templates', deps.asyncHandler(async (req, res) => {
|
||||
const { RECIPE_TEMPLATES, RECIPE_CATEGORIES } = require('../../../src/recipes/recipe-templates');
|
||||
const { RECIPE_TEMPLATES, RECIPE_CATEGORIES } = require('../../src/recipes/recipe-templates');
|
||||
const templates = Object.entries(RECIPE_TEMPLATES).map(([id, recipe]) => ({
|
||||
id,
|
||||
name: recipe.name,
|
||||
@@ -61,7 +61,7 @@ module.exports = function(ctx) {
|
||||
|
||||
// GET /api/recipes/templates/:recipeId — get single recipe template detail
|
||||
router.get('/templates/:recipeId', deps.asyncHandler(async (req, res) => {
|
||||
const { RECIPE_TEMPLATES } = require('../../../src/recipes/recipe-templates');
|
||||
const { RECIPE_TEMPLATES } = require('../../src/recipes/recipe-templates');
|
||||
const recipe = RECIPE_TEMPLATES[req.params.recipeId];
|
||||
if (!recipe) throw new NotFoundError(`Recipe template ${req.params.recipeId}`);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const express = require('express');
|
||||
const { DOCKER } = require('../../../src/utilities/constants');
|
||||
const { NotFoundError } = require('../../../src/utilities/errors');
|
||||
const { ok } = require('../src/utils/responses');
|
||||
const { DOCKER } = require('../../src/utilities/constants');
|
||||
const { NotFoundError } = require('../../src/utilities/errors');
|
||||
const { ok } = require('../../src/utils/responses');
|
||||
|
||||
module.exports = function({ servicesStateManager, asyncHandler, log, docker, notification, buildDomain, caddy }) {
|
||||
const router = express.Router();
|
||||
@@ -269,7 +269,7 @@ module.exports = function({ servicesStateManager, asyncHandler, log, docker, not
|
||||
* Find all Docker containers belonging to a recipe by label
|
||||
*/
|
||||
async function findRecipeContainers(recipeId) {
|
||||
const { RECIPE_TEMPLATES } = require('../../../src/recipes/recipe-templates');
|
||||
const { RECIPE_TEMPLATES } = require('../../src/recipes/recipe-templates');
|
||||
const recipe = RECIPE_TEMPLATES[recipeId];
|
||||
const recipeLabel = recipe
|
||||
? recipe.name.toLowerCase().replace(/\s+/g, '-')
|
||||
@@ -293,7 +293,7 @@ module.exports = function({ servicesStateManager, asyncHandler, log, docker, not
|
||||
* Find recipe ID by its label (name slug)
|
||||
*/
|
||||
function findRecipeIdByLabel(label) {
|
||||
const { RECIPE_TEMPLATES } = require('../../../src/recipes/recipe-templates');
|
||||
const { RECIPE_TEMPLATES } = require('../../src/recipes/recipe-templates');
|
||||
for (const [id, recipe] of Object.entries(RECIPE_TEMPLATES)) {
|
||||
if (recipe.name.toLowerCase().replace(/\s+/g, '-') === label) {
|
||||
return id;
|
||||
|
||||
Reference in New Issue
Block a user