diff mbox series

[RFC,2/2] oeqa/selftest: Add tests for OpenVEX integration

Message ID 20260331141956.608976-3-stondo@gmail.com
State New
Headers show
Series spdx30: Add OpenVEX standalone document generation | expand

Commit Message

Stefano Tondo March 31, 2026, 2:19 p.m. UTC
From: Stefano Tondo <stefano.tondo.ext@siemens.com>

Add two test methods to SPDX30Check:
- test_openvex_integration: Verifies VEX relationships exist in SPDX
  output and packages have PURLs for VEX product identification
- test_openvex_standalone_files: Verifies standalone .vex.json files
  are created with proper metadata when OPENVEX_GENERATE_STANDALONE=1

Signed-off-by: Stefano Tondo <stefano.tondo.ext@siemens.com>
---
 meta/lib/oeqa/selftest/cases/spdx.py | 90 ++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)
diff mbox series

Patch

diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py
index 8285189382..661daa17d8 100644
--- a/meta/lib/oeqa/selftest/cases/spdx.py
+++ b/meta/lib/oeqa/selftest/cases/spdx.py
@@ -443,3 +443,93 @@  class SPDX30Check(SPDX3CheckBase, OESelftestTestCase):
                 r'\d',
                 f"Version '{version}' for package '{name}' should contain digits"
             )
+
+    def test_openvex_integration(self):
+        """
+        Test that OpenVEX generation is integrated into SPDX workflow.
+
+        Verifies VEX relationships are created for vulnerabilities and
+        packages have PURLs suitable for VEX product identification.
+        """
+        objset = self.check_recipe_spdx(
+            "busybox",
+            "{DEPLOY_DIR_SPDX}/{SSTATE_PKGARCH}/static/static-busybox.spdx.json",
+            task="create_recipe_spdx",
+            extraconf="""                OPENVEX_AUTHOR = "Test Author"
+                OPENVEX_ROLE = "securityAdvisor"
+                """,
+        )
+
+        # Check for VEX relationships (any type: Fixed, Affected, NotAffected, etc.)
+        vex_count = 0
+        for rel in objset.foreach_type(oe.spdx30.security_VexVulnAssessmentRelationship):
+            vex_count += 1
+            self.assertIsNotNone(rel.from_, "VEX relationship missing 'from' field")
+            self.assertIsNotNone(rel.to, "VEX relationship missing 'to' field")
+
+        if vex_count:
+            self.logger.info(f"Found {vex_count} VEX relationships in SPDX")
+        else:
+            self.logger.info("No VEX relationships found (expected if no CVEs)")
+
+        # Verify packages have PURLs for VEX product identification
+        packages_with_purls = []
+        for pkg in objset.foreach_type(oe.spdx30.software_Package):
+            if hasattr(pkg, "externalIdentifier") and pkg.externalIdentifier:
+                for ext_id in pkg.externalIdentifier:
+                    if hasattr(ext_id, "externalIdentifierType"):
+                        if "packageurl" in str(ext_id.externalIdentifierType).lower():
+                            packages_with_purls.append(pkg.name)
+                            break
+
+        self.assertGreater(
+            len(packages_with_purls), 0,
+            "Should have packages with PURLs for VEX product identification"
+        )
+        self.logger.info(f"Found {len(packages_with_purls)} packages with PURLs")
+
+    def test_openvex_standalone_files(self):
+        """
+        Test that standalone OpenVEX files are generated when enabled.
+
+        Verifies OpenVEX JSON files are created with required metadata
+        for a recipe with known CVEs (busybox).
+        """
+        import json
+        from pathlib import Path
+
+        self.check_recipe_spdx(
+            "busybox",
+            "{DEPLOY_DIR_SPDX}/{SSTATE_PKGARCH}/static/static-busybox.spdx.json",
+            task="create_recipe_spdx",
+            extraconf="""                OPENVEX_GENERATE_STANDALONE = "1"
+                OPENVEX_AUTHOR = "Test Security Team"
+                OPENVEX_ROLE = "securityAdvisor"
+                """,
+        )
+
+        deploy_dir_spdx = get_bb_var("DEPLOY_DIR_SPDX")
+        sstate_pkgarch = get_bb_var("SSTATE_PKGARCH", "busybox")
+
+        vex_file = Path(deploy_dir_spdx) / sstate_pkgarch / "recipes" / "busybox.vex.json"
+
+        self.assertExists(str(vex_file), "busybox.vex.json should exist (busybox has known CVEs)")
+
+        with open(vex_file, "r") as f:
+            vex_data = json.load(f)
+
+        self.assertIn("@context", vex_data, "VEX missing @context")
+        self.assertIn("statements", vex_data, "VEX missing statements")
+        self.assertGreater(len(vex_data["statements"]), 0, "VEX should have at least one statement")
+
+        self.assertEqual(
+            vex_data["author"],
+            "Test Security Team",
+            "VEX author not set correctly"
+        )
+
+        self.logger.info(
+            f"Validated OpenVEX file: busybox.vex.json "
+            f"({len(vex_data['statements'])} statements)"
+        )
+