Merge krystie-improvements into main
Resolves 24 conflicts between Hermes (DC-008/009/010 + response-helper
envelope standardization) and Krystie (DC-005 src/ refactor path fixes,
DC-006 TOTP integration, DC-007 new test suites, cloud backup
destinations).
Conflict resolutions:
- src/utils/logging.js: took ours (consumers depend on logError/
safeErrorMessage/createLogger exports)
- src/config/site.js: merged (her factored validateAndLogConfig +
applyConfigFields helpers)
- src/context/dns.js: took hers (admin/readonly role iteration for
write operations)
- src/utilities/backup-
manager.js: took hers (Dropbox/WebDAV/SFTP cloud feature)
- status/dist/*, status/
sw.js: took hers (minified bundles + newer SW cache)
Additional fix (post-merge regression):
- src/monitoring/health-checker.js: fixed DC-005 path miss —
'require(./platform-paths)' → 'require(../../platform-paths)'
Test status: 921/922 passing. One known failure in logging.test.js
(async file-handle timing) tracked as follow-up.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
const express = require('express');
|
||||
const fsp = require('fs').promises;
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { success } = require('../response-helpers');
|
||||
const path = require('path');
|
||||
const { success } = require('../src/utils/responses');
|
||||
|
||||
const DEFAULT_BACKUP_DIR = process.env.BACKUP_DIR || path.join(__dirname, '..', 'backups');
|
||||
const DEFAULT_MAX_STORAGE_BYTES = process.env.BACKUP_MAX_STORAGE_BYTES
|
||||
@@ -60,7 +60,7 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
const { appId, enabled, schedule, retention, runImmediately, destination, destinationPath, maxStorageBytes } = req.body;
|
||||
|
||||
if (!appId) {
|
||||
const { ValidationError } = require('../errors');
|
||||
const { ValidationError } = require('../src/utilities/errors');
|
||||
throw new ValidationError('appId is required');
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
const config = backupManager.getConfig();
|
||||
|
||||
if (!config.backups || !config.backups[appId]) {
|
||||
const { NotFoundError } = require('../errors');
|
||||
const { NotFoundError } = require('../src/utilities/errors');
|
||||
throw new NotFoundError(`No backup schedule found for app: ${appId}`, 'DC-404');
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
|
||||
const backupConfig = config.backups && config.backups[appId];
|
||||
if (!backupConfig) {
|
||||
const { NotFoundError } = require('../errors');
|
||||
const { NotFoundError } = require('../src/utilities/errors');
|
||||
throw new NotFoundError(`No backup schedule found for app: ${appId}`, 'DC-404');
|
||||
}
|
||||
|
||||
@@ -240,13 +240,13 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
|
||||
// Security: prevent path traversal
|
||||
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
|
||||
const { ValidationError } = require('../errors');
|
||||
const { ValidationError } = require('../src/utilities/errors');
|
||||
throw new ValidationError('Invalid filename');
|
||||
}
|
||||
|
||||
const filepath = path.join(DEFAULT_BACKUP_DIR, filename);
|
||||
if (!fs.existsSync(filepath)) {
|
||||
const { NotFoundError } = require('../errors');
|
||||
const { NotFoundError } = require('../src/utilities/errors');
|
||||
throw new NotFoundError(`Backup file not found: ${filename}`, 'DC-404');
|
||||
}
|
||||
|
||||
@@ -376,13 +376,13 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
|
||||
// Security: prevent path traversal
|
||||
if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
|
||||
const { ValidationError } = require('../errors');
|
||||
const { ValidationError } = require('../src/utilities/errors');
|
||||
throw new ValidationError('Invalid filename');
|
||||
}
|
||||
|
||||
const filepath = path.join(DEFAULT_BACKUP_DIR, filename);
|
||||
if (!fs.existsSync(filepath)) {
|
||||
const { NotFoundError } = require('../errors');
|
||||
const { NotFoundError } = require('../src/utilities/errors');
|
||||
throw new NotFoundError(`Backup file not found: ${filename}`, 'DC-404');
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
router.post('/backups/test-destination', asyncHandler(async (req, res) => {
|
||||
const destination = req.body;
|
||||
if (!destination || !destination.type) {
|
||||
const { ValidationError } = require('../errors');
|
||||
const { ValidationError } = require('../src/utilities/errors');
|
||||
throw new ValidationError('destination.type is required');
|
||||
}
|
||||
const result = await backupManager.testDestination(destination);
|
||||
@@ -556,10 +556,10 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
// Get cloud credentials (masked) for a provider
|
||||
// Provider: dropbox | webdav | sftp
|
||||
router.get('/backups/credentials/:provider', asyncHandler(async (req, res) => {
|
||||
const credentialManager = require('../credential-manager');
|
||||
const credentialManager = require('../src/managers/credential-manager');
|
||||
const provider = req.params.provider;
|
||||
if (!['dropbox', 'webdav', 'sftp'].includes(provider)) {
|
||||
const { ValidationError } = require('../errors');
|
||||
const { ValidationError } = require('../src/utilities/errors');
|
||||
throw new ValidationError('Invalid provider');
|
||||
}
|
||||
|
||||
@@ -588,8 +588,8 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
|
||||
// Save cloud credentials for a provider
|
||||
router.post('/backups/credentials/:provider', asyncHandler(async (req, res) => {
|
||||
const credentialManager = require('../credential-manager');
|
||||
const { ValidationError } = require('../errors');
|
||||
const credentialManager = require('../src/managers/credential-manager');
|
||||
const { ValidationError } = require('../src/utilities/errors');
|
||||
const provider = req.params.provider;
|
||||
|
||||
if (!['dropbox', 'webdav', 'sftp'].includes(provider)) {
|
||||
@@ -629,8 +629,8 @@ module.exports = function({ backupManager, licenseManager, asyncHandler }) {
|
||||
|
||||
// Delete cloud credentials for a provider
|
||||
router.delete('/backups/credentials/:provider', asyncHandler(async (req, res) => {
|
||||
const credentialManager = require('../credential-manager');
|
||||
const { ValidationError } = require('../errors');
|
||||
const credentialManager = require('../src/managers/credential-manager');
|
||||
const { ValidationError } = require('../src/utilities/errors');
|
||||
const provider = req.params.provider;
|
||||
|
||||
if (!['dropbox', 'webdav', 'sftp'].includes(provider)) {
|
||||
|
||||
Reference in New Issue
Block a user