UNPKG

task-master-neo-sdlc

Version:

Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.

361 lines (311 loc) 11.7 kB
import { KnowledgeGraph } from '../knowledge-graph'; import { AgentWorkflowSystem } from '../agent-workflow'; export class SecurityAuditorAgent { constructor(knowledgeGraph, workflow) { this.knowledgeGraph = knowledgeGraph; this.workflow = workflow; } async createSecurityAudit(type, scope) { const audit = { id: `audit_${Date.now()}`, timestamp: Date.now(), type, scope, findings: [], summary: { critical: 0, high: 0, medium: 0, low: 0 }, recommendations: [] }; // Add audit to knowledge graph await this.knowledgeGraph.addNode({ id: `audit:${audit.id}`, type: 'security_audit', data: audit }); return audit; } async addVulnerability(auditId, vulnerability) { const audit = await this.knowledgeGraph.findNodes({ type: 'security_audit', id: `audit:${auditId}` })[0]; if (!audit) { throw new Error(`Audit ${auditId} not found`); } const newVulnerability = { ...vulnerability, id: `vuln_${Date.now()}`, status: 'open' }; audit.data.findings.push(newVulnerability); audit.data.summary[newVulnerability.severity]++; await this.knowledgeGraph.updateContext({ id: audit.id, data: audit.data }); return newVulnerability; } async updateVulnerabilityStatus(auditId, vulnerabilityId, status) { const audit = await this.knowledgeGraph.findNodes({ type: 'security_audit', id: `audit:${auditId}` })[0]; if (!audit) { throw new Error(`Audit ${auditId} not found`); } const vulnerability = audit.data.findings.find(v => v.id === vulnerabilityId); if (!vulnerability) { throw new Error(`Vulnerability ${vulnerabilityId} not found in audit ${auditId}`); } vulnerability.status = status; await this.knowledgeGraph.updateContext({ id: audit.id, data: audit.data }); } async createSecurityPolicy(name, description, rules) { const policy = { id: `policy_${Date.now()}`, name, description, rules, enabled: true }; // Add policy to knowledge graph await this.knowledgeGraph.addNode({ id: `policy:${policy.id}`, type: 'security_policy', data: policy }); return policy; } // --- RBAC Methods --- /** * Defines a role with specific permissions. * @param {string} roleId - Unique identifier for the role (e.g., 'admin', 'developer'). * @param {string} description - Description of the role. * @param {string[]} permissions - List of permissions granted to this role (e.g., 'manage_users', 'deploy_staging'). * @returns {Promise<object>} The created role node data. */ async defineRole(roleId, description, permissions) { console.log(`Defining role: ${roleId}`); const roleData = { id: `role:${roleId}`, description, permissions: Array.from(new Set(permissions)) // Ensure unique permissions }; // Add role definition to knowledge graph await this.knowledgeGraph.addNode({ id: roleData.id, type: 'rbac_role', data: roleData }); console.log(`Role ${roleId} defined with ${permissions.length} permissions.`); return roleData; } /** * Assigns a role to an agent. * @param {string} agentId - The ID of the agent node. * @param {string} roleId - The ID of the role to assign. * @returns {Promise<void>} */ async assignRole(agentId, roleId) { console.log(`Assigning role ${roleId} to agent ${agentId}`); const roleNodeId = `role:${roleId}`; // Ensure agent and role exist (optional, addEdge might handle implicitly) const [agentNode, roleNode] = await Promise.all([ this.knowledgeGraph.findNodes({ id: agentId }).then(n => n[0]), // Assuming agent nodes exist this.knowledgeGraph.findNodes({ id: roleNodeId, type: 'rbac_role' }).then(n => n[0]) ]); if (!agentNode) { throw new Error(`Agent ${agentId} not found.`); } if (!roleNode) { throw new Error(`Role ${roleId} (${roleNodeId}) not found.`); } // Add edge representing the role assignment await this.knowledgeGraph.addEdge({ source: agentId, target: roleNodeId, relationship: 'has_role' }); console.log(`Role ${roleId} assigned to ${agentId}.`); } /** * Checks if an agent has a specific permission. * (This would likely be called by the orchestrator or workflow system before allowing an action). * @param {string} agentId - The ID of the agent. * @param {string} requiredPermission - The permission string to check for. * @returns {Promise<boolean>} True if the agent has the permission, false otherwise. */ async checkPermission(agentId, requiredPermission) { console.log(`Checking permission '${requiredPermission}' for agent ${agentId}`); const edges = await this.knowledgeGraph.findEdges({ source: agentId, relationship: 'has_role' }); const roleIds = edges.map(e => e.target); if (roleIds.length === 0) { console.log(`Agent ${agentId} has no assigned roles.`); return false; // No roles, no permissions } const roleNodes = await this.knowledgeGraph.findNodes({ ids: roleIds, type: 'rbac_role' }); for (const roleNode of roleNodes) { if (roleNode.data?.permissions?.includes(requiredPermission)) { console.log(`Permission granted via role: ${roleNode.id}`); return true; } } console.log(`Permission '${requiredPermission}' denied for agent ${agentId}.`); return false; } // --- End RBAC Methods --- // --- Credential Management Audit --- /** * Audits specified configuration sources for potentially insecure credential storage. * @param {Array<object>} sources - List of sources to audit (e.g., { type: 'file', path: '.env' }, { type: 'kg_node', id: 'config:db' }). * @returns {Promise<Array<object>>} A list of findings (potential credential exposures). */ async auditCredentialStorage(sources) { console.log('Auditing credential storage sources...'); const findings = []; const commonSecretPatterns = [ /API_KEY['"\s:=]+['"\s]?([a-zA-Z0-9\-_\.+]{16,})/i, // Common API Key format /SECRET['"\s:=]+['"\s]?([a-zA-Z0-9\-_\.+]{20,})/i, // Generic Secret /PASSWORD['"\s:=]+['"\s]?([^'"\s]{8,})/i, // Password /TOKEN['"\s:=]+['"\s]?([a-zA-Z0-9\-_\.=]{20,})/i, // Token /ACCESS_KEY_ID['"\s:=]+['"\s]?AKIA[A-Z0-9]{16}/i, // AWS Access Key ID /SECRET_ACCESS_KEY['"\s:=]+['"\s]?([a-zA-Z0-9\/\+=]{40})/i // AWS Secret Key ]; for (const source of sources) { let content = ''; let sourceDescription = ''; try { if (source.type === 'file') { sourceDescription = `file:${source.path}`; console.log(` - Auditing file: ${source.path}`); // Placeholder: In reality, read file content securely // content = await fsUtils.readFile(source.path); content = `PASSWORD = \"insecurePassword123\"\nAPI_KEY: 'abc123def456ghi789jkl'`; // Example content } else if (source.type === 'kg_node') { sourceDescription = `kg_node:${source.id}`; console.log(` - Auditing KG node: ${source.id}`); const node = await this.knowledgeGraph.findNodes({ id: source.id }).then(n => n[0]); if (node && node.data) { content = JSON.stringify(node.data, null, 2); } else { console.warn(` - KG node ${source.id} not found or has no data.`); continue; } } else { console.warn(` - Unsupported source type: ${source.type}`); continue; } for (const pattern of commonSecretPatterns) { const matches = content.matchAll(pattern); for (const match of matches) { findings.push({ source: sourceDescription, finding: 'Potential hardcoded credential detected.', match: match[0], // The full matched string pattern: pattern.source, recommendation: 'Store secrets securely using environment variables, a secrets manager (e.g., Vault, AWS Secrets Manager), or encrypted configuration.', severity: 'high' }); } } } catch (error) { console.error(`Error auditing source ${sourceDescription}:`, error); findings.push({ source: sourceDescription, finding: 'Error during audit', details: error.message, severity: 'low' }); } } console.log(`Credential storage audit completed. Found ${findings.length} potential issues.`); // Optionally add findings to a security audit report // if (findings.length > 0) { // const audit = await this.createSecurityAudit('configuration', { sources: sources.map(s => s.type+':'+(s.path||s.id)) }); // for (const finding of findings) { await this.addVulnerability(audit.id, finding); } // } return findings; } // --- End Credential Management Audit --- async evaluateAgainstPolicy(auditId, policyId) { const [audit, policy] = await Promise.all([ this.knowledgeGraph.findNodes({ type: 'security_audit', id: `audit:${auditId}` })[0], this.knowledgeGraph.findNodes({ type: 'security_policy', id: `policy:${policyId}` })[0] ]); if (!audit) { throw new Error(`Audit ${auditId} not found`); } if (!policy) { throw new Error(`Policy ${policyId} not found`); } if (!policy.data.enabled) { return { compliant: true, violations: [] }; } const violations = []; for (const rule of policy.data.rules) { // Evaluate rule condition against audit findings // This is a simplified example - in practice, you'd have more sophisticated // rule evaluation logic based on the rule type and condition const matchingFindings = audit.data.findings.filter( f => f.type === rule.type && f.status === 'open' ); if (matchingFindings.length > 0) { violations.push({ ruleId: rule.id, severity: rule.severity, message: rule.message }); } } return { compliant: violations.length === 0, violations }; } async generateSecurityReport(auditId) { const audit = await this.knowledgeGraph.findNodes({ type: 'security_audit', id: `audit:${auditId}` })[0]; if (!audit) { throw new Error(`Audit ${auditId} not found`); } const criticalFindings = audit.data.findings.filter( f => f.severity === 'critical' && f.status === 'open' ); return { auditSummary: audit.data.summary, criticalFindings, recommendations: audit.data.recommendations }; } } // Add a call to create the E2E policy // This would typically happen during initialization or when security policies are defined. const securityAuditor = new SecurityAuditorAgent(knowledgeGraph, workflow); await securityAuditor.createSecurityPolicy( 'E2E Encryption Required', 'All inter-agent communication must use end-to-end encryption.', [ { id: 'infra-e2e-001', type: 'infrastructure_requirement', // Define appropriate type condition: 'Communication channels use TLS 1.3 or equivalent E2E protocol.', // Example condition severity: 'critical', message: 'Ensure all agent communication channels are encrypted end-to-end.' } ] );