@cyclonedx/cdxgen 12.4.2 → 12.4.4
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/README.md +6 -0
- package/bin/audit.js +7 -0
- package/bin/cdxgen.js +48 -2
- package/bin/evinse.js +7 -0
- package/lib/audit/index.js +165 -2
- package/lib/audit/index.poku.js +462 -0
- package/lib/cli/index.js +320 -172
- package/lib/cli/index.poku.js +81 -0
- package/lib/evinser/evinser.js +31 -9
- package/lib/helpers/analyzer.js +890 -0
- package/lib/helpers/analyzer.poku.js +341 -0
- package/lib/helpers/atomUtils.js +445 -0
- package/lib/helpers/atomUtils.poku.js +137 -0
- package/lib/helpers/bomUtils.js +71 -0
- package/lib/helpers/bomUtils.poku.js +45 -0
- package/lib/helpers/depsUtils.js +146 -0
- package/lib/helpers/depsUtils.poku.js +183 -0
- package/lib/helpers/display.js +12 -6
- package/lib/helpers/display.poku.js +38 -0
- package/lib/helpers/utils.js +653 -191
- package/lib/helpers/utils.poku.js +414 -4
- package/lib/managers/binary.js +18 -9
- package/lib/stages/postgen/postgen.js +215 -0
- package/lib/stages/postgen/postgen.poku.js +218 -3
- package/lib/validator/bomValidator.js +11 -2
- package/package.json +8 -8
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/atomUtils.d.ts +18 -0
- package/types/lib/helpers/atomUtils.d.ts.map +1 -0
- package/types/lib/helpers/bomUtils.d.ts +10 -0
- package/types/lib/helpers/bomUtils.d.ts.map +1 -1
- package/types/lib/helpers/depsUtils.d.ts +9 -0
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/dosaiParsers.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +19 -0
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +2 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
|
@@ -106,7 +106,9 @@ import {
|
|
|
106
106
|
parseLeinDep,
|
|
107
107
|
parseLeiningenData,
|
|
108
108
|
parseMakeDFile,
|
|
109
|
+
parseMavenArgs,
|
|
109
110
|
parseMavenTree,
|
|
111
|
+
parseMavenTreeJson,
|
|
110
112
|
parseMillDependency,
|
|
111
113
|
parseMinJs,
|
|
112
114
|
parseMixLockData,
|
|
@@ -339,6 +341,32 @@ it("safeSpawnSync() does not classify non-probe -v commands as version checks",
|
|
|
339
341
|
}
|
|
340
342
|
});
|
|
341
343
|
|
|
344
|
+
it("safeSpawnSync() blocks shell metacharacters with shell execution", () => {
|
|
345
|
+
const markerFile = path.join(tmpdir(), "cdxgen-safe-spawn-shell-marker");
|
|
346
|
+
const originalConsoleWarn = console.warn;
|
|
347
|
+
const warnings = [];
|
|
348
|
+
rmSync(markerFile, { force: true });
|
|
349
|
+
resetRecordedActivities();
|
|
350
|
+
console.warn = (message) => {
|
|
351
|
+
warnings.push(message);
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
const result = safeSpawnSync("printf", ["blocked", ">", markerFile], {
|
|
356
|
+
shell: true,
|
|
357
|
+
});
|
|
358
|
+
assert.strictEqual(result.status, 1);
|
|
359
|
+
assert.ok(result.error);
|
|
360
|
+
assert.match(result.error.message, /shell metacharacters/);
|
|
361
|
+
assert.strictEqual(existsSync(markerFile), false);
|
|
362
|
+
assert.ok(warnings.some((warning) => /Security Alert/.test(warning)));
|
|
363
|
+
} finally {
|
|
364
|
+
console.warn = originalConsoleWarn;
|
|
365
|
+
resetRecordedActivities();
|
|
366
|
+
rmSync(markerFile, { force: true });
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
342
370
|
it("safeSpawnSync() reads CDXGEN_ALLOWED_COMMANDS once per invocation", () => {
|
|
343
371
|
const originalAllowedCommands = process.env.CDXGEN_ALLOWED_COMMANDS;
|
|
344
372
|
process.env.CDXGEN_ALLOWED_COMMANDS = "echo-cdxgen-test";
|
|
@@ -598,6 +626,37 @@ it("records recursive file discovery activity in dry-run mode", () => {
|
|
|
598
626
|
}
|
|
599
627
|
});
|
|
600
628
|
|
|
629
|
+
it("records suspicious discovered paths with shell metacharacters in dry-run mode", () => {
|
|
630
|
+
const tmpRoot = mkdtempSync(
|
|
631
|
+
path.join(tmpdir(), "cdxgen-dry-run-shell-path-"),
|
|
632
|
+
);
|
|
633
|
+
const shellIfs = "$" + "{IFS}";
|
|
634
|
+
const maliciousDirName =
|
|
635
|
+
platform() === "win32"
|
|
636
|
+
? "evil&echo%CDXGEN_GITURL_E2E_MARKER%&rem"
|
|
637
|
+
: `evil;cd${shellIfs}..;printf${shellIfs}marker>CDXGEN_GITURL_E2E_MARKER;#`;
|
|
638
|
+
const maliciousDir = path.join(tmpRoot, maliciousDirName);
|
|
639
|
+
const pomFile = path.join(maliciousDir, "pom.xml");
|
|
640
|
+
mkdirSync(maliciousDir, { recursive: true });
|
|
641
|
+
writeFileSync(pomFile, "<project />");
|
|
642
|
+
setDryRunMode(true);
|
|
643
|
+
resetRecordedActivities();
|
|
644
|
+
try {
|
|
645
|
+
assert.deepStrictEqual(getAllFiles(tmpRoot, "**/pom.xml"), [pomFile]);
|
|
646
|
+
const suspiciousActivity = getRecordedActivities().find(
|
|
647
|
+
(activity) => activity.classification === "suspicious-path",
|
|
648
|
+
);
|
|
649
|
+
assert.ok(suspiciousActivity);
|
|
650
|
+
assert.strictEqual(suspiciousActivity.risk, "shell-metacharacters");
|
|
651
|
+
assert.strictEqual(suspiciousActivity.target, pomFile);
|
|
652
|
+
assert.match(suspiciousActivity.reason, /shell metacharacters/);
|
|
653
|
+
} finally {
|
|
654
|
+
setDryRunMode(false);
|
|
655
|
+
resetRecordedActivities();
|
|
656
|
+
rmSync(tmpRoot, { force: true, recursive: true });
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
|
|
601
660
|
it("records updated discovery activity when a repeated glob match count changes", () => {
|
|
602
661
|
const tmpRoot = mkdtempSync(path.join(tmpdir(), "cdxgen-dry-run-glob-"));
|
|
603
662
|
const packageJsonFile = path.join(tmpRoot, "package.json");
|
|
@@ -1508,7 +1567,7 @@ it("parse maven tree", () => {
|
|
|
1508
1567
|
name: "com.ibm.icu",
|
|
1509
1568
|
version: "67.1.0.v20200706-1749",
|
|
1510
1569
|
qualifiers: { type: "eclipse-plugin" },
|
|
1511
|
-
scope:
|
|
1570
|
+
scope: "excluded",
|
|
1512
1571
|
properties: [],
|
|
1513
1572
|
});
|
|
1514
1573
|
assert.deepStrictEqual(parsedList.dependenciesList.length, 79);
|
|
@@ -1550,12 +1609,12 @@ it("parse maven tree", () => {
|
|
|
1550
1609
|
encoding: "utf-8",
|
|
1551
1610
|
}),
|
|
1552
1611
|
);
|
|
1553
|
-
assert.deepStrictEqual(parsedList.pkgList.length,
|
|
1612
|
+
assert.deepStrictEqual(parsedList.pkgList.length, 102);
|
|
1554
1613
|
assert.deepStrictEqual(
|
|
1555
1614
|
parsedList.parentComponent["bom-ref"],
|
|
1556
1615
|
"pkg:maven/org.apache.dubbo/dubbo-spring-boot-starter@3.3.0?type=jar",
|
|
1557
1616
|
);
|
|
1558
|
-
assert.deepStrictEqual(parsedList.dependenciesList.length,
|
|
1617
|
+
assert.deepStrictEqual(parsedList.dependenciesList.length, 102);
|
|
1559
1618
|
assert.deepStrictEqual(parsedList.dependenciesList[0], {
|
|
1560
1619
|
ref: "pkg:maven/org.apache.dubbo/dubbo-spring-boot-starter@3.3.0?type=jar",
|
|
1561
1620
|
dependsOn: [
|
|
@@ -1571,11 +1630,109 @@ it("parse maven tree", () => {
|
|
|
1571
1630
|
"pkg:maven/org.junit.vintage/junit-vintage-engine@5.8.2?type=jar",
|
|
1572
1631
|
"pkg:maven/org.mockito/mockito-core@4.11.0?type=jar",
|
|
1573
1632
|
"pkg:maven/org.mockito/mockito-inline@4.11.0?type=jar",
|
|
1574
|
-
"pkg:maven/org.
|
|
1633
|
+
"pkg:maven/org.springframework.boot/spring-boot-starter@2.7.18?type=jar",
|
|
1575
1634
|
],
|
|
1576
1635
|
});
|
|
1577
1636
|
});
|
|
1578
1637
|
|
|
1638
|
+
it("parse maven tree optional and repeated dependency edges", () => {
|
|
1639
|
+
const parsedOptional = parseMavenTree(`example:optional-sample:jar:1.0.0
|
|
1640
|
+
\\- org.apache.maven:maven-artifact:jar:3.9.9:compile (optional)
|
|
1641
|
+
\\- org.codehaus.plexus:plexus-utils:jar:3.5.1:compile (optional)
|
|
1642
|
+
`);
|
|
1643
|
+
assert.strictEqual(parsedOptional.pkgList.length, 3);
|
|
1644
|
+
assert.strictEqual(parsedOptional.pkgList[1].scope, "optional");
|
|
1645
|
+
assert.deepStrictEqual(parsedOptional.pkgList[1].properties, []);
|
|
1646
|
+
assert.deepStrictEqual(parsedOptional.dependenciesList[0], {
|
|
1647
|
+
ref: "pkg:maven/example/optional-sample@1.0.0?type=jar",
|
|
1648
|
+
dependsOn: ["pkg:maven/org.apache.maven/maven-artifact@3.9.9?type=jar"],
|
|
1649
|
+
});
|
|
1650
|
+
const parsedDuplicate = parseMavenTree(`example:dup-root:jar:1.0.0
|
|
1651
|
+
+- g:a:jar:1:compile
|
|
1652
|
+
| \\- g:c:jar:1:compile
|
|
1653
|
+
\\- g:b:jar:1:compile
|
|
1654
|
+
\\- g:c:jar:1:compile
|
|
1655
|
+
`);
|
|
1656
|
+
const bDependency = parsedDuplicate.dependenciesList.find(
|
|
1657
|
+
(dep) => dep.ref === "pkg:maven/g/b@1?type=jar",
|
|
1658
|
+
);
|
|
1659
|
+
assert.deepStrictEqual(bDependency.dependsOn, ["pkg:maven/g/c@1?type=jar"]);
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1662
|
+
it("parse maven tree json", () => {
|
|
1663
|
+
const parsedList = parseMavenTreeJson(
|
|
1664
|
+
JSON.stringify({
|
|
1665
|
+
groupId: "example",
|
|
1666
|
+
artifactId: "json-root",
|
|
1667
|
+
version: "1.0.0",
|
|
1668
|
+
type: "jar",
|
|
1669
|
+
scope: "",
|
|
1670
|
+
classifier: "",
|
|
1671
|
+
optional: "false",
|
|
1672
|
+
children: [
|
|
1673
|
+
{
|
|
1674
|
+
groupId: "org.apache.maven",
|
|
1675
|
+
artifactId: "maven-artifact",
|
|
1676
|
+
version: "3.9.9",
|
|
1677
|
+
type: "jar",
|
|
1678
|
+
scope: "compile",
|
|
1679
|
+
classifier: "",
|
|
1680
|
+
optional: "true",
|
|
1681
|
+
children: [
|
|
1682
|
+
{
|
|
1683
|
+
groupId: "org.codehaus.plexus",
|
|
1684
|
+
artifactId: "plexus-utils",
|
|
1685
|
+
version: "3.5.1",
|
|
1686
|
+
type: "jar",
|
|
1687
|
+
scope: "compile",
|
|
1688
|
+
classifier: "",
|
|
1689
|
+
optional: "true",
|
|
1690
|
+
},
|
|
1691
|
+
],
|
|
1692
|
+
},
|
|
1693
|
+
],
|
|
1694
|
+
}),
|
|
1695
|
+
);
|
|
1696
|
+
assert.strictEqual(parsedList.pkgList.length, 3);
|
|
1697
|
+
assert.strictEqual(parsedList.pkgList[1].scope, "optional");
|
|
1698
|
+
assert.deepStrictEqual(parsedList.dependenciesList[0], {
|
|
1699
|
+
ref: "pkg:maven/example/json-root@1.0.0?type=jar",
|
|
1700
|
+
dependsOn: ["pkg:maven/org.apache.maven/maven-artifact@3.9.9?type=jar"],
|
|
1701
|
+
});
|
|
1702
|
+
assert.deepStrictEqual(parsedList.dependenciesList[1], {
|
|
1703
|
+
ref: "pkg:maven/org.apache.maven/maven-artifact@3.9.9?type=jar",
|
|
1704
|
+
dependsOn: ["pkg:maven/org.codehaus.plexus/plexus-utils@3.5.1?type=jar"],
|
|
1705
|
+
});
|
|
1706
|
+
assert.deepStrictEqual(parseMavenTreeJson("{not-json"), {});
|
|
1707
|
+
assert.deepStrictEqual(parseMavenTree("{not-json"), {});
|
|
1708
|
+
});
|
|
1709
|
+
|
|
1710
|
+
it("parse maven args", () => {
|
|
1711
|
+
assert.deepStrictEqual(
|
|
1712
|
+
parseMavenArgs(
|
|
1713
|
+
'--settings "/tmp/path with spaces/settings.xml" -P dev,test -DskipTests',
|
|
1714
|
+
),
|
|
1715
|
+
[
|
|
1716
|
+
"--settings",
|
|
1717
|
+
"/tmp/path with spaces/settings.xml",
|
|
1718
|
+
"-P",
|
|
1719
|
+
"dev,test",
|
|
1720
|
+
"-DskipTests",
|
|
1721
|
+
],
|
|
1722
|
+
);
|
|
1723
|
+
assert.deepStrictEqual(
|
|
1724
|
+
parseMavenArgs(String.raw`-s C:\Users\me\settings.xml -Dpath=C:\repo\demo`),
|
|
1725
|
+
[
|
|
1726
|
+
"-s",
|
|
1727
|
+
String.raw`C:\Users\me\settings.xml`,
|
|
1728
|
+
String.raw`-Dpath=C:\repo\demo`,
|
|
1729
|
+
],
|
|
1730
|
+
);
|
|
1731
|
+
assert.deepStrictEqual(parseMavenArgs(String.raw`-Dname=hello\ world`), [
|
|
1732
|
+
"-Dname=hello world",
|
|
1733
|
+
]);
|
|
1734
|
+
});
|
|
1735
|
+
|
|
1579
1736
|
// Slow test
|
|
1580
1737
|
/*
|
|
1581
1738
|
it("get maven metadata", async () => {
|
|
@@ -5147,6 +5304,41 @@ it("parsePomFile", () => {
|
|
|
5147
5304
|
assert.deepStrictEqual(data.isQuarkus, false);
|
|
5148
5305
|
});
|
|
5149
5306
|
|
|
5307
|
+
it("parsePomFile maven 4 model", () => {
|
|
5308
|
+
const tempDir = mkdtempSync(path.join(tmpdir(), "cdxgen-maven4-pom-"));
|
|
5309
|
+
const pomFile = path.join(tempDir, "pom.xml");
|
|
5310
|
+
writeFileSync(
|
|
5311
|
+
pomFile,
|
|
5312
|
+
`<project xmlns="http://maven.apache.org/POM/4.1.0" root="true" preserve.model.version="true">
|
|
5313
|
+
<modelVersion>4.1.0</modelVersion>
|
|
5314
|
+
<groupId>example</groupId>
|
|
5315
|
+
<artifactId>maven4-root</artifactId>
|
|
5316
|
+
<version>1.0.0</version>
|
|
5317
|
+
<packaging>pom</packaging>
|
|
5318
|
+
<subprojects><subproject>app</subproject></subprojects>
|
|
5319
|
+
<dependencies>
|
|
5320
|
+
<dependency>
|
|
5321
|
+
<groupId>org.example</groupId>
|
|
5322
|
+
<artifactId>demo</artifactId>
|
|
5323
|
+
<version>1.2.3</version>
|
|
5324
|
+
<type>test-jar</type>
|
|
5325
|
+
<classifier>tests</classifier>
|
|
5326
|
+
<optional>true</optional>
|
|
5327
|
+
</dependency>
|
|
5328
|
+
</dependencies>
|
|
5329
|
+
</project>`,
|
|
5330
|
+
);
|
|
5331
|
+
const data = parsePom(pomFile);
|
|
5332
|
+
assert.deepStrictEqual(data.modules, ["app"]);
|
|
5333
|
+
assert.strictEqual(data.properties.modelVersion, "4.1.0");
|
|
5334
|
+
assert.strictEqual(data.properties.mavenRoot, "true");
|
|
5335
|
+
assert.strictEqual(data.properties.preserveModelVersion, "true");
|
|
5336
|
+
assert.strictEqual(data.dependencies[0].qualifiers.type, "test-jar");
|
|
5337
|
+
assert.strictEqual(data.dependencies[0].qualifiers.classifier, "tests");
|
|
5338
|
+
assert.strictEqual(data.dependencies[0].scope, "optional");
|
|
5339
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
5340
|
+
});
|
|
5341
|
+
|
|
5150
5342
|
it("parsePomMetadata", async () => {
|
|
5151
5343
|
const deps = parsePom("./test/pom.xml");
|
|
5152
5344
|
const data = await getMvnMetadata(deps.dependencies);
|
|
@@ -6111,6 +6303,73 @@ it("parsePnpmWorkspace", async () => {
|
|
|
6111
6303
|
assert.deepStrictEqual(Object.keys(wobj.catalogs).length, 217);
|
|
6112
6304
|
});
|
|
6113
6305
|
|
|
6306
|
+
it("parsePnpmWorkspace handles scalar package fixtures", async () => {
|
|
6307
|
+
const projectDir = mkdtempSync(path.join(tmpdir(), "cdxgen-pnpm-workspace-"));
|
|
6308
|
+
try {
|
|
6309
|
+
const workspaceFile = path.join(projectDir, "pnpm-workspace.yaml");
|
|
6310
|
+
writeFileSync(workspaceFile, 'packages: "pkg"\n');
|
|
6311
|
+
|
|
6312
|
+
const wobj = parsePnpmWorkspace(workspaceFile);
|
|
6313
|
+
|
|
6314
|
+
assert.deepStrictEqual(wobj.packages, ["pkg"]);
|
|
6315
|
+
assert.deepStrictEqual(wobj.packagePatterns, ["pkg"]);
|
|
6316
|
+
} finally {
|
|
6317
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
6318
|
+
}
|
|
6319
|
+
});
|
|
6320
|
+
|
|
6321
|
+
it("parsePnpmWorkspace preserves negated package patterns", async () => {
|
|
6322
|
+
const projectDir = mkdtempSync(path.join(tmpdir(), "cdxgen-pnpm-workspace-"));
|
|
6323
|
+
try {
|
|
6324
|
+
const workspaceFile = path.join(projectDir, "pnpm-workspace.yaml");
|
|
6325
|
+
writeFileSync(workspaceFile, 'packages:\n - "pkg"\n - "!**/test/**"\n');
|
|
6326
|
+
|
|
6327
|
+
const wobj = parsePnpmWorkspace(workspaceFile);
|
|
6328
|
+
|
|
6329
|
+
assert.deepStrictEqual(wobj.packages, ["pkg"]);
|
|
6330
|
+
assert.deepStrictEqual(wobj.packagePatterns, ["pkg"]);
|
|
6331
|
+
assert.deepStrictEqual(wobj.excludePackages, ["**/test/**"]);
|
|
6332
|
+
} finally {
|
|
6333
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
6334
|
+
}
|
|
6335
|
+
});
|
|
6336
|
+
|
|
6337
|
+
it("parsePnpmLock relativizes pnpm evidence paths from project root", async () => {
|
|
6338
|
+
const projectDir = mkdtempSync(path.join(tmpdir(), "cdxgen-pnpm-lock-"));
|
|
6339
|
+
try {
|
|
6340
|
+
const nestedDir = path.join(projectDir, "packages", "app");
|
|
6341
|
+
mkdirSync(nestedDir, { recursive: true });
|
|
6342
|
+
const lockFile = path.join(nestedDir, "pnpm-lock.yaml");
|
|
6343
|
+
writeFileSync(
|
|
6344
|
+
lockFile,
|
|
6345
|
+
readFileSync("./test/data/pnpm-lock6.yaml", "utf-8"),
|
|
6346
|
+
);
|
|
6347
|
+
|
|
6348
|
+
const parsedList = await parsePnpmLock(
|
|
6349
|
+
lockFile,
|
|
6350
|
+
null,
|
|
6351
|
+
[],
|
|
6352
|
+
{},
|
|
6353
|
+
{},
|
|
6354
|
+
{},
|
|
6355
|
+
{},
|
|
6356
|
+
projectDir,
|
|
6357
|
+
);
|
|
6358
|
+
const firstPkg = parsedList.pkgList[0];
|
|
6359
|
+
|
|
6360
|
+
assert.strictEqual(
|
|
6361
|
+
firstPkg.properties.find((p) => p.name === "SrcFile")?.value,
|
|
6362
|
+
path.join("packages", "app", "pnpm-lock.yaml"),
|
|
6363
|
+
);
|
|
6364
|
+
assert.strictEqual(
|
|
6365
|
+
firstPkg.evidence.identity.methods[0].value,
|
|
6366
|
+
path.join("packages", "app", "pnpm-lock.yaml"),
|
|
6367
|
+
);
|
|
6368
|
+
} finally {
|
|
6369
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
6370
|
+
}
|
|
6371
|
+
});
|
|
6372
|
+
|
|
6114
6373
|
it("parsePnpmLock", async () => {
|
|
6115
6374
|
let parsedList = await parsePnpmLock("./test/pnpm-lock.yaml");
|
|
6116
6375
|
assert.deepStrictEqual(parsedList.pkgList.length, 1706);
|
|
@@ -6599,6 +6858,55 @@ it("pnpmMetadata with scoped packages", async () => {
|
|
|
6599
6858
|
assert.deepStrictEqual(babelPkg.name, "@babel/core");
|
|
6600
6859
|
});
|
|
6601
6860
|
|
|
6861
|
+
it("pnpmMetadata enriches split scoped package metadata from pnpm virtual store", async () => {
|
|
6862
|
+
const projectDir = mkdtempSync(path.join(tmpdir(), "cdxgen-pnpm-scope-"));
|
|
6863
|
+
try {
|
|
6864
|
+
const scopedPackageDir = path.join(
|
|
6865
|
+
projectDir,
|
|
6866
|
+
"node_modules",
|
|
6867
|
+
".pnpm",
|
|
6868
|
+
"@example+scoped-lib@1.2.3",
|
|
6869
|
+
"node_modules",
|
|
6870
|
+
"@example",
|
|
6871
|
+
"scoped-lib",
|
|
6872
|
+
);
|
|
6873
|
+
mkdirSync(scopedPackageDir, { recursive: true });
|
|
6874
|
+
writeFileSync(
|
|
6875
|
+
path.join(scopedPackageDir, "package.json"),
|
|
6876
|
+
JSON.stringify({
|
|
6877
|
+
name: "@example/scoped-lib",
|
|
6878
|
+
version: "1.2.3",
|
|
6879
|
+
description: "Scoped pnpm metadata fixture",
|
|
6880
|
+
license: "MIT",
|
|
6881
|
+
}),
|
|
6882
|
+
);
|
|
6883
|
+
|
|
6884
|
+
const result = await pnpmMetadata(
|
|
6885
|
+
[
|
|
6886
|
+
{
|
|
6887
|
+
group: "@example",
|
|
6888
|
+
name: "scoped-lib",
|
|
6889
|
+
version: "1.2.3",
|
|
6890
|
+
properties: [],
|
|
6891
|
+
},
|
|
6892
|
+
],
|
|
6893
|
+
path.join(projectDir, "pnpm-lock.yaml"),
|
|
6894
|
+
);
|
|
6895
|
+
|
|
6896
|
+
assert.strictEqual(result[0].description, "Scoped pnpm metadata fixture");
|
|
6897
|
+
assert.strictEqual(result[0].license, "MIT");
|
|
6898
|
+
assert.ok(
|
|
6899
|
+
result[0].properties.some(
|
|
6900
|
+
(p) =>
|
|
6901
|
+
p.name === "LocalNodeModulesPath" &&
|
|
6902
|
+
p.value.includes("@example+scoped-lib@1.2.3"),
|
|
6903
|
+
),
|
|
6904
|
+
);
|
|
6905
|
+
} finally {
|
|
6906
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
6907
|
+
}
|
|
6908
|
+
});
|
|
6909
|
+
|
|
6602
6910
|
it("pnpmMetadata integration with parsePnpmLock", async () => {
|
|
6603
6911
|
// Test that the integration works by parsing a real pnpm lock file
|
|
6604
6912
|
const parsedList = await parsePnpmLock("./pnpm-lock.yaml");
|
|
@@ -7034,6 +7342,97 @@ it("parseYarnLock", async () => {
|
|
|
7034
7342
|
});
|
|
7035
7343
|
});
|
|
7036
7344
|
|
|
7345
|
+
it("parseYarnLock marks root dev, optional, peer and dependency-only closures", async () => {
|
|
7346
|
+
const projectDir = mkdtempSync(path.join(tmpdir(), "cdxgen-yarn-scope-"));
|
|
7347
|
+
try {
|
|
7348
|
+
writeFileSync(
|
|
7349
|
+
path.join(projectDir, "package.json"),
|
|
7350
|
+
JSON.stringify({
|
|
7351
|
+
dependencies: {
|
|
7352
|
+
"runtime-a": "^1.0.0",
|
|
7353
|
+
},
|
|
7354
|
+
devDependencies: {
|
|
7355
|
+
"dev-tool": "^1.0.0",
|
|
7356
|
+
},
|
|
7357
|
+
optionalDependencies: {
|
|
7358
|
+
"optional-root": "^1.0.0",
|
|
7359
|
+
},
|
|
7360
|
+
peerDependencies: {
|
|
7361
|
+
"peer-root": "^1.0.0",
|
|
7362
|
+
},
|
|
7363
|
+
}),
|
|
7364
|
+
);
|
|
7365
|
+
writeFileSync(
|
|
7366
|
+
path.join(projectDir, "yarn.lock"),
|
|
7367
|
+
[
|
|
7368
|
+
"runtime-a@^1.0.0:",
|
|
7369
|
+
' version "1.0.0"',
|
|
7370
|
+
" dependencies:",
|
|
7371
|
+
' runtime-child "^1.0.0"',
|
|
7372
|
+
" optionalDependencies:",
|
|
7373
|
+
' optional-lock-child "^1.0.0"',
|
|
7374
|
+
"",
|
|
7375
|
+
"runtime-child@^1.0.0:",
|
|
7376
|
+
' version "1.0.0"',
|
|
7377
|
+
"",
|
|
7378
|
+
"optional-lock-child@^1.0.0:",
|
|
7379
|
+
' version "1.0.0"',
|
|
7380
|
+
"",
|
|
7381
|
+
"dev-tool@^1.0.0:",
|
|
7382
|
+
' version "1.0.0"',
|
|
7383
|
+
" dependencies:",
|
|
7384
|
+
' dev-child "^1.0.0"',
|
|
7385
|
+
"",
|
|
7386
|
+
"dev-child@^1.0.0:",
|
|
7387
|
+
' version "1.0.0"',
|
|
7388
|
+
"",
|
|
7389
|
+
"optional-root@^1.0.0:",
|
|
7390
|
+
' version "1.0.0"',
|
|
7391
|
+
" dependencies:",
|
|
7392
|
+
' optional-child "^1.0.0"',
|
|
7393
|
+
"",
|
|
7394
|
+
"optional-child@^1.0.0:",
|
|
7395
|
+
' version "1.0.0"',
|
|
7396
|
+
"",
|
|
7397
|
+
"peer-root@^1.0.0:",
|
|
7398
|
+
' version "1.0.0"',
|
|
7399
|
+
" dependencies:",
|
|
7400
|
+
' peer-child "^1.0.0"',
|
|
7401
|
+
"",
|
|
7402
|
+
"peer-child@^1.0.0:",
|
|
7403
|
+
' version "1.0.0"',
|
|
7404
|
+
"",
|
|
7405
|
+
].join("\n"),
|
|
7406
|
+
);
|
|
7407
|
+
|
|
7408
|
+
const parsedList = await parseYarnLock(path.join(projectDir, "yarn.lock"));
|
|
7409
|
+
const byName = Object.fromEntries(
|
|
7410
|
+
parsedList.pkgList.map((pkg) => [pkg.name, pkg]),
|
|
7411
|
+
);
|
|
7412
|
+
const hasProperty = (pkg, name) =>
|
|
7413
|
+
pkg.properties?.some(
|
|
7414
|
+
(property) => property.name === name && property.value === "true",
|
|
7415
|
+
);
|
|
7416
|
+
|
|
7417
|
+
assert.equal(byName["runtime-a"].scope, undefined);
|
|
7418
|
+
assert.equal(byName["runtime-child"].scope, undefined);
|
|
7419
|
+
assert.equal(byName["dev-tool"].scope, "optional");
|
|
7420
|
+
assert.equal(byName["dev-child"].scope, "optional");
|
|
7421
|
+
assert.equal(byName["optional-root"].scope, "optional");
|
|
7422
|
+
assert.equal(byName["optional-child"].scope, "optional");
|
|
7423
|
+
assert.equal(byName["optional-lock-child"].scope, "optional");
|
|
7424
|
+
assert.equal(byName["peer-root"].scope, "optional");
|
|
7425
|
+
assert.equal(byName["peer-child"].scope, "optional");
|
|
7426
|
+
assert.ok(hasProperty(byName["dev-child"], "cdx:npm:package:development"));
|
|
7427
|
+
assert.ok(
|
|
7428
|
+
hasProperty(byName["optional-child"], "cdx:npm:package:optional"),
|
|
7429
|
+
);
|
|
7430
|
+
assert.ok(hasProperty(byName["peer-child"], "cdx:npm:package:peer"));
|
|
7431
|
+
} finally {
|
|
7432
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
7433
|
+
}
|
|
7434
|
+
});
|
|
7435
|
+
|
|
7037
7436
|
describe("yarn workspace functionality", () => {
|
|
7038
7437
|
it("should parse yarn workspace lock file with workspace packages", async () => {
|
|
7039
7438
|
const mockWorkspacePackages = [
|
|
@@ -10295,6 +10694,17 @@ it("jar manifest inference and pom properties parsing tests", () => {
|
|
|
10295
10694
|
groupId: "org.apache.commons",
|
|
10296
10695
|
version: "3.6.1",
|
|
10297
10696
|
});
|
|
10697
|
+
assert.deepStrictEqual(parsePomProperties("artifactId=demo\ncustom=a=b=c"), {
|
|
10698
|
+
artifactId: "demo",
|
|
10699
|
+
custom: "a=b=c",
|
|
10700
|
+
});
|
|
10701
|
+
assert.deepStrictEqual(
|
|
10702
|
+
parsePomProperties("artifactId=demo\r\r\ncustom=a\r=b\r=c"),
|
|
10703
|
+
{
|
|
10704
|
+
artifactId: "demo",
|
|
10705
|
+
custom: "a=b=c",
|
|
10706
|
+
},
|
|
10707
|
+
);
|
|
10298
10708
|
});
|
|
10299
10709
|
|
|
10300
10710
|
it("jar group suffix trimming tests", () => {
|
package/lib/managers/binary.js
CHANGED
|
@@ -11,6 +11,7 @@ import process from "node:process";
|
|
|
11
11
|
|
|
12
12
|
import { PackageURL } from "packageurl-js";
|
|
13
13
|
|
|
14
|
+
import { isCycloneDxComponentTypeEnabled } from "../helpers/bomUtils.js";
|
|
14
15
|
import { createContainerRiskProperties } from "../helpers/containerRisk.js";
|
|
15
16
|
import { createGtfoBinsProperties } from "../helpers/gtfobins.js";
|
|
16
17
|
import {
|
|
@@ -608,10 +609,11 @@ export function executeSourcekitten(args) {
|
|
|
608
609
|
*
|
|
609
610
|
* @param src {String} Source directory containing the extracted filesystem.
|
|
610
611
|
* @param imageConfig {Object} Image configuration containing environment variables, command, entrypoints etc
|
|
612
|
+
* @param options CLI options controlling inventory generation
|
|
611
613
|
*
|
|
612
614
|
* @returns {Object} Metadata containing packages, dependencies, etc
|
|
613
615
|
*/
|
|
614
|
-
export async function getOSPackages(src, imageConfig) {
|
|
616
|
+
export async function getOSPackages(src, imageConfig, options = {}) {
|
|
615
617
|
if (isDryRun) {
|
|
616
618
|
recordActivity({
|
|
617
619
|
kind: "container",
|
|
@@ -1101,7 +1103,10 @@ export async function getOSPackages(src, imageConfig) {
|
|
|
1101
1103
|
}
|
|
1102
1104
|
}
|
|
1103
1105
|
}
|
|
1104
|
-
const rootfsRepositoryInventory = await collectRootfsRepositoryInventory(
|
|
1106
|
+
const rootfsRepositoryInventory = await collectRootfsRepositoryInventory(
|
|
1107
|
+
src,
|
|
1108
|
+
options,
|
|
1109
|
+
);
|
|
1105
1110
|
if (rootfsRepositoryInventory.components.length) {
|
|
1106
1111
|
pkgList.push(...rootfsRepositoryInventory.components);
|
|
1107
1112
|
}
|
|
@@ -1393,13 +1398,17 @@ function promoteTrivyOsPackageIdentity(component, trivyMetadata) {
|
|
|
1393
1398
|
return fallbackProperties;
|
|
1394
1399
|
}
|
|
1395
1400
|
|
|
1396
|
-
async function collectRootfsRepositoryInventory(basePath) {
|
|
1397
|
-
let
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
trustedKeyComponents,
|
|
1401
|
-
|
|
1402
|
-
|
|
1401
|
+
async function collectRootfsRepositoryInventory(basePath, options = {}) {
|
|
1402
|
+
let trustedKeyComponents = [];
|
|
1403
|
+
let refsByPath = new Map();
|
|
1404
|
+
if (isCycloneDxComponentTypeEnabled("cryptographic-asset", options)) {
|
|
1405
|
+
({ components: trustedKeyComponents, refsByPath } =
|
|
1406
|
+
await collectTrustedKeyComponents(basePath));
|
|
1407
|
+
trustedKeyComponents = applyTrustMaterialEnhancements(
|
|
1408
|
+
trustedKeyComponents,
|
|
1409
|
+
collectTrustInspectorRootfsInventory(basePath),
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1403
1412
|
refsByPath = new Map(
|
|
1404
1413
|
trustedKeyComponents
|
|
1405
1414
|
.map((component) => {
|