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
@@ -0,0 +1,69 @@
1
+ export interface ModuleConfig {
2
+ id: string;
3
+ name: string;
4
+ description?: string;
5
+ critical_paths?: string[];
6
+ connections?: string[];
7
+ }
8
+ export interface IntegrationConfig {
9
+ github?: {
10
+ enabled: boolean;
11
+ token?: string;
12
+ webhook_secret?: string;
13
+ };
14
+ gitlab?: {
15
+ enabled: boolean;
16
+ token?: string;
17
+ api_url?: string;
18
+ };
19
+ scanners?: {
20
+ snyk?: {
21
+ enabled: boolean;
22
+ };
23
+ trivy?: {
24
+ enabled: boolean;
25
+ };
26
+ semgrep?: {
27
+ enabled: boolean;
28
+ };
29
+ npm_audit?: {
30
+ enabled: boolean;
31
+ };
32
+ };
33
+ }
34
+ export interface AuditorConfig {
35
+ version: string;
36
+ name?: string;
37
+ description?: string;
38
+ server: {
39
+ port: number;
40
+ host?: string;
41
+ };
42
+ webhook?: {
43
+ enabled: boolean;
44
+ port: number;
45
+ secret?: string;
46
+ };
47
+ visualizer?: {
48
+ enabled: boolean;
49
+ port: number;
50
+ };
51
+ modules: ModuleConfig[];
52
+ policy: {
53
+ critical_assets: string[];
54
+ risk_tolerance: 'low' | 'medium' | 'high';
55
+ };
56
+ integrations?: IntegrationConfig;
57
+ }
58
+ export declare class ConfigLoader {
59
+ private config;
60
+ constructor();
61
+ loadFromFile(filePath: string): AuditorConfig;
62
+ loadFromEnv(): AuditorConfig;
63
+ autoLoad(basePath?: string): AuditorConfig;
64
+ getConfig(): AuditorConfig;
65
+ validate(): string[];
66
+ private parseSimpleYaml;
67
+ private mergeConfig;
68
+ }
69
+ export declare const configLoader: ConfigLoader;
@@ -0,0 +1,212 @@
1
+ // Configuration System - Load and validate auditor configuration
2
+ // Supports: JSON, YAML (with js-yaml), and environment variables
3
+ import { readFileSync, existsSync } from 'fs';
4
+ import { join } from 'path';
5
+ const DEFAULT_CONFIG = {
6
+ version: '1.0',
7
+ server: {
8
+ port: 3000,
9
+ host: '127.0.0.1'
10
+ },
11
+ webhook: {
12
+ enabled: false,
13
+ port: 3001
14
+ },
15
+ visualizer: {
16
+ enabled: true,
17
+ port: 8080
18
+ },
19
+ modules: [
20
+ { id: 'auth', name: 'AUTH', description: 'Authentication & Identity', critical_paths: ['**/auth/**', '**/login/**', '**/oauth/**'] },
21
+ { id: 'database', name: 'DATABASE', description: 'Data Storage', critical_paths: ['**/db/**', '**/database/**', '**/models/**'] },
22
+ { id: 'api', name: 'API', description: 'External Endpoints', critical_paths: ['**/api/**', '**/routes/**', '**/controllers/**'] },
23
+ { id: 'infra', name: 'INFRA', description: 'Infrastructure', critical_paths: ['**/*.tf', '**/terraform/**', '**/k8s/**', '**/docker/**'] },
24
+ { id: 'billing', name: 'BILLING', description: 'Payment Processing', critical_paths: ['**/billing/**', '**/payment/**', '**/stripe/**'] },
25
+ { id: 'secrets', name: 'SECRETS', description: 'Credentials & Keys', critical_paths: ['**/.env*', '**/secrets/**', '**/config/**'] }
26
+ ],
27
+ policy: {
28
+ critical_assets: ['auth', 'billing', 'database', 'secrets'],
29
+ risk_tolerance: 'medium'
30
+ },
31
+ integrations: {
32
+ github: { enabled: false },
33
+ gitlab: { enabled: false },
34
+ scanners: {
35
+ snyk: { enabled: false },
36
+ trivy: { enabled: false },
37
+ semgrep: { enabled: false },
38
+ npm_audit: { enabled: true }
39
+ }
40
+ }
41
+ };
42
+ export class ConfigLoader {
43
+ config;
44
+ constructor() {
45
+ this.config = { ...DEFAULT_CONFIG };
46
+ }
47
+ // Load from file
48
+ loadFromFile(filePath) {
49
+ if (!existsSync(filePath)) {
50
+ console.warn(`[Config] File not found: ${filePath}, using defaults`);
51
+ return this.config;
52
+ }
53
+ const content = readFileSync(filePath, 'utf-8');
54
+ const ext = filePath.split('.').pop()?.toLowerCase();
55
+ let parsed;
56
+ if (ext === 'json') {
57
+ parsed = JSON.parse(content);
58
+ }
59
+ else if (ext === 'yaml' || ext === 'yml') {
60
+ // Simple YAML parsing (key: value format)
61
+ parsed = this.parseSimpleYaml(content);
62
+ }
63
+ else {
64
+ throw new Error(`Unsupported config format: ${ext}`);
65
+ }
66
+ this.config = this.mergeConfig(this.config, parsed);
67
+ return this.config;
68
+ }
69
+ // Load from environment variables
70
+ loadFromEnv() {
71
+ const env = process.env;
72
+ if (env.AURA_PORT) {
73
+ this.config.server.port = parseInt(env.AURA_PORT, 10);
74
+ }
75
+ if (env.AURA_HOST) {
76
+ this.config.server.host = env.AURA_HOST;
77
+ }
78
+ if (env.WEBHOOK_PORT) {
79
+ this.config.webhook = { ...this.config.webhook, enabled: true, port: parseInt(env.WEBHOOK_PORT, 10) };
80
+ }
81
+ if (env.WEBHOOK_SECRET) {
82
+ this.config.webhook = { ...this.config.webhook, secret: env.WEBHOOK_SECRET };
83
+ }
84
+ if (env.VISUALIZER_PORT) {
85
+ this.config.visualizer = { ...this.config.visualizer, port: parseInt(env.VISUALIZER_PORT, 10) };
86
+ }
87
+ if (env.GITHUB_TOKEN) {
88
+ this.config.integrations = {
89
+ ...this.config.integrations,
90
+ github: { enabled: true, token: env.GITHUB_TOKEN }
91
+ };
92
+ }
93
+ if (env.GITLAB_TOKEN) {
94
+ this.config.integrations = {
95
+ ...this.config.integrations,
96
+ gitlab: { enabled: true, token: env.GITLAB_TOKEN }
97
+ };
98
+ }
99
+ if (env.RISK_TOLERANCE) {
100
+ this.config.policy.risk_tolerance = env.RISK_TOLERANCE;
101
+ }
102
+ return this.config;
103
+ }
104
+ // Auto-detect and load config
105
+ autoLoad(basePath = process.cwd()) {
106
+ const configFiles = [
107
+ 'aura.config.json',
108
+ 'aura.config.yaml',
109
+ 'aura.config.yml',
110
+ '.aurarc.json',
111
+ '.aurarc'
112
+ ];
113
+ for (const file of configFiles) {
114
+ const fullPath = join(basePath, file);
115
+ if (existsSync(fullPath)) {
116
+ console.log(`[Config] Loading from ${file}`);
117
+ this.loadFromFile(fullPath);
118
+ break;
119
+ }
120
+ }
121
+ // Override with env vars
122
+ this.loadFromEnv();
123
+ return this.config;
124
+ }
125
+ getConfig() {
126
+ return this.config;
127
+ }
128
+ // Validate configuration
129
+ validate() {
130
+ const errors = [];
131
+ if (!this.config.server?.port) {
132
+ errors.push('server.port is required');
133
+ }
134
+ if (this.config.server.port < 1 || this.config.server.port > 65535) {
135
+ errors.push('server.port must be between 1 and 65535');
136
+ }
137
+ if (!this.config.modules || this.config.modules.length === 0) {
138
+ errors.push('At least one module must be configured');
139
+ }
140
+ if (!this.config.policy?.critical_assets) {
141
+ errors.push('policy.critical_assets is required');
142
+ }
143
+ return errors;
144
+ }
145
+ parseSimpleYaml(content) {
146
+ // Very basic YAML parser for simple configs
147
+ const result = {};
148
+ const lines = content.split('\n');
149
+ let currentSection = result;
150
+ let sectionStack = [result];
151
+ let indentStack = [0];
152
+ for (const line of lines) {
153
+ if (line.trim() === '' || line.trim().startsWith('#'))
154
+ continue;
155
+ const indent = line.search(/\S/);
156
+ const trimmed = line.trim();
157
+ // Handle section end
158
+ while (indent <= indentStack[indentStack.length - 1] && indentStack.length > 1) {
159
+ sectionStack.pop();
160
+ indentStack.pop();
161
+ currentSection = sectionStack[sectionStack.length - 1];
162
+ }
163
+ if (trimmed.endsWith(':')) {
164
+ // New section
165
+ const key = trimmed.slice(0, -1);
166
+ currentSection[key] = {};
167
+ sectionStack.push(currentSection[key]);
168
+ indentStack.push(indent);
169
+ currentSection = currentSection[key];
170
+ }
171
+ else if (trimmed.includes(':')) {
172
+ // Key-value pair
173
+ const [key, ...valueParts] = trimmed.split(':');
174
+ let value = valueParts.join(':').trim();
175
+ // Parse value type
176
+ if (value === 'true')
177
+ value = true;
178
+ else if (value === 'false')
179
+ value = false;
180
+ else if (!isNaN(Number(value)))
181
+ value = Number(value);
182
+ else if (value.startsWith('[')) {
183
+ // Simple array
184
+ value = value.slice(1, -1).split(',').map(v => v.trim().replace(/['"]/g, ''));
185
+ }
186
+ currentSection[key.trim()] = value;
187
+ }
188
+ }
189
+ return result;
190
+ }
191
+ mergeConfig(base, override) {
192
+ return {
193
+ version: override.version || base.version,
194
+ name: override.name || base.name,
195
+ description: override.description || base.description,
196
+ server: { ...base.server, ...override.server },
197
+ webhook: base.webhook && override.webhook
198
+ ? { ...base.webhook, ...override.webhook }
199
+ : (override.webhook || base.webhook),
200
+ visualizer: base.visualizer && override.visualizer
201
+ ? { ...base.visualizer, ...override.visualizer }
202
+ : (override.visualizer || base.visualizer),
203
+ modules: override.modules || base.modules,
204
+ policy: { ...base.policy, ...override.policy },
205
+ integrations: override.integrations
206
+ ? { ...base.integrations, ...override.integrations }
207
+ : base.integrations
208
+ };
209
+ }
210
+ }
211
+ // Export singleton loader
212
+ export const configLoader = new ConfigLoader();
@@ -0,0 +1,45 @@
1
+ import type { AuditorInput, AuditorOutput } from '../types/events.js';
2
+ export interface GitHubConfig {
3
+ token: string;
4
+ apiUrl?: string;
5
+ }
6
+ export interface PullRequest {
7
+ number: number;
8
+ title: string;
9
+ body: string;
10
+ head: {
11
+ sha: string;
12
+ ref: string;
13
+ };
14
+ base: {
15
+ ref: string;
16
+ };
17
+ user: {
18
+ login: string;
19
+ };
20
+ changed_files: number;
21
+ additions: number;
22
+ deletions: number;
23
+ }
24
+ export interface ChangedFile {
25
+ filename: string;
26
+ status: string;
27
+ additions: number;
28
+ deletions: number;
29
+ patch?: string;
30
+ }
31
+ export declare class GitHubIntegration {
32
+ private token;
33
+ private apiUrl;
34
+ constructor(config: GitHubConfig);
35
+ private fetch;
36
+ getPullRequest(owner: string, repo: string, prNumber: number): Promise<PullRequest>;
37
+ getPullRequestFiles(owner: string, repo: string, prNumber: number): Promise<ChangedFile[]>;
38
+ getPullRequestDiff(owner: string, repo: string, prNumber: number): Promise<string>;
39
+ createAuditInput(owner: string, repo: string, prNumber: number, criticalAssets?: string[]): Promise<AuditorInput>;
40
+ createCheckRun(owner: string, repo: string, headSha: string, output: AuditorOutput): Promise<void>;
41
+ createPRComment(owner: string, repo: string, prNumber: number, output: AuditorOutput): Promise<void>;
42
+ private formatCheckSummary;
43
+ private formatAnnotations;
44
+ private formatCommentBody;
45
+ }
@@ -0,0 +1,201 @@
1
+ // GitHub Integration - Fetch PR details, diffs, and create check runs
2
+ // Requires: GITHUB_TOKEN environment variable
3
+ export class GitHubIntegration {
4
+ token;
5
+ apiUrl;
6
+ constructor(config) {
7
+ this.token = config.token;
8
+ this.apiUrl = config.apiUrl || 'https://api.github.com';
9
+ }
10
+ async fetch(endpoint, options = {}) {
11
+ const res = await fetch(`${this.apiUrl}${endpoint}`, {
12
+ ...options,
13
+ headers: {
14
+ 'Authorization': `Bearer ${this.token}`,
15
+ 'Accept': 'application/vnd.github.v3+json',
16
+ 'X-GitHub-Api-Version': '2022-11-28',
17
+ ...options.headers
18
+ }
19
+ });
20
+ if (!res.ok) {
21
+ throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
22
+ }
23
+ return res.json();
24
+ }
25
+ // Get pull request details
26
+ async getPullRequest(owner, repo, prNumber) {
27
+ return this.fetch(`/repos/${owner}/${repo}/pulls/${prNumber}`);
28
+ }
29
+ // Get files changed in PR
30
+ async getPullRequestFiles(owner, repo, prNumber) {
31
+ return this.fetch(`/repos/${owner}/${repo}/pulls/${prNumber}/files`);
32
+ }
33
+ // Get full diff
34
+ async getPullRequestDiff(owner, repo, prNumber) {
35
+ const res = await fetch(`${this.apiUrl}/repos/${owner}/${repo}/pulls/${prNumber}`, {
36
+ headers: {
37
+ 'Authorization': `Bearer ${this.token}`,
38
+ 'Accept': 'application/vnd.github.v3.diff'
39
+ }
40
+ });
41
+ if (!res.ok) {
42
+ throw new Error(`GitHub API error: ${res.status}`);
43
+ }
44
+ return res.text();
45
+ }
46
+ // Create audit input from PR
47
+ async createAuditInput(owner, repo, prNumber, criticalAssets = ['auth', 'billing', 'database', 'secrets', 'infra']) {
48
+ const [pr, files, diff] = await Promise.all([
49
+ this.getPullRequest(owner, repo, prNumber),
50
+ this.getPullRequestFiles(owner, repo, prNumber),
51
+ this.getPullRequestDiff(owner, repo, prNumber)
52
+ ]);
53
+ const isProd = pr.base.ref === 'main' || pr.base.ref === 'master';
54
+ return {
55
+ change_event: {
56
+ id: `github-${owner}-${repo}-pr-${prNumber}`,
57
+ type: 'pull_request',
58
+ environment: isProd ? 'prod' : 'staging',
59
+ repo: `${owner}/${repo}`,
60
+ commit: pr.head.sha,
61
+ files_changed: files.map(f => f.filename),
62
+ diff: diff
63
+ },
64
+ evidence_bundle: {
65
+ // Can be populated by scanner integrations
66
+ },
67
+ policy_context: {
68
+ critical_assets: criticalAssets,
69
+ risk_tolerance: isProd ? 'low' : 'medium'
70
+ }
71
+ };
72
+ }
73
+ // Create a check run for the PR
74
+ async createCheckRun(owner, repo, headSha, output) {
75
+ const criticalCount = output.events.filter(e => e.payload.severity === 'critical').length;
76
+ const highCount = output.events.filter(e => e.payload.severity === 'high').length;
77
+ const conclusion = criticalCount > 0 ? 'failure' :
78
+ highCount > 0 ? 'neutral' : 'success';
79
+ const summary = this.formatCheckSummary(output);
80
+ const annotations = this.formatAnnotations(output);
81
+ await this.fetch(`/repos/${owner}/${repo}/check-runs`, {
82
+ method: 'POST',
83
+ headers: { 'Content-Type': 'application/json' },
84
+ body: JSON.stringify({
85
+ name: 'aurasecurity Audit',
86
+ head_sha: headSha,
87
+ status: 'completed',
88
+ conclusion,
89
+ output: {
90
+ title: `Security Audit: ${output.agent_state.toUpperCase()}`,
91
+ summary,
92
+ annotations: annotations.slice(0, 50) // GitHub limit
93
+ }
94
+ })
95
+ });
96
+ }
97
+ // Create a PR comment with audit results
98
+ async createPRComment(owner, repo, prNumber, output) {
99
+ const body = this.formatCommentBody(output);
100
+ await this.fetch(`/repos/${owner}/${repo}/issues/${prNumber}/comments`, {
101
+ method: 'POST',
102
+ headers: { 'Content-Type': 'application/json' },
103
+ body: JSON.stringify({ body })
104
+ });
105
+ }
106
+ formatCheckSummary(output) {
107
+ const counts = {
108
+ critical: output.events.filter(e => e.payload.severity === 'critical').length,
109
+ high: output.events.filter(e => e.payload.severity === 'high').length,
110
+ medium: output.events.filter(e => e.payload.severity === 'medium').length,
111
+ low: output.events.filter(e => e.payload.severity === 'low').length
112
+ };
113
+ return `## Security Audit Results
114
+
115
+ **Agent State:** ${output.agent_state.toUpperCase()}
116
+
117
+ ### Findings Summary
118
+ | Severity | Count |
119
+ |----------|-------|
120
+ | Critical | ${counts.critical} |
121
+ | High | ${counts.high} |
122
+ | Medium | ${counts.medium} |
123
+ | Low | ${counts.low} |
124
+
125
+ ### Details
126
+ ${output.events.filter(e => e.event_type !== 'analysis_started').map(e => `
127
+ #### ${e.payload.severity.toUpperCase()}: ${e.payload.claim}
128
+ - **Confidence:** ${(e.payload.confidence * 100).toFixed(0)}%
129
+ - **Affected:** ${e.payload.affected_assets.join(', ') || 'N/A'}
130
+ - **Attack Path:**
131
+ ${e.payload.attack_path.map(p => ` 1. ${p}`).join('\n')}
132
+ `).join('\n')}
133
+ `;
134
+ }
135
+ formatAnnotations(output) {
136
+ const annotations = [];
137
+ for (const event of output.events) {
138
+ if (event.event_type === 'analysis_started')
139
+ continue;
140
+ for (const ref of event.payload.evidence_refs) {
141
+ if (ref.type === 'diff') {
142
+ const level = event.payload.severity === 'critical' ? 'failure' :
143
+ event.payload.severity === 'high' ? 'warning' : 'notice';
144
+ annotations.push({
145
+ path: ref.pointer.includes('/') ? ref.pointer : 'unknown',
146
+ start_line: 1,
147
+ end_line: 1,
148
+ annotation_level: level,
149
+ message: event.payload.claim,
150
+ title: `${event.payload.severity.toUpperCase()}: Security Finding`
151
+ });
152
+ }
153
+ }
154
+ }
155
+ return annotations;
156
+ }
157
+ formatCommentBody(output) {
158
+ const emoji = output.agent_state === 'blocked' ? '🚨' :
159
+ output.agent_state === 'escalated' ? '⚠️' :
160
+ output.agent_state === 'conflict' ? '⚡' : '✅';
161
+ const counts = {
162
+ critical: output.events.filter(e => e.payload.severity === 'critical').length,
163
+ high: output.events.filter(e => e.payload.severity === 'high').length,
164
+ medium: output.events.filter(e => e.payload.severity === 'medium').length,
165
+ low: output.events.filter(e => e.payload.severity === 'low').length
166
+ };
167
+ let body = `## ${emoji} aurasecurity Audit
168
+
169
+ **Status:** ${output.agent_state.toUpperCase()}
170
+
171
+ | Critical | High | Medium | Low |
172
+ |:--------:|:----:|:------:|:---:|
173
+ | ${counts.critical} | ${counts.high} | ${counts.medium} | ${counts.low} |
174
+
175
+ `;
176
+ if (output.events.length > 1) {
177
+ body += `### Findings\n\n`;
178
+ for (const event of output.events) {
179
+ if (event.event_type === 'analysis_started')
180
+ continue;
181
+ const sevEmoji = event.payload.severity === 'critical' ? '🔴' :
182
+ event.payload.severity === 'high' ? '🟠' :
183
+ event.payload.severity === 'medium' ? '🟡' : '🟢';
184
+ body += `<details>
185
+ <summary>${sevEmoji} <strong>${event.payload.severity.toUpperCase()}</strong>: ${event.payload.claim}</summary>
186
+
187
+ **Confidence:** ${(event.payload.confidence * 100).toFixed(0)}%
188
+ **Affected:** ${event.payload.affected_assets.join(', ') || 'N/A'}
189
+
190
+ **Attack Path:**
191
+ ${event.payload.attack_path.map((p, i) => `${i + 1}. ${p}`).join('\n')}
192
+
193
+ </details>
194
+
195
+ `;
196
+ }
197
+ }
198
+ body += `\n---\n*Powered by aurasecurity*`;
199
+ return body;
200
+ }
201
+ }
@@ -0,0 +1,36 @@
1
+ import type { AuditorInput, AuditorOutput } from '../types/events.js';
2
+ export interface GitLabConfig {
3
+ token: string;
4
+ apiUrl?: string;
5
+ }
6
+ export interface MergeRequest {
7
+ iid: number;
8
+ title: string;
9
+ description: string;
10
+ source_branch: string;
11
+ target_branch: string;
12
+ sha: string;
13
+ author: {
14
+ username: string;
15
+ };
16
+ changes_count: string;
17
+ }
18
+ export interface MergeRequestChange {
19
+ old_path: string;
20
+ new_path: string;
21
+ diff: string;
22
+ }
23
+ export declare class GitLabIntegration {
24
+ private token;
25
+ private apiUrl;
26
+ constructor(config: GitLabConfig);
27
+ private fetch;
28
+ getMergeRequest(projectId: string | number, mrIid: number): Promise<MergeRequest>;
29
+ getMergeRequestChanges(projectId: string | number, mrIid: number): Promise<{
30
+ changes: MergeRequestChange[];
31
+ }>;
32
+ createAuditInput(projectId: string | number, mrIid: number, criticalAssets?: string[]): Promise<AuditorInput>;
33
+ createMRComment(projectId: string | number, mrIid: number, output: AuditorOutput): Promise<void>;
34
+ updateCommitStatus(projectId: string | number, sha: string, output: AuditorOutput): Promise<void>;
35
+ private formatCommentBody;
36
+ }
@@ -0,0 +1,110 @@
1
+ // GitLab Integration - Fetch MR details and create pipeline comments
2
+ // Requires: GITLAB_TOKEN environment variable
3
+ export class GitLabIntegration {
4
+ token;
5
+ apiUrl;
6
+ constructor(config) {
7
+ this.token = config.token;
8
+ this.apiUrl = config.apiUrl || 'https://gitlab.com/api/v4';
9
+ }
10
+ async fetch(endpoint, options = {}) {
11
+ const res = await fetch(`${this.apiUrl}${endpoint}`, {
12
+ ...options,
13
+ headers: {
14
+ 'PRIVATE-TOKEN': this.token,
15
+ 'Content-Type': 'application/json',
16
+ ...options.headers
17
+ }
18
+ });
19
+ if (!res.ok) {
20
+ throw new Error(`GitLab API error: ${res.status} ${res.statusText}`);
21
+ }
22
+ return res.json();
23
+ }
24
+ // Get merge request details
25
+ async getMergeRequest(projectId, mrIid) {
26
+ return this.fetch(`/projects/${encodeURIComponent(projectId)}/merge_requests/${mrIid}`);
27
+ }
28
+ // Get MR changes/diff
29
+ async getMergeRequestChanges(projectId, mrIid) {
30
+ return this.fetch(`/projects/${encodeURIComponent(projectId)}/merge_requests/${mrIid}/changes`);
31
+ }
32
+ // Create audit input from MR
33
+ async createAuditInput(projectId, mrIid, criticalAssets = ['auth', 'billing', 'database', 'secrets', 'infra']) {
34
+ const [mr, changes] = await Promise.all([
35
+ this.getMergeRequest(projectId, mrIid),
36
+ this.getMergeRequestChanges(projectId, mrIid)
37
+ ]);
38
+ const isProd = mr.target_branch === 'main' || mr.target_branch === 'master';
39
+ const diff = changes.changes.map(c => c.diff).join('\n');
40
+ return {
41
+ change_event: {
42
+ id: `gitlab-${projectId}-mr-${mrIid}`,
43
+ type: 'pull_request',
44
+ environment: isProd ? 'prod' : 'staging',
45
+ repo: String(projectId),
46
+ commit: mr.sha,
47
+ files_changed: changes.changes.map(c => c.new_path),
48
+ diff
49
+ },
50
+ evidence_bundle: {},
51
+ policy_context: {
52
+ critical_assets: criticalAssets,
53
+ risk_tolerance: isProd ? 'low' : 'medium'
54
+ }
55
+ };
56
+ }
57
+ // Create MR comment with audit results
58
+ async createMRComment(projectId, mrIid, output) {
59
+ const body = this.formatCommentBody(output);
60
+ await this.fetch(`/projects/${encodeURIComponent(projectId)}/merge_requests/${mrIid}/notes`, {
61
+ method: 'POST',
62
+ body: JSON.stringify({ body })
63
+ });
64
+ }
65
+ // Update pipeline status
66
+ async updateCommitStatus(projectId, sha, output) {
67
+ const criticalCount = output.events.filter(e => e.payload.severity === 'critical').length;
68
+ const highCount = output.events.filter(e => e.payload.severity === 'high').length;
69
+ const state = criticalCount > 0 ? 'failed' :
70
+ highCount > 0 ? 'failed' : 'success';
71
+ await this.fetch(`/projects/${encodeURIComponent(projectId)}/statuses/${sha}`, {
72
+ method: 'POST',
73
+ body: JSON.stringify({
74
+ state,
75
+ name: 'aurasecurity Audit',
76
+ description: `${output.agent_state.toUpperCase()} - ${criticalCount} critical, ${highCount} high`,
77
+ context: 'security/aura-audit'
78
+ })
79
+ });
80
+ }
81
+ formatCommentBody(output) {
82
+ const emoji = output.agent_state === 'blocked' ? '🚨' :
83
+ output.agent_state === 'escalated' ? '⚠️' : '✅';
84
+ const counts = {
85
+ critical: output.events.filter(e => e.payload.severity === 'critical').length,
86
+ high: output.events.filter(e => e.payload.severity === 'high').length,
87
+ medium: output.events.filter(e => e.payload.severity === 'medium').length,
88
+ low: output.events.filter(e => e.payload.severity === 'low').length
89
+ };
90
+ let body = `## ${emoji} aurasecurity Audit
91
+
92
+ **Status:** \`${output.agent_state.toUpperCase()}\`
93
+
94
+ | Critical | High | Medium | Low |
95
+ |:--------:|:----:|:------:|:---:|
96
+ | ${counts.critical} | ${counts.high} | ${counts.medium} | ${counts.low} |
97
+
98
+ `;
99
+ for (const event of output.events) {
100
+ if (event.event_type === 'analysis_started')
101
+ continue;
102
+ body += `### ${event.payload.severity.toUpperCase()}: ${event.payload.claim}
103
+ - Confidence: ${(event.payload.confidence * 100).toFixed(0)}%
104
+ - Affected: ${event.payload.affected_assets.join(', ') || 'N/A'}
105
+
106
+ `;
107
+ }
108
+ return body;
109
+ }
110
+ }
@@ -0,0 +1,11 @@
1
+ export { WebhookServer, WebhookHandler } from './webhook.js';
2
+ export { GitHubIntegration } from './github.js';
3
+ export { GitLabIntegration } from './gitlab.js';
4
+ export { ScannerParser, SnykParser, TrivyParser, SemgrepParser } from './scanners.js';
5
+ export { ConfigLoader, AuditorConfig } from './config.js';
6
+ export { LocalScanner, quickLocalScan } from './local-scanner.js';
7
+ export type { LocalScanConfig, LocalScanResult, SecretFinding, PackageFinding, SastFinding, GitInfo, EnvFileFinding, SystemInfo, DiscoveredService, DiscoveredModule } from './local-scanner.js';
8
+ export { NotificationService, createNotificationFromAudit } from './notifications.js';
9
+ export { auraScan, getAuraState, getAvailableAgents, orchestrator } from './aura-scanner.js';
10
+ export type { AuraScanConfig, AuraScanResult } from './aura-scanner.js';
11
+ export type { NotificationConfig, NotificationPayload } from './notifications.js';