Skip to content

Commit f7b9579

Browse files
authored
Store SBOMs headers in the Project.extra_data field #1253 (#1266)
* Store SBOMs headers in the `Project.extra_data` field #1253 Signed-off-by: tdruez <tdruez@nexb.com> * Add unit test for the SBOM headers on Project.extra_data #1253 Signed-off-by: tdruez <tdruez@nexb.com> --------- Signed-off-by: tdruez <tdruez@nexb.com>
1 parent f4f0aec commit f7b9579

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
Changelog
22
=========
33

4+
v34.6.2 (unreleased)
5+
--------------------
6+
7+
- Store SBOMs headers in the `Project.extra_data` field during the load_sboms
8+
pipeline.
9+
https://github.com/nexB/scancode.io/issues/1253
10+
411
v34.6.1 (2024-06-07)
512
--------------------
613

scanpipe/pipes/resolve.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def get_packages(project, package_registry, manifest_resources, model=None):
5858
get package data for resolved packages from package requirements.
5959
"""
6060
resolved_packages = []
61+
sboms_headers = {}
6162

6263
if not manifest_resources.exists():
6364
project.add_warning(
@@ -69,13 +70,18 @@ def get_packages(project, package_registry, manifest_resources, model=None):
6970
for resource in manifest_resources:
7071
if packages := resolve_manifest_resources(resource, package_registry):
7172
resolved_packages.extend(packages)
73+
if headers := get_manifest_headers(resource):
74+
sboms_headers[resource.name] = headers
7275
else:
7376
project.add_error(
7477
description="No packages could be resolved",
7578
model=model,
7679
resource=resource,
7780
)
7881

82+
if sboms_headers:
83+
project.update_extra_data({"sboms_headers": sboms_headers})
84+
7985
return resolved_packages
8086

8187

@@ -320,3 +326,49 @@ def set_license_expression(package_data):
320326
package_data["declared_license_expression"] = license_expression
321327

322328
return package_data
329+
330+
331+
def get_manifest_headers(resource):
332+
"""Extract headers from a manifest file based on its package type."""
333+
input_location = resource.location
334+
package_type = get_default_package_type(input_location)
335+
extract_fields = []
336+
337+
if package_type == "cyclonedx":
338+
extract_fields = [
339+
"bomFormat",
340+
"specVersion",
341+
"serialNumber",
342+
"version",
343+
"metadata",
344+
]
345+
elif package_type == "spdx":
346+
extract_fields = [
347+
"spdxVersion",
348+
"dataLicense",
349+
"SPDXID",
350+
"name",
351+
"documentNamespace",
352+
"creationInfo",
353+
"comment",
354+
]
355+
356+
if extract_fields:
357+
return extract_headers(input_location, extract_fields)
358+
359+
360+
def extract_headers(input_location, extract_fields):
361+
"""Read a file from the given location and extracts specified fields."""
362+
input_path = Path(input_location)
363+
document_data = input_path.read_text()
364+
365+
if str(input_location).endswith(".json"):
366+
cyclonedx_document = json.loads(document_data)
367+
extracted_headers = {
368+
field: value
369+
for field, value in cyclonedx_document.items()
370+
if field in extract_fields
371+
}
372+
return extracted_headers
373+
374+
return {}

scanpipe/tests/pipes/test_resolve.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
from django.test import TestCase
2626

27+
import mock
28+
2729
from scanpipe import pipes
2830
from scanpipe.models import Project
2931
from scanpipe.pipes import resolve
@@ -201,6 +203,20 @@ def test_scanpipe_resolve_get_packages_from_sbom(self):
201203
resource1 = project1.codebaseresources.get(name="toml.spdx.json")
202204
self.assertEqual([resource1], package.get("codebase_resources"))
203205

206+
self.assertEqual(["sboms_headers"], list(project1.extra_data.keys()))
207+
sboms_headers = project1.extra_data["sboms_headers"]
208+
self.assertEqual(["toml.spdx.json"], list(sboms_headers.keys()))
209+
expected = [
210+
"spdxVersion",
211+
"dataLicense",
212+
"SPDXID",
213+
"name",
214+
"documentNamespace",
215+
"creationInfo",
216+
"comment",
217+
]
218+
self.assertEqual(expected, list(sboms_headers["toml.spdx.json"].keys()))
219+
204220
def test_scanpipe_resolve_create_packages_and_dependencies(self):
205221
project1 = Project.objects.create(name="Analysis")
206222
input_location = self.data_location / "manifests" / "toml.spdx.json"
@@ -221,3 +237,18 @@ def test_scanpipe_resolve_create_packages_and_dependencies(self):
221237
resource1 = project1.codebaseresources.get(name="toml.spdx.json")
222238
package = project1.discoveredpackages.get()
223239
self.assertEqual(resource1, package.codebase_resources.get())
240+
241+
def test_scanpipe_resolve_get_manifest_headers(self):
242+
input_location = self.data_location / "manifests" / "toml.spdx.json"
243+
resource = mock.Mock(location=input_location)
244+
expected = [
245+
"spdxVersion",
246+
"dataLicense",
247+
"SPDXID",
248+
"name",
249+
"documentNamespace",
250+
"creationInfo",
251+
"comment",
252+
]
253+
headers = resolve.get_manifest_headers(resource)
254+
self.assertEqual(expected, list(headers.keys()))

0 commit comments

Comments
 (0)