aura-security 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +446 -0
  3. package/deploy/AWS-DEPLOYMENT.md +358 -0
  4. package/deploy/terraform/main.tf +362 -0
  5. package/deploy/terraform/terraform.tfvars.example +6 -0
  6. package/dist/agents/base.d.ts +44 -0
  7. package/dist/agents/base.js +96 -0
  8. package/dist/agents/index.d.ts +14 -0
  9. package/dist/agents/index.js +17 -0
  10. package/dist/agents/policy/evaluator.d.ts +15 -0
  11. package/dist/agents/policy/evaluator.js +183 -0
  12. package/dist/agents/policy/index.d.ts +12 -0
  13. package/dist/agents/policy/index.js +15 -0
  14. package/dist/agents/policy/validator.d.ts +15 -0
  15. package/dist/agents/policy/validator.js +182 -0
  16. package/dist/agents/scanners/gitleaks.d.ts +14 -0
  17. package/dist/agents/scanners/gitleaks.js +155 -0
  18. package/dist/agents/scanners/grype.d.ts +14 -0
  19. package/dist/agents/scanners/grype.js +109 -0
  20. package/dist/agents/scanners/index.d.ts +15 -0
  21. package/dist/agents/scanners/index.js +27 -0
  22. package/dist/agents/scanners/npm-audit.d.ts +13 -0
  23. package/dist/agents/scanners/npm-audit.js +129 -0
  24. package/dist/agents/scanners/semgrep.d.ts +14 -0
  25. package/dist/agents/scanners/semgrep.js +131 -0
  26. package/dist/agents/scanners/trivy.d.ts +14 -0
  27. package/dist/agents/scanners/trivy.js +122 -0
  28. package/dist/agents/types.d.ts +137 -0
  29. package/dist/agents/types.js +91 -0
  30. package/dist/auditor/index.d.ts +3 -0
  31. package/dist/auditor/index.js +2 -0
  32. package/dist/auditor/pipeline.d.ts +19 -0
  33. package/dist/auditor/pipeline.js +240 -0
  34. package/dist/auditor/validator.d.ts +17 -0
  35. package/dist/auditor/validator.js +58 -0
  36. package/dist/aura/client.d.ts +29 -0
  37. package/dist/aura/client.js +125 -0
  38. package/dist/aura/index.d.ts +4 -0
  39. package/dist/aura/index.js +2 -0
  40. package/dist/aura/server.d.ts +45 -0
  41. package/dist/aura/server.js +343 -0
  42. package/dist/cli.d.ts +17 -0
  43. package/dist/cli.js +1433 -0
  44. package/dist/client/index.d.ts +41 -0
  45. package/dist/client/index.js +170 -0
  46. package/dist/compliance/index.d.ts +40 -0
  47. package/dist/compliance/index.js +292 -0
  48. package/dist/database/index.d.ts +77 -0
  49. package/dist/database/index.js +395 -0
  50. package/dist/index.d.ts +25 -0
  51. package/dist/index.js +762 -0
  52. package/dist/integrations/aura-scanner.d.ts +69 -0
  53. package/dist/integrations/aura-scanner.js +155 -0
  54. package/dist/integrations/aws-scanner.d.ts +63 -0
  55. package/dist/integrations/aws-scanner.js +624 -0
  56. package/dist/integrations/config.d.ts +69 -0
  57. package/dist/integrations/config.js +212 -0
  58. package/dist/integrations/github.d.ts +45 -0
  59. package/dist/integrations/github.js +201 -0
  60. package/dist/integrations/gitlab.d.ts +36 -0
  61. package/dist/integrations/gitlab.js +110 -0
  62. package/dist/integrations/index.d.ts +11 -0
  63. package/dist/integrations/index.js +11 -0
  64. package/dist/integrations/local-scanner.d.ts +146 -0
  65. package/dist/integrations/local-scanner.js +1654 -0
  66. package/dist/integrations/notifications.d.ts +99 -0
  67. package/dist/integrations/notifications.js +305 -0
  68. package/dist/integrations/scanners.d.ts +57 -0
  69. package/dist/integrations/scanners.js +217 -0
  70. package/dist/integrations/slop-scanner.d.ts +69 -0
  71. package/dist/integrations/slop-scanner.js +155 -0
  72. package/dist/integrations/webhook.d.ts +37 -0
  73. package/dist/integrations/webhook.js +256 -0
  74. package/dist/orchestrator/index.d.ts +72 -0
  75. package/dist/orchestrator/index.js +187 -0
  76. package/dist/output/index.d.ts +152 -0
  77. package/dist/output/index.js +399 -0
  78. package/dist/pipeline/index.d.ts +72 -0
  79. package/dist/pipeline/index.js +313 -0
  80. package/dist/sbom/index.d.ts +94 -0
  81. package/dist/sbom/index.js +298 -0
  82. package/dist/schemas/index.d.ts +2 -0
  83. package/dist/schemas/index.js +2 -0
  84. package/dist/schemas/input.schema.d.ts +87 -0
  85. package/dist/schemas/input.schema.js +44 -0
  86. package/dist/schemas/output.schema.d.ts +115 -0
  87. package/dist/schemas/output.schema.js +64 -0
  88. package/dist/serve-visualizer.d.ts +2 -0
  89. package/dist/serve-visualizer.js +78 -0
  90. package/dist/slop/client.d.ts +29 -0
  91. package/dist/slop/client.js +125 -0
  92. package/dist/slop/index.d.ts +4 -0
  93. package/dist/slop/index.js +2 -0
  94. package/dist/slop/server.d.ts +45 -0
  95. package/dist/slop/server.js +343 -0
  96. package/dist/types/events.d.ts +62 -0
  97. package/dist/types/events.js +2 -0
  98. package/dist/types/index.d.ts +1 -0
  99. package/dist/types/index.js +1 -0
  100. package/dist/visualizer/index.d.ts +4 -0
  101. package/dist/visualizer/index.js +181 -0
  102. package/dist/websocket/index.d.ts +88 -0
  103. package/dist/websocket/index.js +195 -0
  104. package/dist/zones/index.d.ts +7 -0
  105. package/dist/zones/index.js +7 -0
  106. package/dist/zones/manager.d.ts +101 -0
  107. package/dist/zones/manager.js +304 -0
  108. package/dist/zones/types.d.ts +78 -0
  109. package/dist/zones/types.js +33 -0
  110. package/package.json +84 -0
  111. package/visualizer/app.js +0 -0
  112. package/visualizer/index-minimal.html +1771 -0
  113. package/visualizer/index.html +2933 -0
  114. package/visualizer/landing.html +1328 -0
  115. package/visualizer/styles.css +0 -0
package/dist/index.js ADDED
@@ -0,0 +1,762 @@
1
+ // aurasecurity - Main entry point
2
+ // No Aura bus = No run (fail-closed)
3
+ import { AuraServer } from './aura/server.js';
4
+ import { AuraClient } from './aura/client.js';
5
+ import { AuditorPipeline } from './auditor/pipeline.js';
6
+ import { SchemaValidator, ValidationError } from './auditor/validator.js';
7
+ import { LocalScanner, scanRemoteGit } from './integrations/local-scanner.js';
8
+ import { auraScan, getAuraState, getAvailableAgents } from './integrations/aura-scanner.js';
9
+ import { getWebSocketServer } from './websocket/index.js';
10
+ const PORT = parseInt(process.env.AURA_PORT ?? '3000', 10);
11
+ const WS_PORT = parseInt(process.env.WS_PORT ?? '3001', 10);
12
+ const AURA_BUS_URL = process.env.AURA_BUS_URL;
13
+ // Secret patterns for remote scanning - stricter patterns to avoid false positives
14
+ const REMOTE_SECRET_PATTERNS = [
15
+ { name: 'AWS Access Key', regex: /AKIA[0-9A-Z]{16}/g, severity: 'critical' },
16
+ // AWS Secret Key - must have mixed chars (not just ===), and be in quotes or after =
17
+ { name: 'AWS Secret Key', regex: /(?:secret|aws)[_-]?(?:key|access)?\s*[=:]\s*['"]([A-Za-z0-9\/+]{40})['"]/gi, severity: 'critical' },
18
+ { name: 'Private Key', regex: /-----BEGIN\s+(RSA|EC|OPENSSH|PGP|ENCRYPTED)?\s*PRIVATE\s+KEY-----/g, severity: 'critical' },
19
+ { name: 'GitHub Token', regex: /gh[pousr]_[A-Za-z0-9_]{36,}/g, severity: 'critical' },
20
+ { name: 'GitLab Token', regex: /glpat-[A-Za-z0-9_-]{20,}/g, severity: 'critical' },
21
+ { name: 'Stripe Key', regex: /sk_live_[A-Za-z0-9]{24,}/g, severity: 'critical' },
22
+ { name: 'Stripe Test Key', regex: /sk_test_[A-Za-z0-9]{24,}/g, severity: 'medium' },
23
+ { name: 'Slack Token', regex: /xox[baprs]-[A-Za-z0-9-]{10,}/g, severity: 'high' },
24
+ { name: 'Database URL', regex: /(mongodb|postgres|mysql|redis):\/\/[^:]+:[^@]+@[^\s"']+/gi, severity: 'critical' },
25
+ { name: 'JWT Token', regex: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{20,}/g, severity: 'medium' },
26
+ { name: 'OpenAI Key', regex: /sk-[A-Za-z0-9]{32,}/g, severity: 'high' },
27
+ { name: 'API Key Assignment', regex: /api[_-]?key\s*[=:]\s*['"]([A-Za-z0-9_\-]{20,})['"]/gi, severity: 'high' },
28
+ { name: 'Password Assignment', regex: /password\s*[=:]\s*['"]([^'"]{8,})['"]/gi, severity: 'critical' },
29
+ // Generic secret/key assignment with actual values (not placeholders)
30
+ { name: 'Secret Assignment', regex: /(?:secret|private)[_-]?key\s*[=:]\s*['"]([A-Fa-f0-9]{32,})['"]/gi, severity: 'critical' },
31
+ { name: 'Hex Private Key', regex: /(?:private[_-]?key|priv[_-]?key)\s*[=:]\s*['"]?([A-Fa-f0-9]{64})['"]?/gi, severity: 'critical' },
32
+ ];
33
+ // Scan a remote Git repo via API without cloning
34
+ async function scanRemoteGitRepo(gitUrl) {
35
+ // Parse GitHub URL: https://github.com/owner/repo
36
+ const githubMatch = gitUrl.match(/github\.com\/([^\/]+)\/([^\/]+)/);
37
+ const gitlabMatch = gitUrl.match(/gitlab\.com\/([^\/]+)\/([^\/]+)/);
38
+ if (!githubMatch && !gitlabMatch) {
39
+ throw new Error('Only GitHub and GitLab URLs are supported for remote scanning');
40
+ }
41
+ const isGitHub = !!githubMatch;
42
+ const owner = (githubMatch || gitlabMatch)[1];
43
+ const repo = (githubMatch || gitlabMatch)[2].replace(/\.git$/, '');
44
+ console.log(`[AURA] Fetching ${isGitHub ? 'GitHub' : 'GitLab'} repo: ${owner}/${repo}`);
45
+ const secrets = [];
46
+ const discoveredServices = [];
47
+ const discoveredModules = [];
48
+ const scannedFiles = [];
49
+ try {
50
+ // Fetch repo tree
51
+ let treeUrl;
52
+ let headers = { 'User-Agent': 'Aura-Security' };
53
+ if (isGitHub) {
54
+ treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/HEAD?recursive=1`;
55
+ if (process.env.GITHUB_TOKEN) {
56
+ headers['Authorization'] = `token ${process.env.GITHUB_TOKEN}`;
57
+ }
58
+ }
59
+ else {
60
+ treeUrl = `https://gitlab.com/api/v4/projects/${encodeURIComponent(`${owner}/${repo}`)}/repository/tree?recursive=true&per_page=100`;
61
+ if (process.env.GITLAB_TOKEN) {
62
+ headers['PRIVATE-TOKEN'] = process.env.GITLAB_TOKEN;
63
+ }
64
+ }
65
+ const treeRes = await fetch(treeUrl, { headers });
66
+ if (!treeRes.ok) {
67
+ throw new Error(`Failed to fetch repo tree: ${treeRes.status} ${treeRes.statusText}`);
68
+ }
69
+ const treeData = await treeRes.json();
70
+ // Get file list
71
+ let files;
72
+ if (isGitHub) {
73
+ const ghData = treeData;
74
+ files = ghData.tree?.filter(f => f.type === 'blob') || [];
75
+ }
76
+ else {
77
+ files = treeData.filter(f => f.type === 'blob');
78
+ }
79
+ console.log(`[AURA] Found ${files.length} files in repo`);
80
+ // Filter to scannable files
81
+ const scanExtensions = ['.js', '.ts', '.jsx', '.tsx', '.json', '.yaml', '.yml', '.env', '.py', '.go', '.rb', '.php', '.java', '.cs', '.config', '.conf', '.sh', '.bash'];
82
+ const scanFiles = files.filter(f => {
83
+ const ext = f.path.substring(f.path.lastIndexOf('.')).toLowerCase();
84
+ const name = f.path.split('/').pop() || '';
85
+ return scanExtensions.includes(ext) || name.startsWith('.env') || name === 'package.json' || name === 'Dockerfile';
86
+ }).slice(0, 100); // Limit to 100 files for API rate limits
87
+ console.log(`[AURA] Scanning ${scanFiles.length} relevant files`);
88
+ // Scan each file
89
+ for (const file of scanFiles) {
90
+ try {
91
+ let contentUrl;
92
+ if (isGitHub) {
93
+ contentUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${encodeURIComponent(file.path)}`;
94
+ }
95
+ else {
96
+ contentUrl = `https://gitlab.com/api/v4/projects/${encodeURIComponent(`${owner}/${repo}`)}/repository/files/${encodeURIComponent(file.path)}/raw?ref=HEAD`;
97
+ }
98
+ const contentRes = await fetch(contentUrl, { headers });
99
+ if (!contentRes.ok)
100
+ continue;
101
+ let content;
102
+ if (isGitHub) {
103
+ const contentData = await contentRes.json();
104
+ if (contentData.content && contentData.encoding === 'base64') {
105
+ content = Buffer.from(contentData.content, 'base64').toString('utf-8');
106
+ }
107
+ else {
108
+ continue;
109
+ }
110
+ }
111
+ else {
112
+ content = await contentRes.text();
113
+ }
114
+ scannedFiles.push(file.path);
115
+ // Scan for secrets
116
+ const lines = content.split('\n');
117
+ for (let i = 0; i < lines.length; i++) {
118
+ const line = lines[i];
119
+ for (const pattern of REMOTE_SECRET_PATTERNS) {
120
+ pattern.regex.lastIndex = 0;
121
+ if (pattern.regex.test(line)) {
122
+ secrets.push({
123
+ file: file.path,
124
+ line: i + 1,
125
+ type: pattern.name,
126
+ severity: pattern.severity
127
+ });
128
+ }
129
+ }
130
+ }
131
+ // Check for service usage
132
+ if (content.includes('mongodb') || content.includes('mongoose')) {
133
+ if (!discoveredServices.find(s => s.id === 'mongodb')) {
134
+ discoveredServices.push({ id: 'mongodb', name: 'MongoDB', type: 'database', source: file.path, severity: 'high' });
135
+ }
136
+ }
137
+ if (content.includes('postgres') || content.includes('pg.')) {
138
+ if (!discoveredServices.find(s => s.id === 'postgres')) {
139
+ discoveredServices.push({ id: 'postgres', name: 'PostgreSQL', type: 'database', source: file.path, severity: 'high' });
140
+ }
141
+ }
142
+ if (content.includes('redis')) {
143
+ if (!discoveredServices.find(s => s.id === 'redis')) {
144
+ discoveredServices.push({ id: 'redis', name: 'Redis', type: 'cache', source: file.path, severity: 'medium' });
145
+ }
146
+ }
147
+ if (content.includes('stripe')) {
148
+ if (!discoveredServices.find(s => s.id === 'stripe')) {
149
+ discoveredServices.push({ id: 'stripe', name: 'Stripe', type: 'api', source: file.path, severity: 'critical' });
150
+ }
151
+ }
152
+ if (content.includes('aws-sdk') || content.includes('AWS')) {
153
+ if (!discoveredServices.find(s => s.id === 'aws')) {
154
+ discoveredServices.push({ id: 'aws', name: 'AWS', type: 'cloud', source: file.path, severity: 'critical' });
155
+ }
156
+ }
157
+ if (content.includes('firebase')) {
158
+ if (!discoveredServices.find(s => s.id === 'firebase')) {
159
+ discoveredServices.push({ id: 'firebase', name: 'Firebase', type: 'cloud', source: file.path, severity: 'high' });
160
+ }
161
+ }
162
+ if (content.includes('openai')) {
163
+ if (!discoveredServices.find(s => s.id === 'openai')) {
164
+ discoveredServices.push({ id: 'openai', name: 'OpenAI', type: 'api', source: file.path, severity: 'high' });
165
+ }
166
+ }
167
+ }
168
+ catch {
169
+ // Skip files that can't be fetched
170
+ }
171
+ }
172
+ // Detect modules from directory structure
173
+ const dirs = new Set();
174
+ files.forEach(f => {
175
+ const parts = f.path.split('/');
176
+ if (parts.length > 1) {
177
+ dirs.add(parts[0]);
178
+ }
179
+ });
180
+ const modulePatterns = {
181
+ 'src': { type: 'source', name: 'Source' },
182
+ 'lib': { type: 'lib', name: 'Library' },
183
+ 'components': { type: 'component', name: 'Components' },
184
+ 'pages': { type: 'component', name: 'Pages' },
185
+ 'api': { type: 'api', name: 'API' },
186
+ 'services': { type: 'service', name: 'Services' },
187
+ 'utils': { type: 'lib', name: 'Utils' },
188
+ 'config': { type: 'config', name: 'Config' },
189
+ 'tests': { type: 'test', name: 'Tests' },
190
+ 'test': { type: 'test', name: 'Tests' },
191
+ '__tests__': { type: 'test', name: 'Tests' },
192
+ };
193
+ dirs.forEach(dir => {
194
+ const match = modulePatterns[dir.toLowerCase()];
195
+ if (match) {
196
+ const dirFiles = files.filter(f => f.path.startsWith(dir + '/')).map(f => f.path);
197
+ discoveredModules.push({
198
+ id: dir.toLowerCase(),
199
+ name: match.name,
200
+ type: match.type,
201
+ fileCount: dirFiles.length,
202
+ path: dir,
203
+ files: dirFiles.slice(0, 10)
204
+ });
205
+ }
206
+ });
207
+ // Build result
208
+ const hasCritical = secrets.some(s => s.severity === 'critical');
209
+ const hasHigh = secrets.some(s => s.severity === 'high');
210
+ const events = secrets.map(s => ({
211
+ event_type: s.severity === 'critical' ? 'escalation_triggered' : 'finding_raised',
212
+ target: 'self',
213
+ payload: {
214
+ severity: s.severity,
215
+ claim: `${s.type} found in ${s.file}:${s.line}`,
216
+ attack_path: ['Secret detected in source code', 'Exposed in public repository', 'Attacker extracts credentials'],
217
+ affected_assets: ['secrets'],
218
+ evidence_refs: [{ type: 'diff', pointer: `${s.file}:${s.line}` }],
219
+ assurance_break: ['integrity', 'access_control'],
220
+ confidence: 0.9
221
+ },
222
+ timestamp: new Date().toISOString()
223
+ }));
224
+ console.log(`[AURA] Remote scan complete. Found ${secrets.length} secrets, ${discoveredServices.length} services, ${discoveredModules.length} modules`);
225
+ return {
226
+ agent_id: 'exploit-reviewer',
227
+ agent_state: hasCritical ? 'escalated' : hasHigh ? 'conflict' : 'idle',
228
+ events,
229
+ meta: { assumptions: [], uncertainties: [] },
230
+ scan_details: {
231
+ path: `${isGitHub ? 'github' : 'gitlab'}:${owner}/${repo}`,
232
+ secrets_found: secrets.length,
233
+ packages_scanned: 0,
234
+ env_files: 0,
235
+ services_discovered: discoveredServices.length,
236
+ modules_discovered: discoveredModules.length,
237
+ git_info: { branch: 'HEAD', remoteUrl: gitUrl },
238
+ system_info: { platform: 'remote', hostname: isGitHub ? 'github.com' : 'gitlab.com' },
239
+ raw_findings: { secrets, packages: [], envFiles: [] },
240
+ discovered_services: discoveredServices,
241
+ discovered_modules: discoveredModules,
242
+ files_scanned: scannedFiles.length
243
+ }
244
+ };
245
+ }
246
+ catch (err) {
247
+ console.error('[AURA] Remote scan error:', err);
248
+ throw err;
249
+ }
250
+ }
251
+ async function main() {
252
+ console.log('[AURA] Starting auditor pipeline...');
253
+ // Create Aura server
254
+ const server = new AuraServer({ port: PORT });
255
+ // Create Aura client for publishing to bus (if configured)
256
+ let busClient = null;
257
+ if (AURA_BUS_URL) {
258
+ busClient = new AuraClient({ baseUrl: AURA_BUS_URL });
259
+ try {
260
+ await busClient.connect();
261
+ console.log(`[AURA] Connected to bus at ${AURA_BUS_URL}`);
262
+ }
263
+ catch (err) {
264
+ console.error('[AURA] FATAL: Cannot connect to Aura bus - fail-closed');
265
+ process.exit(1);
266
+ }
267
+ }
268
+ else {
269
+ // Self-contained mode: client publishes to own server
270
+ busClient = new AuraClient({ baseUrl: `http://127.0.0.1:${PORT}` });
271
+ }
272
+ // Create pipeline
273
+ const pipeline = new AuditorPipeline({ auraClient: busClient });
274
+ const validator = new SchemaValidator();
275
+ // Register auditor tool
276
+ server.registerTool({
277
+ name: 'audit',
278
+ description: 'Analyze change event for security findings',
279
+ parameters: {
280
+ type: 'object',
281
+ required: ['change_event', 'evidence_bundle', 'policy_context']
282
+ },
283
+ handler: async (args) => {
284
+ try {
285
+ return await pipeline.analyze(args);
286
+ }
287
+ catch (err) {
288
+ if (err instanceof ValidationError) {
289
+ return {
290
+ agent_id: 'exploit-reviewer',
291
+ agent_state: 'blocked',
292
+ events: [{
293
+ event_type: 'escalation_triggered',
294
+ target: 'self',
295
+ payload: {
296
+ severity: 'critical',
297
+ claim: 'Input validation failed - blocking execution',
298
+ attack_path: ['Malformed input received', 'Validation rejected payload'],
299
+ affected_assets: [],
300
+ evidence_refs: [],
301
+ assurance_break: ['integrity'],
302
+ confidence: 1.0
303
+ },
304
+ timestamp: new Date().toISOString()
305
+ }],
306
+ meta: {
307
+ assumptions: [],
308
+ uncertainties: [],
309
+ validation_errors: err.errors
310
+ }
311
+ };
312
+ }
313
+ throw err;
314
+ }
315
+ }
316
+ });
317
+ // Register local scan tool
318
+ server.registerTool({
319
+ name: 'scan-local',
320
+ description: 'Scan local filesystem or Git repo for security issues (secrets, vulnerabilities, env files)',
321
+ parameters: {
322
+ type: 'object',
323
+ properties: {
324
+ targetPath: { type: 'string', description: 'Path to scan (defaults to current directory)' },
325
+ gitUrl: { type: 'string', description: 'Git URL to clone and scan' },
326
+ scanSecrets: { type: 'boolean', default: true },
327
+ scanPackages: { type: 'boolean', default: true },
328
+ scanEnvFiles: { type: 'boolean', default: true }
329
+ }
330
+ },
331
+ handler: async (args) => {
332
+ try {
333
+ let targetPath = args.targetPath || process.cwd();
334
+ // Handle Git URL - clone and scan with full tool suite
335
+ if (args.gitUrl) {
336
+ const gitUrl = args.gitUrl;
337
+ console.log(`[AURA] Cloning and scanning remote repo: ${gitUrl}`);
338
+ try {
339
+ // Use the clone-based scanner for full capabilities
340
+ const remoteResult = await scanRemoteGit({
341
+ gitUrl,
342
+ scanSecrets: args.scanSecrets !== false,
343
+ scanPackages: args.scanPackages !== false
344
+ });
345
+ console.log(`[AURA] Remote scan complete in ${remoteResult.cloneDuration + remoteResult.scanDuration}ms`);
346
+ console.log(`[AURA] Found: ${remoteResult.secrets.length} secrets, ${remoteResult.packages.length} vulns`);
347
+ // Convert to audit input and run through pipeline
348
+ const scanner = new LocalScanner({ targetPath: remoteResult.path });
349
+ const auditInput = scanner.toAuditorInput(remoteResult);
350
+ let auditResult;
351
+ try {
352
+ auditResult = await pipeline.analyze(auditInput);
353
+ }
354
+ catch {
355
+ auditResult = {
356
+ agent_id: 'exploit-reviewer',
357
+ agent_state: remoteResult.secrets.length > 0 ? 'conflict' : 'aligned',
358
+ events: [],
359
+ meta: { assumptions: [], uncertainties: [] }
360
+ };
361
+ }
362
+ // Build full response with scan details
363
+ return {
364
+ ...auditResult,
365
+ scan_details: {
366
+ path: remoteResult.gitUrl,
367
+ secrets_found: remoteResult.secrets.length,
368
+ packages_scanned: remoteResult.packages.length,
369
+ package_vulns: remoteResult.packages.length,
370
+ sast_findings: remoteResult.sastFindings.length,
371
+ iac_findings: remoteResult.iacFindings.length,
372
+ dockerfile_findings: remoteResult.dockerfileFindings.length,
373
+ env_files: remoteResult.envFiles.length,
374
+ services_discovered: remoteResult.discoveredServices.length,
375
+ modules_discovered: remoteResult.discoveredModules.length,
376
+ git_info: remoteResult.gitInfo,
377
+ system_info: { platform: 'remote', hostname: 'git-clone' },
378
+ tools_used: remoteResult.toolsUsed,
379
+ languages_detected: remoteResult.languagesDetected,
380
+ clone_duration_ms: remoteResult.cloneDuration,
381
+ scan_duration_ms: remoteResult.scanDuration,
382
+ raw_findings: {
383
+ secrets: remoteResult.secrets,
384
+ packages: remoteResult.packages,
385
+ sastFindings: remoteResult.sastFindings,
386
+ iacFindings: remoteResult.iacFindings,
387
+ dockerfileFindings: remoteResult.dockerfileFindings
388
+ }
389
+ }
390
+ };
391
+ }
392
+ catch (gitErr) {
393
+ console.error(`[AURA] Remote Git scan failed:`, gitErr);
394
+ return {
395
+ agent_id: 'exploit-reviewer',
396
+ agent_state: 'blocked',
397
+ events: [],
398
+ meta: { assumptions: [], uncertainties: [] },
399
+ error: `Remote scan failed: ${gitErr instanceof Error ? gitErr.message : 'Unknown error'}`
400
+ };
401
+ }
402
+ }
403
+ const scanner = new LocalScanner({
404
+ targetPath,
405
+ scanSecrets: args.scanSecrets !== false,
406
+ scanPackages: args.scanPackages !== false,
407
+ scanEnvFiles: args.scanEnvFiles !== false
408
+ });
409
+ console.log(`[AURA] Starting local scan of: ${targetPath}`);
410
+ // Notify WebSocket clients that scan is starting
411
+ const wsScanId = `scan-${Date.now()}`;
412
+ const ws = getWebSocketServer(WS_PORT);
413
+ ws.notifyAuditStarted({
414
+ auditId: wsScanId,
415
+ type: 'code',
416
+ target: targetPath
417
+ });
418
+ const scanResult = await scanner.scan();
419
+ console.log(`[AURA] Scan complete. Found ${scanResult.secrets.length} secrets, ${scanResult.packages.length} package issues, ${scanResult.sastFindings.length} SAST findings`);
420
+ // Convert to audit input and run through pipeline
421
+ const auditInput = scanner.toAuditorInput(scanResult);
422
+ let auditResult;
423
+ try {
424
+ auditResult = await pipeline.analyze(auditInput);
425
+ }
426
+ catch (pipelineErr) {
427
+ // If pipeline fails, create a basic result from scan data
428
+ console.log(`[AURA] Pipeline analysis skipped: ${pipelineErr}`);
429
+ const events = scanResult.secrets.map(s => ({
430
+ event_type: s.severity === 'critical' ? 'escalation_triggered' : 'finding_raised',
431
+ target: 'self',
432
+ payload: {
433
+ severity: s.severity,
434
+ claim: `${s.type} found in ${s.file}:${s.line}`,
435
+ attack_path: ['Secret detected in source code', 'Exposed in repository', 'Attacker extracts credentials'],
436
+ affected_assets: [s.type.toLowerCase().includes('aws') ? 'infra' : s.type.toLowerCase().includes('password') ? 'auth' : 'secrets'],
437
+ evidence_refs: [{ type: 'diff', pointer: `${s.file}:${s.line}` }],
438
+ assurance_break: ['integrity', 'access_control'],
439
+ confidence: 0.9
440
+ },
441
+ timestamp: new Date().toISOString()
442
+ }));
443
+ auditResult = {
444
+ agent_id: 'exploit-reviewer',
445
+ agent_state: scanResult.secrets.some(s => s.severity === 'critical') ? 'escalated' :
446
+ scanResult.secrets.length > 0 ? 'conflict' : 'idle',
447
+ events,
448
+ meta: { assumptions: [], uncertainties: [] }
449
+ };
450
+ }
451
+ // Include raw scan results in response
452
+ const scanId = `local-scan-${Date.now()}`;
453
+ const fullResult = {
454
+ ...auditResult,
455
+ scan_details: {
456
+ path: scanResult.path,
457
+ secrets_found: scanResult.secrets.length,
458
+ packages_scanned: scanResult.packages.length,
459
+ package_vulns: scanResult.packages.filter(p => p.vulnerabilities > 0).length,
460
+ sast_findings: scanResult.sastFindings.length,
461
+ env_files: scanResult.envFiles.length,
462
+ services_discovered: scanResult.discoveredServices.length,
463
+ modules_discovered: scanResult.discoveredModules.length,
464
+ git_info: scanResult.gitInfo,
465
+ system_info: scanResult.systemInfo,
466
+ tools_used: scanResult.toolsUsed,
467
+ raw_findings: {
468
+ secrets: scanResult.secrets,
469
+ packages: scanResult.packages,
470
+ envFiles: scanResult.envFiles,
471
+ sastFindings: scanResult.sastFindings
472
+ },
473
+ // Discovered services for dynamic map building
474
+ discovered_services: scanResult.discoveredServices,
475
+ // Discovered code modules/directories for codebase mapping
476
+ discovered_modules: scanResult.discoveredModules
477
+ }
478
+ };
479
+ // Store scan result to memory for history browsing
480
+ try {
481
+ await busClient.publishToMemory({
482
+ key: `audit:${scanId}:${Date.now()}`,
483
+ value: fullResult,
484
+ metadata: {
485
+ type: 'local-scan',
486
+ path: scanResult.path,
487
+ timestamp: new Date().toISOString()
488
+ }
489
+ });
490
+ console.log(`[AURA] Scan result stored to memory: ${scanId}`);
491
+ }
492
+ catch (storeErr) {
493
+ console.error('[AURA] Failed to store scan result to memory:', storeErr);
494
+ }
495
+ // Store to SQLite database for persistent history
496
+ let auditId;
497
+ try {
498
+ const db = server.getDatabase();
499
+ auditId = db.saveAudit('code', scanResult.path, scanResult);
500
+ console.log(`[AURA] Scan result saved to database: ${auditId}`);
501
+ }
502
+ catch (dbErr) {
503
+ console.error('[AURA] Failed to save to database:', dbErr);
504
+ }
505
+ // Send notifications if enabled
506
+ if (auditId) {
507
+ try {
508
+ const notifyService = server.getNotificationService();
509
+ const summary = {
510
+ critical: scanResult.secrets?.filter((s) => s.severity === 'critical').length || 0,
511
+ high: scanResult.secrets?.filter((s) => s.severity === 'high').length || 0,
512
+ medium: (scanResult.packages?.length || 0) + (scanResult.sastFindings?.length || 0),
513
+ low: scanResult.envFiles?.length || 0
514
+ };
515
+ const result = await notifyService.notify({
516
+ title: `Security Scan Complete`,
517
+ message: `Scanned \`${scanResult.path}\``,
518
+ severity: summary.critical > 0 ? 'critical' : summary.high > 0 ? 'high' : 'low',
519
+ auditId,
520
+ target: scanResult.path,
521
+ findings: summary
522
+ });
523
+ if (result.sent.length > 0) {
524
+ console.log(`[AURA] Notifications sent: ${result.sent.join(', ')}`);
525
+ }
526
+ // Notify WebSocket clients that scan is complete
527
+ ws.notifyAuditCompleted({
528
+ auditId,
529
+ type: 'code',
530
+ target: scanResult.path,
531
+ summary
532
+ });
533
+ }
534
+ catch (notifyErr) {
535
+ console.error('[AURA] Notification error:', notifyErr);
536
+ }
537
+ }
538
+ return fullResult;
539
+ }
540
+ catch (err) {
541
+ console.error('[AURA] Local scan error:', err);
542
+ return {
543
+ agent_id: 'exploit-reviewer',
544
+ agent_state: 'blocked',
545
+ events: [{
546
+ event_type: 'escalation_triggered',
547
+ target: 'self',
548
+ payload: {
549
+ severity: 'medium',
550
+ claim: `Local scan failed: ${err instanceof Error ? err.message : 'Unknown error'}`,
551
+ attack_path: ['Scan execution failed'],
552
+ affected_assets: [],
553
+ evidence_refs: [],
554
+ assurance_break: [],
555
+ confidence: 1.0
556
+ },
557
+ timestamp: new Date().toISOString()
558
+ }],
559
+ meta: { assumptions: [], uncertainties: [`Scan error: ${err}`] }
560
+ };
561
+ }
562
+ }
563
+ });
564
+ // Register Aura Protocol scan tool (multi-agent architecture)
565
+ server.registerTool({
566
+ name: 'scan-aura',
567
+ description: 'Aura Protocol scan - Multi-agent parallel security scanning with isolated zones',
568
+ parameters: {
569
+ type: 'object',
570
+ properties: {
571
+ targetPath: { type: 'string', description: 'Path to scan (defaults to current directory)' },
572
+ fullScan: { type: 'boolean', default: true, description: 'Run policy evaluation (slower, fewer false positives)' }
573
+ }
574
+ },
575
+ handler: async (args) => {
576
+ try {
577
+ const targetPath = args.targetPath || process.cwd();
578
+ const fullScan = args.fullScan !== false;
579
+ console.log(`[AURA] Starting Aura Protocol scan of: ${targetPath}`);
580
+ console.log(`[AURA] Mode: ${fullScan ? 'Full (with policy evaluation)' : 'Quick (scanner only)'}`);
581
+ // Notify WebSocket clients that scan is starting
582
+ const wsScanId = `aura-scan-${Date.now()}`;
583
+ const ws = getWebSocketServer(WS_PORT);
584
+ ws.notifyAuditStarted({
585
+ auditId: wsScanId,
586
+ type: 'aura-protocol',
587
+ target: targetPath
588
+ });
589
+ // Run Aura Protocol scan
590
+ const result = await auraScan({
591
+ targetPath,
592
+ fullScan
593
+ });
594
+ console.log(`[AURA] Aura Protocol scan complete`);
595
+ console.log(`[AURA] Zones executed: ${result.aura.zones.map(z => z.name).join(', ')}`);
596
+ console.log(`[AURA] Agents used: ${result.aura.agents.filter(a => a.status === 'success').map(a => a.name).join(', ')}`);
597
+ console.log(`[AURA] Findings: ${result.aura.summary.totalFindings}`);
598
+ // Store in database
599
+ let auditId;
600
+ try {
601
+ const db = server.getDatabase();
602
+ auditId = db.saveAudit('code', targetPath, {
603
+ path: targetPath,
604
+ timestamp: new Date().toISOString(),
605
+ secrets: result.legacy.secrets,
606
+ packages: result.legacy.packages,
607
+ sastFindings: result.legacy.sastFindings,
608
+ iacFindings: [],
609
+ dockerfileFindings: [],
610
+ gitInfo: null,
611
+ envFiles: [],
612
+ systemInfo: result.legacy.systemInfo,
613
+ discoveredServices: [],
614
+ discoveredModules: [],
615
+ toolsUsed: result.aura.summary.agentsUsed,
616
+ languagesDetected: [],
617
+ zones: result.aura.zones,
618
+ agents: result.aura.agents
619
+ });
620
+ console.log(`[AURA] Aura scan saved to database: ${auditId}`);
621
+ }
622
+ catch (dbErr) {
623
+ console.error('[AURA] Database save error:', dbErr);
624
+ auditId = `aura-${Date.now()}`;
625
+ }
626
+ // Notify WebSocket clients
627
+ ws.notifyAuditCompleted({
628
+ auditId: auditId || `aura-${Date.now()}`,
629
+ type: 'aura-protocol',
630
+ target: targetPath,
631
+ summary: {
632
+ critical: result.aura.summary.bySeverity['critical'] || 0,
633
+ high: result.aura.summary.bySeverity['high'] || 0,
634
+ medium: result.aura.summary.bySeverity['medium'] || 0,
635
+ low: result.aura.summary.bySeverity['low'] || 0
636
+ }
637
+ });
638
+ return {
639
+ agent_id: 'aura-orchestrator',
640
+ agent_state: result.aura.summary.totalFindings > 0 ? 'conflict' : 'aligned',
641
+ events: result.aura.findings.map(f => ({
642
+ event_type: f.severity === 'critical' ? 'escalation_triggered' : 'finding_raised',
643
+ target: 'self',
644
+ payload: {
645
+ severity: f.severity,
646
+ claim: f.title,
647
+ description: f.description,
648
+ file: f.file,
649
+ line: f.line,
650
+ type: f.type,
651
+ agent: f.agentId
652
+ },
653
+ timestamp: new Date(f.timestamp).toISOString()
654
+ })),
655
+ meta: {
656
+ zones: result.aura.zones,
657
+ agents: result.aura.agents,
658
+ summary: result.aura.summary
659
+ },
660
+ scan_details: {
661
+ path: targetPath,
662
+ mode: fullScan ? 'full' : 'quick',
663
+ secrets_found: result.aura.summary.byType['secret'] || 0,
664
+ vulnerabilities_found: result.aura.summary.byType['vulnerability'] || 0,
665
+ total_findings: result.aura.summary.totalFindings,
666
+ tools_used: result.aura.summary.agentsUsed,
667
+ zones_executed: result.aura.zones.length,
668
+ agents_executed: result.aura.agents.length,
669
+ raw_findings: {
670
+ secrets: result.legacy.secrets,
671
+ packages: result.legacy.packages,
672
+ sastFindings: result.legacy.sastFindings
673
+ }
674
+ }
675
+ };
676
+ }
677
+ catch (err) {
678
+ console.error('[AURA] Aura Protocol scan error:', err);
679
+ return {
680
+ agent_id: 'aura-orchestrator',
681
+ agent_state: 'blocked',
682
+ events: [],
683
+ meta: { error: err instanceof Error ? err.message : 'Unknown error' }
684
+ };
685
+ }
686
+ }
687
+ });
688
+ // Register Aura state endpoint (for visualization)
689
+ server.registerTool({
690
+ name: 'aura-state',
691
+ description: 'Get current Aura Protocol state (zones, agents) for visualization',
692
+ parameters: { type: 'object', properties: {} },
693
+ handler: async () => {
694
+ const state = getAuraState();
695
+ const availableAgents = await getAvailableAgents();
696
+ return {
697
+ ...state,
698
+ availableAgents: availableAgents.map(a => ({
699
+ id: a.config.id,
700
+ name: a.config.name,
701
+ role: a.config.role,
702
+ description: a.config.description
703
+ }))
704
+ };
705
+ }
706
+ });
707
+ // Start HTTP server
708
+ await server.start();
709
+ console.log(`[AURA] Auditor listening on http://127.0.0.1:${PORT}`);
710
+ console.log('[AURA] Endpoints: /info, /tools, /memory, /settings, /audits, /stats, /notifications');
711
+ // Start WebSocket server for real-time updates
712
+ const wsServer = getWebSocketServer(WS_PORT);
713
+ await wsServer.start();
714
+ console.log(`[AURA] WebSocket server on ws://127.0.0.1:${WS_PORT}`);
715
+ // Connect client to self for memory storage
716
+ if (!AURA_BUS_URL) {
717
+ await busClient.connect();
718
+ console.log('[AURA] Self-contained mode: client connected to local server');
719
+ }
720
+ // Graceful shutdown
721
+ process.on('SIGINT', async () => {
722
+ console.log('\n[AURA] Shutting down...');
723
+ await server.stop();
724
+ await busClient?.disconnect();
725
+ process.exit(0);
726
+ });
727
+ process.on('SIGTERM', async () => {
728
+ console.log('\n[AURA] Shutting down...');
729
+ await server.stop();
730
+ await busClient?.disconnect();
731
+ process.exit(0);
732
+ });
733
+ }
734
+ main().catch((err) => {
735
+ console.error('[AURA] FATAL:', err);
736
+ process.exit(1);
737
+ });
738
+ // Export for programmatic use
739
+ export { AuraServer } from './aura/server.js';
740
+ export { AuraClient } from './aura/client.js';
741
+ export { AuditorPipeline } from './auditor/pipeline.js';
742
+ export { SchemaValidator, ValidationError } from './auditor/validator.js';
743
+ export * from './types/events.js';
744
+ // Client SDK exports
745
+ export { AuditClient, createPullRequestEvent, createDeployEvent, createInfraChangeEvent } from './client/index.js';
746
+ // Pipeline framework exports
747
+ export { SecurityPipeline, SecretsDetectionStage, VulnerabilityScanStage, CriticalAssetStage, InfrastructureChangeStage, ProductionDeployStage } from './pipeline/index.js';
748
+ // Integration exports
749
+ export { WebhookServer, defaultHandlers } from './integrations/webhook.js';
750
+ export { GitHubIntegration } from './integrations/github.js';
751
+ export { GitLabIntegration } from './integrations/gitlab.js';
752
+ export { SnykParser, TrivyParser, SemgrepParser, NpmAuditParser, getParser } from './integrations/scanners.js';
753
+ export { ConfigLoader, configLoader } from './integrations/config.js';
754
+ export { LocalScanner, quickLocalScan, scanRemoteGit, isGitUrl } from './integrations/local-scanner.js';
755
+ // AWS Scanner exports
756
+ export { AWSScanner, scanAWS } from './integrations/aws-scanner.js';
757
+ // Database exports
758
+ export { AuditorDatabase, getDatabase, closeDatabase } from './database/index.js';
759
+ // Notification exports
760
+ export { NotificationService, createNotificationFromAudit } from './integrations/notifications.js';
761
+ // WebSocket exports
762
+ export { AuditorWebSocket, getWebSocketServer, closeWebSocketServer } from './websocket/index.js';