From: Stefano Tondo <[email protected]>

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 <[email protected]>
---
 meta/lib/oeqa/selftest/cases/spdx.py | 90 ++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

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)"
+        )
+
-- 
2.53.0

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#234293): 
https://lists.openembedded.org/g/openembedded-core/message/234293
Mute This Topic: https://lists.openembedded.org/mt/118596972/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to