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,425 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Python Language Analyzer
|
|
4
|
+
*
|
|
5
|
+
* Security analysis for Python projects including:
|
|
6
|
+
* - requirements.txt / Pipfile / pyproject.toml parsing
|
|
7
|
+
* - Import analysis for detecting dangerous modules
|
|
8
|
+
* - Secret detection patterns specific to Python
|
|
9
|
+
* - Common vulnerability patterns (SQL injection, command injection, etc.)
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.pythonAnalyzer = exports.PythonAnalyzer = void 0;
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const path_1 = require("path");
|
|
15
|
+
// Dangerous Python imports that may indicate security issues
|
|
16
|
+
const DANGEROUS_IMPORTS = [
|
|
17
|
+
{
|
|
18
|
+
module: "pickle",
|
|
19
|
+
reason: "Arbitrary code execution via deserialization",
|
|
20
|
+
severity: "high",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
module: "marshal",
|
|
24
|
+
reason: "Unsafe deserialization",
|
|
25
|
+
severity: "high",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
module: "shelve",
|
|
29
|
+
reason: "Uses pickle internally",
|
|
30
|
+
severity: "medium",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
module: "subprocess",
|
|
34
|
+
reason: "Command execution - ensure proper sanitization",
|
|
35
|
+
severity: "medium",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
module: "os.system",
|
|
39
|
+
reason: "Command execution - prefer subprocess",
|
|
40
|
+
severity: "high",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
module: "eval",
|
|
44
|
+
reason: "Arbitrary code execution",
|
|
45
|
+
severity: "critical",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
module: "exec",
|
|
49
|
+
reason: "Arbitrary code execution",
|
|
50
|
+
severity: "critical",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
module: "compile",
|
|
54
|
+
reason: "Dynamic code compilation",
|
|
55
|
+
severity: "medium",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
module: "__import__",
|
|
59
|
+
reason: "Dynamic import - potential for injection",
|
|
60
|
+
severity: "medium",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
// Python-specific secret patterns
|
|
64
|
+
const PYTHON_SECRET_PATTERNS = [
|
|
65
|
+
{ pattern: /(?:api_key|apikey)\s*=\s*['"][^'"]{10,}['"]/gi, type: "API Key" },
|
|
66
|
+
{
|
|
67
|
+
pattern: /(?:secret|password|passwd|pwd)\s*=\s*['"][^'"]{6,}['"]/gi,
|
|
68
|
+
type: "Password/Secret",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
pattern: /(?:token|auth_token|access_token)\s*=\s*['"][^'"]{10,}['"]/gi,
|
|
72
|
+
type: "Token",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
pattern: /AWS_(?:ACCESS_KEY_ID|SECRET_ACCESS_KEY)\s*=\s*['"][^'"]+['"]/gi,
|
|
76
|
+
type: "AWS Credential",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
pattern: /(?:private_key|ssh_key)\s*=\s*['"]-----BEGIN/gi,
|
|
80
|
+
type: "Private Key",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
pattern: /mongodb(?:\+srv)?:\/\/[^:]+:[^@]+@/gi,
|
|
84
|
+
type: "MongoDB Connection String",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
pattern: /postgres(?:ql)?:\/\/[^:]+:[^@]+@/gi,
|
|
88
|
+
type: "PostgreSQL Connection String",
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
// Vulnerability code patterns
|
|
92
|
+
const VULNERABILITY_PATTERNS = [
|
|
93
|
+
{
|
|
94
|
+
pattern: /cursor\.execute\s*\(\s*['"f].*\{.*\}/g,
|
|
95
|
+
type: "SQL Injection",
|
|
96
|
+
message: "String formatting in SQL query - use parameterized queries",
|
|
97
|
+
severity: "critical",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
pattern: /cursor\.execute\s*\(\s*.*%\s*\(/g,
|
|
101
|
+
type: "SQL Injection",
|
|
102
|
+
message: "String interpolation in SQL query - use parameterized queries",
|
|
103
|
+
severity: "critical",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
pattern: /subprocess\.(?:call|run|Popen)\s*\(\s*['"f].*\{/g,
|
|
107
|
+
type: "Command Injection",
|
|
108
|
+
message: "String formatting in shell command - use list arguments",
|
|
109
|
+
severity: "critical",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
pattern: /os\.system\s*\(/g,
|
|
113
|
+
type: "Command Injection",
|
|
114
|
+
message: "os.system is vulnerable to shell injection - use subprocess",
|
|
115
|
+
severity: "high",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
pattern: /yaml\.load\s*\([^)]*\)/g,
|
|
119
|
+
type: "Unsafe Deserialization",
|
|
120
|
+
message: "yaml.load is unsafe - use yaml.safe_load instead",
|
|
121
|
+
severity: "high",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
pattern: /pickle\.loads?\s*\(/g,
|
|
125
|
+
type: "Unsafe Deserialization",
|
|
126
|
+
message: "Pickle is unsafe with untrusted data",
|
|
127
|
+
severity: "high",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
pattern: /render_template_string\s*\(/g,
|
|
131
|
+
type: "Server-Side Template Injection",
|
|
132
|
+
message: "render_template_string with user input is dangerous",
|
|
133
|
+
severity: "critical",
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
pattern: /DEBUG\s*=\s*True/g,
|
|
137
|
+
type: "Debug Mode",
|
|
138
|
+
message: "Debug mode enabled - disable in production",
|
|
139
|
+
severity: "medium",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
pattern: /verify\s*=\s*False/g,
|
|
143
|
+
type: "SSL Verification Disabled",
|
|
144
|
+
message: "SSL verification disabled - vulnerable to MITM attacks",
|
|
145
|
+
severity: "high",
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
class PythonAnalyzer {
|
|
149
|
+
/**
|
|
150
|
+
* Analyze a Python project
|
|
151
|
+
*/
|
|
152
|
+
async analyze(projectPath) {
|
|
153
|
+
const dependencies = await this.extractDependencies(projectPath);
|
|
154
|
+
const securityIssues = [];
|
|
155
|
+
// Scan Python files for security issues
|
|
156
|
+
const pythonFiles = await this.findPythonFiles(projectPath);
|
|
157
|
+
for (const file of pythonFiles) {
|
|
158
|
+
const issues = await this.scanFile(file);
|
|
159
|
+
securityIssues.push(...issues);
|
|
160
|
+
}
|
|
161
|
+
// Get Python version if available
|
|
162
|
+
const pythonVersion = this.detectPythonVersion(projectPath);
|
|
163
|
+
// Calculate summary
|
|
164
|
+
const issuesBySeverity = {
|
|
165
|
+
critical: 0,
|
|
166
|
+
high: 0,
|
|
167
|
+
medium: 0,
|
|
168
|
+
low: 0,
|
|
169
|
+
};
|
|
170
|
+
for (const issue of securityIssues) {
|
|
171
|
+
const severity = issue.severity;
|
|
172
|
+
if (issuesBySeverity[severity] !== undefined) {
|
|
173
|
+
issuesBySeverity[severity]++;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
projectPath,
|
|
178
|
+
pythonVersion,
|
|
179
|
+
dependencies,
|
|
180
|
+
securityIssues,
|
|
181
|
+
summary: {
|
|
182
|
+
totalDependencies: dependencies.length,
|
|
183
|
+
directDependencies: dependencies.length,
|
|
184
|
+
issuesBySeverity,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Extract dependencies from various Python dependency files
|
|
190
|
+
*/
|
|
191
|
+
async extractDependencies(projectPath) {
|
|
192
|
+
const dependencies = [];
|
|
193
|
+
// Check requirements.txt
|
|
194
|
+
const requirementsPath = (0, path_1.join)(projectPath, "requirements.txt");
|
|
195
|
+
if ((0, fs_1.existsSync)(requirementsPath)) {
|
|
196
|
+
const content = (0, fs_1.readFileSync)(requirementsPath, "utf-8");
|
|
197
|
+
dependencies.push(...this.parseRequirementsTxt(content));
|
|
198
|
+
}
|
|
199
|
+
// Check pyproject.toml
|
|
200
|
+
const pyprojectPath = (0, path_1.join)(projectPath, "pyproject.toml");
|
|
201
|
+
if ((0, fs_1.existsSync)(pyprojectPath)) {
|
|
202
|
+
const content = (0, fs_1.readFileSync)(pyprojectPath, "utf-8");
|
|
203
|
+
dependencies.push(...this.parsePyprojectToml(content));
|
|
204
|
+
}
|
|
205
|
+
// Check Pipfile
|
|
206
|
+
const pipfilePath = (0, path_1.join)(projectPath, "Pipfile");
|
|
207
|
+
if ((0, fs_1.existsSync)(pipfilePath)) {
|
|
208
|
+
const content = (0, fs_1.readFileSync)(pipfilePath, "utf-8");
|
|
209
|
+
dependencies.push(...this.parsePipfile(content));
|
|
210
|
+
}
|
|
211
|
+
return dependencies;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Parse requirements.txt format
|
|
215
|
+
*/
|
|
216
|
+
parseRequirementsTxt(content) {
|
|
217
|
+
const dependencies = [];
|
|
218
|
+
const lines = content.split("\n");
|
|
219
|
+
for (const line of lines) {
|
|
220
|
+
const trimmed = line.trim();
|
|
221
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("-")) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
// Match package==version or package>=version etc.
|
|
225
|
+
const match = trimmed.match(/^([a-zA-Z0-9_-]+)\s*([=<>!~]+)?\s*([\d.]+)?/);
|
|
226
|
+
if (match && match[1]) {
|
|
227
|
+
dependencies.push({
|
|
228
|
+
name: match[1],
|
|
229
|
+
version: match[3] ?? "*",
|
|
230
|
+
source: "requirements",
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return dependencies;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Parse pyproject.toml dependencies
|
|
238
|
+
*/
|
|
239
|
+
parsePyprojectToml(content) {
|
|
240
|
+
const dependencies = [];
|
|
241
|
+
// Simple regex parsing for dependencies section
|
|
242
|
+
const depsMatch = content.match(/\[project\.dependencies\]([\s\S]*?)(?:\[|$)/);
|
|
243
|
+
if (depsMatch && depsMatch[1]) {
|
|
244
|
+
const lines = depsMatch[1].split("\n");
|
|
245
|
+
for (const line of lines) {
|
|
246
|
+
const match = line.match(/^\s*"([^"]+)"/);
|
|
247
|
+
if (match && match[1]) {
|
|
248
|
+
const depSpec = match[1];
|
|
249
|
+
const nameMatch = depSpec.match(/^([a-zA-Z0-9_-]+)/);
|
|
250
|
+
const versionMatch = depSpec.match(/[=<>!~]+([\d.]+)/);
|
|
251
|
+
if (nameMatch && nameMatch[1]) {
|
|
252
|
+
dependencies.push({
|
|
253
|
+
name: nameMatch[1],
|
|
254
|
+
version: versionMatch?.[1] ?? "*",
|
|
255
|
+
source: "pyproject",
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return dependencies;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Parse Pipfile dependencies
|
|
265
|
+
*/
|
|
266
|
+
parsePipfile(content) {
|
|
267
|
+
const dependencies = [];
|
|
268
|
+
// Match [packages] section
|
|
269
|
+
const packagesMatch = content.match(/\[packages\]([\s\S]*?)(?:\[|$)/);
|
|
270
|
+
if (packagesMatch && packagesMatch[1]) {
|
|
271
|
+
const lines = packagesMatch[1].split("\n");
|
|
272
|
+
for (const line of lines) {
|
|
273
|
+
const match = line.match(/^([a-zA-Z0-9_-]+)\s*=\s*"?([^"\n]+)"?/);
|
|
274
|
+
if (match && match[1] && match[2]) {
|
|
275
|
+
dependencies.push({
|
|
276
|
+
name: match[1],
|
|
277
|
+
version: match[2] === "*" ? "*" : match[2],
|
|
278
|
+
source: "pipfile",
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return dependencies;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Find all Python files in project
|
|
287
|
+
*/
|
|
288
|
+
async findPythonFiles(projectPath) {
|
|
289
|
+
const files = [];
|
|
290
|
+
// Simple recursive file finder
|
|
291
|
+
const walkDir = (dir) => {
|
|
292
|
+
try {
|
|
293
|
+
const { readdirSync, statSync } = require("fs");
|
|
294
|
+
const entries = readdirSync(dir);
|
|
295
|
+
for (const entry of entries) {
|
|
296
|
+
const fullPath = (0, path_1.join)(dir, entry);
|
|
297
|
+
// Skip common non-source directories
|
|
298
|
+
if ([
|
|
299
|
+
"node_modules",
|
|
300
|
+
".git",
|
|
301
|
+
"__pycache__",
|
|
302
|
+
".venv",
|
|
303
|
+
"venv",
|
|
304
|
+
"env",
|
|
305
|
+
".tox",
|
|
306
|
+
].includes(entry)) {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
const stat = statSync(fullPath);
|
|
311
|
+
if (stat.isDirectory()) {
|
|
312
|
+
walkDir(fullPath);
|
|
313
|
+
}
|
|
314
|
+
else if (entry.endsWith(".py")) {
|
|
315
|
+
files.push(fullPath);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
// Skip files we can't access
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
// Skip directories we can't access
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
walkDir(projectPath);
|
|
328
|
+
return files;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Scan a Python file for security issues
|
|
332
|
+
*/
|
|
333
|
+
async scanFile(filePath) {
|
|
334
|
+
const issues = [];
|
|
335
|
+
try {
|
|
336
|
+
const content = (0, fs_1.readFileSync)(filePath, "utf-8");
|
|
337
|
+
const lines = content.split("\n");
|
|
338
|
+
// Check for dangerous imports
|
|
339
|
+
for (let i = 0; i < lines.length; i++) {
|
|
340
|
+
const line = lines[i];
|
|
341
|
+
for (const dangerous of DANGEROUS_IMPORTS) {
|
|
342
|
+
if (line &&
|
|
343
|
+
(line.includes(`import ${dangerous.module}`) ||
|
|
344
|
+
line.includes(`from ${dangerous.module}`) ||
|
|
345
|
+
line.includes(dangerous.module))) {
|
|
346
|
+
issues.push({
|
|
347
|
+
type: "dangerous_import",
|
|
348
|
+
severity: dangerous.severity,
|
|
349
|
+
file: filePath,
|
|
350
|
+
line: i + 1,
|
|
351
|
+
message: `Dangerous import: ${dangerous.module} - ${dangerous.reason}`,
|
|
352
|
+
recommendation: `Review usage of ${dangerous.module} and ensure proper security controls`,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// Check for secrets
|
|
358
|
+
for (const secretPattern of PYTHON_SECRET_PATTERNS) {
|
|
359
|
+
const matches = content.matchAll(secretPattern.pattern);
|
|
360
|
+
for (const match of matches) {
|
|
361
|
+
const lineNum = content.substring(0, match.index).split("\n").length;
|
|
362
|
+
issues.push({
|
|
363
|
+
type: "secret",
|
|
364
|
+
severity: "critical",
|
|
365
|
+
file: filePath,
|
|
366
|
+
line: lineNum,
|
|
367
|
+
message: `Potential ${secretPattern.type} detected`,
|
|
368
|
+
recommendation: "Move secrets to environment variables or a secure vault",
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// Check for vulnerability patterns
|
|
373
|
+
for (const vulnPattern of VULNERABILITY_PATTERNS) {
|
|
374
|
+
const matches = content.matchAll(vulnPattern.pattern);
|
|
375
|
+
for (const match of matches) {
|
|
376
|
+
const lineNum = content.substring(0, match.index).split("\n").length;
|
|
377
|
+
issues.push({
|
|
378
|
+
type: "code_pattern",
|
|
379
|
+
severity: vulnPattern.severity,
|
|
380
|
+
file: filePath,
|
|
381
|
+
line: lineNum,
|
|
382
|
+
message: `${vulnPattern.type}: ${vulnPattern.message}`,
|
|
383
|
+
recommendation: `Fix the ${vulnPattern.type.toLowerCase()} vulnerability`,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
// Skip files we can't read
|
|
390
|
+
}
|
|
391
|
+
return issues;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Detect Python version from project
|
|
395
|
+
*/
|
|
396
|
+
detectPythonVersion(projectPath) {
|
|
397
|
+
// Check pyproject.toml for requires-python
|
|
398
|
+
const pyprojectPath = (0, path_1.join)(projectPath, "pyproject.toml");
|
|
399
|
+
if ((0, fs_1.existsSync)(pyprojectPath)) {
|
|
400
|
+
const content = (0, fs_1.readFileSync)(pyprojectPath, "utf-8");
|
|
401
|
+
const match = content.match(/requires-python\s*=\s*"([^"]+)"/);
|
|
402
|
+
if (match) {
|
|
403
|
+
return match[1];
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// Check .python-version file
|
|
407
|
+
const pythonVersionPath = (0, path_1.join)(projectPath, ".python-version");
|
|
408
|
+
if ((0, fs_1.existsSync)(pythonVersionPath)) {
|
|
409
|
+
return (0, fs_1.readFileSync)(pythonVersionPath, "utf-8").trim();
|
|
410
|
+
}
|
|
411
|
+
// Check runtime.txt (Heroku)
|
|
412
|
+
const runtimePath = (0, path_1.join)(projectPath, "runtime.txt");
|
|
413
|
+
if ((0, fs_1.existsSync)(runtimePath)) {
|
|
414
|
+
const content = (0, fs_1.readFileSync)(runtimePath, "utf-8").trim();
|
|
415
|
+
const match = content.match(/python-([\d.]+)/);
|
|
416
|
+
if (match) {
|
|
417
|
+
return match[1];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return undefined;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
exports.PythonAnalyzer = PythonAnalyzer;
|
|
424
|
+
// Export singleton
|
|
425
|
+
exports.pythonAnalyzer = new PythonAnalyzer();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* License Compatibility Matrix
|
|
3
|
+
*
|
|
4
|
+
* Defines which licenses are compatible with each other
|
|
5
|
+
*/
|
|
6
|
+
export type LicenseType = "MIT" | "Apache-2.0" | "BSD-2-Clause" | "BSD-3-Clause" | "ISC" | "GPL-2.0" | "GPL-3.0" | "LGPL-2.1" | "LGPL-3.0" | "AGPL-3.0" | "MPL-2.0" | "CDDL-1.0" | "EPL-2.0" | "Unlicense" | "CC0-1.0" | "Proprietary" | "Unknown";
|
|
7
|
+
export type LicenseCategory = "permissive" | "weak_copyleft" | "strong_copyleft" | "public_domain" | "proprietary";
|
|
8
|
+
export interface LicenseInfo {
|
|
9
|
+
name: string;
|
|
10
|
+
category: LicenseCategory;
|
|
11
|
+
requiresAttribution: boolean;
|
|
12
|
+
requiresSourceDisclosure: boolean;
|
|
13
|
+
requiresSameLicense: boolean;
|
|
14
|
+
allowsCommercialUse: boolean;
|
|
15
|
+
allowsModification: boolean;
|
|
16
|
+
allowsDistribution: boolean;
|
|
17
|
+
patentGrant: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* License metadata
|
|
21
|
+
*/
|
|
22
|
+
export declare const LICENSE_INFO: Record<LicenseType, LicenseInfo>;
|
|
23
|
+
/**
|
|
24
|
+
* Compatibility matrix
|
|
25
|
+
* true = compatible, false = incompatible
|
|
26
|
+
*/
|
|
27
|
+
export declare const COMPATIBILITY_MATRIX: Record<LicenseType, Record<LicenseType, boolean>>;
|
|
28
|
+
//# sourceMappingURL=compatibility-matrix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compatibility-matrix.d.ts","sourceRoot":"","sources":["../../src/license/compatibility-matrix.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GACnB,KAAK,GACL,YAAY,GACZ,cAAc,GACd,cAAc,GACd,KAAK,GACL,SAAS,GACT,SAAS,GACT,UAAU,GACV,UAAU,GACV,UAAU,GACV,SAAS,GACT,UAAU,GACV,SAAS,GACT,WAAW,GACX,SAAS,GACT,aAAa,GACb,SAAS,CAAC;AAEd,MAAM,MAAM,eAAe,GACvB,YAAY,GACZ,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,aAAa,CAAC;AAElB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,WAAW,EAAE,WAAW,CA4LzD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CACvC,WAAW,EACX,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAmGtB,CAAC"}
|