UNPKG

@cyclonedx/cdxgen

Version:

Creates CycloneDX Software Bill of Materials (SBOM) from source or container image

161 lines (143 loc) 4.94 kB
import { mkdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import process from "node:process"; import { assert, it } from "poku"; import { findCoursierRegistryUrl, findLocalJarPath, parseSbtLock, parseSbtTree, resolveJarDistribution, } from "./sbtutils.js"; import { readEnvironmentVariable } from "./utils.js"; it("parse scala sbt tree", async () => { const retMap = await parseSbtTree("./test/data/atom-sbt-tree.txt"); assert.deepStrictEqual(retMap.pkgList.length, 153); assert.deepStrictEqual(retMap.dependenciesList.length, 153); // Assert Scala suffix was trimmed and registered as property const coursierPkg = retMap.pkgList.find( (p) => p.name === "coursier" && p.group === "io.get-coursier", ); assert.ok(coursierPkg); assert.ok( coursierPkg.purl.startsWith("pkg:maven/io.get-coursier/coursier@2.1.2?"), ); assert.ok(coursierPkg.purl.includes("type=jar")); const compilerVersionProp = coursierPkg.properties.find( (prop) => prop.name === "cdx:scala:compilerVersion", ); assert.ok(compilerVersionProp); assert.strictEqual(compilerVersionProp.value, "2.13"); }); it("parse scala sbt lock", async () => { const deps = await parseSbtLock("./test/data/build.sbt.lock"); assert.deepStrictEqual(deps.length, 117); // Assert Scala suffix was trimmed and registered as property in sbt lock const akkaActorPkg = deps.find( (p) => p.name === "akka-actor" && p.group === "com.typesafe.akka", ); assert.ok(akkaActorPkg); const compilerVersionProp = akkaActorPkg.properties.find( (prop) => prop.name === "cdx:scala:compilerVersion", ); assert.ok(compilerVersionProp); assert.strictEqual(compilerVersionProp.value, "2.13"); }); it("parse scala sbt tree with spaces for columns (monorepo tree)", async () => { const retMap = await parseSbtTree("./test/data/chen-sbt-tree.txt"); // The first component is the root "c2cpg", the rest are dependencies. // There are some evicted lines, let's check unique parsed non-evicted pkg entries. assert.ok(retMap.pkgList.length > 50); // Verify that a node with space indentation like org.slf4j:slf4j-api:2.0.18 under slf4j-nop // is correctly identified as a child of its parent (org.slf4j:slf4j-nop:2.0.18) const nopDep = retMap.dependenciesList.find((d) => d.ref.includes("slf4j-nop"), ); assert.ok(nopDep); assert.ok(nopDep.dependsOn.some((child) => child.includes("slf4j-api"))); }); it("findCoursierRegistryUrl resolves registry URL from local cache path structure", () => { const tmpCacheRoot = path.join( tmpdir(), `cdxgen-coursier-test-${Date.now()}`, ); const targetDir = path.join( tmpCacheRoot, "https", "repo1.maven.org", "maven2", "org", "scala-lang", "scala-library", "2.13.8", ); mkdirSync(targetDir, { recursive: true }); writeFileSync(path.join(targetDir, "scala-library-2.13.8.jar"), "mock"); const oldCacheEnv = readEnvironmentVariable("COURSIER_CACHE"); process.env.COURSIER_CACHE = tmpCacheRoot; try { const url = findCoursierRegistryUrl( "org.scala-lang", "scala-library", "2.13.8", ); assert.strictEqual(url, "https://repo1.maven.org/maven2"); } finally { if (oldCacheEnv) { process.env.COURSIER_CACHE = oldCacheEnv; } else { delete process.env.COURSIER_CACHE; } rmSync(tmpCacheRoot, { recursive: true, force: true }); } }); it("resolveJarDistribution resolves registry URLs, validates existence, and extracts hashes", async () => { const tmpCacheRoot = path.join( tmpdir(), `cdxgen-coursier-https-test-${Date.now()}`, ); const cacheTargetDir = path.join( tmpCacheRoot, "https", "repo1.maven.org", "maven2", "org", "scala-lang", "scala-library", "2.13.8", ); mkdirSync(cacheTargetDir, { recursive: true }); writeFileSync(path.join(cacheTargetDir, "scala-library-2.13.8.jar"), "mock"); const oldCacheEnv = readEnvironmentVariable("COURSIER_CACHE"); process.env.COURSIER_CACHE = tmpCacheRoot; try { const localJar = findLocalJarPath( "org.scala-lang", "scala-library", "2.13.8", ); assert.ok(localJar); const dist = await resolveJarDistribution( "org.scala-lang", "scala-library", "2.13.8", ); assert.ok(dist); assert.strictEqual(dist.repoUrl, "https://repo1.maven.org/maven2"); assert.strictEqual( dist.jarUrl, "https://repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.8/scala-library-2.13.8.jar", ); assert.ok(dist.hashes); const sha256Hash = dist.hashes.find((h) => h.alg === "SHA-256"); assert.ok(sha256Hash); } finally { if (oldCacheEnv) { process.env.COURSIER_CACHE = oldCacheEnv; } else { delete process.env.COURSIER_CACHE; } rmSync(tmpCacheRoot, { recursive: true, force: true }); } });