support/testing/utils: add basic tests for utils/generate-cyclonedx

Introduce unit-tests for the generate-cyclonedx script, covering basic
script invocation, patch CVE extraction and virtual packages.

Signed-off-by: Martin Willi <martin@strongswan.org>
Acked-By: Thomas Perale <thomas.perale@mind.be>
[Arnout: fix check-package errors]
Signed-off-by: Arnout Vandecappelle <arnout@rnout.be>
This commit is contained in:
Martin Willi
2026-04-09 10:13:56 +02:00
committed by Arnout Vandecappelle
parent d1517a34bc
commit 929e7cb005
2 changed files with 153 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
"""Unit tests for utils/generate-cyclonedx."""
import json
import os
import subprocess
import tempfile
import unittest
from pathlib import Path
import infra
PATCH = "support/testing/tests/utils/test_generate_cyclonedx/0001-cve_upstream.patch"
SCHEMA_LICENSES = ["MIT", "Apache-2.0", "GPL-3.0-only"]
class TestGenerateCycloneDX(unittest.TestCase):
def setUp(self):
# Provide a fake SPDX schema so the script never hits the network.
self.schema_dir = tempfile.TemporaryDirectory()
self.addCleanup(self.schema_dir.cleanup)
cyclonedx_dir = Path(self.schema_dir.name) / "cyclonedx"
cyclonedx_dir.mkdir(parents=True)
schema_path = cyclonedx_dir / "spdx-1.6.schema.json"
schema_path.write_text(json.dumps({"enum": SCHEMA_LICENSES}))
self.env = os.environ.copy()
self.env["BR2_DL_DIR"] = self.schema_dir.name
self.script = infra.basepath("utils/generate-cyclonedx")
self.cwd = infra.basepath()
def _make_show_info(self) -> dict:
return {
"package-foo": {
"name": "foo",
"version": "1.2",
"type": "target",
"virtual": False,
"licenses": "MIT",
"cpe-id": "cpe:2.3:a:example:foo:1.2:*:*:*:*:*:*:*",
"patches": [PATCH],
"provides": ["package-virtual"],
"dependencies": ["skeleton-baz", "package-bar"],
"ignore_cves": ["CVE-2025-0001"],
"package_dir": "package/package-foo",
},
"skeleton-baz": {
"name": "skeleton-baz",
"version": "0.1",
"type": "target",
"virtual": False,
"licenses": "Apache-2.0",
"dependencies": [],
"package_dir": "package/skeleton-baz",
},
"package-bar": {
"name": "bar",
"version": "0.2",
"type": "target",
"virtual": False,
"licenses": "MIT",
"ignore_cves": ["CVE-2025-0002"],
"dependencies": ["package-virtual"],
"package_dir": "package/package-bar",
},
"host-tool": {
"name": "host-tool",
"version": "0.3",
"type": "host",
"virtual": False,
"licenses": "GPL-3.0-only",
"dependencies": [],
"package_dir": "package/host-tool",
},
"package-virtual": {
"name": "virtual-provider",
"virtual": True,
"type": "target",
"dependencies": ["package-foo"],
"package_dir": "package/package-virtual",
},
}
def _run_script(self, extra_args=(), show_info=None):
data = show_info if show_info is not None else self._make_show_info()
completed = subprocess.run(
[self.script, *extra_args],
cwd=self.cwd,
env=self.env,
input=json.dumps(data),
text=True,
capture_output=True,
check=True,
)
return json.loads(completed.stdout)
def _find_component(self, result: dict, name: str) -> dict:
for component in result["components"]:
if component["bom-ref"] == name:
return component
self.fail(f"component {name} missing")
def test_default(self):
result = self._run_script()
self.assertEqual(len(result["components"]), 4)
self.assertIn("vulnerabilities", result)
vulnerabilities = {v["id"]: v for v in result["vulnerabilities"]}
self.assertEqual(len(vulnerabilities), 2)
self.assertEqual(vulnerabilities["CVE-2025-0001"]["analysis"]["state"], "resolved_with_pedigree")
self.assertEqual(vulnerabilities["CVE-2025-0002"]["analysis"]["state"], "in_triage")
foo = self._find_component(result, "package-foo")
patch = foo["pedigree"]["patches"][0]
self.assertIn("text", patch["diff"])
self.assertIn("content", patch["diff"]["text"])
host = self._find_component(result, "host-tool")
self.assertEqual(host["properties"][0]["value"], "host")
names = {c["bom-ref"] for c in result["components"]}
self.assertIn("skeleton-baz", names)
self.assertIn("package-bar", names)
self.assertNotIn("package-virtual", names)
foo_deps = next(d for d in result["dependencies"] if d["ref"] == "package-foo")
self.assertEqual(foo_deps["dependsOn"], ["package-bar", "skeleton-baz"])
bar_deps = next(d for d in result["dependencies"] if d["ref"] == "package-bar")
self.assertEqual(bar_deps["dependsOn"], ["package-foo"])
def test_virtual(self):
result = self._run_script(["--virtual"])
names = {c["bom-ref"] for c in result["components"]}
self.assertEqual(names, {"package-foo", "skeleton-baz", "host-tool", "package-virtual", "package-bar"})
foo_deps = next(d for d in result["dependencies"] if d["ref"] == "package-foo")
self.assertEqual(foo_deps["dependsOn"], ["package-bar", "skeleton-baz"])

View File

@@ -0,0 +1,14 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
CVE: CVE-2025-0001
Upstream: https://patches.example/foo.patch
Signed-off-by: the contributor
diff --git a/foo.txt b/foo.txt
index 0000001..0000002 100644
--- a/foo.txt
+++ b/foo.txt
@@
-foo
+bar