@visulima/vis 1.0.0-alpha.11 → 1.0.0-alpha.13

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 (116) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/LICENSE.md +559 -186
  3. package/README.md +18 -0
  4. package/dist/bin.js +1 -9
  5. package/dist/config/index.d.ts +477 -556
  6. package/dist/config/index.js +1 -2
  7. package/dist/generate/index.js +1 -3
  8. package/dist/packem_chunks/applyDefaults.js +2 -336
  9. package/dist/packem_chunks/bin.js +234 -9552
  10. package/dist/packem_chunks/doctor-probe.js +2 -112
  11. package/dist/packem_chunks/fix.js +11 -234
  12. package/dist/packem_chunks/handler.js +1 -99
  13. package/dist/packem_chunks/handler10.js +2 -53
  14. package/dist/packem_chunks/handler11.js +1 -32
  15. package/dist/packem_chunks/handler12.js +5 -100
  16. package/dist/packem_chunks/handler13.js +1 -25
  17. package/dist/packem_chunks/handler14.js +18 -916
  18. package/dist/packem_chunks/handler15.js +15 -201
  19. package/dist/packem_chunks/handler16.js +1 -124
  20. package/dist/packem_chunks/handler17.js +1 -13
  21. package/dist/packem_chunks/handler18.js +1 -106
  22. package/dist/packem_chunks/handler19.js +1 -19
  23. package/dist/packem_chunks/handler2.js +2 -75
  24. package/dist/packem_chunks/handler20.js +5 -29
  25. package/dist/packem_chunks/handler21.js +1 -222
  26. package/dist/packem_chunks/handler22.js +1 -237
  27. package/dist/packem_chunks/handler23.js +5 -101
  28. package/dist/packem_chunks/handler24.js +1 -110
  29. package/dist/packem_chunks/handler25.js +3 -402
  30. package/dist/packem_chunks/handler26.js +1 -13
  31. package/dist/packem_chunks/handler27.js +1 -63
  32. package/dist/packem_chunks/handler28.js +7 -34
  33. package/dist/packem_chunks/handler29.js +21 -456
  34. package/dist/packem_chunks/handler3.js +4 -95
  35. package/dist/packem_chunks/handler30.js +3 -170
  36. package/dist/packem_chunks/handler31.js +1 -530
  37. package/dist/packem_chunks/handler32.js +2 -214
  38. package/dist/packem_chunks/handler33.js +25 -119
  39. package/dist/packem_chunks/handler34.js +2 -630
  40. package/dist/packem_chunks/handler35.js +3 -283
  41. package/dist/packem_chunks/handler36.js +22 -542
  42. package/dist/packem_chunks/handler37.js +410 -744
  43. package/dist/packem_chunks/handler38.js +22 -989
  44. package/dist/packem_chunks/handler39.js +22 -574
  45. package/dist/packem_chunks/handler4.js +2 -90
  46. package/dist/packem_chunks/handler40.js +22 -1685
  47. package/dist/packem_chunks/handler41.js +6 -1088
  48. package/dist/packem_chunks/handler42.js +5 -797
  49. package/dist/packem_chunks/handler43.js +10 -2658
  50. package/dist/packem_chunks/handler44.js +51 -3784
  51. package/dist/packem_chunks/handler45.js +25 -2574
  52. package/dist/packem_chunks/handler46.js +3 -3769
  53. package/dist/packem_chunks/handler47.js +21 -1485
  54. package/dist/packem_chunks/handler48.js +42 -0
  55. package/dist/packem_chunks/handler5.js +8 -174
  56. package/dist/packem_chunks/handler6.js +1 -95
  57. package/dist/packem_chunks/handler7.js +1 -115
  58. package/dist/packem_chunks/handler8.js +1 -12
  59. package/dist/packem_chunks/handler9.js +1 -29
  60. package/dist/packem_chunks/heal-accept.js +10 -522
  61. package/dist/packem_chunks/heal.js +14 -673
  62. package/dist/packem_chunks/index.js +7 -873
  63. package/dist/packem_chunks/loader.js +1 -23
  64. package/dist/packem_chunks/tar.js +3 -0
  65. package/dist/packem_shared/ai-analysis-hm8d2W7z.js +67 -0
  66. package/dist/packem_shared/ai-cache-DoiF80AR.js +1 -0
  67. package/dist/packem_shared/ai-fix-nn4zOE95.js +43 -0
  68. package/dist/packem_shared/cache-directory-CwHlJhgx.js +1 -0
  69. package/dist/packem_shared/dependency-scan-COr5n63B.js +2 -0
  70. package/dist/packem_shared/docker-D6OGr5_S.js +2 -0
  71. package/dist/packem_shared/failure-log-iUVLf6ts.js +2 -0
  72. package/dist/packem_shared/flakiness-D9wf0t56.js +1 -0
  73. package/dist/packem_shared/giget-CcEy_Elm.js +2 -0
  74. package/dist/packem_shared/index-DH-5hsrC.js +1 -0
  75. package/dist/packem_shared/otel-DxDUPJJH.js +6 -0
  76. package/dist/packem_shared/otelPlugin-CQq6poq8.js +1 -0
  77. package/dist/packem_shared/registry-CkubDdiY.js +2 -0
  78. package/dist/packem_shared/run-summary-utils-BfBvjzhY.js +1 -0
  79. package/dist/packem_shared/runtime-check-BXZ43CBW.js +1 -0
  80. package/dist/packem_shared/selectors-BylODRiM.js +3 -0
  81. package/dist/packem_shared/symbols-CQmER5MT.js +1 -0
  82. package/dist/packem_shared/toolchain-BgBOUHII.js +5 -0
  83. package/dist/packem_shared/typosquats-CcZl99B1.js +1 -0
  84. package/dist/packem_shared/use-measured-height-DjYgUOKk.js +1 -0
  85. package/dist/packem_shared/utils-DrNg0XTR.js +1 -0
  86. package/dist/packem_shared/verify-Baj5mFJ7.js +1 -0
  87. package/dist/packem_shared/vis-update-app-D1jl0UZZ.js +1 -0
  88. package/dist/packem_shared/xxh3-DrAUNq4n.js +1 -0
  89. package/index.js +556 -727
  90. package/package.json +19 -29
  91. package/schemas/project.schema.json +739 -297
  92. package/schemas/vis-config.schema.json +3365 -384
  93. package/templates/buildkite-ci/template.yml +20 -20
  94. package/dist/packem_shared/VisUpdateApp-D-Yz_wvg.js +0 -1316
  95. package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +0 -5
  96. package/dist/packem_shared/ai-analysis-CHeB1joD.js +0 -367
  97. package/dist/packem_shared/ai-cache-Be_jexe4.js +0 -142
  98. package/dist/packem_shared/ai-fix-B9iQVcD2.js +0 -379
  99. package/dist/packem_shared/cache-directory-2qvs4goY.js +0 -98
  100. package/dist/packem_shared/catalog-BJTtyi-O.js +0 -1371
  101. package/dist/packem_shared/dependency-scan-A0KSklpG.js +0 -188
  102. package/dist/packem_shared/docker-2iZzc280.js +0 -181
  103. package/dist/packem_shared/failure-log-Cz3Z4SKL.js +0 -100
  104. package/dist/packem_shared/flakiness-goTxXuCX.js +0 -180
  105. package/dist/packem_shared/otel-DCvqCTz_.js +0 -158
  106. package/dist/packem_shared/otelPlugin-DFaLDvJf.js +0 -3
  107. package/dist/packem_shared/registry-CbqXI0rc.js +0 -272
  108. package/dist/packem_shared/run-summary-utils-PVMl4aIh.js +0 -130
  109. package/dist/packem_shared/runtime-check-Cobi3p6l.js +0 -127
  110. package/dist/packem_shared/selectors-SM69TfqC.js +0 -194
  111. package/dist/packem_shared/symbols-Ta7g2nU-.js +0 -14
  112. package/dist/packem_shared/toolchain-BdZd9eBi.js +0 -975
  113. package/dist/packem_shared/typosquats-C-bCh3PX.js +0 -1210
  114. package/dist/packem_shared/use-measured-height-CNP0vT4M.js +0 -20
  115. package/dist/packem_shared/utils-CthVdBPS.js +0 -40
  116. package/dist/packem_shared/xxh3-Ck8mXNg1.js +0 -239
@@ -1,530 +1 @@
1
- import { dim, yellow, cyan, magenta, red } from '@visulima/colorize';
2
- import { isAccessibleSync, readFileSync, writeFileSync } from '@visulima/fs';
3
- import { readYamlSync } from '@visulima/fs/yaml';
4
- import { join } from '@visulima/path';
5
- import { c as detectPm, p as pail, f as fetchSocketReports, t as findAcceptedRisk, D as DEFAULT_LOW_SCORE_THRESHOLD, a as buildSocketOptions, H as scoreLabel, J as getFullPackageName } from './bin.js';
6
- import { l as lockedPackages, f as findDuplicateDependencies, s as startScanProgress } from '../packem_shared/dependency-scan-A0KSklpG.js';
7
- import { a as fetchVulnerabilities } from '../packem_shared/catalog-BJTtyi-O.js';
8
-
9
- const toStringArray = (value) => {
10
- if (!Array.isArray(value)) {
11
- return [];
12
- }
13
- return value.filter((v) => typeof v === "string");
14
- };
15
- const matchesGlobList = (value, patterns) => {
16
- for (const pattern of patterns) {
17
- if (pattern === value) {
18
- return true;
19
- }
20
- if (pattern.endsWith("*") && value.startsWith(pattern.slice(0, -1))) {
21
- return true;
22
- }
23
- }
24
- return false;
25
- };
26
- const readPnpmAuditExclusions = (workspaceRoot) => {
27
- const filePath = join(workspaceRoot, "pnpm-workspace.yaml");
28
- if (!isAccessibleSync(filePath)) {
29
- return { excludedPackages: [], ignoredAdvisories: [] };
30
- }
31
- try {
32
- const data = readYamlSync(filePath);
33
- return {
34
- excludedPackages: [],
35
- ignoredAdvisories: [...toStringArray(data?.auditConfig?.ignoreCves), ...toStringArray(data?.auditConfig?.ignoreGhsas)]
36
- };
37
- } catch {
38
- return { excludedPackages: [], ignoredAdvisories: [] };
39
- }
40
- };
41
- const readYarnAuditExclusions = (workspaceRoot) => {
42
- const filePath = join(workspaceRoot, ".yarnrc.yml");
43
- if (!isAccessibleSync(filePath)) {
44
- return { excludedPackages: [], ignoredAdvisories: [] };
45
- }
46
- try {
47
- const data = readYamlSync(filePath);
48
- return {
49
- excludedPackages: toStringArray(data?.npmAuditExcludePackages),
50
- ignoredAdvisories: toStringArray(data?.npmAuditIgnoreAdvisories)
51
- };
52
- } catch {
53
- return { excludedPackages: [], ignoredAdvisories: [] };
54
- }
55
- };
56
- const readNativeAuditExclusions = (workspaceRoot, pm) => {
57
- switch (pm) {
58
- case "pnpm": {
59
- return readPnpmAuditExclusions(workspaceRoot);
60
- }
61
- case "yarn": {
62
- return readYarnAuditExclusions(workspaceRoot);
63
- }
64
- default: {
65
- return { excludedPackages: [], ignoredAdvisories: [] };
66
- }
67
- }
68
- };
69
- const isAdvisoryExcluded = (vulnId, exclusions, aliases) => {
70
- if (matchesGlobList(vulnId, exclusions.ignoredAdvisories)) {
71
- return true;
72
- }
73
- if (aliases) {
74
- for (const alias of aliases) {
75
- if (matchesGlobList(alias, exclusions.ignoredAdvisories)) {
76
- return true;
77
- }
78
- }
79
- }
80
- return false;
81
- };
82
- const isPackageExcluded = (packageName, exclusions) => matchesGlobList(packageName, exclusions.excludedPackages);
83
- const syncAcceptedRisksToNativeConfig = (pm, workspaceRoot, advisoryIds) => {
84
- if (advisoryIds.length === 0) {
85
- return ["No advisory IDs to sync."];
86
- }
87
- const actions = [];
88
- switch (pm) {
89
- case "bun": {
90
- actions.push(`bun has no audit config file. Use CLI flags: bun audit ${advisoryIds.map((id) => `--ignore ${id}`).join(" ")}`);
91
- break;
92
- }
93
- case "npm": {
94
- actions.push("npm has no native audit exclusion config. vis accepted risks are the only layer.");
95
- break;
96
- }
97
- case "pnpm": {
98
- const filePath = join(workspaceRoot, "pnpm-workspace.yaml");
99
- if (!isAccessibleSync(filePath)) {
100
- actions.push("pnpm-workspace.yaml not found. Cannot sync.");
101
- break;
102
- }
103
- const existing = readPnpmAuditExclusions(workspaceRoot);
104
- const existingCves = new Set(existing.ignoredAdvisories.filter((id) => id.startsWith("CVE-")));
105
- const existingGhsas = new Set(existing.ignoredAdvisories.filter((id) => id.startsWith("GHSA-")));
106
- const newCves = advisoryIds.filter((id) => id.startsWith("CVE-"));
107
- const newGhsas = advisoryIds.filter((id) => id.startsWith("GHSA-"));
108
- const mergedCves = [.../* @__PURE__ */ new Set([...existingCves, ...newCves])];
109
- const mergedGhsas = [.../* @__PURE__ */ new Set([...existingGhsas, ...newGhsas])];
110
- const addedCves = newCves.filter((id) => !existingCves.has(id)).length;
111
- const addedGhsas = newGhsas.filter((id) => !existingGhsas.has(id)).length;
112
- if (addedCves === 0 && addedGhsas === 0) {
113
- actions.push("All advisory IDs already present in pnpm-workspace.yaml.");
114
- break;
115
- }
116
- let content = readFileSync(filePath);
117
- if (mergedCves.length > 0) {
118
- const cveBlock = ` ignoreCves:
119
- ${mergedCves.map((id) => ` - ${id}`).join("\n")}
120
- `;
121
- if (/auditConfig:/.test(content)) {
122
- content = /ignoreCves:/.test(content) ? content.replace(/ignoreCves:\s*\n(?:\s+-\s+(?:\S.*|[\t\v\f \u00A0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF])\n)*/, cveBlock) : content.replace(/auditConfig:\s*\n/, `auditConfig:
123
- ${cveBlock}`);
124
- } else {
125
- content = `${content.trimEnd()}
126
-
127
- auditConfig:
128
- ${cveBlock}`;
129
- }
130
- if (addedCves > 0) {
131
- actions.push(`Added ${String(addedCves)} new CVE${addedCves === 1 ? "" : "s"} to pnpm-workspace.yaml (${String(mergedCves.length)} total)`);
132
- }
133
- }
134
- if (mergedGhsas.length > 0) {
135
- const ghsaBlock = ` ignoreGhsas:
136
- ${mergedGhsas.map((id) => ` - ${id}`).join("\n")}
137
- `;
138
- if (/auditConfig:/.test(content)) {
139
- content = /ignoreGhsas:/.test(content) ? content.replace(/ignoreGhsas:\s*\n(?:\s+-\s+(?:\S.*|[\t\v\f \u00A0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF])\n)*/, ghsaBlock) : content.replace(/(auditConfig:[\s\S]*?)(\n\S|\n?$)/m, `$1${ghsaBlock}$2`);
140
- }
141
- if (addedGhsas > 0) {
142
- actions.push(
143
- `Added ${String(addedGhsas)} new GHSA${addedGhsas === 1 ? "" : "s"} to pnpm-workspace.yaml (${String(mergedGhsas.length)} total)`
144
- );
145
- }
146
- }
147
- writeFileSync(filePath, content);
148
- break;
149
- }
150
- case "yarn": {
151
- const filePath = join(workspaceRoot, ".yarnrc.yml");
152
- if (!isAccessibleSync(filePath)) {
153
- actions.push(".yarnrc.yml not found. Cannot sync.");
154
- break;
155
- }
156
- const existingYarn = readYarnAuditExclusions(workspaceRoot);
157
- const existingSet = new Set(existingYarn.ignoredAdvisories);
158
- const merged = [.../* @__PURE__ */ new Set([...existingSet, ...advisoryIds])];
159
- const added = advisoryIds.filter((id) => !existingSet.has(id)).length;
160
- if (added === 0) {
161
- actions.push("All advisory IDs already present in .yarnrc.yml.");
162
- break;
163
- }
164
- let content = readFileSync(filePath);
165
- const advisoryBlock = `npmAuditIgnoreAdvisories:
166
- ${merged.map((id) => ` - "${id}"`).join("\n")}
167
- `;
168
- content = /npmAuditIgnoreAdvisories:/.test(content) ? content.replace(
169
- /npmAuditIgnoreAdvisories:\s*\n(?:\s+-\s+(?:\S.*|[\t\v\f \u00A0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF])\n)*/,
170
- advisoryBlock
171
- ) : `${content.trimEnd()}
172
-
173
- ${advisoryBlock}`;
174
- writeFileSync(filePath, content);
175
- actions.push(`Synced ${String(added)} advisor${added === 1 ? "y" : "ies"} to .yarnrc.yml (${String(merged.length)} total)`);
176
- break;
177
- }
178
- default: {
179
- actions.push(`Unknown package manager: ${pm}`);
180
- }
181
- }
182
- return actions;
183
- };
184
-
185
- const SEVERITY_ORDER = {
186
- CRITICAL: 0,
187
- HIGH: 1,
188
- LOW: 3,
189
- MODERATE: 2,
190
- UNKNOWN: 4
191
- };
192
- const SOCKET_ALERT_COLORS = {
193
- critical: red,
194
- high: magenta,
195
- low: cyan,
196
- medium: yellow
197
- };
198
- const severityPassesFilter = (severity, filter) => {
199
- const filterLevel = SEVERITY_ORDER[filter.toUpperCase()] ?? SEVERITY_ORDER.MODERATE ?? 2;
200
- const vulnLevel = SEVERITY_ORDER[severity.toUpperCase()] ?? 4;
201
- return vulnLevel <= filterLevel;
202
- };
203
- const SEVERITY_COLOR_FN = {
204
- CRITICAL: red,
205
- HIGH: magenta,
206
- LOW: cyan,
207
- MODERATE: yellow,
208
- UNKNOWN: dim
209
- };
210
- const formatVulnLine = (name, version, vuln, isAccepted) => {
211
- const colorFunction = SEVERITY_COLOR_FN[vuln.severity] ?? dim;
212
- const badge = isAccepted ? ` ${dim("[acknowledged]")}` : "";
213
- const fixedVersions = vuln.fixedVersions ?? [];
214
- const fixed = fixedVersions.length > 0 ? ` (fix: ${fixedVersions.join(", ")})` : "";
215
- return ` ${colorFunction(vuln.severity)} ${vuln.id} — ${name}@${version}${badge}
216
- ${vuln.summary}${fixed}`;
217
- };
218
- const formatSocketLine = (report, isAccepted) => {
219
- const name = getFullPackageName(report);
220
- const pct = `${String(Math.round(report.score.overall * 100))}%`;
221
- const badge = isAccepted ? ` ${dim("[acknowledged]")}` : "";
222
- const alerts = report.alerts.length > 0 ? `, ${String(report.alerts.length)} alert${report.alerts.length === 1 ? "" : "s"}` : "";
223
- return ` ${pct} ${name}@${report.version} (${scoreLabel(report.score.overall)}${alerts})${badge}`;
224
- };
225
- const executeAudit = async (workspaceRoot, options, visConfig, _logger) => {
226
- const severityFilter = options.severity ?? "low";
227
- const isJson = options.format === "json" || Boolean(options.json);
228
- const showFixes = Boolean(options.fix);
229
- const showAccepted = Boolean(options.showAccepted);
230
- const socketConfig = visConfig?.security?.socket;
231
- const acceptedRisks = socketConfig?.acceptedRisks;
232
- const pm = detectPm(workspaceRoot);
233
- const nativeExclusions = readNativeAuditExclusions(workspaceRoot, pm.name);
234
- if (nativeExclusions.ignoredAdvisories.length > 0 || nativeExclusions.excludedPackages.length > 0) {
235
- pail.info(
236
- `Loaded ${String(nativeExclusions.ignoredAdvisories.length)} ignored advisor${nativeExclusions.ignoredAdvisories.length === 1 ? "y" : "ies"} and ${String(nativeExclusions.excludedPackages.length)} excluded package${nativeExclusions.excludedPackages.length === 1 ? "" : "s"} from ${pm.name} config.`
237
- );
238
- }
239
- const installed = lockedPackages(workspaceRoot, pm.name);
240
- if (installed.length === 0) {
241
- pail.info(`No ${pm.name} lockfile entries found. Run ${pm.name} install first.`);
242
- return;
243
- }
244
- if (!isJson) {
245
- pail.info(`Scanning ${String(installed.length)} installed packages…`);
246
- }
247
- const packagesToScan = installed.map((p) => {
248
- return { name: p.name, version: p.version };
249
- });
250
- const socketOptions = buildSocketOptions(socketConfig);
251
- const duplicates = findDuplicateDependencies(workspaceRoot, pm.name);
252
- const progressTasks = [
253
- { id: "vulnerabilities", label: "Known vulnerabilities (OSV)" },
254
- ...socketOptions ? [{ id: "socket", label: "Socket.dev supply-chain reports" }] : []
255
- ];
256
- const progress = startScanProgress(progressTasks, { live: !isJson });
257
- const startedAt = Date.now();
258
- const fmtElapsed = (start) => {
259
- const ms = Date.now() - start;
260
- return ms >= 1e3 ? `${(ms / 1e3).toFixed(1)}s` : `${String(Math.round(ms))}ms`;
261
- };
262
- let vulnMap;
263
- let socketReports;
264
- try {
265
- const vulnStart = Date.now();
266
- const socketStart = Date.now();
267
- progress.start("vulnerabilities");
268
- if (socketOptions) {
269
- progress.start("socket");
270
- }
271
- [vulnMap, socketReports] = await Promise.all([
272
- fetchVulnerabilities(packagesToScan).then((map) => {
273
- let count = 0;
274
- for (const list of map.values()) {
275
- count += list.length;
276
- }
277
- progress.finish(
278
- "vulnerabilities",
279
- count > 0 ? "warn" : "ok",
280
- count > 0 ? `${String(count)} found · ${fmtElapsed(vulnStart)}` : `none found · ${fmtElapsed(vulnStart)}`
281
- );
282
- return map;
283
- }).catch((error) => {
284
- const message = error instanceof Error ? error.message : String(error);
285
- progress.finish("vulnerabilities", "error", message);
286
- return /* @__PURE__ */ new Map();
287
- }),
288
- socketOptions ? fetchSocketReports(packagesToScan, socketOptions).then((reports) => {
289
- let alerts = 0;
290
- let low = 0;
291
- for (const report of reports.values()) {
292
- alerts += report.alerts.length;
293
- if (report.score.overall < DEFAULT_LOW_SCORE_THRESHOLD) {
294
- low += 1;
295
- }
296
- }
297
- const total = alerts + low;
298
- progress.finish(
299
- "socket",
300
- total > 0 ? "warn" : "ok",
301
- total > 0 ? `${String(alerts)} alert${alerts === 1 ? "" : "s"}, ${String(low)} low-score · ${fmtElapsed(socketStart)}` : `clean · ${fmtElapsed(socketStart)}`
302
- );
303
- return reports;
304
- }).catch((error) => {
305
- const message = error instanceof Error ? error.message : String(error);
306
- progress.finish("socket", "error", message);
307
- return /* @__PURE__ */ new Map();
308
- }) : Promise.resolve(/* @__PURE__ */ new Map())
309
- ]);
310
- } finally {
311
- progress.stop();
312
- }
313
- if (!isJson) {
314
- pail.info(dim(`Scan completed in ${fmtElapsed(startedAt)}`));
315
- }
316
- const entries = [];
317
- for (const pkg of installed) {
318
- if (isPackageExcluded(pkg.name, nativeExclusions)) {
319
- continue;
320
- }
321
- const vulns = vulnMap.get(pkg.name) ?? [];
322
- const report = socketReports.get(`${pkg.name}@${pkg.version}`);
323
- const accepted = findAcceptedRisk(pkg.name, pkg.version, acceptedRisks);
324
- const hasVulns = vulns.length > 0;
325
- const hasLowScore = report ? report.score.overall < DEFAULT_LOW_SCORE_THRESHOLD : false;
326
- const hasAlerts = report ? report.alerts.length > 0 : false;
327
- if (hasVulns || hasLowScore || hasAlerts) {
328
- entries.push({
329
- acceptedRisk: accepted,
330
- name: pkg.name,
331
- socketReport: report,
332
- version: pkg.version,
333
- vulnerabilities: vulns
334
- });
335
- }
336
- }
337
- const filtered = entries.filter((entry) => {
338
- const vulnPasses = entry.vulnerabilities.some((v) => severityPassesFilter(v.severity, severityFilter));
339
- const socketPasses = entry.socketReport?.alerts.some(
340
- (a) => severityPassesFilter(a.severity === "medium" ? "MODERATE" : a.severity.toUpperCase(), severityFilter)
341
- );
342
- const lowScorePasses = entry.socketReport && entry.socketReport.score.overall < DEFAULT_LOW_SCORE_THRESHOLD;
343
- return vulnPasses || socketPasses || lowScorePasses;
344
- });
345
- if (isJson) {
346
- const jsonResult = {
347
- duplicates: duplicates.map((d) => {
348
- return {
349
- name: d.name,
350
- versionCount: d.versions.length,
351
- versions: d.versions
352
- };
353
- }),
354
- packages: installed.length,
355
- results: filtered.map((e) => {
356
- return {
357
- acceptedRisk: e.acceptedRisk ?? null,
358
- name: e.name,
359
- socketAlerts: e.socketReport?.alerts ?? [],
360
- socketScore: e.socketReport?.score.overall ?? null,
361
- version: e.version,
362
- vulnerabilities: e.vulnerabilities
363
- };
364
- }),
365
- summary: {
366
- accepted: filtered.filter((e) => e.acceptedRisk).length,
367
- duplicatePackages: duplicates.length,
368
- issues: filtered.filter((e) => !e.acceptedRisk).length,
369
- total: filtered.length
370
- }
371
- };
372
- process.stdout.write(`${JSON.stringify(jsonResult, void 0, 2)}
373
- `);
374
- if (options.exitCode && jsonResult.summary.issues > 0) {
375
- process.exitCode = 1;
376
- }
377
- return;
378
- }
379
- if (filtered.length === 0) {
380
- pail.success(`No security issues found across ${String(installed.length)} packages.`);
381
- return;
382
- }
383
- const vulnsBySeverity = {
384
- CRITICAL: [],
385
- HIGH: [],
386
- LOW: [],
387
- MODERATE: []
388
- };
389
- for (const entry of filtered) {
390
- for (const vuln of entry.vulnerabilities) {
391
- if (severityPassesFilter(vuln.severity, severityFilter)) {
392
- const key = vuln.severity === "UNKNOWN" ? "LOW" : vuln.severity;
393
- vulnsBySeverity[key]?.push({ entry, vuln });
394
- }
395
- }
396
- }
397
- let totalVulns = 0;
398
- let acknowledgedVulns = 0;
399
- for (const severity of ["CRITICAL", "HIGH", "MODERATE", "LOW"]) {
400
- const items = vulnsBySeverity[severity];
401
- if (!items || items.length === 0) {
402
- continue;
403
- }
404
- pail.info(`
405
- ── ${severity} (${String(items.length)}) ──`);
406
- for (const { entry, vuln } of items) {
407
- const isExcluded = Boolean(entry.acceptedRisk) || isAdvisoryExcluded(vuln.id, nativeExclusions, vuln.aliases);
408
- if (isExcluded) {
409
- acknowledgedVulns++;
410
- if (!showAccepted) {
411
- continue;
412
- }
413
- }
414
- totalVulns++;
415
- pail.info(formatVulnLine(entry.name, entry.version, vuln, isExcluded));
416
- if (showFixes && (vuln.fixedVersions ?? []).length > 0) {
417
- pail.notice(` Fix: update to ${vuln.fixedVersions.at(-1)}`);
418
- }
419
- }
420
- }
421
- const socketIssues = filtered.filter(
422
- (e) => e.socketReport && (e.socketReport.score.overall < DEFAULT_LOW_SCORE_THRESHOLD || e.socketReport.alerts.length > 0)
423
- );
424
- if (socketIssues.length > 0) {
425
- pail.info(`
426
- ── Socket.dev Supply Chain (${String(socketIssues.length)}) ──`);
427
- for (const entry of socketIssues) {
428
- if (!entry.socketReport) {
429
- continue;
430
- }
431
- const isExcluded = Boolean(entry.acceptedRisk);
432
- if (isExcluded && !showAccepted) {
433
- continue;
434
- }
435
- pail.info(formatSocketLine(entry.socketReport, isExcluded));
436
- for (const alert of entry.socketReport.alerts) {
437
- const alertColorFunction = SOCKET_ALERT_COLORS[alert.severity] ?? dim;
438
- pail.info(` ${alertColorFunction(`[${alert.severity.toUpperCase()}]`)} ${alert.type} — ${alert.category}`);
439
- }
440
- }
441
- }
442
- if (duplicates.length > 0) {
443
- pail.info(`
444
- ── Duplicate Dependencies (${String(duplicates.length)}) ──`);
445
- for (const dup of duplicates) {
446
- const versionList = dup.versions.join(", ");
447
- pail.info(` ${dup.name} — ${String(dup.versions.length)} versions: ${yellow(versionList)}`);
448
- }
449
- }
450
- const isEntryExcluded = (e) => Boolean(e.acceptedRisk) || e.vulnerabilities.length > 0 && e.vulnerabilities.every((v) => isAdvisoryExcluded(v.id, nativeExclusions, v.aliases));
451
- const unacknowledgedCount = filtered.filter((e) => !isEntryExcluded(e)).length;
452
- pail.info("");
453
- pail.info(`─ Audit Summary`);
454
- pail.info(` ${String(installed.length)} packages scanned`);
455
- if (nativeExclusions.ignoredAdvisories.length > 0) {
456
- pail.info(
457
- ` ${String(nativeExclusions.ignoredAdvisories.length)} ${pm.name} audit exclusion${nativeExclusions.ignoredAdvisories.length === 1 ? "" : "s"} applied`
458
- );
459
- }
460
- if (totalVulns > 0) {
461
- const critCount = vulnsBySeverity.CRITICAL?.filter((i) => !isEntryExcluded(i.entry)).length ?? 0;
462
- const highCount = vulnsBySeverity.HIGH?.filter((i) => !isEntryExcluded(i.entry)).length ?? 0;
463
- pail.error(` ${String(totalVulns)} vulnerabilit${totalVulns === 1 ? "y" : "ies"} found`);
464
- if (critCount > 0) {
465
- pail.error(` ${String(critCount)} critical`);
466
- }
467
- if (highCount > 0) {
468
- pail.warn(` ${String(highCount)} high`);
469
- }
470
- } else {
471
- pail.success(" No vulnerabilities found");
472
- }
473
- if (socketIssues.length > 0) {
474
- const unacknowledgedSocket = socketIssues.filter((e) => !isEntryExcluded(e)).length;
475
- pail.warn(` ${String(unacknowledgedSocket)} package${unacknowledgedSocket === 1 ? "" : "s"} with Socket.dev supply chain issues`);
476
- }
477
- if (duplicates.length > 0) {
478
- pail.warn(` ${String(duplicates.length)} package${duplicates.length === 1 ? "" : "s"} with duplicate versions`);
479
- pail.notice(" Run 'vis dedupe' or your package manager's dedupe command to reduce duplicates.");
480
- }
481
- if (acknowledgedVulns > 0) {
482
- pail.info(` ${String(acknowledgedVulns)} acknowledged (accepted risks)`);
483
- if (!showAccepted) {
484
- pail.notice(" Use --show-accepted to see acknowledged issues.");
485
- }
486
- }
487
- if (unacknowledgedCount === 0) {
488
- pail.success("\n All issues are acknowledged. No action required.");
489
- }
490
- if (options.sync && acceptedRisks) {
491
- const idSet = /* @__PURE__ */ new Set();
492
- for (const entry of entries) {
493
- if (entry.acceptedRisk) {
494
- for (const vuln of entry.vulnerabilities) {
495
- if (vuln.id.startsWith("CVE-") || vuln.id.startsWith("GHSA-")) {
496
- idSet.add(vuln.id);
497
- }
498
- if (vuln.aliases) {
499
- for (const alias of vuln.aliases) {
500
- if (alias.startsWith("CVE-") || alias.startsWith("GHSA-")) {
501
- idSet.add(alias);
502
- }
503
- }
504
- }
505
- }
506
- }
507
- }
508
- const advisoryIds = [...idSet];
509
- if (advisoryIds.length > 0) {
510
- pail.info("");
511
- const actions = syncAcceptedRisksToNativeConfig(pm.name, workspaceRoot, advisoryIds);
512
- for (const action of actions) {
513
- pail.success(` ${action}`);
514
- }
515
- } else {
516
- pail.info("\nNo advisory IDs to sync to native PM config.");
517
- }
518
- }
519
- if (options.exitCode && unacknowledgedCount > 0) {
520
- process.exitCode = 1;
521
- }
522
- };
523
- const execute = async ({ logger, options, visConfig, workspaceRoot: wsRoot }) => {
524
- if (!wsRoot) {
525
- throw new Error("Could not determine workspace root. Run this command inside a monorepo.");
526
- }
527
- await executeAudit(wsRoot, options, visConfig);
528
- };
529
-
530
- export { execute as default };
1
+ var C=Object.defineProperty;var T=(e,t)=>C(e,"name",{value:t,configurable:!0});import{relative as S}from"@visulima/path";import{K as q,k as b}from"./bin.js";import{f as $}from"../packem_shared/selectors-BylODRiM.js";import{o as L}from"../packem_shared/index-DH-5hsrC.js";var M=Object.defineProperty,I=T((e,t)=>M(e,"name",{value:t,configurable:!0}),"p");const D=I((e,t)=>{for(const f of t)if(L(f,e))return!0;return!1},"matchesAny"),B=I((e,t={})=>{const{depTypes:f,excludePatterns:l,externalOnly:y,includePatterns:d,internalOnly:j}=t;if(j&&y)return[];const u=f&&f.length>0?new Set(f):void 0,N=d&&d.length>0?d:void 0,O=l&&l.length>0?l:void 0,w=[];for(const m of e)j&&!m.isInternal||y&&m.isInternal||u&&!u.has(m.depType)||N&&(!m.packageName||!D(m.packageName,N))||O&&m.packageName&&D(m.packageName,O)||w.push(m);return w},"filterDepInstances");var F=Object.defineProperty,v=T((e,t)=>F(e,"name",{value:t,configurable:!0}),"y");const R=new Set(["json","ndjson","table"]),V=v(e=>{if(e===void 0)return"table";const t=e.toLowerCase();if(!R.has(t))throw new Error(`--format must be one of: table, json, ndjson (got "${e}")`);return t},"resolveFormat"),x=v((e,t)=>({depName:e.depName,depType:e.depType,isInternal:e.isInternal,packageDir:e.packageDir,packageJsonPath:S(t,e.packageJsonPath),packageName:e.packageName,specifier:e.specifier}),"toDepRecord"),P=new Set(["dependencies","devDependencies","optionalDependencies","overrides","peerDependencies","pnpm.overrides","resolutions"]),A=v(e=>{if(!e||e.length===0)return;const t=[],f=[];for(const l of e)for(const y of l.split(",")){const d=y.trim();d&&(P.has(d)?t.push(d):f.push(d))}if(f.length>0)throw new Error(`Unknown --dep-type value(s): ${f.join(", ")}. Valid: ${[...P].join(", ")}`);return t.length>0?t:void 0},"parseDepTypes"),G=v(async({logger:e,options:t,visConfig:f,workspaceRoot:l})=>{if(!l)throw new Error("Could not determine workspace root.");const y=V(t.format);if(t.deps===!0){if(t.internalOnly&&t.externalOnly)throw new Error("--internal-only and --external-only are mutually exclusive");const c=A(t.depType),i=q(l);let n=B(i,{depTypes:c,excludePatterns:t.exclude,externalOnly:t.externalOnly,includePatterns:t.include,internalOnly:t.internalOnly});if(t.query){const{workspace:r}=b(l,f),p=new Set($(Object.keys(r.projects),r,t.query));n=n.filter(k=>k.packageName!==void 0&&p.has(k.packageName))}const g=[...n].sort((r,p)=>{const k=`${r.packageName??r.packageDir} ${r.depType} ${r.depName}`,J=`${p.packageName??p.packageDir} ${p.depType} ${p.depName}`;return k.localeCompare(J)});if(y==="ndjson"){for(const r of g)e.info(JSON.stringify(x(r,l)));return}if(y==="json"){const r=g.map(p=>x(p,l));e.info(JSON.stringify(r,null,t.pretty===!0?2:void 0));return}if(g.length===0){e.info("No matching dep-instances.");return}const a=["Package","Block","Dep","Specifier","Internal","Path"],o=g.map(r=>[r.packageName??r.packageDir,r.depType,r.depName,r.specifier,r.isInternal?"yes":"no",S(l,r.packageJsonPath)]),s=a.map((r,p)=>Math.max(r.length,...o.map(k=>(k[p]??"").length))),h=v((r,p)=>r.padEnd(p),"pad");e.info(a.map((r,p)=>h(r,s[p])).join(" ")),e.info(s.map(r=>"─".repeat(r)).join("──"));for(const r of o)e.info(r.map((p,k)=>h(p,s[k])).join(" "));e.info(""),e.info(`${String(g.length)} dep-instance(s)`);return}if(y==="ndjson")throw new Error("--format=ndjson is only supported with --deps");const{projectOptions:d,workspace:j}=b(l,f);let u=Object.keys(j.projects).sort();if(t.query&&(u=$(u,j,t.query)),u.length===0){e.info("No projects found.");return}const N=t.inferred===!0,O=t.targets===!0||N;if(y==="json"){const c=u.map(i=>{const n=j.projects[i],g=d.get(i)??{},a=Object.entries(n.targets??{}).map(([o])=>{const s=g[o],h=s?.inferred===!0;return{aliases:s?.aliases??[],command:s?.command,description:s?.description,...h?{inferred:!0}:{},name:o,type:s?.type}}).filter(o=>!N||o.inferred===!0);return{language:n.language,layer:n.layer,name:i,root:n.root,stack:n.stack,tags:n.tags??[],targets:a,type:n.projectType??"library"}});e.info(JSON.stringify(c,null,2));return}const w=v((c,i)=>{const n=c.map((a,o)=>{let s=0;for(const h of i)s=Math.max(s,(h[o]??"").length);return Math.max(a.length,s)}),g=v((a,o)=>a.padEnd(o),"pad");e.info(c.map((a,o)=>g(a,n[o])).join(" ")),e.info(n.map(a=>"─".repeat(a)).join("──"));for(const a of i)e.info(a.map((o,s)=>g(o,n[s])).join(" "))},"renderTable");if(O){const c=[];for(const i of u){const n=j.projects[i],g=d.get(i)??{};for(const a of Object.keys(n.targets??{}).sort()){const o=g[a],s=o?.inferred===!0;if(N&&!s)continue;const h=n.targets?.[a],r=h?.cache===!1?"no":h?.cache===!0?"yes":"default";c.push([i,a,o?.type??"—",r,s?"yes":"no",o?.description??"—"])}}if(c.length===0){e.info(N?"No inferred targets found.":"No targets found.");return}w(["Project","Target","Type","Cache","Inferred","Description"],c),e.info(""),e.info(`${String(c.length)} target(s) across ${String(u.length)} project(s)`);return}const m=["Project","Type","Layer","Tags","Targets"],E=u.map(c=>{const i=j.projects[c],n=Object.keys(i.targets??{});return[c,i.projectType??"library",i.layer??"—",(i.tags??[]).join(", ")||"—",n.length>4?`${n.slice(0,4).join(", ")}… (${String(n.length)})`:n.join(", ")||"—"]});w(m,E),e.info(""),e.info(`${String(u.length)} project(s)`)},"execute");export{G as default};