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.
- package/dist/attack-surface/analyzer.d.ts +50 -0
- package/dist/attack-surface/analyzer.d.ts.map +1 -0
- package/dist/attack-surface/analyzer.js +83 -0
- package/dist/attack-surface/index.d.ts +5 -0
- package/dist/attack-surface/index.d.ts.map +1 -0
- package/dist/attack-surface/index.js +20 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/languages/index.d.ts +21 -0
- package/dist/languages/index.d.ts.map +1 -0
- package/dist/languages/index.js +78 -0
- package/dist/languages/java-analyzer.d.ts +72 -0
- package/dist/languages/java-analyzer.d.ts.map +1 -0
- package/dist/languages/java-analyzer.js +417 -0
- package/dist/languages/python-analyzer.d.ts +70 -0
- package/dist/languages/python-analyzer.d.ts.map +1 -0
- package/dist/languages/python-analyzer.js +425 -0
- package/dist/license/compatibility-matrix.d.ts +28 -0
- package/dist/license/compatibility-matrix.d.ts.map +1 -0
- package/dist/license/compatibility-matrix.js +323 -0
- package/dist/license/engine.d.ts +77 -0
- package/dist/license/engine.d.ts.map +1 -0
- package/dist/license/engine.js +264 -0
- package/dist/license/index.d.ts +6 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +21 -0
- package/dist/sbom/generator.d.ts +108 -0
- package/dist/sbom/generator.d.ts.map +1 -0
- package/dist/sbom/generator.js +271 -0
- package/dist/sbom/index.d.ts +5 -0
- package/dist/sbom/index.d.ts.map +1 -0
- package/dist/sbom/index.js +20 -0
- package/dist/secrets/guardian.d.ts +113 -0
- package/dist/secrets/guardian.d.ts.map +1 -0
- package/dist/secrets/guardian.js +334 -0
- package/dist/secrets/index.d.ts +10 -0
- package/dist/secrets/index.d.ts.map +1 -0
- package/dist/secrets/index.js +30 -0
- package/dist/secrets/patterns.d.ts +42 -0
- package/dist/secrets/patterns.d.ts.map +1 -0
- package/dist/secrets/patterns.js +165 -0
- package/dist/secrets/pre-commit.d.ts +39 -0
- package/dist/secrets/pre-commit.d.ts.map +1 -0
- package/dist/secrets/pre-commit.js +127 -0
- package/dist/secrets/vault-integration.d.ts +83 -0
- package/dist/secrets/vault-integration.d.ts.map +1 -0
- package/dist/secrets/vault-integration.js +295 -0
- package/dist/secrets/vault-providers.d.ts +110 -0
- package/dist/secrets/vault-providers.d.ts.map +1 -0
- package/dist/secrets/vault-providers.js +417 -0
- package/dist/supply-chain/detector.d.ts +80 -0
- package/dist/supply-chain/detector.d.ts.map +1 -0
- package/dist/supply-chain/detector.js +168 -0
- package/dist/supply-chain/index.d.ts +11 -0
- package/dist/supply-chain/index.d.ts.map +1 -0
- package/dist/supply-chain/index.js +26 -0
- package/dist/supply-chain/malicious-db.d.ts +41 -0
- package/dist/supply-chain/malicious-db.d.ts.map +1 -0
- package/dist/supply-chain/malicious-db.js +82 -0
- package/dist/supply-chain/script-analyzer.d.ts +54 -0
- package/dist/supply-chain/script-analyzer.d.ts.map +1 -0
- package/dist/supply-chain/script-analyzer.js +160 -0
- package/dist/supply-chain/typosquat.d.ts +58 -0
- package/dist/supply-chain/typosquat.d.ts.map +1 -0
- package/dist/supply-chain/typosquat.js +257 -0
- package/dist/supply-chain/vulnerability-db.d.ts +114 -0
- package/dist/supply-chain/vulnerability-db.d.ts.map +1 -0
- package/dist/supply-chain/vulnerability-db.js +310 -0
- package/package.json +34 -0
- package/src/__tests__/license/engine.test.ts +250 -0
- package/src/__tests__/supply-chain/typosquat.test.ts +191 -0
- package/src/attack-surface/analyzer.ts +152 -0
- package/src/attack-surface/index.ts +5 -0
- package/src/index.ts +21 -0
- package/src/languages/index.ts +91 -0
- package/src/languages/java-analyzer.ts +490 -0
- package/src/languages/python-analyzer.ts +498 -0
- package/src/license/compatibility-matrix.ts +366 -0
- package/src/license/engine.ts +345 -0
- package/src/license/index.ts +6 -0
- package/src/sbom/generator.ts +355 -0
- package/src/sbom/index.ts +5 -0
- package/src/secrets/guardian.ts +448 -0
- package/src/secrets/index.ts +10 -0
- package/src/secrets/patterns.ts +186 -0
- package/src/secrets/pre-commit.ts +158 -0
- package/src/secrets/vault-integration.ts +360 -0
- package/src/secrets/vault-providers.ts +446 -0
- package/src/supply-chain/detector.ts +252 -0
- package/src/supply-chain/index.ts +11 -0
- package/src/supply-chain/malicious-db.ts +103 -0
- package/src/supply-chain/script-analyzer.ts +194 -0
- package/src/supply-chain/typosquat.ts +302 -0
- package/src/supply-chain/vulnerability-db.ts +386 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Vault Providers
|
|
4
|
+
*
|
|
5
|
+
* Real implementations for secret vault integrations:
|
|
6
|
+
* - AWS Secrets Manager
|
|
7
|
+
* - HashiCorp Vault
|
|
8
|
+
* - Azure Key Vault
|
|
9
|
+
* - GCP Secret Manager
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.LocalEnvProvider = exports.GCPSecretManagerProvider = exports.AzureKeyVaultProvider = exports.HashiCorpVaultProvider = exports.AWSSecretsManagerProvider = void 0;
|
|
46
|
+
exports.createVaultProvider = createVaultProvider;
|
|
47
|
+
/**
|
|
48
|
+
* AWS Secrets Manager Provider
|
|
49
|
+
*/
|
|
50
|
+
class AWSSecretsManagerProvider {
|
|
51
|
+
name = 'AWS Secrets Manager';
|
|
52
|
+
client;
|
|
53
|
+
region;
|
|
54
|
+
constructor(config) {
|
|
55
|
+
this.region = config.region || 'us-east-1';
|
|
56
|
+
}
|
|
57
|
+
async getClient() {
|
|
58
|
+
if (!this.client) {
|
|
59
|
+
const { SecretsManagerClient } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-secrets-manager')));
|
|
60
|
+
this.client = new SecretsManagerClient({ region: this.region });
|
|
61
|
+
}
|
|
62
|
+
return this.client;
|
|
63
|
+
}
|
|
64
|
+
async createSecret(name, value) {
|
|
65
|
+
const client = await this.getClient();
|
|
66
|
+
const { CreateSecretCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-secrets-manager')));
|
|
67
|
+
try {
|
|
68
|
+
const result = await client.send(new CreateSecretCommand({
|
|
69
|
+
Name: name,
|
|
70
|
+
SecretString: value,
|
|
71
|
+
Description: 'Migrated by Guardrail AI',
|
|
72
|
+
}));
|
|
73
|
+
return result.ARN || name;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error.name === 'ResourceExistsException') {
|
|
77
|
+
const { PutSecretValueCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-secrets-manager')));
|
|
78
|
+
await client.send(new PutSecretValueCommand({
|
|
79
|
+
SecretId: name,
|
|
80
|
+
SecretString: value,
|
|
81
|
+
}));
|
|
82
|
+
return name;
|
|
83
|
+
}
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async getSecret(name) {
|
|
88
|
+
const client = await this.getClient();
|
|
89
|
+
const { GetSecretValueCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-secrets-manager')));
|
|
90
|
+
try {
|
|
91
|
+
const result = await client.send(new GetSecretValueCommand({ SecretId: name }));
|
|
92
|
+
return result.SecretString || null;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error.name === 'ResourceNotFoundException') {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async deleteSecret(name) {
|
|
102
|
+
const client = await this.getClient();
|
|
103
|
+
const { DeleteSecretCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-secrets-manager')));
|
|
104
|
+
try {
|
|
105
|
+
await client.send(new DeleteSecretCommand({
|
|
106
|
+
SecretId: name,
|
|
107
|
+
ForceDeleteWithoutRecovery: false,
|
|
108
|
+
}));
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async listSecrets() {
|
|
116
|
+
const client = await this.getClient();
|
|
117
|
+
const { ListSecretsCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-secrets-manager')));
|
|
118
|
+
const result = await client.send(new ListSecretsCommand({}));
|
|
119
|
+
return (result.SecretList || []).map((s) => s.Name).filter(Boolean);
|
|
120
|
+
}
|
|
121
|
+
async testConnection() {
|
|
122
|
+
try {
|
|
123
|
+
await this.listSecrets();
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
exports.AWSSecretsManagerProvider = AWSSecretsManagerProvider;
|
|
132
|
+
/**
|
|
133
|
+
* HashiCorp Vault Provider
|
|
134
|
+
*/
|
|
135
|
+
class HashiCorpVaultProvider {
|
|
136
|
+
name = 'HashiCorp Vault';
|
|
137
|
+
client;
|
|
138
|
+
endpoint;
|
|
139
|
+
token;
|
|
140
|
+
mountPath;
|
|
141
|
+
constructor(config) {
|
|
142
|
+
this.endpoint = config.endpoint || 'http://127.0.0.1:8200';
|
|
143
|
+
this.token = config.credentials?.token || process.env['VAULT_TOKEN'] || '';
|
|
144
|
+
this.mountPath = 'secret';
|
|
145
|
+
}
|
|
146
|
+
async getClient() {
|
|
147
|
+
if (!this.client) {
|
|
148
|
+
const vault = (await Promise.resolve().then(() => __importStar(require('node-vault')))).default;
|
|
149
|
+
this.client = vault({
|
|
150
|
+
endpoint: this.endpoint,
|
|
151
|
+
token: this.token,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return this.client;
|
|
155
|
+
}
|
|
156
|
+
async createSecret(name, value) {
|
|
157
|
+
const client = await this.getClient();
|
|
158
|
+
const path = `${this.mountPath}/data/${name}`;
|
|
159
|
+
await client.write(path, {
|
|
160
|
+
data: { value },
|
|
161
|
+
metadata: { created_by: 'Guardrail-ai' },
|
|
162
|
+
});
|
|
163
|
+
return path;
|
|
164
|
+
}
|
|
165
|
+
async getSecret(name) {
|
|
166
|
+
const client = await this.getClient();
|
|
167
|
+
const path = `${this.mountPath}/data/${name}`;
|
|
168
|
+
try {
|
|
169
|
+
const result = await client.read(path);
|
|
170
|
+
return result?.data?.data?.value || null;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (error.response?.statusCode === 404) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async deleteSecret(name) {
|
|
180
|
+
const client = await this.getClient();
|
|
181
|
+
const path = `${this.mountPath}/metadata/${name}`;
|
|
182
|
+
try {
|
|
183
|
+
await client.delete(path);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async listSecrets() {
|
|
191
|
+
const client = await this.getClient();
|
|
192
|
+
const path = `${this.mountPath}/metadata`;
|
|
193
|
+
try {
|
|
194
|
+
const result = await client.list(path);
|
|
195
|
+
return result?.data?.keys || [];
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async testConnection() {
|
|
202
|
+
try {
|
|
203
|
+
const client = await this.getClient();
|
|
204
|
+
await client.health();
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
exports.HashiCorpVaultProvider = HashiCorpVaultProvider;
|
|
213
|
+
/**
|
|
214
|
+
* Azure Key Vault Provider
|
|
215
|
+
*/
|
|
216
|
+
class AzureKeyVaultProvider {
|
|
217
|
+
name = 'Azure Key Vault';
|
|
218
|
+
client;
|
|
219
|
+
vaultUrl;
|
|
220
|
+
constructor(config) {
|
|
221
|
+
this.vaultUrl = config.endpoint || '';
|
|
222
|
+
if (!this.vaultUrl) {
|
|
223
|
+
throw new Error('Azure Key Vault URL is required');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async getClient() {
|
|
227
|
+
if (!this.client) {
|
|
228
|
+
const { SecretClient } = await Promise.resolve().then(() => __importStar(require('@azure/keyvault-secrets')));
|
|
229
|
+
const { DefaultAzureCredential } = await Promise.resolve().then(() => __importStar(require('@azure/identity')));
|
|
230
|
+
const credential = new DefaultAzureCredential();
|
|
231
|
+
this.client = new SecretClient(this.vaultUrl, credential);
|
|
232
|
+
}
|
|
233
|
+
return this.client;
|
|
234
|
+
}
|
|
235
|
+
async createSecret(name, value) {
|
|
236
|
+
const client = await this.getClient();
|
|
237
|
+
const sanitizedName = name.replace(/[^a-zA-Z0-9-]/g, '-');
|
|
238
|
+
const result = await client.setSecret(sanitizedName, value, {
|
|
239
|
+
tags: { createdBy: 'Guardrail-ai' },
|
|
240
|
+
});
|
|
241
|
+
return result.properties.id || sanitizedName;
|
|
242
|
+
}
|
|
243
|
+
async getSecret(name) {
|
|
244
|
+
const client = await this.getClient();
|
|
245
|
+
const sanitizedName = name.replace(/[^a-zA-Z0-9-]/g, '-');
|
|
246
|
+
try {
|
|
247
|
+
const result = await client.getSecret(sanitizedName);
|
|
248
|
+
return result.value || null;
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
if (error.code === 'SecretNotFound') {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async deleteSecret(name) {
|
|
258
|
+
const client = await this.getClient();
|
|
259
|
+
const sanitizedName = name.replace(/[^a-zA-Z0-9-]/g, '-');
|
|
260
|
+
try {
|
|
261
|
+
await client.beginDeleteSecret(sanitizedName);
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async listSecrets() {
|
|
269
|
+
const client = await this.getClient();
|
|
270
|
+
const secrets = [];
|
|
271
|
+
for await (const secretProperties of client.listPropertiesOfSecrets()) {
|
|
272
|
+
secrets.push(secretProperties.name);
|
|
273
|
+
}
|
|
274
|
+
return secrets;
|
|
275
|
+
}
|
|
276
|
+
async testConnection() {
|
|
277
|
+
try {
|
|
278
|
+
await this.listSecrets();
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
exports.AzureKeyVaultProvider = AzureKeyVaultProvider;
|
|
287
|
+
/**
|
|
288
|
+
* GCP Secret Manager Provider
|
|
289
|
+
*/
|
|
290
|
+
class GCPSecretManagerProvider {
|
|
291
|
+
name = 'GCP Secret Manager';
|
|
292
|
+
client;
|
|
293
|
+
projectId;
|
|
294
|
+
constructor(config) {
|
|
295
|
+
this.projectId = config.projectId || process.env['GOOGLE_CLOUD_PROJECT'] || '';
|
|
296
|
+
if (!this.projectId) {
|
|
297
|
+
throw new Error('GCP Project ID is required');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async getClient() {
|
|
301
|
+
if (!this.client) {
|
|
302
|
+
const { SecretManagerServiceClient } = await Promise.resolve().then(() => __importStar(require('@google-cloud/secret-manager')));
|
|
303
|
+
this.client = new SecretManagerServiceClient();
|
|
304
|
+
}
|
|
305
|
+
return this.client;
|
|
306
|
+
}
|
|
307
|
+
async createSecret(name, value) {
|
|
308
|
+
const client = await this.getClient();
|
|
309
|
+
const parent = `projects/${this.projectId}`;
|
|
310
|
+
const sanitizedName = name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
311
|
+
try {
|
|
312
|
+
await client.createSecret({
|
|
313
|
+
parent,
|
|
314
|
+
secretId: sanitizedName,
|
|
315
|
+
secret: {
|
|
316
|
+
replication: { automatic: {} },
|
|
317
|
+
labels: { created_by: 'Guardrail-ai' },
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
if (error.code !== 6) {
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const secretName = `${parent}/secrets/${sanitizedName}`;
|
|
327
|
+
await client.addSecretVersion({
|
|
328
|
+
parent: secretName,
|
|
329
|
+
payload: { data: Buffer.from(value, 'utf8') },
|
|
330
|
+
});
|
|
331
|
+
return secretName;
|
|
332
|
+
}
|
|
333
|
+
async getSecret(name) {
|
|
334
|
+
const client = await this.getClient();
|
|
335
|
+
const sanitizedName = name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
336
|
+
const secretName = `projects/${this.projectId}/secrets/${sanitizedName}/versions/latest`;
|
|
337
|
+
try {
|
|
338
|
+
const [version] = await client.accessSecretVersion({ name: secretName });
|
|
339
|
+
return version.payload?.data?.toString() || null;
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
if (error.code === 5) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
throw error;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
async deleteSecret(name) {
|
|
349
|
+
const client = await this.getClient();
|
|
350
|
+
const sanitizedName = name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
351
|
+
const secretName = `projects/${this.projectId}/secrets/${sanitizedName}`;
|
|
352
|
+
try {
|
|
353
|
+
await client.deleteSecret({ name: secretName });
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async listSecrets() {
|
|
361
|
+
const client = await this.getClient();
|
|
362
|
+
const parent = `projects/${this.projectId}`;
|
|
363
|
+
const [secrets] = await client.listSecrets({ parent });
|
|
364
|
+
return secrets.map((s) => s.name?.split('/').pop()).filter(Boolean);
|
|
365
|
+
}
|
|
366
|
+
async testConnection() {
|
|
367
|
+
try {
|
|
368
|
+
await this.listSecrets();
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
exports.GCPSecretManagerProvider = GCPSecretManagerProvider;
|
|
377
|
+
/**
|
|
378
|
+
* Factory function to create vault provider
|
|
379
|
+
*/
|
|
380
|
+
function createVaultProvider(config) {
|
|
381
|
+
switch (config.type) {
|
|
382
|
+
case 'aws_secrets_manager':
|
|
383
|
+
return new AWSSecretsManagerProvider(config);
|
|
384
|
+
case 'hashicorp_vault':
|
|
385
|
+
return new HashiCorpVaultProvider(config);
|
|
386
|
+
case 'azure_keyvault':
|
|
387
|
+
return new AzureKeyVaultProvider(config);
|
|
388
|
+
case 'gcp_secret_manager':
|
|
389
|
+
return new GCPSecretManagerProvider(config);
|
|
390
|
+
default:
|
|
391
|
+
throw new Error(`Unsupported vault type: ${config.type}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Local environment provider (for development/testing)
|
|
396
|
+
*/
|
|
397
|
+
class LocalEnvProvider {
|
|
398
|
+
name = 'Local Environment';
|
|
399
|
+
secrets = new Map();
|
|
400
|
+
async createSecret(name, value) {
|
|
401
|
+
this.secrets.set(name, value);
|
|
402
|
+
return `local://${name}`;
|
|
403
|
+
}
|
|
404
|
+
async getSecret(name) {
|
|
405
|
+
return this.secrets.get(name) || process.env[name] || null;
|
|
406
|
+
}
|
|
407
|
+
async deleteSecret(name) {
|
|
408
|
+
return this.secrets.delete(name);
|
|
409
|
+
}
|
|
410
|
+
async listSecrets() {
|
|
411
|
+
return Array.from(this.secrets.keys());
|
|
412
|
+
}
|
|
413
|
+
async testConnection() {
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
exports.LocalEnvProvider = LocalEnvProvider;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { TyposquatResult } from "./typosquat";
|
|
2
|
+
import { ScriptAnalysisResult } from "./script-analyzer";
|
|
3
|
+
/**
|
|
4
|
+
* Package analysis result
|
|
5
|
+
*/
|
|
6
|
+
export interface PackageAnalysisResult {
|
|
7
|
+
packageName: string;
|
|
8
|
+
version: string;
|
|
9
|
+
registry: string;
|
|
10
|
+
riskScore: number;
|
|
11
|
+
threats: Threat[];
|
|
12
|
+
isMalicious: boolean;
|
|
13
|
+
isTyposquat: boolean;
|
|
14
|
+
isDeprecated: boolean;
|
|
15
|
+
typosquatResult?: TyposquatResult;
|
|
16
|
+
scriptAnalysis?: ScriptAnalysisResult[];
|
|
17
|
+
license?: string;
|
|
18
|
+
maintainerRisk?: MaintainerRisk;
|
|
19
|
+
}
|
|
20
|
+
export interface Threat {
|
|
21
|
+
type: string;
|
|
22
|
+
severity: "low" | "medium" | "high" | "critical";
|
|
23
|
+
description: string;
|
|
24
|
+
}
|
|
25
|
+
export interface MaintainerRisk {
|
|
26
|
+
accountAge: number;
|
|
27
|
+
packageCount: number;
|
|
28
|
+
suspiciousActivity: boolean;
|
|
29
|
+
riskLevel: "low" | "medium" | "high";
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* SBOM (Software Bill of Materials)
|
|
33
|
+
*/
|
|
34
|
+
export interface SBOM {
|
|
35
|
+
id?: string;
|
|
36
|
+
projectId: string;
|
|
37
|
+
version: number;
|
|
38
|
+
format: "CycloneDX" | "SPDX";
|
|
39
|
+
specVersion: string;
|
|
40
|
+
components: SBOMComponent[];
|
|
41
|
+
generatedAt: Date;
|
|
42
|
+
}
|
|
43
|
+
export interface SBOMComponent {
|
|
44
|
+
type: "library" | "application" | "framework";
|
|
45
|
+
name: string;
|
|
46
|
+
version: string;
|
|
47
|
+
purl: string;
|
|
48
|
+
licenses?: string[];
|
|
49
|
+
hashes?: {
|
|
50
|
+
algorithm: string;
|
|
51
|
+
value: string;
|
|
52
|
+
}[];
|
|
53
|
+
dependencies?: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Supply Chain Attack Detector
|
|
57
|
+
*/
|
|
58
|
+
export declare class SupplyChainDetector {
|
|
59
|
+
/**
|
|
60
|
+
* Detect typosquatting
|
|
61
|
+
*/
|
|
62
|
+
detectTyposquatting(packageName: string): Promise<TyposquatResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Detect dependency confusion
|
|
65
|
+
*/
|
|
66
|
+
detectDependencyConfusion(_packageName: string, internalRegistry?: string): Promise<{
|
|
67
|
+
isDependencyConfusion: boolean;
|
|
68
|
+
reason: string;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Full package analysis
|
|
72
|
+
*/
|
|
73
|
+
analyzePackage(packageName: string, version: string, projectId: string): Promise<PackageAnalysisResult>;
|
|
74
|
+
/**
|
|
75
|
+
* Generate SBOM (CycloneDX format)
|
|
76
|
+
*/
|
|
77
|
+
generateSBOM(projectPath: string, projectId: string): Promise<SBOM>;
|
|
78
|
+
}
|
|
79
|
+
export declare const supplyChainDetector: SupplyChainDetector;
|
|
80
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/supply-chain/detector.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,eAAe,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAkB,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAIzE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,cAAc,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACjD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,WAAW,EAAE,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACG,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAIxE;;OAEG;IACG,yBAAyB,CAC7B,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC;QAAE,qBAAqB,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAoB9D;;OAEG;IACG,cAAc,CAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC;IAiFjC;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA2D1E;AAGD,eAAO,MAAM,mBAAmB,qBAA4B,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.supplyChainDetector = exports.SupplyChainDetector = void 0;
|
|
4
|
+
const database_1 = require("@guardrail/database");
|
|
5
|
+
const typosquat_1 = require("./typosquat");
|
|
6
|
+
const malicious_db_1 = require("./malicious-db");
|
|
7
|
+
const script_analyzer_1 = require("./script-analyzer");
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
/**
|
|
11
|
+
* Supply Chain Attack Detector
|
|
12
|
+
*/
|
|
13
|
+
class SupplyChainDetector {
|
|
14
|
+
/**
|
|
15
|
+
* Detect typosquatting
|
|
16
|
+
*/
|
|
17
|
+
async detectTyposquatting(packageName) {
|
|
18
|
+
return typosquat_1.typosquatDetector.detectTyposquatting(packageName);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Detect dependency confusion
|
|
22
|
+
*/
|
|
23
|
+
async detectDependencyConfusion(_packageName, internalRegistry) {
|
|
24
|
+
// Check if package exists in both public and internal registries
|
|
25
|
+
// This is a simplified implementation
|
|
26
|
+
if (!internalRegistry) {
|
|
27
|
+
return {
|
|
28
|
+
isDependencyConfusion: false,
|
|
29
|
+
reason: "No internal registry configured",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// In production, this would check both registries
|
|
33
|
+
// and compare versions, publish dates, etc.
|
|
34
|
+
return {
|
|
35
|
+
isDependencyConfusion: false,
|
|
36
|
+
reason: "Package only found in public registry",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Full package analysis
|
|
41
|
+
*/
|
|
42
|
+
async analyzePackage(packageName, version, projectId) {
|
|
43
|
+
const threats = [];
|
|
44
|
+
let riskScore = 0;
|
|
45
|
+
// Check for typosquatting
|
|
46
|
+
const typosquatResult = await this.detectTyposquatting(packageName);
|
|
47
|
+
const isTyposquat = typosquatResult.isTyposquat;
|
|
48
|
+
if (isTyposquat) {
|
|
49
|
+
threats.push({
|
|
50
|
+
type: "typosquatting",
|
|
51
|
+
severity: "high",
|
|
52
|
+
description: `Possible typosquatting of ${typosquatResult.targetPackage}`,
|
|
53
|
+
});
|
|
54
|
+
riskScore += 40;
|
|
55
|
+
}
|
|
56
|
+
// Check against malicious database
|
|
57
|
+
const maliciousCheck = await malicious_db_1.maliciousPackageDB.checkPackage(packageName, version);
|
|
58
|
+
const isMalicious = maliciousCheck.isMalicious;
|
|
59
|
+
if (isMalicious) {
|
|
60
|
+
for (const match of maliciousCheck.matches) {
|
|
61
|
+
threats.push({
|
|
62
|
+
type: "known_malicious",
|
|
63
|
+
severity: match.severity,
|
|
64
|
+
description: match.reason,
|
|
65
|
+
});
|
|
66
|
+
riskScore += 50;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Analyze scripts
|
|
70
|
+
const scriptAnalysis = await script_analyzer_1.scriptAnalyzer.analyzeScripts(packageName, version);
|
|
71
|
+
for (const analysis of scriptAnalysis) {
|
|
72
|
+
if (analysis.isSuspicious) {
|
|
73
|
+
threats.push({
|
|
74
|
+
type: "suspicious_script",
|
|
75
|
+
severity: "high",
|
|
76
|
+
description: `Suspicious script: ${analysis.scriptName}`,
|
|
77
|
+
});
|
|
78
|
+
riskScore += analysis.riskScore * 0.5;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Save to database
|
|
82
|
+
await database_1.prisma.dependencyAnalysis.create({
|
|
83
|
+
data: {
|
|
84
|
+
projectId,
|
|
85
|
+
packageName,
|
|
86
|
+
version,
|
|
87
|
+
registry: "npm",
|
|
88
|
+
isMalicious,
|
|
89
|
+
isTyposquat,
|
|
90
|
+
isDeprecated: false,
|
|
91
|
+
riskScore: Math.min(100, riskScore),
|
|
92
|
+
threats: JSON.parse(JSON.stringify(threats)),
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
packageName,
|
|
97
|
+
version,
|
|
98
|
+
registry: "npm",
|
|
99
|
+
riskScore: Math.min(100, riskScore),
|
|
100
|
+
threats,
|
|
101
|
+
isMalicious,
|
|
102
|
+
isTyposquat,
|
|
103
|
+
isDeprecated: false,
|
|
104
|
+
typosquatResult: isTyposquat ? typosquatResult : undefined,
|
|
105
|
+
scriptAnalysis,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Generate SBOM (CycloneDX format)
|
|
110
|
+
*/
|
|
111
|
+
async generateSBOM(projectPath, projectId) {
|
|
112
|
+
const components = [];
|
|
113
|
+
try {
|
|
114
|
+
// Read package.json
|
|
115
|
+
const packageJsonPath = (0, path_1.join)(projectPath, "package.json");
|
|
116
|
+
const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, "utf-8"));
|
|
117
|
+
// Extract dependencies
|
|
118
|
+
const deps = {
|
|
119
|
+
...packageJson.dependencies,
|
|
120
|
+
...packageJson.devDependencies,
|
|
121
|
+
};
|
|
122
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
123
|
+
components.push({
|
|
124
|
+
type: "library",
|
|
125
|
+
name,
|
|
126
|
+
version: version,
|
|
127
|
+
purl: `pkg:npm/${name}@${version}`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
// Handle error
|
|
133
|
+
}
|
|
134
|
+
const sbom = {
|
|
135
|
+
id: `sbom_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
136
|
+
projectId,
|
|
137
|
+
version: 1,
|
|
138
|
+
format: "CycloneDX",
|
|
139
|
+
specVersion: "1.4",
|
|
140
|
+
components,
|
|
141
|
+
generatedAt: new Date(),
|
|
142
|
+
};
|
|
143
|
+
// @ts-ignore - SBOM model exists in schema, Prisma client may need regeneration
|
|
144
|
+
const savedSBOM = await database_1.prisma.sBOM.create({
|
|
145
|
+
data: {
|
|
146
|
+
id: sbom.id,
|
|
147
|
+
projectId,
|
|
148
|
+
version: sbom.version,
|
|
149
|
+
format: sbom.format,
|
|
150
|
+
specVersion: sbom.specVersion,
|
|
151
|
+
components: JSON.parse(JSON.stringify(components)),
|
|
152
|
+
generatedAt: sbom.generatedAt,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
id: savedSBOM.id,
|
|
157
|
+
projectId: savedSBOM.projectId,
|
|
158
|
+
version: savedSBOM.version,
|
|
159
|
+
format: savedSBOM.format,
|
|
160
|
+
specVersion: savedSBOM.specVersion,
|
|
161
|
+
components: savedSBOM.components,
|
|
162
|
+
generatedAt: savedSBOM.generatedAt,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.SupplyChainDetector = SupplyChainDetector;
|
|
167
|
+
// Export singleton
|
|
168
|
+
exports.supplyChainDetector = new SupplyChainDetector();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supply Chain Attack Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects typosquatting, malicious packages, and generates SBOMs
|
|
5
|
+
*/
|
|
6
|
+
export * from './detector';
|
|
7
|
+
export * from './typosquat';
|
|
8
|
+
export * from './malicious-db';
|
|
9
|
+
export * from './script-analyzer';
|
|
10
|
+
export * from './vulnerability-db';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/supply-chain/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
|