aienvmp 0.1.9 → 0.1.10
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/security.js +58 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.10
|
|
4
|
+
|
|
5
|
+
- Added optional `pip-audit` JSON parsing for Python security summaries.
|
|
6
|
+
- Combined npm and Python vulnerable package summaries into the same AI-facing security context.
|
|
7
|
+
- Kept missing Python scanners non-blocking with explicit scanner availability metadata.
|
|
8
|
+
|
|
3
9
|
## 0.1.9
|
|
4
10
|
|
|
5
11
|
- Added top vulnerable package summaries for AI context, handoff, `AIENV.md`, and the dashboard.
|
package/package.json
CHANGED
package/src/security.js
CHANGED
|
@@ -14,15 +14,15 @@ export async function scanSecurity(dir, options = {}) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const npmAudit = await scanNpmAudit(dir);
|
|
17
|
+
const pipAudit = await scanPipAudit(dir);
|
|
18
|
+
const scanners = { npmAudit, pipAudit };
|
|
17
19
|
return {
|
|
18
20
|
mode: "security",
|
|
19
21
|
enabled: true,
|
|
20
22
|
note: "Read-only vulnerability summary. Use for review and CI policy, not automatic fixes.",
|
|
21
|
-
scanners
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
summary: summarizeScanners({ npmAudit }),
|
|
25
|
-
topPackages: topVulnerablePackages({ npmAudit })
|
|
23
|
+
scanners,
|
|
24
|
+
summary: summarizeScanners(scanners),
|
|
25
|
+
topPackages: topVulnerablePackages(scanners)
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -50,6 +50,29 @@ export async function scanNpmAudit(dir) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
export async function scanPipAudit(dir) {
|
|
54
|
+
const hasPythonHints = await exists(path.join(dir, "pyproject.toml")) || await exists(path.join(dir, "requirements.txt"));
|
|
55
|
+
if (!hasPythonHints) return unavailable("pip-audit", "Python project hints not found");
|
|
56
|
+
|
|
57
|
+
const result = await commandResult("pip-audit", ["-f", "json"], {
|
|
58
|
+
cwd: dir,
|
|
59
|
+
timeout: 15000,
|
|
60
|
+
maxBuffer: 4 * 1024 * 1024
|
|
61
|
+
});
|
|
62
|
+
const parsed = parsePipAudit(result.stdout);
|
|
63
|
+
if (!parsed.available) {
|
|
64
|
+
return unavailable("pip-audit", result.stderr || "pip-audit did not return parseable JSON");
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
scanner: "pip-audit",
|
|
68
|
+
available: true,
|
|
69
|
+
ok: result.ok,
|
|
70
|
+
exitCode: result.code,
|
|
71
|
+
summary: parsed.summary,
|
|
72
|
+
vulnerablePackages: parsed.vulnerablePackages
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
53
76
|
export function parseNpmAudit(raw) {
|
|
54
77
|
try {
|
|
55
78
|
const parsed = JSON.parse(raw || "{}");
|
|
@@ -73,6 +96,32 @@ export function parseNpmAudit(raw) {
|
|
|
73
96
|
}
|
|
74
97
|
}
|
|
75
98
|
|
|
99
|
+
export function parsePipAudit(raw) {
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(raw || "{}");
|
|
102
|
+
const dependencies = Array.isArray(parsed.dependencies) ? parsed.dependencies : [];
|
|
103
|
+
const vulnerablePackages = dependencies
|
|
104
|
+
.filter((dependency) => Array.isArray(dependency.vulns) && dependency.vulns.length)
|
|
105
|
+
.slice(0, 20)
|
|
106
|
+
.map((dependency) => ({
|
|
107
|
+
name: dependency.name || "unknown",
|
|
108
|
+
version: dependency.version || "unknown",
|
|
109
|
+
severity: "unknown",
|
|
110
|
+
viaCount: dependency.vulns.length,
|
|
111
|
+
fixAvailable: dependency.vulns.some((vuln) => Array.isArray(vuln.fix_versions) && vuln.fix_versions.length),
|
|
112
|
+
fixVersions: unique(dependency.vulns.flatMap((vuln) => vuln.fix_versions || [])).slice(0, 5)
|
|
113
|
+
}));
|
|
114
|
+
const total = vulnerablePackages.reduce((sum, pkg) => sum + pkg.viaCount, 0);
|
|
115
|
+
return {
|
|
116
|
+
available: true,
|
|
117
|
+
summary: { total, critical: 0, high: 0, moderate: 0, low: 0, info: 0 },
|
|
118
|
+
vulnerablePackages
|
|
119
|
+
};
|
|
120
|
+
} catch {
|
|
121
|
+
return { available: false };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
76
125
|
export function summarizeScanners(scanners = {}) {
|
|
77
126
|
const summary = { total: 0, critical: 0, high: 0, moderate: 0, low: 0, info: 0 };
|
|
78
127
|
for (const scanner of Object.values(scanners)) {
|
|
@@ -98,3 +147,7 @@ function unavailable(scanner, reason) {
|
|
|
98
147
|
reason
|
|
99
148
|
};
|
|
100
149
|
}
|
|
150
|
+
|
|
151
|
+
function unique(items) {
|
|
152
|
+
return [...new Set(items.filter(Boolean))];
|
|
153
|
+
}
|