UNPKG

datapilot-cli

Version:

Enterprise-grade streaming multi-format data analysis with comprehensive statistical insights and intelligent relationship detection - supports CSV, JSON, Excel, TSV, Parquet - memory-efficient, cross-platform

562 lines 20.4 kB
"use strict"; /** * Security Configuration Management * Centralised security settings and policy management */ Object.defineProperty(exports, "__esModule", { value: true }); exports.SecurityProfiles = exports.SecurityPolicyBuilder = exports.SecurityConfigManager = exports.DEFAULT_SECURITY_POLICY = void 0; exports.getSecurityConfig = getSecurityConfig; const logger_1 = require("../utils/logger"); const types_1 = require("../core/types"); /** * Default security policy with secure defaults */ exports.DEFAULT_SECURITY_POLICY = { inputValidation: { maxFileSize: 1024 * 1024 * 1024, // 1GB allowedExtensions: ['.csv', '.tsv', '.txt'], allowedMimeTypes: ['text/csv', 'text/plain', 'text/tab-separated-values'], allowSymlinks: false, maxPathDepth: 10, rateLimit: 10, // operations per second }, fileAccess: { defaultOperations: ['read', 'metadata'], requireIntegrityCheck: true, tempFileTimeout: 300000, // 5 minutes maxConcurrentHandles: 100, auditLogRetention: 86400000, // 24 hours }, errorHandling: { hideSystemPaths: true, sanitiseErrorMessages: true, maxStackTraceDepth: 3, logSecurityEvents: true, }, cryptography: { hashAlgorithm: 'sha256', encryptSensitiveData: true, keyDerivationIterations: 100000, saltLength: 32, }, network: { allowExternalConnections: false, allowedDomains: [], requestTimeout: 30000, // 30 seconds maxRequestSize: 10 * 1024 * 1024, // 10MB }, process: { restrictFileSystemAccess: true, disableShellExecution: true, memoryLimit: 2 * 1024 * 1024 * 1024, // 2GB cpuLimit: 80, // 80% CPU usage }, }; /** * Security Configuration Manager */ class SecurityConfigManager { static instance; config; configValidators = new Map(); sensitiveKeys = new Set(); constructor() { this.config = { policy: { ...exports.DEFAULT_SECURITY_POLICY }, environmentOverrides: new Map(), features: { enableAdvancedThreatDetection: false, enableRealTimeMonitoring: true, enableBehaviouralAnalysis: false, enableIntrusionDetection: true, }, compliance: { enableGDPRMode: false, enableSOXCompliance: false, enableHIPAAMode: false, dataRetentionDays: 30, }, }; this.initializeValidators(); this.initializeSensitiveKeys(); this.loadEnvironmentOverrides(); } static getInstance() { if (!SecurityConfigManager.instance) { SecurityConfigManager.instance = new SecurityConfigManager(); } return SecurityConfigManager.instance; } /** * Get current security policy */ getSecurityPolicy() { return JSON.parse(JSON.stringify(this.config.policy)); } /** * Update security policy with validation */ updateSecurityPolicy(updates, context) { try { // Validate updates const validation = this.validatePolicyUpdates(updates); if (!validation.isValid) { throw types_1.DataPilotError.security(`Security policy validation failed: ${validation.errors.join(', ')}`, 'INVALID_SECURITY_POLICY', context); } // Apply updates with deep merge this.config.policy = this.deepMergePolicy(this.config.policy, updates); // Log security policy change this.logSecurityEvent('SECURITY_POLICY_UPDATED', { updates: this.sanitiseForLogging(updates), timestamp: new Date(), }, context); logger_1.logger.info('Security policy updated', { updatedKeys: Object.keys(updates), ...context, }); } catch (error) { logger_1.logger.error('Failed to update security policy', { error: error instanceof Error ? error.message : 'Unknown error', ...context, }); throw error; } } /** * Apply environment-specific security overrides */ applyEnvironmentOverrides(environment) { const overrides = this.config.environmentOverrides.get(environment); if (overrides) { this.config.policy = this.deepMergePolicy(this.config.policy, overrides); logger_1.logger.info('Applied security environment overrides', { environment, overriddenKeys: Object.keys(overrides), }); } } /** * Get security features configuration */ getSecurityFeatures() { return { ...this.config.features }; } /** * Enable or disable security features */ updateSecurityFeatures(features, context) { const previousFeatures = { ...this.config.features }; Object.assign(this.config.features, features); this.logSecurityEvent('SECURITY_FEATURES_UPDATED', { previous: previousFeatures, current: this.config.features, changes: features, }, context); logger_1.logger.info('Security features updated', { features: Object.keys(features), ...context, }); } /** * Get compliance settings */ getComplianceSettings() { return { ...this.config.compliance }; } /** * Check if a specific security feature is enabled */ isFeatureEnabled(feature) { return this.config.features[feature] || false; } /** * Get effective security policy for environment */ getEffectivePolicy(environment) { let policy = { ...this.config.policy }; if (environment) { const overrides = this.config.environmentOverrides.get(environment); if (overrides) { policy = this.deepMergePolicy(policy, overrides); } } return policy; } /** * Validate current security configuration */ validateConfiguration() { const errors = []; const warnings = []; const recommendations = []; const policy = this.config.policy; // Validate input validation settings if (policy.inputValidation.maxFileSize > 10 * 1024 * 1024 * 1024) { warnings.push('Very large maximum file size may pose security risks'); } if (policy.inputValidation.allowSymlinks) { warnings.push('Allowing symbolic links may enable path traversal attacks'); } if (policy.inputValidation.rateLimit > 100) { warnings.push('High rate limit may allow abuse'); } // Validate file access settings if (!policy.fileAccess.requireIntegrityCheck) { warnings.push('Disabling integrity checks reduces security'); } if (policy.fileAccess.maxConcurrentHandles > 1000) { warnings.push('Very high concurrent handle limit may enable resource exhaustion'); } // Validate error handling if (!policy.errorHandling.hideSystemPaths) { errors.push('System paths should be hidden in error messages'); } if (!policy.errorHandling.sanitiseErrorMessages) { errors.push('Error messages should be sanitised'); } // Validate cryptography settings if (policy.cryptography.hashAlgorithm === 'sha256') { recommendations.push('Consider upgrading to SHA-512 for enhanced security'); } if (policy.cryptography.keyDerivationIterations < 50000) { warnings.push('Low key derivation iterations may be vulnerable to brute force'); } // Validate network settings if (policy.network.allowExternalConnections && policy.network.allowedDomains.length === 0) { errors.push('External connections allowed but no domains whitelisted'); } // Validate process settings if (!policy.process.restrictFileSystemAccess) { warnings.push('Unrestricted file system access increases attack surface'); } if (!policy.process.disableShellExecution) { errors.push('Shell execution should be disabled for security'); } return { isValid: errors.length === 0, errors, warnings, recommendations, }; } /** * Export security configuration (with sensitive data redacted) */ exportConfiguration(includeSensitive = false) { const exported = JSON.parse(JSON.stringify(this.config)); if (!includeSensitive) { // Redact sensitive information exported.policy = this.sanitiseForLogging(exported.policy); } return exported; } /** * Import security configuration with validation */ importConfiguration(configData, context) { try { // Validate imported configuration const validation = this.validateImportedConfig(configData); if (!validation.isValid) { throw types_1.DataPilotError.security(`Configuration import validation failed: ${validation.errors.join(', ')}`, 'INVALID_IMPORTED_CONFIG', context); } // Backup current configuration const backup = JSON.parse(JSON.stringify(this.config)); try { // Apply imported configuration // First validate the structure, then merge with existing config const updatedConfig = { ...this.config, ...configData, }; this.config = updatedConfig; this.logSecurityEvent('SECURITY_CONFIG_IMPORTED', { timestamp: new Date(), }, context); logger_1.logger.info('Security configuration imported successfully', context); } catch (error) { // Restore backup on failure this.config = backup; throw error; } } catch (error) { logger_1.logger.error('Failed to import security configuration', { error: error instanceof Error ? error.message : 'Unknown error', ...context, }); throw error; } } // Private helper methods initializeValidators() { this.configValidators.set('maxFileSize', (value) => typeof value === 'number' && value > 0 && value <= 100 * 1024 * 1024 * 1024); this.configValidators.set('allowedExtensions', (value) => Array.isArray(value) && value.every((ext) => typeof ext === 'string' && ext.startsWith('.'))); this.configValidators.set('rateLimit', (value) => typeof value === 'number' && value > 0 && value <= 1000); this.configValidators.set('hashAlgorithm', (value) => typeof value === 'string' && ['sha256', 'sha512'].includes(value)); } initializeSensitiveKeys() { this.sensitiveKeys.add('cryptography.keyDerivationIterations'); this.sensitiveKeys.add('cryptography.saltLength'); this.sensitiveKeys.add('network.allowedDomains'); this.sensitiveKeys.add('process.memoryLimit'); this.sensitiveKeys.add('process.cpuLimit'); } loadEnvironmentOverrides() { // Development environment - more permissive for debugging this.config.environmentOverrides.set('development', { errorHandling: { hideSystemPaths: false, sanitiseErrorMessages: false, maxStackTraceDepth: 10, logSecurityEvents: true, }, inputValidation: { maxFileSize: 100 * 1024 * 1024, // 100MB allowedExtensions: ['.csv', '.tsv', '.txt', '.json'], allowedMimeTypes: ['text/csv', 'text/plain', 'application/json'], allowSymlinks: false, maxPathDepth: 10, rateLimit: 50, }, }); // Production environment - maximum security this.config.environmentOverrides.set('production', { errorHandling: { hideSystemPaths: true, sanitiseErrorMessages: true, maxStackTraceDepth: 1, logSecurityEvents: true, }, inputValidation: { maxFileSize: 50 * 1024 * 1024, // 50MB allowedExtensions: ['.csv', '.tsv', '.txt'], allowedMimeTypes: ['text/csv', 'text/plain'], allowSymlinks: false, maxPathDepth: 5, rateLimit: 5, }, network: { allowExternalConnections: false, allowedDomains: [], requestTimeout: 5000, maxRequestSize: 1024 * 1024, }, process: { restrictFileSystemAccess: true, disableShellExecution: true, memoryLimit: 512 * 1024 * 1024, cpuLimit: 1000, }, }); // CI environment - optimised for testing this.config.environmentOverrides.set('ci', { inputValidation: { maxFileSize: 10 * 1024 * 1024, // 10MB allowedExtensions: ['.csv', '.tsv', '.txt'], allowedMimeTypes: ['text/csv', 'text/plain'], allowSymlinks: false, maxPathDepth: 5, rateLimit: 100, }, fileAccess: { defaultOperations: ['read', 'metadata'], requireIntegrityCheck: false, tempFileTimeout: 60000, // 1 minute maxConcurrentHandles: 10, auditLogRetention: 24 * 60 * 60 * 1000, // 24 hours }, }); } validatePolicyUpdates(updates) { const errors = []; // Recursive validation of nested objects const validateObject = (obj, path = '') => { for (const [key, value] of Object.entries(obj)) { const fullPath = path ? `${path}.${key}` : key; const validator = this.configValidators.get(key); if (validator && !validator(value)) { errors.push(`Invalid value for ${fullPath}: ${value}`); } if (typeof value === 'object' && value !== null && !Array.isArray(value)) { validateObject(value, fullPath); } } }; validateObject(updates); return { isValid: errors.length === 0, errors, }; } validateImportedConfig(configData) { const errors = []; // Check required structure if (!configData.policy || typeof configData.policy !== 'object') { errors.push('Missing or invalid policy section'); } if (!configData.features || typeof configData.features !== 'object') { errors.push('Missing or invalid features section'); } // Validate policy if present if (configData.policy) { const policyValidation = this.validatePolicyUpdates(configData.policy); errors.push(...policyValidation.errors); } return { isValid: errors.length === 0, errors, }; } deepMergePolicy(target, source) { const result = JSON.parse(JSON.stringify(target)); const merge = (targetObj, sourceObj) => { // Use Object.keys() instead of for...in to avoid inherited properties for (const key of Object.keys(sourceObj)) { // Explicitly check for prototype pollution attempts if (key === '__proto__' || key === 'constructor' || key === 'prototype') { continue; // Skip dangerous property names } if (sourceObj[key] && typeof sourceObj[key] === 'object' && !Array.isArray(sourceObj[key])) { if (!targetObj[key]) targetObj[key] = {}; merge(targetObj[key], sourceObj[key]); } else { // Safe assignment - key is guaranteed to be a safe property name targetObj[key] = sourceObj[key]; } } }; merge(result, source); return result; } sanitiseForLogging(data) { const sanitised = JSON.parse(JSON.stringify(data)); const sanitise = (obj, path = '') => { for (const key in obj) { const fullPath = path ? `${path}.${key}` : key; if (this.sensitiveKeys.has(fullPath)) { obj[key] = '[REDACTED]'; } else if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { sanitise(obj[key], fullPath); } } }; sanitise(sanitised); return sanitised; } logSecurityEvent(event, data, context) { logger_1.logger.info(`Security Configuration Event: ${event}`, { ...context, securityEvent: event, eventData: data, timestamp: new Date(), }); } } exports.SecurityConfigManager = SecurityConfigManager; /** * Factory function for easy access */ function getSecurityConfig() { return SecurityConfigManager.getInstance(); } /** * Security policy builder for fluent configuration */ class SecurityPolicyBuilder { policy = {}; static create() { return new SecurityPolicyBuilder(); } inputValidation(config) { this.policy.inputValidation = { ...this.policy.inputValidation, ...config }; return this; } fileAccess(config) { this.policy.fileAccess = { ...this.policy.fileAccess, ...config }; return this; } errorHandling(config) { this.policy.errorHandling = { ...this.policy.errorHandling, ...config }; return this; } cryptography(config) { this.policy.cryptography = { ...this.policy.cryptography, ...config }; return this; } network(config) { this.policy.network = { ...this.policy.network, ...config }; return this; } process(config) { this.policy.process = { ...this.policy.process, ...config }; return this; } build() { return JSON.parse(JSON.stringify(this.policy)); } } exports.SecurityPolicyBuilder = SecurityPolicyBuilder; /** * Pre-defined security profiles */ exports.SecurityProfiles = { /** High security profile for production environments */ HIGH_SECURITY: SecurityPolicyBuilder.create() .inputValidation({ maxFileSize: 100 * 1024 * 1024, // 100MB allowSymlinks: false, rateLimit: 5, }) .fileAccess({ requireIntegrityCheck: true, maxConcurrentHandles: 50, }) .errorHandling({ hideSystemPaths: true, sanitiseErrorMessages: true, maxStackTraceDepth: 1, }) .network({ allowExternalConnections: false, }) .process({ restrictFileSystemAccess: true, disableShellExecution: true, }) .build(), /** Balanced security profile for general use */ BALANCED: SecurityPolicyBuilder.create() .inputValidation({ maxFileSize: 500 * 1024 * 1024, // 500MB rateLimit: 10, }) .fileAccess({ requireIntegrityCheck: true, }) .errorHandling({ hideSystemPaths: true, sanitiseErrorMessages: true, }) .build(), /** Development profile with relaxed security for debugging */ DEVELOPMENT: SecurityPolicyBuilder.create() .inputValidation({ rateLimit: 50, }) .errorHandling({ hideSystemPaths: false, sanitiseErrorMessages: false, maxStackTraceDepth: 10, }) .build(), }; //# sourceMappingURL=security-config.js.map