From: stondo@gmail.com
To: openembedded-core@lists.openembedded.org
Cc: JPEWhacker@gmail.com, richard.purdie@linuxfoundation.org,
ross.burton@arm.com, marta.rybczynska@syslinbit.com,
benjamin.robin@bootlin.com, peter.marko@siemens.com,
adrian.freihofer@siemens.com, mathieu.dubois-briand@bootlin.com,
stefano.tondo.ext@siemens.com
Subject: [RFC PATCH 2/2] oeqa/selftest: Add tests for OpenVEX integration
Date: Tue, 31 Mar 2026 16:19:56 +0200 [thread overview]
Message-ID: <20260331141956.608976-3-stondo@gmail.com> (raw)
In-Reply-To: <20260331141956.608976-1-stondo@gmail.com>
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 --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
next prev parent reply other threads:[~2026-03-31 14:20 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-31 14:19 [RFC PATCH 0/2] spdx30: Add OpenVEX standalone document generation stondo
2026-03-31 14:19 ` [RFC PATCH 1/2] " stondo
2026-03-31 14:19 ` stondo [this message]
2026-03-31 14:23 ` [RFC PATCH 0/2] " Richard Purdie
2026-03-31 14:46 ` [OE-core] " Marta Rybczynska
2026-03-31 15:04 ` Joshua Watt
2026-03-31 22:05 ` Freihofer, Adrian
2026-04-01 7:43 ` Benjamin Robin
2026-04-01 9:58 ` Freihofer, Adrian
2026-04-01 11:34 ` Benjamin Robin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260331141956.608976-3-stondo@gmail.com \
--to=stondo@gmail.com \
--cc=JPEWhacker@gmail.com \
--cc=adrian.freihofer@siemens.com \
--cc=benjamin.robin@bootlin.com \
--cc=marta.rybczynska@syslinbit.com \
--cc=mathieu.dubois-briand@bootlin.com \
--cc=openembedded-core@lists.openembedded.org \
--cc=peter.marko@siemens.com \
--cc=richard.purdie@linuxfoundation.org \
--cc=ross.burton@arm.com \
--cc=stefano.tondo.ext@siemens.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox