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,355 @@
1
+ /**
2
+ * SBOM (Software Bill of Materials) Generator
3
+ *
4
+ * Generates SBOMs in CycloneDX and SPDX formats for compliance and security
5
+ */
6
+
7
+ import { readFileSync, existsSync, writeFileSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { createHash } from 'crypto';
10
+
11
+ export type SBOMFormat = 'cyclonedx' | 'spdx' | 'json';
12
+
13
+ export interface SBOMComponent {
14
+ type: 'library' | 'framework' | 'application' | 'file' | 'container';
15
+ name: string;
16
+ version: string;
17
+ purl?: string;
18
+ licenses: string[];
19
+ hashes?: { algorithm: string; content: string }[];
20
+ description?: string;
21
+ author?: string;
22
+ supplier?: string;
23
+ externalReferences?: { type: string; url: string }[];
24
+ }
25
+
26
+ export interface SBOMDependency {
27
+ ref: string;
28
+ dependsOn: string[];
29
+ }
30
+
31
+ export interface SBOM {
32
+ format: SBOMFormat;
33
+ specVersion: string;
34
+ serialNumber: string;
35
+ version: number;
36
+ metadata: {
37
+ timestamp: string;
38
+ tools: { vendor: string; name: string; version: string }[];
39
+ component: {
40
+ type: string;
41
+ name: string;
42
+ version: string;
43
+ };
44
+ authors?: { name: string; email?: string }[];
45
+ };
46
+ components: SBOMComponent[];
47
+ dependencies: SBOMDependency[];
48
+ }
49
+
50
+ export interface SBOMGeneratorOptions {
51
+ format: SBOMFormat;
52
+ includeDevDependencies?: boolean;
53
+ includeLicenses?: boolean;
54
+ includeHashes?: boolean;
55
+ outputPath?: string;
56
+ }
57
+
58
+ export class SBOMGenerator {
59
+ private readonly toolInfo = {
60
+ vendor: 'Guardrail AI',
61
+ name: 'Guardrail-sbom-generator',
62
+ version: '1.0.0',
63
+ };
64
+
65
+ /**
66
+ * Generate SBOM for a project
67
+ */
68
+ async generate(projectPath: string, options: SBOMGeneratorOptions): Promise<SBOM> {
69
+ const packageJsonPath = join(projectPath, 'package.json');
70
+
71
+ if (!existsSync(packageJsonPath)) {
72
+ throw new Error('package.json not found in project path');
73
+ }
74
+
75
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
76
+ const components = await this.extractComponents(projectPath, packageJson, options);
77
+ const dependencies = this.buildDependencyGraph(packageJson, options);
78
+
79
+ const sbom: SBOM = {
80
+ format: options.format,
81
+ specVersion: options.format === 'cyclonedx' ? '1.5' : '2.3',
82
+ serialNumber: `urn:uuid:${this.generateUUID()}`,
83
+ version: 1,
84
+ metadata: {
85
+ timestamp: new Date().toISOString(),
86
+ tools: [this.toolInfo],
87
+ component: {
88
+ type: 'application',
89
+ name: packageJson.name || 'unknown',
90
+ version: packageJson.version || '0.0.0',
91
+ },
92
+ authors: packageJson.author ? [{ name: packageJson.author }] : undefined,
93
+ },
94
+ components,
95
+ dependencies,
96
+ };
97
+
98
+ if (options.outputPath) {
99
+ await this.writeSBOM(sbom, options.outputPath, options.format);
100
+ }
101
+
102
+ return sbom;
103
+ }
104
+
105
+ /**
106
+ * Extract components from package.json
107
+ */
108
+ private async extractComponents(
109
+ projectPath: string,
110
+ packageJson: any,
111
+ options: SBOMGeneratorOptions
112
+ ): Promise<SBOMComponent[]> {
113
+ const components: SBOMComponent[] = [];
114
+ const deps = { ...packageJson.dependencies };
115
+
116
+ if (options.includeDevDependencies) {
117
+ Object.assign(deps, packageJson.devDependencies);
118
+ }
119
+
120
+ for (const [name, version] of Object.entries(deps)) {
121
+ const versionStr = String(version).replace(/^[\^~]/, '');
122
+
123
+ const component: SBOMComponent = {
124
+ type: 'library',
125
+ name,
126
+ version: versionStr,
127
+ purl: `pkg:npm/${name}@${versionStr}`,
128
+ licenses: [],
129
+ };
130
+
131
+ // Try to get license info
132
+ if (options.includeLicenses) {
133
+ const license = await this.getLicenseForPackage(projectPath, name);
134
+ if (license) {
135
+ component.licenses = [license];
136
+ }
137
+ }
138
+
139
+ // Generate hashes if requested
140
+ if (options.includeHashes) {
141
+ const packagePath = join(projectPath, 'node_modules', name, 'package.json');
142
+ if (existsSync(packagePath)) {
143
+ const content = readFileSync(packagePath, 'utf-8');
144
+ component.hashes = [
145
+ { algorithm: 'SHA-256', content: this.hashContent(content, 'sha256') },
146
+ { algorithm: 'SHA-512', content: this.hashContent(content, 'sha512') },
147
+ ];
148
+ }
149
+ }
150
+
151
+ components.push(component);
152
+ }
153
+
154
+ return components;
155
+ }
156
+
157
+ /**
158
+ * Build dependency graph
159
+ */
160
+ private buildDependencyGraph(packageJson: any, options: SBOMGeneratorOptions): SBOMDependency[] {
161
+ const dependencies: SBOMDependency[] = [];
162
+ const rootRef = `pkg:npm/${packageJson.name}@${packageJson.version}`;
163
+
164
+ const deps = Object.keys(packageJson.dependencies || {});
165
+ const devDeps = options.includeDevDependencies
166
+ ? Object.keys(packageJson.devDependencies || {})
167
+ : [];
168
+
169
+ // Root dependency
170
+ dependencies.push({
171
+ ref: rootRef,
172
+ dependsOn: [...deps, ...devDeps].map(name => {
173
+ const version = packageJson.dependencies?.[name] || packageJson.devDependencies?.[name];
174
+ return `pkg:npm/${name}@${String(version).replace(/^[\^~]/, '')}`;
175
+ }),
176
+ });
177
+
178
+ return dependencies;
179
+ }
180
+
181
+ /**
182
+ * Get license for a package
183
+ */
184
+ private async getLicenseForPackage(projectPath: string, packageName: string): Promise<string | null> {
185
+ const packagePath = join(projectPath, 'node_modules', packageName, 'package.json');
186
+
187
+ if (existsSync(packagePath)) {
188
+ try {
189
+ const pkgJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
190
+ return pkgJson.license || null;
191
+ } catch {
192
+ return null;
193
+ }
194
+ }
195
+
196
+ return null;
197
+ }
198
+
199
+ /**
200
+ * Hash content
201
+ */
202
+ private hashContent(content: string, algorithm: string): string {
203
+ return createHash(algorithm).update(content).digest('hex');
204
+ }
205
+
206
+ /**
207
+ * Generate UUID
208
+ */
209
+ private generateUUID(): string {
210
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
211
+ const r = Math.random() * 16 | 0;
212
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
213
+ return v.toString(16);
214
+ });
215
+ }
216
+
217
+ /**
218
+ * Write SBOM to file
219
+ */
220
+ private async writeSBOM(sbom: SBOM, outputPath: string, format: SBOMFormat): Promise<void> {
221
+ let content: string;
222
+
223
+ switch (format) {
224
+ case 'cyclonedx':
225
+ content = this.toCycloneDXJSON(sbom);
226
+ break;
227
+ case 'spdx':
228
+ content = this.toSPDXJSON(sbom);
229
+ break;
230
+ default:
231
+ content = JSON.stringify(sbom, null, 2);
232
+ }
233
+
234
+ writeFileSync(outputPath, content, 'utf-8');
235
+ }
236
+
237
+ /**
238
+ * Convert to CycloneDX JSON format
239
+ */
240
+ toCycloneDXJSON(sbom: SBOM): string {
241
+ const cyclonedx = {
242
+ bomFormat: 'CycloneDX',
243
+ specVersion: '1.5',
244
+ serialNumber: sbom.serialNumber,
245
+ version: sbom.version,
246
+ metadata: {
247
+ timestamp: sbom.metadata.timestamp,
248
+ tools: sbom.metadata.tools.map(t => ({
249
+ vendor: t.vendor,
250
+ name: t.name,
251
+ version: t.version,
252
+ })),
253
+ component: {
254
+ type: sbom.metadata.component.type,
255
+ name: sbom.metadata.component.name,
256
+ version: sbom.metadata.component.version,
257
+ 'bom-ref': `pkg:npm/${sbom.metadata.component.name}@${sbom.metadata.component.version}`,
258
+ },
259
+ },
260
+ components: sbom.components.map(c => ({
261
+ type: c.type,
262
+ name: c.name,
263
+ version: c.version,
264
+ purl: c.purl,
265
+ 'bom-ref': c.purl,
266
+ licenses: c.licenses.map(l => ({ license: { id: l } })),
267
+ hashes: c.hashes?.map(h => ({ alg: h.algorithm, content: h.content })),
268
+ })),
269
+ dependencies: sbom.dependencies.map(d => ({
270
+ ref: d.ref,
271
+ dependsOn: d.dependsOn,
272
+ })),
273
+ };
274
+
275
+ return JSON.stringify(cyclonedx, null, 2);
276
+ }
277
+
278
+ /**
279
+ * Convert to SPDX JSON format
280
+ */
281
+ toSPDXJSON(sbom: SBOM): string {
282
+ const spdx = {
283
+ spdxVersion: 'SPDX-2.3',
284
+ dataLicense: 'CC0-1.0',
285
+ SPDXID: 'SPDXRef-DOCUMENT',
286
+ name: sbom.metadata.component.name,
287
+ documentNamespace: `https://Guardrail.ai/sbom/${sbom.serialNumber}`,
288
+ creationInfo: {
289
+ created: sbom.metadata.timestamp,
290
+ creators: [`Tool: ${sbom.metadata.tools[0]?.name}-${sbom.metadata.tools[0]?.version}`],
291
+ },
292
+ packages: sbom.components.map((c, i) => ({
293
+ SPDXID: `SPDXRef-Package-${i}`,
294
+ name: c.name,
295
+ versionInfo: c.version,
296
+ downloadLocation: `https://registry.npmjs.org/${c.name}/-/${c.name}-${c.version}.tgz`,
297
+ filesAnalyzed: false,
298
+ licenseConcluded: c.licenses[0] || 'NOASSERTION',
299
+ licenseDeclared: c.licenses[0] || 'NOASSERTION',
300
+ copyrightText: 'NOASSERTION',
301
+ externalRefs: c.purl ? [{
302
+ referenceCategory: 'PACKAGE-MANAGER',
303
+ referenceType: 'purl',
304
+ referenceLocator: c.purl,
305
+ }] : [],
306
+ })),
307
+ relationships: [
308
+ {
309
+ spdxElementId: 'SPDXRef-DOCUMENT',
310
+ relatedSpdxElement: 'SPDXRef-Package-0',
311
+ relationshipType: 'DESCRIBES',
312
+ },
313
+ ...sbom.components.slice(1).map((_, i) => ({
314
+ spdxElementId: 'SPDXRef-Package-0',
315
+ relatedSpdxElement: `SPDXRef-Package-${i + 1}`,
316
+ relationshipType: 'DEPENDS_ON',
317
+ })),
318
+ ],
319
+ };
320
+
321
+ return JSON.stringify(spdx, null, 2);
322
+ }
323
+
324
+ /**
325
+ * Validate SBOM structure
326
+ */
327
+ validateSBOM(sbom: SBOM): { valid: boolean; errors: string[] } {
328
+ const errors: string[] = [];
329
+
330
+ if (!sbom.metadata?.component?.name) {
331
+ errors.push('Missing component name in metadata');
332
+ }
333
+
334
+ if (!sbom.components || sbom.components.length === 0) {
335
+ errors.push('No components found in SBOM');
336
+ }
337
+
338
+ for (const component of sbom.components) {
339
+ if (!component.name) {
340
+ errors.push('Component missing name');
341
+ }
342
+ if (!component.version) {
343
+ errors.push(`Component ${component.name} missing version`);
344
+ }
345
+ }
346
+
347
+ return {
348
+ valid: errors.length === 0,
349
+ errors,
350
+ };
351
+ }
352
+ }
353
+
354
+ // Export singleton
355
+ export const sbomGenerator = new SBOMGenerator();
@@ -0,0 +1,5 @@
1
+ /**
2
+ * SBOM (Software Bill of Materials) Module
3
+ */
4
+
5
+ export * from './generator';