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
JavaScript
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.'
}
]
);