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,41 @@
1
+ import type { AuditorInput, AuditorOutput, ChangeEvent, EvidenceBundle, PolicyContext } from '../types/events.js';
2
+ export interface AuditClientConfig {
3
+ serverUrl?: string;
4
+ apiKey?: string;
5
+ timeout?: number;
6
+ retries?: number;
7
+ }
8
+ export interface AuditRequest {
9
+ changeEvent: ChangeEvent;
10
+ evidenceBundle?: Partial<EvidenceBundle>;
11
+ policyContext?: Partial<PolicyContext>;
12
+ }
13
+ export interface AuditResult {
14
+ success: boolean;
15
+ output?: AuditorOutput;
16
+ error?: string;
17
+ duration: number;
18
+ }
19
+ export interface ServerInfo {
20
+ name: string;
21
+ version: string;
22
+ endpoints: string[];
23
+ tools: string[];
24
+ }
25
+ export declare class AuditClient {
26
+ private config;
27
+ constructor(config?: AuditClientConfig);
28
+ private headers;
29
+ private fetchWithRetry;
30
+ private delay;
31
+ getServerInfo(): Promise<ServerInfo>;
32
+ isHealthy(): Promise<boolean>;
33
+ audit(request: AuditRequest): Promise<AuditResult>;
34
+ getAuditLogs(): Promise<string[]>;
35
+ getAuditEntry(key: string): Promise<AuditorOutput | null>;
36
+ watchAudits(pollInterval?: number): AsyncGenerator<AuditorOutput>;
37
+ }
38
+ export declare function createPullRequestEvent(repo: string, commit: string, filesChanged: string[], diff: string, environment?: 'dev' | 'staging' | 'prod'): ChangeEvent;
39
+ export declare function createDeployEvent(repo: string, commit: string, environment: 'dev' | 'staging' | 'prod'): ChangeEvent;
40
+ export declare function createInfraChangeEvent(repo: string, commit: string, filesChanged: string[], diff: string): ChangeEvent;
41
+ export { AuditorInput, AuditorOutput, ChangeEvent, EvidenceBundle, PolicyContext };
@@ -0,0 +1,170 @@
1
+ // Aura Client SDK - High-level API for interacting with the auditor
2
+ // Provides typed methods, automatic retries, and event streaming
3
+ export class AuditClient {
4
+ config;
5
+ constructor(config = {}) {
6
+ this.config = {
7
+ serverUrl: config.serverUrl ?? 'http://127.0.0.1:3000',
8
+ apiKey: config.apiKey ?? '',
9
+ timeout: config.timeout ?? 30000,
10
+ retries: config.retries ?? 3
11
+ };
12
+ }
13
+ headers() {
14
+ const h = {
15
+ 'Content-Type': 'application/json'
16
+ };
17
+ if (this.config.apiKey) {
18
+ h['Authorization'] = `Bearer ${this.config.apiKey}`;
19
+ }
20
+ return h;
21
+ }
22
+ async fetchWithRetry(url, options, retries = this.config.retries) {
23
+ const controller = new AbortController();
24
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
25
+ try {
26
+ const res = await fetch(url, {
27
+ ...options,
28
+ signal: controller.signal
29
+ });
30
+ clearTimeout(timeoutId);
31
+ if (!res.ok) {
32
+ throw new Error(`HTTP ${res.status}: ${res.statusText}`);
33
+ }
34
+ return await res.json();
35
+ }
36
+ catch (err) {
37
+ clearTimeout(timeoutId);
38
+ if (retries > 0 && !(err instanceof DOMException && err.name === 'AbortError')) {
39
+ await this.delay(1000);
40
+ return this.fetchWithRetry(url, options, retries - 1);
41
+ }
42
+ throw err;
43
+ }
44
+ }
45
+ delay(ms) {
46
+ return new Promise(resolve => setTimeout(resolve, ms));
47
+ }
48
+ async getServerInfo() {
49
+ return this.fetchWithRetry(`${this.config.serverUrl}/info`, { method: 'GET', headers: this.headers() });
50
+ }
51
+ async isHealthy() {
52
+ try {
53
+ await this.getServerInfo();
54
+ return true;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
60
+ async audit(request) {
61
+ const startTime = Date.now();
62
+ const input = {
63
+ change_event: request.changeEvent,
64
+ evidence_bundle: {
65
+ sbom: request.evidenceBundle?.sbom,
66
+ vuln_scan: request.evidenceBundle?.vuln_scan,
67
+ sast_results: request.evidenceBundle?.sast_results,
68
+ iac_scan: request.evidenceBundle?.iac_scan,
69
+ provenance: request.evidenceBundle?.provenance,
70
+ runtime_delta: request.evidenceBundle?.runtime_delta
71
+ },
72
+ policy_context: {
73
+ critical_assets: request.policyContext?.critical_assets ?? ['auth', 'billing', 'phi', 'infra'],
74
+ risk_tolerance: request.policyContext?.risk_tolerance ?? 'medium'
75
+ }
76
+ };
77
+ try {
78
+ const response = await this.fetchWithRetry(`${this.config.serverUrl}/tools`, {
79
+ method: 'POST',
80
+ headers: this.headers(),
81
+ body: JSON.stringify({ tool: 'audit', arguments: input })
82
+ });
83
+ return {
84
+ success: true,
85
+ output: response.result,
86
+ duration: Date.now() - startTime
87
+ };
88
+ }
89
+ catch (err) {
90
+ return {
91
+ success: false,
92
+ error: err instanceof Error ? err.message : String(err),
93
+ duration: Date.now() - startTime
94
+ };
95
+ }
96
+ }
97
+ async getAuditLogs() {
98
+ const response = await this.fetchWithRetry(`${this.config.serverUrl}/memory`, { method: 'GET', headers: this.headers() });
99
+ return response.keys;
100
+ }
101
+ async getAuditEntry(key) {
102
+ try {
103
+ const response = await this.fetchWithRetry(`${this.config.serverUrl}/memory?key=${encodeURIComponent(key)}`, { method: 'GET', headers: this.headers() });
104
+ return response.value;
105
+ }
106
+ catch {
107
+ return null;
108
+ }
109
+ }
110
+ // Stream audit logs in real-time
111
+ async *watchAudits(pollInterval = 2000) {
112
+ let lastCount = 0;
113
+ const seenKeys = new Set();
114
+ while (true) {
115
+ try {
116
+ const keys = await this.getAuditLogs();
117
+ if (keys.length > lastCount) {
118
+ for (const key of keys) {
119
+ if (!seenKeys.has(key)) {
120
+ seenKeys.add(key);
121
+ const entry = await this.getAuditEntry(key);
122
+ if (entry) {
123
+ yield entry;
124
+ }
125
+ }
126
+ }
127
+ lastCount = keys.length;
128
+ }
129
+ }
130
+ catch {
131
+ // Ignore errors in watch mode
132
+ }
133
+ await this.delay(pollInterval);
134
+ }
135
+ }
136
+ }
137
+ // Helper functions for building audit requests
138
+ export function createPullRequestEvent(repo, commit, filesChanged, diff, environment = 'dev') {
139
+ return {
140
+ id: `pr-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
141
+ type: 'pull_request',
142
+ environment,
143
+ repo,
144
+ commit,
145
+ files_changed: filesChanged,
146
+ diff
147
+ };
148
+ }
149
+ export function createDeployEvent(repo, commit, environment) {
150
+ return {
151
+ id: `deploy-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
152
+ type: 'deploy',
153
+ environment,
154
+ repo,
155
+ commit,
156
+ files_changed: [],
157
+ diff: ''
158
+ };
159
+ }
160
+ export function createInfraChangeEvent(repo, commit, filesChanged, diff) {
161
+ return {
162
+ id: `infra-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
163
+ type: 'infra_change',
164
+ environment: 'prod',
165
+ repo,
166
+ commit,
167
+ files_changed: filesChanged,
168
+ diff
169
+ };
170
+ }
@@ -0,0 +1,40 @@
1
+ export interface LicenseInfo {
2
+ package: string;
3
+ version: string;
4
+ license: string;
5
+ licenseFile?: string;
6
+ repository?: string;
7
+ }
8
+ export interface LicensePolicy {
9
+ name: string;
10
+ description: string;
11
+ allowed: string[];
12
+ denied: string[];
13
+ unknown: 'allow' | 'warn' | 'deny';
14
+ }
15
+ export interface LicenseViolation {
16
+ package: string;
17
+ version: string;
18
+ license: string;
19
+ violation: string;
20
+ severity: 'high' | 'medium' | 'low';
21
+ }
22
+ export interface LicenseCheckResult {
23
+ policy: string;
24
+ licenses: LicenseInfo[];
25
+ violations: LicenseViolation[];
26
+ summary: {
27
+ total: number;
28
+ compliant: number;
29
+ violations: number;
30
+ unknown: number;
31
+ };
32
+ }
33
+ export declare const POLICIES: Record<string, LicensePolicy>;
34
+ export interface LicenseCheckOptions {
35
+ policy?: string | LicensePolicy;
36
+ allowedLicenses?: string[];
37
+ deniedLicenses?: string[];
38
+ }
39
+ export declare function checkLicenses(targetPath: string, options?: LicenseCheckOptions): LicenseCheckResult;
40
+ export declare const POLICY_NAMES: string[];
@@ -0,0 +1,292 @@
1
+ // License Compliance Checker
2
+ // Checks dependencies for license compliance with configurable policies
3
+ import { spawnSync } from 'child_process';
4
+ import { existsSync, readFileSync } from 'fs';
5
+ import { join } from 'path';
6
+ // ============ Built-in Policies ============
7
+ export const POLICIES = {
8
+ permissive: {
9
+ name: 'Permissive',
10
+ description: 'Only allow permissive open source licenses',
11
+ allowed: [
12
+ 'MIT', 'ISC', 'BSD-2-Clause', 'BSD-3-Clause', 'Apache-2.0',
13
+ 'Unlicense', '0BSD', 'CC0-1.0', 'WTFPL', 'Zlib', 'BlueOak-1.0.0'
14
+ ],
15
+ denied: [
16
+ 'GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'LGPL-2.1', 'LGPL-3.0',
17
+ 'GPL-2.0-only', 'GPL-3.0-only', 'AGPL-3.0-only',
18
+ 'GPL-2.0-or-later', 'GPL-3.0-or-later', 'AGPL-3.0-or-later'
19
+ ],
20
+ unknown: 'warn'
21
+ },
22
+ strict: {
23
+ name: 'Strict',
24
+ description: 'Strict policy - only well-known permissive licenses',
25
+ allowed: ['MIT', 'ISC', 'BSD-2-Clause', 'BSD-3-Clause', 'Apache-2.0'],
26
+ denied: [
27
+ 'GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'LGPL-2.1', 'LGPL-3.0',
28
+ 'GPL-2.0-only', 'GPL-3.0-only', 'AGPL-3.0-only',
29
+ 'SSPL-1.0', 'BSL-1.1', 'Elastic-2.0'
30
+ ],
31
+ unknown: 'deny'
32
+ },
33
+ copyleft: {
34
+ name: 'Copyleft Allowed',
35
+ description: 'Allow copyleft licenses (for open source projects)',
36
+ allowed: [
37
+ 'MIT', 'ISC', 'BSD-2-Clause', 'BSD-3-Clause', 'Apache-2.0',
38
+ 'GPL-2.0', 'GPL-3.0', 'LGPL-2.1', 'LGPL-3.0', 'MPL-2.0',
39
+ 'GPL-2.0-only', 'GPL-3.0-only', 'LGPL-2.1-only', 'LGPL-3.0-only'
40
+ ],
41
+ denied: ['AGPL-3.0', 'AGPL-3.0-only', 'SSPL-1.0'],
42
+ unknown: 'warn'
43
+ }
44
+ };
45
+ // ============ License Detection ============
46
+ function isToolAvailable(tool) {
47
+ try {
48
+ const result = spawnSync(tool, ['--version'], { encoding: 'utf-8', timeout: 5000 });
49
+ return result.status === 0;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ // Run license-checker for Node.js projects
56
+ function runLicenseChecker(targetPath) {
57
+ const licenses = [];
58
+ if (!existsSync(join(targetPath, 'package.json'))) {
59
+ return licenses;
60
+ }
61
+ // Try license-checker (npm package)
62
+ if (isToolAvailable('npx')) {
63
+ try {
64
+ const result = spawnSync('npx', ['license-checker', '--json', '--production'], {
65
+ cwd: targetPath,
66
+ encoding: 'utf-8',
67
+ timeout: 60000,
68
+ maxBuffer: 10 * 1024 * 1024
69
+ });
70
+ if (result.stdout) {
71
+ try {
72
+ const data = JSON.parse(result.stdout);
73
+ for (const [pkgKey, info] of Object.entries(data)) {
74
+ const match = pkgKey.match(/^(.+)@([^@]+)$/);
75
+ if (match) {
76
+ licenses.push({
77
+ package: match[1],
78
+ version: match[2],
79
+ license: info.licenses || 'UNKNOWN',
80
+ repository: info.repository,
81
+ licenseFile: info.licenseFile
82
+ });
83
+ }
84
+ }
85
+ }
86
+ catch { }
87
+ }
88
+ }
89
+ catch { }
90
+ }
91
+ // Fallback: read from package-lock.json
92
+ if (licenses.length === 0) {
93
+ const lockPath = join(targetPath, 'package-lock.json');
94
+ if (existsSync(lockPath)) {
95
+ try {
96
+ const lock = JSON.parse(readFileSync(lockPath, 'utf-8'));
97
+ const packages = lock.packages || {};
98
+ for (const [path, info] of Object.entries(packages)) {
99
+ if (path === '' || !path.includes('node_modules/'))
100
+ continue;
101
+ const pkgInfo = info;
102
+ const name = path.replace(/^node_modules\//, '').replace(/.*node_modules\//, '');
103
+ if (name && pkgInfo.version) {
104
+ licenses.push({
105
+ package: name,
106
+ version: pkgInfo.version,
107
+ license: pkgInfo.license || 'UNKNOWN'
108
+ });
109
+ }
110
+ }
111
+ }
112
+ catch { }
113
+ }
114
+ }
115
+ return licenses;
116
+ }
117
+ // Run pip-licenses for Python projects
118
+ function runPipLicenses(targetPath) {
119
+ const licenses = [];
120
+ if (!existsSync(join(targetPath, 'requirements.txt')) &&
121
+ !existsSync(join(targetPath, 'pyproject.toml'))) {
122
+ return licenses;
123
+ }
124
+ if (isToolAvailable('pip-licenses')) {
125
+ try {
126
+ const result = spawnSync('pip-licenses', ['--format=json'], {
127
+ cwd: targetPath,
128
+ encoding: 'utf-8',
129
+ timeout: 60000
130
+ });
131
+ if (result.stdout) {
132
+ try {
133
+ const data = JSON.parse(result.stdout);
134
+ for (const pkg of data) {
135
+ licenses.push({
136
+ package: pkg.Name,
137
+ version: pkg.Version,
138
+ license: pkg.License || 'UNKNOWN'
139
+ });
140
+ }
141
+ }
142
+ catch { }
143
+ }
144
+ }
145
+ catch { }
146
+ }
147
+ return licenses;
148
+ }
149
+ // Normalize license identifier to SPDX format
150
+ function normalizeLicense(license) {
151
+ const normalized = license.trim().toUpperCase();
152
+ // Common mappings
153
+ const mappings = {
154
+ 'MIT LICENSE': 'MIT',
155
+ 'APACHE LICENSE 2.0': 'Apache-2.0',
156
+ 'APACHE-2.0': 'Apache-2.0',
157
+ 'APACHE 2.0': 'Apache-2.0',
158
+ 'BSD': 'BSD-3-Clause',
159
+ 'BSD LICENSE': 'BSD-3-Clause',
160
+ 'BSD-2': 'BSD-2-Clause',
161
+ 'BSD-3': 'BSD-3-Clause',
162
+ 'ISC LICENSE': 'ISC',
163
+ 'GPL': 'GPL-3.0',
164
+ 'GPL V2': 'GPL-2.0',
165
+ 'GPL V3': 'GPL-3.0',
166
+ 'LGPL': 'LGPL-3.0',
167
+ 'MPL': 'MPL-2.0',
168
+ 'UNLICENSED': 'UNLICENSED',
169
+ 'UNKNOWN': 'UNKNOWN',
170
+ '(MIT OR APACHE-2.0)': 'MIT', // Take first option for OR
171
+ 'MIT AND CC-BY-3.0': 'MIT' // Take first option for AND
172
+ };
173
+ return mappings[normalized] || license;
174
+ }
175
+ // Check if a license matches the policy
176
+ function checkLicense(license, policy) {
177
+ const normalized = normalizeLicense(license);
178
+ // Check denied list first
179
+ for (const denied of policy.denied) {
180
+ if (normalized.includes(denied.toUpperCase()) || denied.toUpperCase().includes(normalized)) {
181
+ return {
182
+ compliant: false,
183
+ reason: `License "${license}" is explicitly denied`,
184
+ severity: 'high'
185
+ };
186
+ }
187
+ }
188
+ // Check allowed list
189
+ for (const allowed of policy.allowed) {
190
+ if (normalized.includes(allowed.toUpperCase()) || allowed.toUpperCase().includes(normalized)) {
191
+ return { compliant: true };
192
+ }
193
+ }
194
+ // Handle unknown licenses
195
+ if (normalized === 'UNKNOWN' || normalized === 'UNLICENSED') {
196
+ switch (policy.unknown) {
197
+ case 'allow':
198
+ return { compliant: true };
199
+ case 'deny':
200
+ return {
201
+ compliant: false,
202
+ reason: `Unknown license not allowed by policy`,
203
+ severity: 'high'
204
+ };
205
+ case 'warn':
206
+ default:
207
+ return {
208
+ compliant: false,
209
+ reason: `Unknown license requires manual review`,
210
+ severity: 'low'
211
+ };
212
+ }
213
+ }
214
+ // License not in allowed list
215
+ switch (policy.unknown) {
216
+ case 'allow':
217
+ return { compliant: true };
218
+ case 'deny':
219
+ return {
220
+ compliant: false,
221
+ reason: `License "${license}" is not in the allowed list`,
222
+ severity: 'medium'
223
+ };
224
+ case 'warn':
225
+ default:
226
+ return {
227
+ compliant: false,
228
+ reason: `License "${license}" requires review (not in allowed list)`,
229
+ severity: 'low'
230
+ };
231
+ }
232
+ }
233
+ export function checkLicenses(targetPath, options = {}) {
234
+ // Determine policy
235
+ let policy;
236
+ if (typeof options.policy === 'string') {
237
+ policy = POLICIES[options.policy] || POLICIES.permissive;
238
+ }
239
+ else if (options.policy) {
240
+ policy = options.policy;
241
+ }
242
+ else {
243
+ policy = { ...POLICIES.permissive };
244
+ }
245
+ // Apply custom allowed/denied overrides
246
+ if (options.allowedLicenses) {
247
+ policy = { ...policy, allowed: [...policy.allowed, ...options.allowedLicenses] };
248
+ }
249
+ if (options.deniedLicenses) {
250
+ policy = { ...policy, denied: [...policy.denied, ...options.deniedLicenses] };
251
+ }
252
+ // Collect licenses from all sources
253
+ const licenses = [
254
+ ...runLicenseChecker(targetPath),
255
+ ...runPipLicenses(targetPath)
256
+ ];
257
+ // Check each license
258
+ const violations = [];
259
+ let compliant = 0;
260
+ let unknown = 0;
261
+ for (const info of licenses) {
262
+ const result = checkLicense(info.license, policy);
263
+ if (result.compliant) {
264
+ compliant++;
265
+ }
266
+ else {
267
+ if (info.license === 'UNKNOWN') {
268
+ unknown++;
269
+ }
270
+ violations.push({
271
+ package: info.package,
272
+ version: info.version,
273
+ license: info.license,
274
+ violation: result.reason || 'License not compliant',
275
+ severity: result.severity || 'medium'
276
+ });
277
+ }
278
+ }
279
+ return {
280
+ policy: policy.name,
281
+ licenses,
282
+ violations,
283
+ summary: {
284
+ total: licenses.length,
285
+ compliant,
286
+ violations: violations.length,
287
+ unknown
288
+ }
289
+ };
290
+ }
291
+ // Export policy names for CLI
292
+ export const POLICY_NAMES = Object.keys(POLICIES);
@@ -0,0 +1,77 @@
1
+ /**
2
+ * SQLite Database for aurasecurity
3
+ *
4
+ * Provides persistent storage for:
5
+ * - Audit history
6
+ * - Configuration settings
7
+ * - Scan results
8
+ * - Notification history
9
+ */
10
+ import type { AuditorOutput } from '../types/events.js';
11
+ import type { LocalScanResult } from '../integrations/local-scanner.js';
12
+ import type { AWSScanResult } from '../integrations/aws-scanner.js';
13
+ export interface AuditRecord {
14
+ id: string;
15
+ type: 'code' | 'aws' | 'audit';
16
+ timestamp: string;
17
+ target: string;
18
+ summary: {
19
+ critical: number;
20
+ high: number;
21
+ medium: number;
22
+ low: number;
23
+ };
24
+ data: string;
25
+ }
26
+ export interface SettingsRecord {
27
+ key: string;
28
+ value: string;
29
+ updated_at: string;
30
+ }
31
+ export interface NotificationRecord {
32
+ id: number;
33
+ type: 'slack' | 'discord' | 'webhook';
34
+ audit_id: string;
35
+ status: 'sent' | 'failed' | 'pending';
36
+ message: string;
37
+ timestamp: string;
38
+ error?: string;
39
+ }
40
+ export declare class AuditorDatabase {
41
+ private db;
42
+ private dbPath;
43
+ constructor(dbPath?: string);
44
+ private initTables;
45
+ saveAudit(type: 'code' | 'aws' | 'audit', target: string, result: LocalScanResult | AWSScanResult | AuditorOutput): string;
46
+ getAudit(id: string): AuditRecord | null;
47
+ getAudits(limit?: number, offset?: number, type?: string): AuditRecord[];
48
+ getAuditCount(type?: string): number;
49
+ deleteAudit(id: string): boolean;
50
+ getSetting(key: string): string | null;
51
+ getSettings(prefix?: string): Record<string, string>;
52
+ getAllSettings(): Record<string, string>;
53
+ setSetting(key: string, value: string): void;
54
+ setSettings(settings: Record<string, string>): void;
55
+ saveNotification(type: 'slack' | 'discord' | 'webhook', auditId: string, status: 'sent' | 'failed' | 'pending', message: string, error?: string): number;
56
+ recordNotification(auditId: string, channels: string, success: boolean, error?: string): void;
57
+ getNotifications(auditId?: string, limit?: number): NotificationRecord[];
58
+ getStats(): {
59
+ totalAudits: number;
60
+ byType: Record<string, number>;
61
+ byDay: Array<{
62
+ date: string;
63
+ count: number;
64
+ }>;
65
+ severityCounts: {
66
+ critical: number;
67
+ high: number;
68
+ medium: number;
69
+ low: number;
70
+ };
71
+ };
72
+ close(): void;
73
+ vacuum(): void;
74
+ deleteOldAudits(daysToKeep?: number): number;
75
+ }
76
+ export declare function getDatabase(dbPath?: string): AuditorDatabase;
77
+ export declare function closeDatabase(): void;