@cyclonedx/cdxgen 12.3.0 → 12.3.2

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 (121) hide show
  1. package/README.md +15 -5
  2. package/bin/audit.js +7 -0
  3. package/bin/cdxgen.js +241 -81
  4. package/bin/repl.js +138 -0
  5. package/data/rules/ai-agent-governance.yaml +249 -0
  6. package/data/rules/dependency-sources.yaml +41 -0
  7. package/data/rules/mcp-servers.yaml +304 -0
  8. package/data/rules/package-integrity.yaml +123 -0
  9. package/lib/audit/index.js +353 -29
  10. package/lib/audit/index.poku.js +247 -7
  11. package/lib/audit/reporters.js +26 -0
  12. package/lib/audit/scoring.js +262 -13
  13. package/lib/audit/scoring.poku.js +179 -0
  14. package/lib/audit/targets.js +391 -2
  15. package/lib/audit/targets.poku.js +416 -3
  16. package/lib/cli/index.js +588 -45
  17. package/lib/cli/index.poku.js +735 -1
  18. package/lib/evinser/evinser.js +8 -5
  19. package/lib/helpers/agentFormulationParser.js +318 -0
  20. package/lib/helpers/aiInventory.js +262 -0
  21. package/lib/helpers/aiInventory.poku.js +111 -0
  22. package/lib/helpers/analyzer.js +1769 -0
  23. package/lib/helpers/analyzer.poku.js +284 -3
  24. package/lib/helpers/auditCategories.js +76 -0
  25. package/lib/helpers/ciParsers/githubActions.js +140 -16
  26. package/lib/helpers/ciParsers/githubActions.poku.js +110 -0
  27. package/lib/helpers/communityAiConfigParser.js +672 -0
  28. package/lib/helpers/communityAiConfigParser.poku.js +63 -0
  29. package/lib/helpers/depsUtils.js +108 -0
  30. package/lib/helpers/depsUtils.poku.js +72 -1
  31. package/lib/helpers/display.js +325 -3
  32. package/lib/helpers/display.poku.js +301 -0
  33. package/lib/helpers/formulationParsers.js +28 -0
  34. package/lib/helpers/formulationParsers.poku.js +504 -1
  35. package/lib/helpers/jsonLike.js +102 -0
  36. package/lib/helpers/jsonLike.poku.js +34 -0
  37. package/lib/helpers/mcp.js +248 -0
  38. package/lib/helpers/mcp.poku.js +101 -0
  39. package/lib/helpers/mcpConfigParser.js +656 -0
  40. package/lib/helpers/mcpConfigParser.poku.js +126 -0
  41. package/lib/helpers/mcpDiscovery.js +84 -0
  42. package/lib/helpers/mcpDiscovery.poku.js +21 -0
  43. package/lib/helpers/protobom.js +3 -3
  44. package/lib/helpers/provenanceUtils.js +29 -4
  45. package/lib/helpers/provenanceUtils.poku.js +29 -3
  46. package/lib/helpers/registryProvenance.js +210 -0
  47. package/lib/helpers/registryProvenance.poku.js +144 -0
  48. package/lib/helpers/rustFormulationParser.js +330 -0
  49. package/lib/helpers/source.js +21 -2
  50. package/lib/helpers/source.poku.js +38 -0
  51. package/lib/helpers/utils.js +1331 -83
  52. package/lib/helpers/utils.poku.js +599 -188
  53. package/lib/helpers/vsixutils.js +12 -4
  54. package/lib/helpers/vsixutils.poku.js +34 -0
  55. package/lib/managers/binary.js +36 -12
  56. package/lib/managers/binary.poku.js +68 -0
  57. package/lib/managers/docker.js +59 -9
  58. package/lib/managers/docker.poku.js +61 -0
  59. package/lib/managers/piptree.js +12 -7
  60. package/lib/managers/piptree.poku.js +44 -0
  61. package/lib/stages/postgen/annotator.js +2 -1
  62. package/lib/stages/postgen/annotator.poku.js +15 -0
  63. package/lib/stages/postgen/auditBom.js +20 -6
  64. package/lib/stages/postgen/auditBom.poku.js +694 -1
  65. package/lib/stages/postgen/postgen.js +262 -11
  66. package/lib/stages/postgen/postgen.poku.js +306 -2
  67. package/lib/stages/postgen/ruleEngine.js +49 -1
  68. package/lib/stages/postgen/spdxConverter.poku.js +70 -0
  69. package/lib/stages/pregen/pregen.js +6 -4
  70. package/package.json +1 -1
  71. package/types/bin/repl.d.ts.map +1 -1
  72. package/types/lib/audit/index.d.ts.map +1 -1
  73. package/types/lib/audit/reporters.d.ts.map +1 -1
  74. package/types/lib/audit/scoring.d.ts.map +1 -1
  75. package/types/lib/audit/targets.d.ts +12 -0
  76. package/types/lib/audit/targets.d.ts.map +1 -1
  77. package/types/lib/cli/index.d.ts +2 -8
  78. package/types/lib/cli/index.d.ts.map +1 -1
  79. package/types/lib/evinser/evinser.d.ts.map +1 -1
  80. package/types/lib/helpers/agentFormulationParser.d.ts +19 -0
  81. package/types/lib/helpers/agentFormulationParser.d.ts.map +1 -0
  82. package/types/lib/helpers/aiInventory.d.ts +23 -0
  83. package/types/lib/helpers/aiInventory.d.ts.map +1 -0
  84. package/types/lib/helpers/analyzer.d.ts +10 -0
  85. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  86. package/types/lib/helpers/auditCategories.d.ts +12 -0
  87. package/types/lib/helpers/auditCategories.d.ts.map +1 -0
  88. package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
  89. package/types/lib/helpers/communityAiConfigParser.d.ts +29 -0
  90. package/types/lib/helpers/communityAiConfigParser.d.ts.map +1 -0
  91. package/types/lib/helpers/depsUtils.d.ts +8 -0
  92. package/types/lib/helpers/depsUtils.d.ts.map +1 -1
  93. package/types/lib/helpers/display.d.ts +17 -1
  94. package/types/lib/helpers/display.d.ts.map +1 -1
  95. package/types/lib/helpers/formulationParsers.d.ts.map +1 -1
  96. package/types/lib/helpers/jsonLike.d.ts +4 -0
  97. package/types/lib/helpers/jsonLike.d.ts.map +1 -0
  98. package/types/lib/helpers/mcp.d.ts +29 -0
  99. package/types/lib/helpers/mcp.d.ts.map +1 -0
  100. package/types/lib/helpers/mcpConfigParser.d.ts +30 -0
  101. package/types/lib/helpers/mcpConfigParser.d.ts.map +1 -0
  102. package/types/lib/helpers/mcpDiscovery.d.ts +5 -0
  103. package/types/lib/helpers/mcpDiscovery.d.ts.map +1 -0
  104. package/types/lib/helpers/provenanceUtils.d.ts +5 -3
  105. package/types/lib/helpers/provenanceUtils.d.ts.map +1 -1
  106. package/types/lib/helpers/registryProvenance.d.ts +9 -0
  107. package/types/lib/helpers/registryProvenance.d.ts.map +1 -1
  108. package/types/lib/helpers/rustFormulationParser.d.ts +17 -0
  109. package/types/lib/helpers/rustFormulationParser.d.ts.map +1 -0
  110. package/types/lib/helpers/source.d.ts.map +1 -1
  111. package/types/lib/helpers/utils.d.ts +31 -1
  112. package/types/lib/helpers/utils.d.ts.map +1 -1
  113. package/types/lib/helpers/vsixutils.d.ts.map +1 -1
  114. package/types/lib/managers/binary.d.ts.map +1 -1
  115. package/types/lib/managers/docker.d.ts.map +1 -1
  116. package/types/lib/managers/piptree.d.ts.map +1 -1
  117. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  118. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
  119. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  120. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  121. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
@@ -1,10 +1,15 @@
1
- import { readFileSync, rmSync } from "node:fs";
1
+ import { readFileSync } from "node:fs";
2
2
  import { basename, join, relative, sep } from "node:path";
3
3
  import process from "node:process";
4
4
 
5
5
  import { PackageURL } from "packageurl-js";
6
6
 
7
- import { mergeDependencies } from "../../helpers/depsUtils.js";
7
+ import {
8
+ AI_INVENTORY_PROJECT_TYPES,
9
+ matchesAiInventoryExcludeType,
10
+ optionIncludesAiInventoryProjectType,
11
+ } from "../../helpers/aiInventory.js";
12
+ import { mergeDependencies, mergeServices } from "../../helpers/depsUtils.js";
8
13
  import { addFormulationSection } from "../../helpers/formulationParsers.js";
9
14
  import { thoughtLog } from "../../helpers/logger.js";
10
15
  import { buildReleaseNotesFromGit } from "../../helpers/source.js";
@@ -14,7 +19,11 @@ import {
14
19
  getTimestamp,
15
20
  getTmpDir,
16
21
  hasAnyProjectType,
22
+ isDryRun,
23
+ resetActivityContext,
17
24
  safeExistsSync,
25
+ safeRmSync,
26
+ setActivityContext,
18
27
  } from "../../helpers/utils.js";
19
28
  import { extractTags, findBomType, textualMetadata } from "./annotator.js";
20
29
 
@@ -68,11 +77,29 @@ function applyFormulation(bomJson, options, filePath, formulationList) {
68
77
  return bomJson;
69
78
  }
70
79
  const context = formulationList?.length ? { formulationList } : {};
71
- const formulationData = addFormulationSection(filePath, options, context);
80
+ setActivityContext({
81
+ projectType: "Formulation",
82
+ sourcePath: filePath || options.filePath || process.cwd(),
83
+ });
84
+ let formulationData;
85
+ try {
86
+ formulationData = addFormulationSection(filePath, options, context);
87
+ } finally {
88
+ resetActivityContext();
89
+ }
72
90
  if (!formulationData) {
73
91
  return bomJson;
74
92
  }
75
93
  bomJson.formulation = formulationData.formulation;
94
+ const formulationServices = formulationData.formulation.flatMap(
95
+ (entry) => entry?.services || [],
96
+ );
97
+ if (formulationServices.length) {
98
+ bomJson.services = mergeServices(
99
+ bomJson.services || [],
100
+ formulationServices,
101
+ );
102
+ }
76
103
  if (formulationData.dependencies?.length) {
77
104
  bomJson.dependencies = mergeDependencies(
78
105
  bomJson.dependencies || [],
@@ -82,6 +109,189 @@ function applyFormulation(bomJson, options, filePath, formulationList) {
82
109
  return bomJson;
83
110
  }
84
111
 
112
+ const WEAK_TLP_CLASSIFICATIONS = new Set(["CLEAR", "GREEN", "AMBER"]);
113
+ const SENSITIVE_PROPERTY_NAMES = new Set([
114
+ "cdx:agent:description",
115
+ "cdx:agent:hiddenMcpUrls",
116
+ "cdx:agent:permission",
117
+ "cdx:mcp:command",
118
+ "cdx:mcp:configuredEndpoints",
119
+ "cdx:mcp:description",
120
+ "cdx:mcp:resourceUri",
121
+ "cdx:skill:metadata",
122
+ ]);
123
+ const SENSITIVE_PROPERTY_PREFIXES = ["cdx:crewai:", "cdx:mcp:auth:"];
124
+ const SECRET_ASSIGNMENT_PATTERN =
125
+ /(?:^|[\s,{\[])(?:authorization|password|passwd|pwd|token|access[_-]?token|id[_-]?token|refresh[_-]?token|api[_-]?key|client[_-]?secret|secret|session(?:id)?|cookie)\s*(?:[:=]|=>)\s*["'`]?[^"'`\s,}\]]{4,}/iu;
126
+ const ENV_SECRET_PATTERN =
127
+ /\b[A-Z0-9_]*(?:TOKEN|PASSWORD|SECRET|API_KEY|CLIENT_SECRET|SESSION|COOKIE)[A-Z0-9_]*=\S+/u;
128
+ const AUTH_HEADER_PATTERN =
129
+ /\bAuthorization\s*:\s*(?:Bearer|Basic)\s+[A-Za-z0-9._~+/=-]{8,}/iu;
130
+ const BEARER_TOKEN_PATTERN = /\b(?:Bearer|Basic)\s+[A-Za-z0-9._~+/=-]{12,}/u;
131
+ const PRIVATE_KEY_PATTERN =
132
+ /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/u;
133
+ const SIGNED_URL_PARAM_NAMES = new Set([
134
+ "access_token",
135
+ "api_key",
136
+ "client_secret",
137
+ "id_token",
138
+ "signature",
139
+ "sig",
140
+ "token",
141
+ "x-amz-signature",
142
+ "x-goog-signature",
143
+ ]);
144
+
145
+ function normalizeSpecVersion(specVersion) {
146
+ return Number.parseFloat(String(specVersion || 0));
147
+ }
148
+
149
+ function normalizeTlpClassification(tlpClassification) {
150
+ return String(tlpClassification || "")
151
+ .trim()
152
+ .toUpperCase();
153
+ }
154
+
155
+ function hasSensitivePropertyName(propertyName) {
156
+ if (SENSITIVE_PROPERTY_NAMES.has(propertyName)) {
157
+ return true;
158
+ }
159
+ return SENSITIVE_PROPERTY_PREFIXES.some((prefix) =>
160
+ propertyName.startsWith(prefix),
161
+ );
162
+ }
163
+
164
+ function extractUrlCandidates(value) {
165
+ return Array.from(value.matchAll(/https?:\/\/[^\s]+/gu), (match) =>
166
+ match[0].replace(/[),.;]+$/u, ""),
167
+ );
168
+ }
169
+
170
+ function hasSensitiveUrlValue(value) {
171
+ for (const candidate of extractUrlCandidates(value)) {
172
+ if (!URL.canParse(candidate)) {
173
+ continue;
174
+ }
175
+ const parsedUrl = new URL(candidate);
176
+ if (parsedUrl.username || parsedUrl.password || parsedUrl.hash) {
177
+ return true;
178
+ }
179
+ for (const [paramName] of parsedUrl.searchParams) {
180
+ if (SIGNED_URL_PARAM_NAMES.has(paramName.toLowerCase())) {
181
+ return true;
182
+ }
183
+ }
184
+ }
185
+ return false;
186
+ }
187
+
188
+ function hasKnownSensitiveText(value) {
189
+ return (
190
+ SECRET_ASSIGNMENT_PATTERN.test(value) ||
191
+ ENV_SECRET_PATTERN.test(value) ||
192
+ AUTH_HEADER_PATTERN.test(value) ||
193
+ BEARER_TOKEN_PATTERN.test(value) ||
194
+ PRIVATE_KEY_PATTERN.test(value)
195
+ );
196
+ }
197
+
198
+ function propertyContainsSensitiveValue(propertyName, propertyValue) {
199
+ if (!hasSensitivePropertyName(propertyName) || !propertyValue?.trim()) {
200
+ return false;
201
+ }
202
+ return (
203
+ hasSensitiveUrlValue(propertyValue) || hasKnownSensitiveText(propertyValue)
204
+ );
205
+ }
206
+
207
+ function collectSensitivePropertyViolations(
208
+ subject,
209
+ violations = [],
210
+ location = "bom",
211
+ seen = new Set(),
212
+ ) {
213
+ if (!subject || typeof subject !== "object" || seen.has(subject)) {
214
+ return violations;
215
+ }
216
+ seen.add(subject);
217
+ if (Array.isArray(subject.properties)) {
218
+ const subjectLabel = subject["bom-ref"] || subject.name || location;
219
+ for (const property of subject.properties) {
220
+ if (
221
+ typeof property?.name === "string" &&
222
+ typeof property?.value === "string" &&
223
+ propertyContainsSensitiveValue(property.name, property.value)
224
+ ) {
225
+ violations.push({
226
+ propertyName: property.name,
227
+ subjectLabel,
228
+ });
229
+ }
230
+ }
231
+ }
232
+ if (Array.isArray(subject)) {
233
+ subject.forEach((entry, index) => {
234
+ collectSensitivePropertyViolations(
235
+ entry,
236
+ violations,
237
+ `${location}[${index}]`,
238
+ seen,
239
+ );
240
+ });
241
+ return violations;
242
+ }
243
+ for (const [key, value] of Object.entries(subject)) {
244
+ if (key === "properties") {
245
+ continue;
246
+ }
247
+ collectSensitivePropertyViolations(
248
+ value,
249
+ violations,
250
+ `${location}.${key}`,
251
+ seen,
252
+ );
253
+ }
254
+ return violations;
255
+ }
256
+
257
+ function validateTlpClassification(bomJson, options) {
258
+ const specVersion = normalizeSpecVersion(
259
+ bomJson?.specVersion || options?.specVersion,
260
+ );
261
+ if (specVersion < 1.7) {
262
+ return bomJson;
263
+ }
264
+ const tlpClassification = normalizeTlpClassification(
265
+ bomJson?.metadata?.distributionConstraints?.tlp ||
266
+ bomJson?.metadata?.distribution ||
267
+ options?.tlpClassification,
268
+ );
269
+ if (!WEAK_TLP_CLASSIFICATIONS.has(tlpClassification)) {
270
+ return bomJson;
271
+ }
272
+ const violations = collectSensitivePropertyViolations(bomJson);
273
+ if (!violations.length) {
274
+ return bomJson;
275
+ }
276
+ const uniqueViolations = [
277
+ ...new Set(
278
+ violations.map(
279
+ ({ propertyName, subjectLabel }) =>
280
+ `${propertyName} on ${subjectLabel}`,
281
+ ),
282
+ ),
283
+ ];
284
+ const errorMessage =
285
+ `CycloneDX 1.7+ BOMs with TLP classification '${tlpClassification}' must not include known sensitive property values. ` +
286
+ "Redact the values or raise the TLP classification to AMBER_AND_STRICT or RED. " +
287
+ `Found: ${uniqueViolations.slice(0, 5).join("; ")}${uniqueViolations.length > 5 ? `; and ${uniqueViolations.length - 5} more` : ""}`;
288
+ if (options?.failOnError) {
289
+ throw new Error(errorMessage);
290
+ }
291
+ console.warn(errorMessage);
292
+ return bomJson;
293
+ }
294
+
85
295
  /**
86
296
  * Filter and enhance BOM post generation.
87
297
  *
@@ -109,6 +319,7 @@ export function postProcess(bomNSData, options, filePath) {
109
319
  bomNSData.formulationList,
110
320
  );
111
321
  bomNSData.bomJson = applyReleaseNotes(bomNSData.bomJson, options, filePath);
322
+ bomNSData.bomJson = validateTlpClassification(bomNSData.bomJson, options);
112
323
  // Support for automatic annotations
113
324
  if (options.specVersion >= 1.6) {
114
325
  bomNSData.bomJson = annotate(bomNSData.bomJson, options);
@@ -409,12 +620,17 @@ function getIdentityTechniques(comp) {
409
620
  */
410
621
  export function filterBom(bomJson, options) {
411
622
  const newPkgMap = {};
623
+ const newServices = [];
412
624
  let filtered = false;
413
625
  let anyFiltered = false;
414
626
  if (!bomJson?.components) {
415
627
  return bomJson;
416
628
  }
417
629
  for (const comp of bomJson.components) {
630
+ if (shouldExcludeInventoryType(comp, options)) {
631
+ filtered = true;
632
+ continue;
633
+ }
418
634
  // minimum confidence filter
419
635
  if (options?.minConfidence > 0) {
420
636
  const confidence = Math.min(options.minConfidence, 1);
@@ -448,6 +664,7 @@ export function filterBom(bomJson, options) {
448
664
  ) {
449
665
  filtered = true;
450
666
  } else if (options.only?.length) {
667
+ const componentPurl = comp.purl?.toLowerCase?.() || "";
451
668
  if (!Array.isArray(options.only)) {
452
669
  options.only = [options.only];
453
670
  }
@@ -456,7 +673,7 @@ export function filterBom(bomJson, options) {
456
673
  for (const filterstr of options.only) {
457
674
  if (
458
675
  filterstr.length &&
459
- comp.purl.toLowerCase().includes(filterstr.toLowerCase())
676
+ componentPurl.includes(filterstr.toLowerCase())
460
677
  ) {
461
678
  filtered = true;
462
679
  purlfiltered = false;
@@ -471,11 +688,12 @@ export function filterBom(bomJson, options) {
471
688
  options.filter = [options.filter];
472
689
  }
473
690
  let purlfiltered = false;
691
+ const componentPurl = comp.purl?.toLowerCase?.() || "";
474
692
  for (const filterstr of options.filter) {
475
693
  // Check the purl
476
694
  if (
477
695
  filterstr.length &&
478
- comp.purl.toLowerCase().includes(filterstr.toLowerCase())
696
+ componentPurl.includes(filterstr.toLowerCase())
479
697
  ) {
480
698
  filtered = true;
481
699
  purlfiltered = true;
@@ -500,40 +718,59 @@ export function filterBom(bomJson, options) {
500
718
  newPkgMap[comp["bom-ref"]] = comp;
501
719
  }
502
720
  }
721
+ for (const service of bomJson.services || []) {
722
+ if (shouldExcludeInventoryType(service, options)) {
723
+ filtered = true;
724
+ continue;
725
+ }
726
+ newServices.push(service);
727
+ }
503
728
  if (filtered) {
504
729
  if (!anyFiltered) {
505
730
  anyFiltered = true;
506
731
  }
507
732
  const newcomponents = [];
508
733
  const newdependencies = [];
734
+ const retainedRefs = new Set();
509
735
  for (const aref of Object.keys(newPkgMap).sort()) {
510
736
  newcomponents.push(newPkgMap[aref]);
737
+ retainedRefs.add(aref);
738
+ }
739
+ for (const service of newServices) {
740
+ if (service?.["bom-ref"]) {
741
+ retainedRefs.add(service["bom-ref"]);
742
+ }
511
743
  }
512
744
  if (bomJson.metadata?.component?.["bom-ref"]) {
513
745
  newPkgMap[bomJson.metadata.component["bom-ref"]] =
514
746
  bomJson.metadata.component;
747
+ retainedRefs.add(bomJson.metadata.component["bom-ref"]);
515
748
  }
516
749
  if (bomJson.metadata?.component?.components) {
517
750
  for (const comp of bomJson.metadata.component.components) {
518
751
  newPkgMap[comp["bom-ref"]] = comp;
752
+ retainedRefs.add(comp["bom-ref"]);
519
753
  }
520
754
  }
521
- for (const adep of bomJson.dependencies) {
522
- if (newPkgMap[adep.ref]) {
523
- const newdepson = (adep.dependsOn || []).filter((d) => newPkgMap[d]);
755
+ for (const adep of bomJson.dependencies || []) {
756
+ if (retainedRefs.has(adep.ref)) {
757
+ const newdepson = (adep.dependsOn || []).filter((d) =>
758
+ retainedRefs.has(d),
759
+ );
524
760
  const obj = {
525
761
  ref: adep.ref,
526
762
  dependsOn: newdepson,
527
763
  };
528
764
  // Filter provides array if needed
529
765
  if (adep.provides?.length) {
530
- obj.provides = adep.provides.filter((d) => newPkgMap[d]);
766
+ obj.provides = adep.provides.filter((d) => retainedRefs.has(d));
531
767
  }
532
768
  newdependencies.push(obj);
533
769
  }
534
770
  }
535
771
  bomJson.components = newcomponents;
536
772
  bomJson.dependencies = newdependencies;
773
+ bomJson.services = newServices;
537
774
  // We set the compositions.aggregate to incomplete by default
538
775
  if (
539
776
  options.specVersion >= 1.5 &&
@@ -571,12 +808,23 @@ export function filterBom(bomJson, options) {
571
808
  return bomJson;
572
809
  }
573
810
 
811
+ function shouldExcludeInventoryType(subject, options) {
812
+ return AI_INVENTORY_PROJECT_TYPES.some(
813
+ (type) =>
814
+ optionIncludesAiInventoryProjectType(options?.excludeType, type) &&
815
+ matchesAiInventoryExcludeType(subject, type),
816
+ );
817
+ }
818
+
574
819
  /**
575
820
  * Clean up
576
821
  */
577
822
  export function cleanupEnv(_options) {
823
+ if (isDryRun) {
824
+ return;
825
+ }
578
826
  if (process.env?.PIP_TARGET?.startsWith(getTmpDir())) {
579
- rmSync(process.env.PIP_TARGET, { recursive: true, force: true });
827
+ safeRmSync(process.env.PIP_TARGET, { recursive: true, force: true });
580
828
  }
581
829
  }
582
830
 
@@ -588,8 +836,11 @@ export function cleanupEnv(_options) {
588
836
  * @returns {void}
589
837
  */
590
838
  export function cleanupTmpDir() {
839
+ if (isDryRun) {
840
+ return;
841
+ }
591
842
  if (process.env?.CDXGEN_TMP_DIR?.startsWith(getTmpDir())) {
592
- rmSync(process.env.CDXGEN_TMP_DIR, { recursive: true, force: true });
843
+ safeRmSync(process.env.CDXGEN_TMP_DIR, { recursive: true, force: true });
593
844
  }
594
845
  }
595
846