codecrucible-synth
Version:
Production-Ready AI Development Platform with Multi-Voice Synthesis, Smithery MCP Integration, Enterprise Security, and Zero-Timeout Reliability
659 lines (595 loc) • 20 kB
text/typescript
import { E2BService } from '../e2b/e2b-service.js';
import { SecurityValidator } from '../e2b/security-validator.js';
import { E2BCodeExecutionTool } from '../tools/e2b/e2b-code-execution-tool.js';
import { E2BTerminalTool } from '../tools/e2b/e2b-terminal-tool.js';
import { SecureTerminalExecuteTool } from '../tools/secure-terminal-tools.js';
import { SecureExecutionManager } from './secure-execution-manager.js';
import { AdvancedInputValidator, ValidationLevel } from './input-validation-system.js';
import {
SecurityAuditLogger,
AuditEventType,
AuditSeverity,
AuditOutcome,
} from './security-audit-logger.js';
import { RBACSystem, AuthorizationContext } from './production-rbac-system.js';
import { z } from 'zod';
import { logger } from '../logger.js';
import crypto from 'crypto';
/**
* Secure Tool Factory
*
* Provides secure, E2B-based alternatives to unsafe execution tools.
* This factory ensures all code and command execution goes through
* sandboxed E2B environments for maximum security.
*/
export class SecureToolFactory {
private e2bService: E2BService | null = null;
private securityValidator: SecurityValidator;
private rbacSystem: RBACSystem;
private auditLogger: SecurityAuditLogger;
private isE2BAvailable: boolean = false;
private toolExecutionCache = new Map<string, { result: any; timestamp: number }>();
private readonly CACHE_TTL = 5 * 60 * 1000; // 5 minutes
constructor(rbacSystem: RBACSystem, auditLogger: SecurityAuditLogger) {
this.securityValidator = new SecurityValidator();
this.rbacSystem = rbacSystem;
this.auditLogger = auditLogger;
this.initializeE2BService();
}
/**
* Initialize E2B service if API key is available
*/
private async initializeE2BService(): Promise<void> {
try {
// Check if E2B API key is available
const apiKey = process.env.E2B_API_KEY;
if (!apiKey) {
logger.warn('🔒 E2B API key not found. Secure execution will be limited.');
logger.warn('💡 Set E2B_API_KEY environment variable to enable full sandboxing.');
return;
}
this.e2bService = new E2BService({ apiKey });
await this.e2bService.initialize();
this.isE2BAvailable = true;
logger.info('✅ E2B service initialized - secure execution enabled');
} catch (error) {
logger.warn('⚠️ E2B service initialization failed:', error);
logger.warn('🔒 Falling back to restricted execution mode');
this.isE2BAvailable = false;
}
}
/**
* Create secure code execution tool with comprehensive security validation
*/
createCodeExecutionTool(agentContext: any): any {
if (this.isE2BAvailable && this.e2bService) {
logger.info('🔐 Using E2B sandboxed code execution');
return new SecureE2BCodeExecutionTool(
this.e2bService,
agentContext,
this.securityValidator,
this.rbacSystem,
this.auditLogger
);
}
// If E2B is not available, return a restricted execution tool
logger.warn('⚠️ E2B not available, using restricted execution mode');
return new RestrictedCodeExecutionTool(agentContext, this.securityValidator, this.auditLogger);
}
/**
* Create secure terminal execution tool
*/
createTerminalTool(agentContext: any): any {
if (this.isE2BAvailable && this.e2bService) {
logger.info('🔐 Using secure E2B terminal execution');
return new SecureE2BTerminalTool(
this.e2bService,
agentContext,
this.securityValidator,
this.rbacSystem,
this.auditLogger
);
}
logger.warn('⚠️ E2B not available, using restricted terminal mode');
return new RestrictedTerminalTool(agentContext, this.securityValidator, this.auditLogger);
}
/**
* Get security status
*/
getSecurityStatus(): SecurityStatus {
return {
e2bAvailable: this.isE2BAvailable,
sandboxingEnabled: this.isE2BAvailable,
securityLevel: this.isE2BAvailable ? 'high' : 'restricted',
recommendations: this.getSecurityRecommendations(),
};
}
/**
* Get security recommendations
*/
private getSecurityRecommendations(): string[] {
const recommendations: string[] = [];
if (!this.isE2BAvailable) {
recommendations.push('Set up E2B API key for full sandboxed execution');
recommendations.push('Visit https://e2b.dev to get API key');
recommendations.push('Set E2B_API_KEY environment variable');
}
if (process.env.NODE_ENV !== 'production') {
recommendations.push('Enable production mode for enhanced security');
}
return recommendations;
}
/**
* Shutdown E2B service
*/
async shutdown(): Promise<void> {
if (this.e2bService) {
await this.e2bService.shutdown();
logger.info('🔒 E2B service shut down');
}
}
}
/**
* Security status interface
*/
export interface SecurityStatus {
e2bAvailable: boolean;
sandboxingEnabled: boolean;
securityLevel: 'high' | 'restricted' | 'disabled';
recommendations: string[];
}
/**
* Base tool interface for restricted tools
*/
interface BaseTool {
definition: {
name: string;
description: string;
category: string;
parameters?: any;
};
execute(args: any): Promise<any>;
}
/**
* Restricted Code Execution Tool (fallback when E2B unavailable)
*/
class RestrictedCodeExecutionTool implements BaseTool {
definition = {
name: 'restrictedCodeExecution',
description: 'Restricted code execution (E2B unavailable)',
category: 'Code Execution',
};
private securityValidator: SecurityValidator;
private auditLogger: SecurityAuditLogger;
constructor(
agentContext: any,
securityValidator: SecurityValidator,
auditLogger: SecurityAuditLogger
) {
this.securityValidator = securityValidator;
this.auditLogger = auditLogger;
}
async execute(args: any): Promise<any> {
const executionId = crypto.randomBytes(16).toString('hex');
try {
logger.warn('🚨 Code execution requested but E2B sandboxing unavailable');
// Log security violation
await this.auditLogger.logSecurityViolation(
AuditSeverity.HIGH,
'restricted-code-tool',
'Code execution attempted without proper sandboxing',
{ executionId },
{ code: args.code?.substring(0, 200) + '...', language: args.language }
);
// Perform strict validation
const validation = this.securityValidator.validateCode(args.code, args.language);
if (!validation.isValid) {
await this.auditLogger.logEvent(
AuditEventType.SECURITY_VIOLATION,
AuditSeverity.CRITICAL,
AuditOutcome.FAILURE,
'code-validation',
'validate',
'code-execution',
`Code execution blocked: ${validation.reason}`,
{ executionId },
{ code: args.code?.substring(0, 200) + '...', reason: validation.reason }
);
return {
success: false,
error: `Code execution blocked: ${validation.reason}`,
securityWarning: 'E2B sandboxing not available - execution denied for security',
executionId,
};
}
return {
success: false,
error: 'Code execution requires E2B sandboxing for security',
recommendation: 'Set up E2B API key to enable secure code execution',
securityLevel: 'restricted',
executionId,
};
} catch (error) {
logger.error('Error in restricted code execution tool', error as Error);
return {
success: false,
error: 'Internal security error',
executionId,
};
}
}
}
/**
* Restricted Terminal Tool (fallback when E2B unavailable)
*/
class RestrictedTerminalTool implements BaseTool {
definition = {
name: 'restrictedTerminal',
description: 'Restricted terminal execution (E2B unavailable)',
category: 'Terminal Operations',
};
private securityValidator: SecurityValidator;
private auditLogger: SecurityAuditLogger;
constructor(
agentContext: any,
securityValidator: SecurityValidator,
auditLogger: SecurityAuditLogger
) {
this.securityValidator = securityValidator;
this.auditLogger = auditLogger;
}
async execute(args: any): Promise<any> {
logger.warn('🚨 Terminal command requested but E2B sandboxing unavailable');
// Only allow very safe read-only commands
const safeCommands = ['ls', 'pwd', 'whoami', 'date', 'echo', 'cat', 'head', 'tail'];
const command = args.command.trim().split(' ')[0];
if (!safeCommands.includes(command)) {
return {
success: false,
error: `Command '${command}' not allowed without E2B sandboxing`,
recommendation: 'Set up E2B API key to enable secure command execution',
allowedCommands: safeCommands,
securityLevel: 'restricted',
};
}
// Even for safe commands, perform validation
const validation = this.securityValidator.validateCommand(args.command);
if (!validation.isValid) {
return {
success: false,
error: `Command validation failed: ${validation.reason}`,
securityWarning: 'Command blocked by security policy',
};
}
return {
success: false,
error: 'Terminal commands require E2B sandboxing for security',
recommendation: 'Set up E2B API key to enable secure terminal access',
securityLevel: 'restricted',
};
}
}
/**
* Enhanced Secure E2B Code Execution Tool with RBAC and audit logging
*/
class SecureE2BCodeExecutionTool implements BaseTool {
definition = {
name: 'secureCodeExecution',
description: 'Secure sandboxed code execution with RBAC',
category: 'Code Execution',
parameters: z.object({
code: z.string().min(1).max(50000),
language: z.enum(['python', 'javascript', 'typescript', 'bash', 'shell']),
timeout: z.number().optional().default(30000),
context: z.any().optional(),
}),
};
constructor(
private e2bService: E2BService,
private agentContext: any,
private securityValidator: SecurityValidator,
private rbacSystem: RBACSystem,
private auditLogger: SecurityAuditLogger
) {}
async execute(args: any): Promise<any> {
const executionId = crypto.randomBytes(16).toString('hex');
const startTime = Date.now();
try {
// Input validation
const inputValidation = AdvancedInputValidator.validateInput(args.code, 'code', {
level: ValidationLevel.STRICT,
allowScripts: true,
allowFileOperations: true,
maxLength: 50000,
});
if (!inputValidation.success) {
await this.auditLogger.logEvent(
AuditEventType.SECURITY_VIOLATION,
AuditSeverity.HIGH,
AuditOutcome.FAILURE,
'secure-code-tool',
'validate_input',
'code-execution',
'Code execution blocked by input validation',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ reason: (inputValidation as any).error.message }
);
return {
success: false,
error: 'Code validation failed',
details: (inputValidation as any).error.message,
executionId,
};
}
// Authorization check
const authResult = await this.rbacSystem.authorize({
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
resource: 'ai_model',
action: 'execute',
context: {
data: { tool: 'code_execution', language: args.language },
ipAddress: this.agentContext.ipAddress,
userAgent: this.agentContext.userAgent,
},
});
if (!authResult.granted) {
await this.auditLogger.logAuthorization(
AuditOutcome.FAILURE,
this.agentContext.userId,
'code-execution',
'execute',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ reason: authResult.reason }
);
return {
success: false,
error: 'Access denied',
details: authResult.reason,
executionId,
};
}
// Security validation
const securityValidation = this.securityValidator.validateCode(args.code, args.language);
if (!securityValidation.isValid) {
await this.auditLogger.logSecurityViolation(
AuditSeverity.HIGH,
'secure-code-tool',
`Malicious code detected: ${securityValidation.reason}`,
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ code: args.code.substring(0, 200) + '...', language: args.language }
);
return {
success: false,
error: 'Security validation failed',
details: securityValidation.reason,
executionId,
};
}
// Execute in E2B sandbox
logger.info('Executing code in E2B sandbox', { executionId, language: args.language });
const result = await this.e2bService.executeCode(
executionId,
inputValidation.data.sanitizedValue,
args.language || 'python'
);
// Log successful execution
await this.auditLogger.logEvent(
AuditEventType.DATA_ACCESS,
AuditSeverity.LOW,
AuditOutcome.SUCCESS,
'secure-code-tool',
'execute',
'code-execution',
'Code executed successfully in sandbox',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{
language: args.language,
executionTime: Date.now() - startTime,
outputLength: result.output?.length || 0,
}
);
return {
success: true,
result,
executionId,
executionTime: Date.now() - startTime,
securityLevel: 'high',
};
} catch (error) {
await this.auditLogger.logEvent(
AuditEventType.ERROR_EVENT,
AuditSeverity.MEDIUM,
AuditOutcome.ERROR,
'secure-code-tool',
'execute',
'code-execution',
'Code execution failed with error',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ error: (error as Error).message }
);
logger.error('Secure code execution failed', error as Error, { executionId });
return {
success: false,
error: 'Execution failed',
details: (error as Error).message,
executionId,
};
}
}
}
/**
* Enhanced Secure E2B Terminal Tool with RBAC and audit logging
*/
class SecureE2BTerminalTool implements BaseTool {
definition = {
name: 'secureTerminal',
description: 'Secure sandboxed terminal execution with RBAC',
category: 'Terminal Operations',
parameters: z.object({
command: z.string().min(1).max(1000),
timeout: z.number().optional().default(30000),
workingDirectory: z.string().optional(),
}),
};
constructor(
private e2bService: E2BService,
private agentContext: any,
private securityValidator: SecurityValidator,
private rbacSystem: RBACSystem,
private auditLogger: SecurityAuditLogger
) {}
async execute(args: any): Promise<any> {
const executionId = crypto.randomBytes(16).toString('hex');
const startTime = Date.now();
try {
// Input validation
const commandValidation = AdvancedInputValidator.validateCommand(args.command);
if (!commandValidation.success) {
await this.auditLogger.logSecurityViolation(
AuditSeverity.HIGH,
'secure-terminal-tool',
'Dangerous command blocked',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ command: args.command, reason: (commandValidation as any).error.message }
);
return {
success: false,
error: 'Command validation failed',
details: (commandValidation as any).error.message,
executionId,
};
}
// Authorization check
const authResult = await this.rbacSystem.authorize({
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
resource: 'system',
action: 'execute',
context: {
data: { tool: 'terminal', command: args.command },
ipAddress: this.agentContext.ipAddress,
userAgent: this.agentContext.userAgent,
},
});
if (!authResult.granted) {
await this.auditLogger.logAuthorization(
AuditOutcome.FAILURE,
this.agentContext.userId,
'terminal-execution',
'execute',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ command: args.command, reason: authResult.reason }
);
return {
success: false,
error: 'Access denied',
details: authResult.reason,
executionId,
};
}
// Security validation
const securityValidation = this.securityValidator.validateCommand(args.command);
if (!securityValidation.isValid) {
await this.auditLogger.logSecurityViolation(
AuditSeverity.CRITICAL,
'secure-terminal-tool',
`Malicious command detected: ${securityValidation.reason}`,
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ command: args.command }
);
return {
success: false,
error: 'Security validation failed',
details: securityValidation.reason,
executionId,
};
}
// Execute in E2B sandbox
logger.info('Executing command in E2B sandbox', { executionId, command: args.command });
const result = await this.e2bService.executeCode(executionId, commandValidation.data, 'bash');
// Log successful execution
await this.auditLogger.logEvent(
AuditEventType.SYSTEM_EVENT,
AuditSeverity.LOW,
AuditOutcome.SUCCESS,
'secure-terminal-tool',
'execute',
'terminal-execution',
'Command executed successfully in sandbox',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{
command: args.command,
executionTime: Date.now() - startTime,
exitCode: result.success ? 0 : 1,
}
);
return {
success: true,
result,
executionId,
executionTime: Date.now() - startTime,
securityLevel: 'high',
};
} catch (error) {
await this.auditLogger.logEvent(
AuditEventType.ERROR_EVENT,
AuditSeverity.MEDIUM,
AuditOutcome.ERROR,
'secure-terminal-tool',
'execute',
'terminal-execution',
'Terminal execution failed with error',
{
userId: this.agentContext.userId,
sessionId: this.agentContext.sessionId,
executionId,
},
{ command: args.command, error: (error as Error).message }
);
logger.error('Secure terminal execution failed', error as Error, { executionId });
return {
success: false,
error: 'Execution failed',
details: (error as Error).message,
executionId,
};
}
}
}