[grade=pending] QA sprint: commit 103 at-risk files from multi-agent sprint work

Committed by Hermes autonomous QA sprint 2026-08-13.
These files were modified during the Aug 12 sprint but never committed.
This commit is contained in:
Krystie
2026-08-12 17:34:10 -07:00
parent 0bf4406253
commit 503de258b8
105 changed files with 14057 additions and 2632 deletions
+17 -21
View File
@@ -8,6 +8,7 @@ const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const platformPaths = require('../../platform-paths');
const { log } = require('../utils/logging');
// Encryption settings
const ALGORITHM = 'aes-256-gcm';
@@ -65,7 +66,7 @@ function loadOrCreateKey() {
// Check for key in environment variable first
if (process.env.DASHCADDY_ENCRYPTION_KEY) {
encryptionKey = Buffer.from(process.env.DASHCADDY_ENCRYPTION_KEY, 'hex');
console.log('[Crypto] Using encryption key from environment variable');
log.info('crypto', 'Using encryption key from environment variable');
return encryptionKey;
}
@@ -75,16 +76,16 @@ function loadOrCreateKey() {
const keyData = fs.readFileSync(KEY_FILE, 'utf8').trim();
if (keyData.length >= 64) {
encryptionKey = Buffer.from(keyData, 'hex');
console.log('[Crypto] Loaded encryption key from file');
log.info('crypto', 'Loaded encryption key from file');
// First-run bootstrap: if .bak doesn't exist yet, write the current
// key to it. This ensures the silent recovery path is available from
// the very next restart without requiring an explicit rotateKey().
if (!fs.existsSync(KEY_FILE + '.bak')) {
try {
fs.writeFileSync(KEY_FILE + '.bak', keyData, { mode: 0o600 });
console.log(`[Crypto] Seeded ${KEY_FILE}.bak with current key for future fallback`);
log.info('crypto', 'Seeded .bak key file for future fallback');
} catch (e) {
console.warn('[Crypto] Could not seed .bak key file:', e.message);
log.warn('crypto', 'Could not seed .bak key file', { error: e.message });
}
}
// Try fallback to .bak key if primary can't decrypt existing credentials.
@@ -98,14 +99,14 @@ function loadOrCreateKey() {
encryptionKey = tryFallbackToBackupKey(Buffer.from(keyData, 'hex'), Buffer.from(backupData, 'hex'));
}
} catch (e) {
console.warn('[Crypto] Could not check backup key:', e.message);
log.warn('crypto', 'Could not check backup key', { error: e.message });
}
}
return encryptionKey;
}
// File exists but key is invalid/empty - will generate new one below
} catch (error) {
console.error('[Crypto] Error loading key file:', error.message);
log.error('crypto', error, { operation: 'loadKey' });
}
}
@@ -115,10 +116,10 @@ function loadOrCreateKey() {
try {
// Save key to file with restricted permissions
fs.writeFileSync(KEY_FILE, encryptionKey.toString('hex'), { mode: 0o600 });
console.log('[Crypto] Generated and saved new encryption key');
log.info('crypto', 'Generated and saved new encryption key');
} catch (error) {
console.warn('[Crypto] Could not save key to file:', error.message);
console.warn('[Crypto] Key will be regenerated on restart - credentials will need to be re-entered');
log.warn('crypto', 'Could not save key to file', { error: error.message });
log.warn('crypto', 'Key will be regenerated on restart - credentials will need to be re-entered');
}
return encryptionKey;
@@ -171,12 +172,7 @@ function tryFallbackToBackupKey(primaryKey, backupKey) {
if (tryDecrypt(primaryKey)) return primaryKey;
if (tryDecrypt(backupKey)) {
console.warn(
'[Crypto] Primary encryption key failed to decrypt credentials; ' +
'fell back to .encryption-key.bak. The current primary key was set ' +
'without preserving the original. Consider rotating the key explicitly ' +
'via the credential-manager API to avoid this warning next restart.'
);
log.warn('crypto', 'Primary encryption key failed to decrypt credentials; fell back to .encryption-key.bak. Consider rotating the key explicitly via the credential-manager API.');
return backupKey;
}
return primaryKey; // neither works — credential-manager.diagnose() will report 'unreadable'
@@ -291,7 +287,7 @@ function decryptFields(obj, fields = null) {
try {
result[field] = decrypt(result[field]);
} catch (error) {
console.error(`[Crypto] Failed to decrypt field '${field}':`, error.message);
log.error('crypto', error, { field, operation: 'decryptField' });
// Leave the field as-is if decryption fails
}
}
@@ -315,7 +311,7 @@ function migrateToEncrypted(credentials, sensitiveFields) {
return credentials; // Already encrypted
}
console.log('[Crypto] Migrating plaintext credentials to encrypted format');
log.info('crypto', 'Migrating plaintext credentials to encrypted format');
return encryptFields(credentials, sensitiveFields);
}
@@ -340,10 +336,10 @@ function readEncryptedFile(filePath, sensitiveFields = ['password', 'token', 'ap
}
// Plain text data - migrate it
console.log(`[Crypto] Found plaintext data in ${filePath}, will encrypt on next save`);
log.info('crypto', 'Found plaintext data', { filePath });
return parsed;
} catch (error) {
console.error(`[Crypto] Error reading ${filePath}:`, error.message);
log.error('crypto', error, { filePath, operation: 'readFile' });
return null;
}
}
@@ -357,7 +353,7 @@ function readEncryptedFile(filePath, sensitiveFields = ['password', 'token', 'ap
function writeEncryptedFile(filePath, credentials, sensitiveFields = ['password', 'token', 'apiKey', 'secret']) {
const encrypted = encryptFields(credentials, sensitiveFields);
fs.writeFileSync(filePath, JSON.stringify(encrypted, null, 2), 'utf8');
console.log(`[Crypto] Saved encrypted credentials to ${filePath}`);
log.info('crypto', 'Saved encrypted credentials', { filePath });
}
/**
@@ -377,7 +373,7 @@ function rotateKey() {
try {
fs.writeFileSync(KEY_FILE + '.bak', oldKey.toString('hex'), { mode: 0o600 });
} catch (error) {
console.warn(`[Crypto] Could not save backup key to ${KEY_FILE}.bak:`, error.message);
log.warn('crypto', 'Could not save backup key', { error: error.message });
}
try {