Skip to content

Commit 113fda8

Browse files
committed
Refactor the dependency support in LoadSBOM #1145
Signed-off-by: tdruez <tdruez@nexb.com>
1 parent dd20d4d commit 113fda8

3 files changed

Lines changed: 44 additions & 15 deletions

File tree

scanpipe/pipelines/load_sbom.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# ScanCode.io is a free software code scanning tool from nexB Inc. and others.
2121
# Visit https://github.com/nexB/scancode.io for support and download.
2222

23+
from scanpipe.models import DiscoveredDependency
2324
from scanpipe.pipelines.scan_codebase import ScanCodebase
2425
from scanpipe.pipes import resolve
2526

@@ -44,7 +45,7 @@ def steps(cls):
4445
cls.flag_empty_files,
4546
cls.flag_ignored_resources,
4647
cls.get_sbom_inputs,
47-
cls.get_packages_from_sboms,
48+
cls.get_data_from_sboms,
4849
cls.create_packages_from_sboms,
4950
cls.create_dependencies_from_sboms,
5051
)
@@ -53,13 +54,13 @@ def get_sbom_inputs(self):
5354
"""Locate all the SBOMs among the codebase resources."""
5455
self.manifest_resources = resolve.get_manifest_resources(self.project)
5556

56-
def get_packages_from_sboms(self):
57+
def get_data_from_sboms(self):
5758
"""Get packages data from SBOMs."""
58-
self.packages = resolve.get_packages(
59+
self.packages, self.dependencies = resolve.get_data_from_manifests(
5960
project=self.project,
6061
package_registry=resolve.sbom_registry,
6162
manifest_resources=self.manifest_resources,
62-
model="get_packages_from_sboms",
63+
model="get_data_from_sboms",
6364
)
6465

6566
def create_packages_from_sboms(self):
@@ -71,4 +72,11 @@ def create_packages_from_sboms(self):
7172

7273
def create_dependencies_from_sboms(self):
7374
"""Create the dependency relationship declared in the SBOMs."""
75+
# TODO: Migrate the CycloneDX behavior too, see get_dependencies_from_manifest
7476
resolve.create_dependencies_from_packages_extra_data(project=self.project)
77+
78+
for dependency_data in self.dependencies:
79+
DiscoveredDependency.create_from_data(
80+
project=self.project,
81+
dependency_data=dependency_data,
82+
)

scanpipe/pipes/cyclonedx.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,12 @@ def cyclonedx_component_to_package_data(cdx_component, dependencies=None):
155155
dependencies = dependencies or {}
156156
extra_data = {}
157157

158-
# Store the original bom_ref and dependencies for future processing.
159158
bom_ref = str(cdx_component.bom_ref)
160-
if bom_ref:
161-
extra_data["bom_ref"] = bom_ref
162-
if depends_on := dependencies.get(bom_ref):
163-
extra_data["depends_on"] = depends_on
159+
if depends_on := dependencies.get(bom_ref):
160+
extra_data["depends_on"] = depends_on
161+
162+
# Store the original "bom_ref" as package_uid for dependencies resolution.
163+
package_uid = bom_ref
164164

165165
package_url_dict = {}
166166
if cdx_component.purl:
@@ -176,6 +176,7 @@ def cyclonedx_component_to_package_data(cdx_component, dependencies=None):
176176
extra_data["nestedComponents"] = sorted(nested_purls)
177177

178178
package_data = {
179+
"package_uid": package_uid,
179180
"name": cdx_component.name,
180181
"extracted_license_statement": declared_license,
181182
"copyright": cdx_component.copyright,

scanpipe/pipes/resolve.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,27 @@ def resolve_manifest_resources(resource, package_registry):
5757
return packages
5858

5959

60-
def get_packages(project, package_registry, manifest_resources, model=None):
60+
def get_dependencies_from_manifest(resource):
61+
"""Get dependency data from resource."""
62+
dependencies = []
63+
64+
default_package_type = get_default_package_type(resource.location)
65+
if not default_package_type:
66+
return []
67+
68+
if default_package_type == "spdx":
69+
dependencies = resolve_spdx_dependencies(input_location=resource.location)
70+
71+
return dependencies
72+
73+
74+
def get_data_from_manifests(project, package_registry, manifest_resources, model=None):
6175
"""
62-
Get package data from package manifests/lockfiles/SBOMs or
63-
get package data for resolved packages from package requirements.
76+
Get package and dependency data from package manifests/lockfiles/SBOMs or
77+
for resolved packages from package requirements.
6478
"""
6579
resolved_packages = []
80+
resolved_dependencies = []
6681
sboms_headers = {}
6782

6883
if not manifest_resources.exists():
@@ -73,7 +88,8 @@ def get_packages(project, package_registry, manifest_resources, model=None):
7388
return []
7489

7590
for resource in manifest_resources:
76-
if packages := resolve_manifest_resources(resource, package_registry):
91+
packages = resolve_manifest_resources(resource, package_registry)
92+
if packages:
7793
resolved_packages.extend(packages)
7894
if headers := get_manifest_headers(resource):
7995
sboms_headers[resource.name] = headers
@@ -84,10 +100,14 @@ def get_packages(project, package_registry, manifest_resources, model=None):
84100
resource=resource,
85101
)
86102

103+
dependencies = get_dependencies_from_manifest(resource)
104+
if dependencies:
105+
resolved_dependencies.extend(dependencies)
106+
87107
if sboms_headers:
88108
project.update_extra_data({"sboms_headers": sboms_headers})
89109

90-
return resolved_packages
110+
return resolved_packages, resolved_dependencies
91111

92112

93113
def create_packages_and_dependencies(project, packages, resolved=False):
@@ -136,7 +156,7 @@ def create_dependencies_from_packages_extra_data(project):
136156

137157
for bom_ref in for_package.extra_data.get("depends_on", []):
138158
try:
139-
resolved_to_package = project_packages.get(extra_data__bom_ref=bom_ref)
159+
resolved_to_package = project_packages.get(package_uid=bom_ref)
140160
except (ObjectDoesNotExist, MultipleObjectsReturned):
141161
project.add_error(
142162
description=f"Could not find resolved_to package entry: {bom_ref}.",

0 commit comments

Comments
 (0)