guardrail-security 1.0.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 (95) hide show
  1. package/dist/attack-surface/analyzer.d.ts +50 -0
  2. package/dist/attack-surface/analyzer.d.ts.map +1 -0
  3. package/dist/attack-surface/analyzer.js +83 -0
  4. package/dist/attack-surface/index.d.ts +5 -0
  5. package/dist/attack-surface/index.d.ts.map +1 -0
  6. package/dist/attack-surface/index.js +20 -0
  7. package/dist/index.d.ts +15 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +33 -0
  10. package/dist/languages/index.d.ts +21 -0
  11. package/dist/languages/index.d.ts.map +1 -0
  12. package/dist/languages/index.js +78 -0
  13. package/dist/languages/java-analyzer.d.ts +72 -0
  14. package/dist/languages/java-analyzer.d.ts.map +1 -0
  15. package/dist/languages/java-analyzer.js +417 -0
  16. package/dist/languages/python-analyzer.d.ts +70 -0
  17. package/dist/languages/python-analyzer.d.ts.map +1 -0
  18. package/dist/languages/python-analyzer.js +425 -0
  19. package/dist/license/compatibility-matrix.d.ts +28 -0
  20. package/dist/license/compatibility-matrix.d.ts.map +1 -0
  21. package/dist/license/compatibility-matrix.js +323 -0
  22. package/dist/license/engine.d.ts +77 -0
  23. package/dist/license/engine.d.ts.map +1 -0
  24. package/dist/license/engine.js +264 -0
  25. package/dist/license/index.d.ts +6 -0
  26. package/dist/license/index.d.ts.map +1 -0
  27. package/dist/license/index.js +21 -0
  28. package/dist/sbom/generator.d.ts +108 -0
  29. package/dist/sbom/generator.d.ts.map +1 -0
  30. package/dist/sbom/generator.js +271 -0
  31. package/dist/sbom/index.d.ts +5 -0
  32. package/dist/sbom/index.d.ts.map +1 -0
  33. package/dist/sbom/index.js +20 -0
  34. package/dist/secrets/guardian.d.ts +113 -0
  35. package/dist/secrets/guardian.d.ts.map +1 -0
  36. package/dist/secrets/guardian.js +334 -0
  37. package/dist/secrets/index.d.ts +10 -0
  38. package/dist/secrets/index.d.ts.map +1 -0
  39. package/dist/secrets/index.js +30 -0
  40. package/dist/secrets/patterns.d.ts +42 -0
  41. package/dist/secrets/patterns.d.ts.map +1 -0
  42. package/dist/secrets/patterns.js +165 -0
  43. package/dist/secrets/pre-commit.d.ts +39 -0
  44. package/dist/secrets/pre-commit.d.ts.map +1 -0
  45. package/dist/secrets/pre-commit.js +127 -0
  46. package/dist/secrets/vault-integration.d.ts +83 -0
  47. package/dist/secrets/vault-integration.d.ts.map +1 -0
  48. package/dist/secrets/vault-integration.js +295 -0
  49. package/dist/secrets/vault-providers.d.ts +110 -0
  50. package/dist/secrets/vault-providers.d.ts.map +1 -0
  51. package/dist/secrets/vault-providers.js +417 -0
  52. package/dist/supply-chain/detector.d.ts +80 -0
  53. package/dist/supply-chain/detector.d.ts.map +1 -0
  54. package/dist/supply-chain/detector.js +168 -0
  55. package/dist/supply-chain/index.d.ts +11 -0
  56. package/dist/supply-chain/index.d.ts.map +1 -0
  57. package/dist/supply-chain/index.js +26 -0
  58. package/dist/supply-chain/malicious-db.d.ts +41 -0
  59. package/dist/supply-chain/malicious-db.d.ts.map +1 -0
  60. package/dist/supply-chain/malicious-db.js +82 -0
  61. package/dist/supply-chain/script-analyzer.d.ts +54 -0
  62. package/dist/supply-chain/script-analyzer.d.ts.map +1 -0
  63. package/dist/supply-chain/script-analyzer.js +160 -0
  64. package/dist/supply-chain/typosquat.d.ts +58 -0
  65. package/dist/supply-chain/typosquat.d.ts.map +1 -0
  66. package/dist/supply-chain/typosquat.js +257 -0
  67. package/dist/supply-chain/vulnerability-db.d.ts +114 -0
  68. package/dist/supply-chain/vulnerability-db.d.ts.map +1 -0
  69. package/dist/supply-chain/vulnerability-db.js +310 -0
  70. package/package.json +34 -0
  71. package/src/__tests__/license/engine.test.ts +250 -0
  72. package/src/__tests__/supply-chain/typosquat.test.ts +191 -0
  73. package/src/attack-surface/analyzer.ts +152 -0
  74. package/src/attack-surface/index.ts +5 -0
  75. package/src/index.ts +21 -0
  76. package/src/languages/index.ts +91 -0
  77. package/src/languages/java-analyzer.ts +490 -0
  78. package/src/languages/python-analyzer.ts +498 -0
  79. package/src/license/compatibility-matrix.ts +366 -0
  80. package/src/license/engine.ts +345 -0
  81. package/src/license/index.ts +6 -0
  82. package/src/sbom/generator.ts +355 -0
  83. package/src/sbom/index.ts +5 -0
  84. package/src/secrets/guardian.ts +448 -0
  85. package/src/secrets/index.ts +10 -0
  86. package/src/secrets/patterns.ts +186 -0
  87. package/src/secrets/pre-commit.ts +158 -0
  88. package/src/secrets/vault-integration.ts +360 -0
  89. package/src/secrets/vault-providers.ts +446 -0
  90. package/src/supply-chain/detector.ts +252 -0
  91. package/src/supply-chain/index.ts +11 -0
  92. package/src/supply-chain/malicious-db.ts +103 -0
  93. package/src/supply-chain/script-analyzer.ts +194 -0
  94. package/src/supply-chain/typosquat.ts +302 -0
  95. package/src/supply-chain/vulnerability-db.ts +386 -0
@@ -0,0 +1,386 @@
1
+ /**
2
+ * Vulnerability Database Integration
3
+ *
4
+ * Integrates with multiple vulnerability databases:
5
+ * - OSV (Open Source Vulnerabilities)
6
+ * - GitHub Security Advisories
7
+ * - NVD (National Vulnerability Database)
8
+ */
9
+
10
+ export interface Vulnerability {
11
+ id: string;
12
+ source: 'osv' | 'github' | 'nvd' | 'npm';
13
+ severity: 'low' | 'medium' | 'high' | 'critical';
14
+ cvssScore?: number;
15
+ title: string;
16
+ description: string;
17
+ affectedVersions: string[];
18
+ patchedVersions: string[];
19
+ references: string[];
20
+ publishedAt: Date;
21
+ updatedAt: Date;
22
+ cwe?: string[];
23
+ }
24
+
25
+ export interface VulnerabilityCheckResult {
26
+ package: string;
27
+ version: string;
28
+ vulnerabilities: Vulnerability[];
29
+ isVulnerable: boolean;
30
+ highestSeverity: 'none' | 'low' | 'medium' | 'high' | 'critical';
31
+ recommendedVersion?: string;
32
+ }
33
+
34
+ export interface VulnerabilityReport {
35
+ projectPath: string;
36
+ scanDate: Date;
37
+ totalPackages: number;
38
+ vulnerablePackages: number;
39
+ results: VulnerabilityCheckResult[];
40
+ summary: {
41
+ critical: number;
42
+ high: number;
43
+ medium: number;
44
+ low: number;
45
+ };
46
+ }
47
+
48
+ const vulnerabilityCache = new Map<string, { data: Vulnerability[]; fetchedAt: Date }>();
49
+ const CACHE_TTL_MS = 6 * 60 * 60 * 1000; // 6 hours
50
+
51
+ export class VulnerabilityDatabase {
52
+ private osvApiUrl = 'https://api.osv.dev/v1';
53
+ private npmAuditUrl = 'https://registry.npmjs.org/-/npm/v1/security/advisories/bulk';
54
+ // GitHub API available for future enhancement with authentication
55
+ // private githubApiUrl = 'https://api.github.com/advisories';
56
+
57
+ /**
58
+ * Check a single package for vulnerabilities
59
+ */
60
+ async checkPackage(name: string, version: string): Promise<VulnerabilityCheckResult> {
61
+ const cacheKey = `${name}@${version}`;
62
+ const cached = vulnerabilityCache.get(cacheKey);
63
+
64
+ if (cached && (Date.now() - cached.fetchedAt.getTime()) < CACHE_TTL_MS) {
65
+ return this.buildResult(name, version, cached.data);
66
+ }
67
+
68
+ const vulnerabilities: Vulnerability[] = [];
69
+
70
+ // Query multiple sources in parallel
71
+ const [osvVulns, npmVulns] = await Promise.allSettled([
72
+ this.queryOSV(name, version),
73
+ this.queryNpmAudit(name, version),
74
+ ]);
75
+
76
+ if (osvVulns.status === 'fulfilled') {
77
+ vulnerabilities.push(...osvVulns.value);
78
+ }
79
+
80
+ if (npmVulns.status === 'fulfilled') {
81
+ vulnerabilities.push(...npmVulns.value);
82
+ }
83
+
84
+ // Deduplicate by ID
85
+ const uniqueVulns = this.deduplicateVulnerabilities(vulnerabilities);
86
+
87
+ // Cache the result
88
+ vulnerabilityCache.set(cacheKey, {
89
+ data: uniqueVulns,
90
+ fetchedAt: new Date(),
91
+ });
92
+
93
+ return this.buildResult(name, version, uniqueVulns);
94
+ }
95
+
96
+ /**
97
+ * Check multiple packages in bulk
98
+ */
99
+ async checkPackages(packages: { name: string; version: string }[]): Promise<VulnerabilityCheckResult[]> {
100
+ const batchSize = 20;
101
+ const results: VulnerabilityCheckResult[] = [];
102
+
103
+ for (let i = 0; i < packages.length; i += batchSize) {
104
+ const batch = packages.slice(i, i + batchSize);
105
+ const batchResults = await Promise.all(
106
+ batch.map(pkg => this.checkPackage(pkg.name, pkg.version))
107
+ );
108
+ results.push(...batchResults);
109
+ }
110
+
111
+ return results;
112
+ }
113
+
114
+ /**
115
+ * Query OSV (Open Source Vulnerabilities) API
116
+ */
117
+ private async queryOSV(packageName: string, version: string): Promise<Vulnerability[]> {
118
+ try {
119
+ const response = await fetch(`${this.osvApiUrl}/query`, {
120
+ method: 'POST',
121
+ headers: {
122
+ 'Content-Type': 'application/json',
123
+ },
124
+ body: JSON.stringify({
125
+ package: {
126
+ name: packageName,
127
+ ecosystem: 'npm',
128
+ },
129
+ version: version,
130
+ }),
131
+ signal: AbortSignal.timeout(10000),
132
+ });
133
+
134
+ if (!response.ok) {
135
+ return [];
136
+ }
137
+
138
+ const data = await response.json();
139
+ return this.parseOSVResponse(data);
140
+ } catch (error) {
141
+ console.error(`OSV query failed for ${packageName}@${version}:`, error);
142
+ return [];
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Parse OSV API response
148
+ */
149
+ private parseOSVResponse(data: any): Vulnerability[] {
150
+ if (!data.vulns || !Array.isArray(data.vulns)) {
151
+ return [];
152
+ }
153
+
154
+ return data.vulns.map((vuln: any) => ({
155
+ id: vuln.id,
156
+ source: 'osv' as const,
157
+ severity: this.mapOSVSeverity(vuln.severity),
158
+ cvssScore: vuln.severity?.[0]?.score,
159
+ title: vuln.summary || vuln.id,
160
+ description: vuln.details || '',
161
+ affectedVersions: this.extractAffectedVersions(vuln.affected),
162
+ patchedVersions: this.extractPatchedVersions(vuln.affected),
163
+ references: (vuln.references || []).map((r: any) => r.url),
164
+ publishedAt: new Date(vuln.published || Date.now()),
165
+ updatedAt: new Date(vuln.modified || Date.now()),
166
+ cwe: vuln.database_specific?.cwe_ids || [],
167
+ }));
168
+ }
169
+
170
+ /**
171
+ * Query npm audit API
172
+ */
173
+ private async queryNpmAudit(packageName: string, version: string): Promise<Vulnerability[]> {
174
+ try {
175
+ const response = await fetch(this.npmAuditUrl, {
176
+ method: 'POST',
177
+ headers: {
178
+ 'Content-Type': 'application/json',
179
+ },
180
+ body: JSON.stringify({
181
+ [packageName]: [version],
182
+ }),
183
+ signal: AbortSignal.timeout(10000),
184
+ });
185
+
186
+ if (!response.ok) {
187
+ return [];
188
+ }
189
+
190
+ const data = await response.json();
191
+ return this.parseNpmAuditResponse(data, packageName);
192
+ } catch (error) {
193
+ console.error(`npm audit query failed for ${packageName}@${version}:`, error);
194
+ return [];
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Parse npm audit response
200
+ */
201
+ private parseNpmAuditResponse(data: any, packageName: string): Vulnerability[] {
202
+ const advisories = data[packageName] || [];
203
+
204
+ return advisories.map((advisory: any) => ({
205
+ id: `npm-${advisory.id || advisory.github_advisory_id}`,
206
+ source: 'npm' as const,
207
+ severity: advisory.severity || 'medium',
208
+ cvssScore: advisory.cvss?.score,
209
+ title: advisory.title || 'Security Advisory',
210
+ description: advisory.overview || advisory.recommendation || '',
211
+ affectedVersions: [advisory.vulnerable_versions || '*'],
212
+ patchedVersions: [advisory.patched_versions || 'No patch available'],
213
+ references: [advisory.url].filter(Boolean),
214
+ publishedAt: new Date(advisory.created || Date.now()),
215
+ updatedAt: new Date(advisory.updated || Date.now()),
216
+ cwe: advisory.cwe ? [advisory.cwe] : [],
217
+ }));
218
+ }
219
+
220
+ /**
221
+ * Map OSV severity to standard levels
222
+ */
223
+ private mapOSVSeverity(severity: any): 'low' | 'medium' | 'high' | 'critical' {
224
+ if (!severity || !Array.isArray(severity) || severity.length === 0) {
225
+ return 'medium';
226
+ }
227
+
228
+ const score = severity[0]?.score || 0;
229
+ if (score >= 9.0) return 'critical';
230
+ if (score >= 7.0) return 'high';
231
+ if (score >= 4.0) return 'medium';
232
+ return 'low';
233
+ }
234
+
235
+ /**
236
+ * Extract affected versions from OSV format
237
+ */
238
+ private extractAffectedVersions(affected: any[]): string[] {
239
+ if (!affected || !Array.isArray(affected)) {
240
+ return ['*'];
241
+ }
242
+
243
+ const versions: string[] = [];
244
+ for (const aff of affected) {
245
+ if (aff.versions) {
246
+ versions.push(...aff.versions);
247
+ }
248
+ if (aff.ranges) {
249
+ for (const range of aff.ranges) {
250
+ if (range.events) {
251
+ const introduced = range.events.find((e: any) => e.introduced);
252
+ const fixed = range.events.find((e: any) => e.fixed);
253
+ if (introduced) {
254
+ versions.push(`>=${introduced.introduced}${fixed ? ` <${fixed.fixed}` : ''}`);
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ return versions.length > 0 ? versions : ['*'];
262
+ }
263
+
264
+ /**
265
+ * Extract patched versions from OSV format
266
+ */
267
+ private extractPatchedVersions(affected: any[]): string[] {
268
+ if (!affected || !Array.isArray(affected)) {
269
+ return [];
270
+ }
271
+
272
+ const versions: string[] = [];
273
+ for (const aff of affected) {
274
+ if (aff.ranges) {
275
+ for (const range of aff.ranges) {
276
+ if (range.events) {
277
+ const fixed = range.events.find((e: any) => e.fixed);
278
+ if (fixed) {
279
+ versions.push(fixed.fixed);
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+
286
+ return versions;
287
+ }
288
+
289
+ /**
290
+ * Deduplicate vulnerabilities by ID
291
+ */
292
+ private deduplicateVulnerabilities(vulns: Vulnerability[]): Vulnerability[] {
293
+ const seen = new Set<string>();
294
+ return vulns.filter(vuln => {
295
+ if (seen.has(vuln.id)) {
296
+ return false;
297
+ }
298
+ seen.add(vuln.id);
299
+ return true;
300
+ });
301
+ }
302
+
303
+ /**
304
+ * Build result object
305
+ */
306
+ private buildResult(name: string, version: string, vulnerabilities: Vulnerability[]): VulnerabilityCheckResult {
307
+ const severityOrder = { critical: 4, high: 3, medium: 2, low: 1, none: 0 };
308
+
309
+ let highestSeverity: 'none' | 'low' | 'medium' | 'high' | 'critical' = 'none';
310
+ for (const vuln of vulnerabilities) {
311
+ if (severityOrder[vuln.severity] > severityOrder[highestSeverity]) {
312
+ highestSeverity = vuln.severity;
313
+ }
314
+ }
315
+
316
+ // Find recommended version from patches
317
+ const patchedVersions = vulnerabilities.flatMap(v => v.patchedVersions).filter(Boolean);
318
+ const recommendedVersion = patchedVersions.length > 0 ? patchedVersions[0] : undefined;
319
+
320
+ return {
321
+ package: name,
322
+ version,
323
+ vulnerabilities,
324
+ isVulnerable: vulnerabilities.length > 0,
325
+ highestSeverity,
326
+ recommendedVersion,
327
+ };
328
+ }
329
+
330
+ /**
331
+ * Generate a full vulnerability report for a project
332
+ */
333
+ async generateReport(projectPath: string, packages: { name: string; version: string }[]): Promise<VulnerabilityReport> {
334
+ const results = await this.checkPackages(packages);
335
+
336
+ const summary = {
337
+ critical: 0,
338
+ high: 0,
339
+ medium: 0,
340
+ low: 0,
341
+ };
342
+
343
+ for (const result of results) {
344
+ for (const vuln of result.vulnerabilities) {
345
+ summary[vuln.severity]++;
346
+ }
347
+ }
348
+
349
+ const vulnerablePackages = results.filter(r => r.isVulnerable).length;
350
+
351
+ return {
352
+ projectPath,
353
+ scanDate: new Date(),
354
+ totalPackages: packages.length,
355
+ vulnerablePackages,
356
+ results,
357
+ summary,
358
+ };
359
+ }
360
+
361
+ /**
362
+ * Clear vulnerability cache
363
+ */
364
+ clearCache(): void {
365
+ vulnerabilityCache.clear();
366
+ }
367
+
368
+ /**
369
+ * Get cache statistics
370
+ */
371
+ getCacheStats(): { size: number; oldestEntry: Date | null } {
372
+ let oldest: Date | null = null;
373
+ for (const entry of vulnerabilityCache.values()) {
374
+ if (!oldest || entry.fetchedAt < oldest) {
375
+ oldest = entry.fetchedAt;
376
+ }
377
+ }
378
+ return {
379
+ size: vulnerabilityCache.size,
380
+ oldestEntry: oldest,
381
+ };
382
+ }
383
+ }
384
+
385
+ // Export singleton
386
+ export const vulnerabilityDatabase = new VulnerabilityDatabase();