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.
- package/LICENSE +21 -0
- package/README.md +446 -0
- package/deploy/AWS-DEPLOYMENT.md +358 -0
- package/deploy/terraform/main.tf +362 -0
- package/deploy/terraform/terraform.tfvars.example +6 -0
- package/dist/agents/base.d.ts +44 -0
- package/dist/agents/base.js +96 -0
- package/dist/agents/index.d.ts +14 -0
- package/dist/agents/index.js +17 -0
- package/dist/agents/policy/evaluator.d.ts +15 -0
- package/dist/agents/policy/evaluator.js +183 -0
- package/dist/agents/policy/index.d.ts +12 -0
- package/dist/agents/policy/index.js +15 -0
- package/dist/agents/policy/validator.d.ts +15 -0
- package/dist/agents/policy/validator.js +182 -0
- package/dist/agents/scanners/gitleaks.d.ts +14 -0
- package/dist/agents/scanners/gitleaks.js +155 -0
- package/dist/agents/scanners/grype.d.ts +14 -0
- package/dist/agents/scanners/grype.js +109 -0
- package/dist/agents/scanners/index.d.ts +15 -0
- package/dist/agents/scanners/index.js +27 -0
- package/dist/agents/scanners/npm-audit.d.ts +13 -0
- package/dist/agents/scanners/npm-audit.js +129 -0
- package/dist/agents/scanners/semgrep.d.ts +14 -0
- package/dist/agents/scanners/semgrep.js +131 -0
- package/dist/agents/scanners/trivy.d.ts +14 -0
- package/dist/agents/scanners/trivy.js +122 -0
- package/dist/agents/types.d.ts +137 -0
- package/dist/agents/types.js +91 -0
- package/dist/auditor/index.d.ts +3 -0
- package/dist/auditor/index.js +2 -0
- package/dist/auditor/pipeline.d.ts +19 -0
- package/dist/auditor/pipeline.js +240 -0
- package/dist/auditor/validator.d.ts +17 -0
- package/dist/auditor/validator.js +58 -0
- package/dist/aura/client.d.ts +29 -0
- package/dist/aura/client.js +125 -0
- package/dist/aura/index.d.ts +4 -0
- package/dist/aura/index.js +2 -0
- package/dist/aura/server.d.ts +45 -0
- package/dist/aura/server.js +343 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.js +1433 -0
- package/dist/client/index.d.ts +41 -0
- package/dist/client/index.js +170 -0
- package/dist/compliance/index.d.ts +40 -0
- package/dist/compliance/index.js +292 -0
- package/dist/database/index.d.ts +77 -0
- package/dist/database/index.js +395 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +762 -0
- package/dist/integrations/aura-scanner.d.ts +69 -0
- package/dist/integrations/aura-scanner.js +155 -0
- package/dist/integrations/aws-scanner.d.ts +63 -0
- package/dist/integrations/aws-scanner.js +624 -0
- package/dist/integrations/config.d.ts +69 -0
- package/dist/integrations/config.js +212 -0
- package/dist/integrations/github.d.ts +45 -0
- package/dist/integrations/github.js +201 -0
- package/dist/integrations/gitlab.d.ts +36 -0
- package/dist/integrations/gitlab.js +110 -0
- package/dist/integrations/index.d.ts +11 -0
- package/dist/integrations/index.js +11 -0
- package/dist/integrations/local-scanner.d.ts +146 -0
- package/dist/integrations/local-scanner.js +1654 -0
- package/dist/integrations/notifications.d.ts +99 -0
- package/dist/integrations/notifications.js +305 -0
- package/dist/integrations/scanners.d.ts +57 -0
- package/dist/integrations/scanners.js +217 -0
- package/dist/integrations/slop-scanner.d.ts +69 -0
- package/dist/integrations/slop-scanner.js +155 -0
- package/dist/integrations/webhook.d.ts +37 -0
- package/dist/integrations/webhook.js +256 -0
- package/dist/orchestrator/index.d.ts +72 -0
- package/dist/orchestrator/index.js +187 -0
- package/dist/output/index.d.ts +152 -0
- package/dist/output/index.js +399 -0
- package/dist/pipeline/index.d.ts +72 -0
- package/dist/pipeline/index.js +313 -0
- package/dist/sbom/index.d.ts +94 -0
- package/dist/sbom/index.js +298 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/input.schema.d.ts +87 -0
- package/dist/schemas/input.schema.js +44 -0
- package/dist/schemas/output.schema.d.ts +115 -0
- package/dist/schemas/output.schema.js +64 -0
- package/dist/serve-visualizer.d.ts +2 -0
- package/dist/serve-visualizer.js +78 -0
- package/dist/slop/client.d.ts +29 -0
- package/dist/slop/client.js +125 -0
- package/dist/slop/index.d.ts +4 -0
- package/dist/slop/index.js +2 -0
- package/dist/slop/server.d.ts +45 -0
- package/dist/slop/server.js +343 -0
- package/dist/types/events.d.ts +62 -0
- package/dist/types/events.js +2 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/visualizer/index.d.ts +4 -0
- package/dist/visualizer/index.js +181 -0
- package/dist/websocket/index.d.ts +88 -0
- package/dist/websocket/index.js +195 -0
- package/dist/zones/index.d.ts +7 -0
- package/dist/zones/index.js +7 -0
- package/dist/zones/manager.d.ts +101 -0
- package/dist/zones/manager.js +304 -0
- package/dist/zones/types.d.ts +78 -0
- package/dist/zones/types.js +33 -0
- package/package.json +84 -0
- package/visualizer/app.js +0 -0
- package/visualizer/index-minimal.html +1771 -0
- package/visualizer/index.html +2933 -0
- package/visualizer/landing.html +1328 -0
- package/visualizer/styles.css +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Gitleaks Agent
|
|
3
|
+
*
|
|
4
|
+
* Scans for secrets and API keys using gitleaks.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { BaseAgent } from '../base.js';
|
|
9
|
+
const CONFIG = {
|
|
10
|
+
id: 'gitleaks',
|
|
11
|
+
name: 'Gitleaks',
|
|
12
|
+
role: 'scanner',
|
|
13
|
+
description: 'Detect secrets and API keys in code',
|
|
14
|
+
enabled: true,
|
|
15
|
+
externalTool: 'gitleaks',
|
|
16
|
+
};
|
|
17
|
+
const CAPABILITIES = {
|
|
18
|
+
fileTypes: ['*'],
|
|
19
|
+
languages: ['*'],
|
|
20
|
+
requiresExternalTool: true,
|
|
21
|
+
supportsParallel: true,
|
|
22
|
+
};
|
|
23
|
+
// Files to skip (lock files, generated files)
|
|
24
|
+
const SKIP_FILES = [
|
|
25
|
+
'package-lock.json',
|
|
26
|
+
'yarn.lock',
|
|
27
|
+
'pnpm-lock.yaml',
|
|
28
|
+
'composer.lock',
|
|
29
|
+
'Gemfile.lock',
|
|
30
|
+
'poetry.lock',
|
|
31
|
+
'Cargo.lock',
|
|
32
|
+
'go.sum',
|
|
33
|
+
];
|
|
34
|
+
// Rules to skip entirely (too many false positives)
|
|
35
|
+
const SKIP_RULES = ['aws-secret-access-key'];
|
|
36
|
+
export class GitleaksAgent extends BaseAgent {
|
|
37
|
+
constructor() {
|
|
38
|
+
super(CONFIG, CAPABILITIES);
|
|
39
|
+
}
|
|
40
|
+
async execute(context) {
|
|
41
|
+
const startTime = Date.now();
|
|
42
|
+
this.status = 'running';
|
|
43
|
+
const findings = [];
|
|
44
|
+
try {
|
|
45
|
+
context.log('info', `Gitleaks scanning: ${context.targetPath}`);
|
|
46
|
+
// Create temp config to exclude lock files
|
|
47
|
+
const tempConfigPath = path.join(context.targetPath, '.gitleaks-temp.toml');
|
|
48
|
+
const configContent = `
|
|
49
|
+
[allowlist]
|
|
50
|
+
paths = [
|
|
51
|
+
${SKIP_FILES.map((f) => `"**/${f}"`).join(',\n ')}
|
|
52
|
+
]
|
|
53
|
+
`;
|
|
54
|
+
fs.writeFileSync(tempConfigPath, configContent);
|
|
55
|
+
// Run gitleaks
|
|
56
|
+
const { stdout, stderr, exitCode } = await this.executeCommand('gitleaks', [
|
|
57
|
+
'detect',
|
|
58
|
+
'--source',
|
|
59
|
+
context.targetPath,
|
|
60
|
+
'--report-format',
|
|
61
|
+
'json',
|
|
62
|
+
'--report-path',
|
|
63
|
+
'/dev/stdout',
|
|
64
|
+
'--config',
|
|
65
|
+
tempConfigPath,
|
|
66
|
+
'--no-git',
|
|
67
|
+
'--exit-code',
|
|
68
|
+
'0',
|
|
69
|
+
], { cwd: context.targetPath, timeout: 300000 });
|
|
70
|
+
// Clean up temp config
|
|
71
|
+
try {
|
|
72
|
+
fs.unlinkSync(tempConfigPath);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Ignore cleanup errors
|
|
76
|
+
}
|
|
77
|
+
if (stdout.trim()) {
|
|
78
|
+
try {
|
|
79
|
+
const results = JSON.parse(stdout);
|
|
80
|
+
for (const result of results) {
|
|
81
|
+
// Skip rules with too many false positives
|
|
82
|
+
if (SKIP_RULES.includes(result.RuleID)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Skip lock files
|
|
86
|
+
if (SKIP_FILES.some((f) => result.File.endsWith(f))) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const finding = this.createFinding('gitleaks', {
|
|
90
|
+
type: 'secret',
|
|
91
|
+
severity: this.getSeverity(result),
|
|
92
|
+
title: result.Description || result.RuleID,
|
|
93
|
+
description: `Secret detected: ${result.RuleID}`,
|
|
94
|
+
file: result.File,
|
|
95
|
+
line: result.StartLine,
|
|
96
|
+
metadata: {
|
|
97
|
+
ruleId: result.RuleID,
|
|
98
|
+
match: this.maskSecret(result.Match),
|
|
99
|
+
entropy: result.Entropy,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
findings.push(finding);
|
|
103
|
+
context.addFinding(finding);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (parseError) {
|
|
107
|
+
context.log('warn', `Failed to parse gitleaks output: ${parseError}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this.status = 'complete';
|
|
111
|
+
context.log('info', `Gitleaks found ${findings.length} secrets`);
|
|
112
|
+
return {
|
|
113
|
+
agentId: this.config.id,
|
|
114
|
+
agentName: this.config.name,
|
|
115
|
+
status: 'success',
|
|
116
|
+
findings,
|
|
117
|
+
duration: Date.now() - startTime,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
this.status = 'error';
|
|
122
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
123
|
+
context.log('error', `Gitleaks error: ${errorMsg}`);
|
|
124
|
+
return {
|
|
125
|
+
agentId: this.config.id,
|
|
126
|
+
agentName: this.config.name,
|
|
127
|
+
status: 'error',
|
|
128
|
+
findings,
|
|
129
|
+
duration: Date.now() - startTime,
|
|
130
|
+
error: errorMsg,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
getSeverity(result) {
|
|
135
|
+
// High entropy secrets are more likely to be real
|
|
136
|
+
if (result.Entropy && result.Entropy > 4.5) {
|
|
137
|
+
return 'critical';
|
|
138
|
+
}
|
|
139
|
+
// Certain rule types are more critical
|
|
140
|
+
const criticalRules = ['private-key', 'aws-access-key', 'github-pat', 'stripe-api-key'];
|
|
141
|
+
if (criticalRules.some((r) => result.RuleID.toLowerCase().includes(r))) {
|
|
142
|
+
return 'critical';
|
|
143
|
+
}
|
|
144
|
+
const highRules = ['api-key', 'token', 'password', 'secret'];
|
|
145
|
+
if (highRules.some((r) => result.RuleID.toLowerCase().includes(r))) {
|
|
146
|
+
return 'high';
|
|
147
|
+
}
|
|
148
|
+
return 'medium';
|
|
149
|
+
}
|
|
150
|
+
maskSecret(secret) {
|
|
151
|
+
if (secret.length <= 8)
|
|
152
|
+
return '***';
|
|
153
|
+
return secret.slice(0, 4) + '...' + secret.slice(-4);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Grype Agent
|
|
3
|
+
*
|
|
4
|
+
* Vulnerability scanner for container images and filesystems.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAgent } from '../base.js';
|
|
7
|
+
import { AgentResult } from '../types.js';
|
|
8
|
+
import { ZoneContext } from '../../zones/types.js';
|
|
9
|
+
export declare class GrypeAgent extends BaseAgent {
|
|
10
|
+
constructor();
|
|
11
|
+
execute(context: ZoneContext): Promise<AgentResult>;
|
|
12
|
+
private mapSeverity;
|
|
13
|
+
private getCvssScore;
|
|
14
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Grype Agent
|
|
3
|
+
*
|
|
4
|
+
* Vulnerability scanner for container images and filesystems.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAgent } from '../base.js';
|
|
7
|
+
const CONFIG = {
|
|
8
|
+
id: 'grype',
|
|
9
|
+
name: 'Grype',
|
|
10
|
+
role: 'scanner',
|
|
11
|
+
description: 'Vulnerability scanner for container images and filesystems',
|
|
12
|
+
enabled: true,
|
|
13
|
+
externalTool: 'grype',
|
|
14
|
+
};
|
|
15
|
+
const CAPABILITIES = {
|
|
16
|
+
fileTypes: ['*'],
|
|
17
|
+
languages: ['*'],
|
|
18
|
+
requiresExternalTool: true,
|
|
19
|
+
supportsParallel: true,
|
|
20
|
+
};
|
|
21
|
+
export class GrypeAgent extends BaseAgent {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(CONFIG, CAPABILITIES);
|
|
24
|
+
}
|
|
25
|
+
async execute(context) {
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
this.status = 'running';
|
|
28
|
+
const findings = [];
|
|
29
|
+
try {
|
|
30
|
+
context.log('info', `Grype scanning: ${context.targetPath}`);
|
|
31
|
+
// Run grype
|
|
32
|
+
const { stdout, stderr, exitCode } = await this.executeCommand('grype', ['dir:' + context.targetPath, '-o', 'json', '--by-cve'], { cwd: context.targetPath, timeout: 300000 });
|
|
33
|
+
if (stdout.trim()) {
|
|
34
|
+
try {
|
|
35
|
+
const output = JSON.parse(stdout);
|
|
36
|
+
if (output.matches) {
|
|
37
|
+
for (const match of output.matches) {
|
|
38
|
+
const finding = this.createFinding('grype', {
|
|
39
|
+
type: 'vulnerability',
|
|
40
|
+
severity: this.mapSeverity(match.vulnerability.severity),
|
|
41
|
+
title: `${match.artifact.name}: ${match.vulnerability.id}`,
|
|
42
|
+
description: match.vulnerability.description ||
|
|
43
|
+
`Vulnerability in ${match.artifact.name}@${match.artifact.version}`,
|
|
44
|
+
file: match.artifact.locations?.[0]?.path,
|
|
45
|
+
metadata: {
|
|
46
|
+
vulnerabilityId: match.vulnerability.id,
|
|
47
|
+
package: match.artifact.name,
|
|
48
|
+
version: match.artifact.version,
|
|
49
|
+
type: match.artifact.type,
|
|
50
|
+
fixVersions: match.vulnerability.fix?.versions,
|
|
51
|
+
fixState: match.vulnerability.fix?.state,
|
|
52
|
+
cvssScore: this.getCvssScore(match),
|
|
53
|
+
references: match.vulnerability.urls?.slice(0, 3),
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
findings.push(finding);
|
|
57
|
+
context.addFinding(finding);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (parseError) {
|
|
62
|
+
context.log('warn', `Failed to parse grype output: ${parseError}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
this.status = 'complete';
|
|
66
|
+
context.log('info', `Grype found ${findings.length} vulnerabilities`);
|
|
67
|
+
return {
|
|
68
|
+
agentId: this.config.id,
|
|
69
|
+
agentName: this.config.name,
|
|
70
|
+
status: 'success',
|
|
71
|
+
findings,
|
|
72
|
+
duration: Date.now() - startTime,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
this.status = 'error';
|
|
77
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
78
|
+
context.log('error', `Grype error: ${errorMsg}`);
|
|
79
|
+
return {
|
|
80
|
+
agentId: this.config.id,
|
|
81
|
+
agentName: this.config.name,
|
|
82
|
+
status: 'error',
|
|
83
|
+
findings,
|
|
84
|
+
duration: Date.now() - startTime,
|
|
85
|
+
error: errorMsg,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
mapSeverity(grypeSeverity) {
|
|
90
|
+
switch (grypeSeverity.toLowerCase()) {
|
|
91
|
+
case 'critical':
|
|
92
|
+
return 'critical';
|
|
93
|
+
case 'high':
|
|
94
|
+
return 'high';
|
|
95
|
+
case 'medium':
|
|
96
|
+
return 'medium';
|
|
97
|
+
case 'low':
|
|
98
|
+
return 'low';
|
|
99
|
+
default:
|
|
100
|
+
return 'info';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
getCvssScore(match) {
|
|
104
|
+
if (!match.vulnerability.cvss || match.vulnerability.cvss.length === 0) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
return match.vulnerability.cvss[0].metrics.baseScore;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Scanner Agents
|
|
3
|
+
*
|
|
4
|
+
* Export all scanner agents.
|
|
5
|
+
*/
|
|
6
|
+
export { GitleaksAgent } from './gitleaks.js';
|
|
7
|
+
export { TrivyAgent } from './trivy.js';
|
|
8
|
+
export { SemgrepAgent } from './semgrep.js';
|
|
9
|
+
export { GrypeAgent } from './grype.js';
|
|
10
|
+
export { NpmAuditAgent } from './npm-audit.js';
|
|
11
|
+
import { Agent } from '../types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Create all scanner agents
|
|
14
|
+
*/
|
|
15
|
+
export declare function createScannerAgents(): Agent[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Scanner Agents
|
|
3
|
+
*
|
|
4
|
+
* Export all scanner agents.
|
|
5
|
+
*/
|
|
6
|
+
export { GitleaksAgent } from './gitleaks.js';
|
|
7
|
+
export { TrivyAgent } from './trivy.js';
|
|
8
|
+
export { SemgrepAgent } from './semgrep.js';
|
|
9
|
+
export { GrypeAgent } from './grype.js';
|
|
10
|
+
export { NpmAuditAgent } from './npm-audit.js';
|
|
11
|
+
import { GitleaksAgent } from './gitleaks.js';
|
|
12
|
+
import { TrivyAgent } from './trivy.js';
|
|
13
|
+
import { SemgrepAgent } from './semgrep.js';
|
|
14
|
+
import { GrypeAgent } from './grype.js';
|
|
15
|
+
import { NpmAuditAgent } from './npm-audit.js';
|
|
16
|
+
/**
|
|
17
|
+
* Create all scanner agents
|
|
18
|
+
*/
|
|
19
|
+
export function createScannerAgents() {
|
|
20
|
+
return [
|
|
21
|
+
new GitleaksAgent(),
|
|
22
|
+
new TrivyAgent(),
|
|
23
|
+
new SemgrepAgent(),
|
|
24
|
+
new GrypeAgent(),
|
|
25
|
+
new NpmAuditAgent(),
|
|
26
|
+
];
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - NPM Audit Agent
|
|
3
|
+
*
|
|
4
|
+
* Audit npm packages for vulnerabilities.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAgent } from '../base.js';
|
|
7
|
+
import { AgentResult } from '../types.js';
|
|
8
|
+
import { ZoneContext } from '../../zones/types.js';
|
|
9
|
+
export declare class NpmAuditAgent extends BaseAgent {
|
|
10
|
+
constructor();
|
|
11
|
+
execute(context: ZoneContext): Promise<AgentResult>;
|
|
12
|
+
private mapSeverity;
|
|
13
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - NPM Audit Agent
|
|
3
|
+
*
|
|
4
|
+
* Audit npm packages for vulnerabilities.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { BaseAgent } from '../base.js';
|
|
9
|
+
const CONFIG = {
|
|
10
|
+
id: 'npm-audit',
|
|
11
|
+
name: 'NPM Audit',
|
|
12
|
+
role: 'scanner',
|
|
13
|
+
description: 'Audit npm packages for vulnerabilities',
|
|
14
|
+
enabled: true,
|
|
15
|
+
externalTool: 'npm',
|
|
16
|
+
};
|
|
17
|
+
const CAPABILITIES = {
|
|
18
|
+
fileTypes: ['package.json', 'package-lock.json'],
|
|
19
|
+
languages: ['javascript', 'typescript'],
|
|
20
|
+
requiresExternalTool: true,
|
|
21
|
+
supportsParallel: true,
|
|
22
|
+
};
|
|
23
|
+
export class NpmAuditAgent extends BaseAgent {
|
|
24
|
+
constructor() {
|
|
25
|
+
super(CONFIG, CAPABILITIES);
|
|
26
|
+
}
|
|
27
|
+
async execute(context) {
|
|
28
|
+
const startTime = Date.now();
|
|
29
|
+
this.status = 'running';
|
|
30
|
+
const findings = [];
|
|
31
|
+
try {
|
|
32
|
+
// Check if package.json exists
|
|
33
|
+
const packageJsonPath = path.join(context.targetPath, 'package.json');
|
|
34
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
35
|
+
context.log('info', 'No package.json found, skipping npm audit');
|
|
36
|
+
this.status = 'complete';
|
|
37
|
+
return {
|
|
38
|
+
agentId: this.config.id,
|
|
39
|
+
agentName: this.config.name,
|
|
40
|
+
status: 'skipped',
|
|
41
|
+
findings: [],
|
|
42
|
+
duration: Date.now() - startTime,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
context.log('info', `NPM Audit scanning: ${context.targetPath}`);
|
|
46
|
+
// Run npm audit
|
|
47
|
+
const { stdout, stderr, exitCode } = await this.executeCommand('npm', ['audit', '--json'], { cwd: context.targetPath, timeout: 120000 });
|
|
48
|
+
if (stdout.trim()) {
|
|
49
|
+
try {
|
|
50
|
+
const output = JSON.parse(stdout);
|
|
51
|
+
if (output.vulnerabilities) {
|
|
52
|
+
for (const [pkgName, vuln] of Object.entries(output.vulnerabilities)) {
|
|
53
|
+
// Get details from the 'via' field
|
|
54
|
+
let title = `Vulnerability in ${pkgName}`;
|
|
55
|
+
let cwe = [];
|
|
56
|
+
let url;
|
|
57
|
+
for (const via of vuln.via) {
|
|
58
|
+
if (typeof via === 'object') {
|
|
59
|
+
title = via.title || title;
|
|
60
|
+
cwe = via.cwe || cwe;
|
|
61
|
+
url = via.url;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const finding = this.createFinding('npm-audit', {
|
|
66
|
+
type: 'vulnerability',
|
|
67
|
+
severity: this.mapSeverity(vuln.severity),
|
|
68
|
+
title: `${pkgName}: ${title}`,
|
|
69
|
+
description: `${title}. Affects versions: ${vuln.range}`,
|
|
70
|
+
file: 'package.json',
|
|
71
|
+
metadata: {
|
|
72
|
+
package: pkgName,
|
|
73
|
+
severity: vuln.severity,
|
|
74
|
+
isDirect: vuln.isDirect,
|
|
75
|
+
range: vuln.range,
|
|
76
|
+
cwe,
|
|
77
|
+
url,
|
|
78
|
+
fixAvailable: vuln.fixAvailable,
|
|
79
|
+
effects: vuln.effects,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
findings.push(finding);
|
|
83
|
+
context.addFinding(finding);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (parseError) {
|
|
88
|
+
context.log('warn', `Failed to parse npm audit output: ${parseError}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
this.status = 'complete';
|
|
92
|
+
context.log('info', `NPM Audit found ${findings.length} vulnerabilities`);
|
|
93
|
+
return {
|
|
94
|
+
agentId: this.config.id,
|
|
95
|
+
agentName: this.config.name,
|
|
96
|
+
status: 'success',
|
|
97
|
+
findings,
|
|
98
|
+
duration: Date.now() - startTime,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
this.status = 'error';
|
|
103
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
104
|
+
context.log('error', `NPM Audit error: ${errorMsg}`);
|
|
105
|
+
return {
|
|
106
|
+
agentId: this.config.id,
|
|
107
|
+
agentName: this.config.name,
|
|
108
|
+
status: 'error',
|
|
109
|
+
findings,
|
|
110
|
+
duration: Date.now() - startTime,
|
|
111
|
+
error: errorMsg,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
mapSeverity(npmSeverity) {
|
|
116
|
+
switch (npmSeverity.toLowerCase()) {
|
|
117
|
+
case 'critical':
|
|
118
|
+
return 'critical';
|
|
119
|
+
case 'high':
|
|
120
|
+
return 'high';
|
|
121
|
+
case 'moderate':
|
|
122
|
+
return 'medium';
|
|
123
|
+
case 'low':
|
|
124
|
+
return 'low';
|
|
125
|
+
default:
|
|
126
|
+
return 'info';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Semgrep Agent
|
|
3
|
+
*
|
|
4
|
+
* Static analysis for security patterns.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAgent } from '../base.js';
|
|
7
|
+
import { AgentResult } from '../types.js';
|
|
8
|
+
import { ZoneContext } from '../../zones/types.js';
|
|
9
|
+
export declare class SemgrepAgent extends BaseAgent {
|
|
10
|
+
constructor();
|
|
11
|
+
execute(context: ZoneContext): Promise<AgentResult>;
|
|
12
|
+
private getType;
|
|
13
|
+
private mapSeverity;
|
|
14
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Semgrep Agent
|
|
3
|
+
*
|
|
4
|
+
* Static analysis for security patterns.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAgent } from '../base.js';
|
|
7
|
+
const CONFIG = {
|
|
8
|
+
id: 'semgrep',
|
|
9
|
+
name: 'Semgrep',
|
|
10
|
+
role: 'scanner',
|
|
11
|
+
description: 'Static analysis for security patterns',
|
|
12
|
+
enabled: true,
|
|
13
|
+
externalTool: 'semgrep',
|
|
14
|
+
};
|
|
15
|
+
const CAPABILITIES = {
|
|
16
|
+
fileTypes: ['*.js', '*.ts', '*.py', '*.go', '*.java', '*.rb', '*.php'],
|
|
17
|
+
languages: ['javascript', 'typescript', 'python', 'go', 'java', 'ruby', 'php'],
|
|
18
|
+
requiresExternalTool: true,
|
|
19
|
+
supportsParallel: true,
|
|
20
|
+
};
|
|
21
|
+
export class SemgrepAgent extends BaseAgent {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(CONFIG, CAPABILITIES);
|
|
24
|
+
}
|
|
25
|
+
async execute(context) {
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
this.status = 'running';
|
|
28
|
+
const findings = [];
|
|
29
|
+
try {
|
|
30
|
+
context.log('info', `Semgrep scanning: ${context.targetPath}`);
|
|
31
|
+
// Run semgrep with security ruleset
|
|
32
|
+
const { stdout, stderr, exitCode } = await this.executeCommand('semgrep', [
|
|
33
|
+
'scan',
|
|
34
|
+
'--config',
|
|
35
|
+
'p/security-audit',
|
|
36
|
+
'--config',
|
|
37
|
+
'p/secrets',
|
|
38
|
+
'--json',
|
|
39
|
+
'--no-git-ignore',
|
|
40
|
+
'--exclude',
|
|
41
|
+
'node_modules',
|
|
42
|
+
'--exclude',
|
|
43
|
+
'.git',
|
|
44
|
+
'--exclude',
|
|
45
|
+
'dist',
|
|
46
|
+
'--exclude',
|
|
47
|
+
'build',
|
|
48
|
+
context.targetPath,
|
|
49
|
+
], { cwd: context.targetPath, timeout: 600000 } // 10 min timeout for semgrep
|
|
50
|
+
);
|
|
51
|
+
if (stdout.trim()) {
|
|
52
|
+
try {
|
|
53
|
+
const output = JSON.parse(stdout);
|
|
54
|
+
if (output.results) {
|
|
55
|
+
for (const result of output.results) {
|
|
56
|
+
const finding = this.createFinding('semgrep', {
|
|
57
|
+
type: this.getType(result),
|
|
58
|
+
severity: this.mapSeverity(result.extra.severity),
|
|
59
|
+
title: result.check_id,
|
|
60
|
+
description: result.extra.message,
|
|
61
|
+
file: result.path,
|
|
62
|
+
line: result.start.line,
|
|
63
|
+
metadata: {
|
|
64
|
+
checkId: result.check_id,
|
|
65
|
+
category: result.extra.metadata?.category,
|
|
66
|
+
cwe: result.extra.metadata?.cwe,
|
|
67
|
+
owasp: result.extra.metadata?.owasp,
|
|
68
|
+
references: result.extra.metadata?.references?.slice(0, 3),
|
|
69
|
+
endLine: result.end.line,
|
|
70
|
+
column: result.start.col,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
findings.push(finding);
|
|
74
|
+
context.addFinding(finding);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (output.errors && output.errors.length > 0) {
|
|
78
|
+
for (const error of output.errors) {
|
|
79
|
+
context.log('warn', `Semgrep error: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (parseError) {
|
|
84
|
+
context.log('warn', `Failed to parse semgrep output: ${parseError}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.status = 'complete';
|
|
88
|
+
context.log('info', `Semgrep found ${findings.length} issues`);
|
|
89
|
+
return {
|
|
90
|
+
agentId: this.config.id,
|
|
91
|
+
agentName: this.config.name,
|
|
92
|
+
status: 'success',
|
|
93
|
+
findings,
|
|
94
|
+
duration: Date.now() - startTime,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
this.status = 'error';
|
|
99
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
100
|
+
context.log('error', `Semgrep error: ${errorMsg}`);
|
|
101
|
+
return {
|
|
102
|
+
agentId: this.config.id,
|
|
103
|
+
agentName: this.config.name,
|
|
104
|
+
status: 'error',
|
|
105
|
+
findings,
|
|
106
|
+
duration: Date.now() - startTime,
|
|
107
|
+
error: errorMsg,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
getType(result) {
|
|
112
|
+
const checkId = result.check_id.toLowerCase();
|
|
113
|
+
const category = result.extra.metadata?.category?.toLowerCase() || '';
|
|
114
|
+
if (checkId.includes('secret') || category.includes('secret')) {
|
|
115
|
+
return 'secret';
|
|
116
|
+
}
|
|
117
|
+
return 'vulnerability';
|
|
118
|
+
}
|
|
119
|
+
mapSeverity(semgrepSeverity) {
|
|
120
|
+
switch (semgrepSeverity.toUpperCase()) {
|
|
121
|
+
case 'ERROR':
|
|
122
|
+
return 'critical';
|
|
123
|
+
case 'WARNING':
|
|
124
|
+
return 'high';
|
|
125
|
+
case 'INFO':
|
|
126
|
+
return 'medium';
|
|
127
|
+
default:
|
|
128
|
+
return 'low';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aura Protocol - Trivy Agent
|
|
3
|
+
*
|
|
4
|
+
* Scans for vulnerabilities in dependencies and containers.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAgent } from '../base.js';
|
|
7
|
+
import { AgentResult } from '../types.js';
|
|
8
|
+
import { ZoneContext } from '../../zones/types.js';
|
|
9
|
+
export declare class TrivyAgent extends BaseAgent {
|
|
10
|
+
constructor();
|
|
11
|
+
execute(context: ZoneContext): Promise<AgentResult>;
|
|
12
|
+
private mapSeverity;
|
|
13
|
+
private getCvssScore;
|
|
14
|
+
}
|