mirror of
https://gitlab.com/buildroot.org/buildroot.git
synced 2026-08-01 21:23:51 -09:00
BSI TR-03183-2 5.4.2 [1] lists source code URIs under "Additional data fields for each component", and as such "MUST additionally be provided, if it exists". If a http or https source download URI is available from show-info, extract it and include it as an externalReference of type "source-distribution" in the CycloneDX output. [1] https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03183/BSI-TR-03183-2_v2_1_0.pdf?__blob=publicationFile&v=5 Signed-off-by: Martin Willi <martin@strongswan.org> Acked-by: Thomas Perale <thomas.perale@mind.be> Signed-off-by: Arnout Vandecappelle <arnout@rnout.be>
169 lines
6.1 KiB
Python
169 lines
6.1 KiB
Python
"""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"])
|
|
|
|
project_deps = next(d for d in result["dependencies"] if d["ref"] == "buildroot")
|
|
self.assertEqual(project_deps["dependsOn"], ["host-tool", "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"])
|
|
|
|
def test_external_references(self):
|
|
info = self._make_show_info()
|
|
info["package-foo"]["downloads"] = [
|
|
{
|
|
"source": "foo-1.2.tar.gz",
|
|
"uris": [
|
|
"https+https://sources.buildroot.net/foo",
|
|
"http|https+https://mirror.example.org/foo",
|
|
],
|
|
},
|
|
]
|
|
|
|
result = self._run_script(show_info=info)
|
|
foo = self._find_component(result, "package-foo")
|
|
|
|
self.assertIn("externalReferences", foo)
|
|
self.assertEqual(
|
|
foo["externalReferences"],
|
|
[
|
|
{
|
|
"type": "source-distribution",
|
|
"url": "https://mirror.example.org/foo/foo-1.2.tar.gz",
|
|
},
|
|
],
|
|
)
|