Skip to content

Commit 785126b

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/1949-d2d-multiple-binaries
merging & resolving conflicts
2 parents 58fa002 + f21f18d commit 785126b

12 files changed

Lines changed: 152 additions & 45 deletions

File tree

README.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,8 @@ for any legal advice.
5757

5858

5959

60-
61-
.. |ci-tests| image:: https://github.com/aboutcode-org/scancode.io/actions/workflows/ci.yml/badge.svg?branch=main
62-
:target: https://github.com/aboutcode-org/scancode.io/actions/workflows/ci.yml
60+
.. |ci-tests| image:: https://github.com/aboutcode-org/scancode.io/actions/workflows/run-unit-tests.yml/badge.svg?branch=main
61+
:target: https://github.com/aboutcode-org/scancode.io/actions/workflows/run-unit-tests.yml
6362
:alt: CI Tests Status
6463

6564
.. |docs-rtd| image:: https://readthedocs.org/projects/scancodeio/badge/?version=latest

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ android_analysis = [
123123
"android_inspector==0.0.1"
124124
]
125125
mining = [
126-
"minecode_pipelines==0.0.1b8"
126+
"minecode_pipelines==0.1.1"
127127
]
128128

129129
[project.urls]

scanpipe/pipes/cyclonedx.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from cyclonedx.model import license as cdx_license_model
3131
from cyclonedx.model.bom import Bom
3232
from cyclonedx.schema import SchemaVersion
33+
from cyclonedx.schema.schema import BaseSchemaVersion
3334
from cyclonedx.validation import ValidationError
3435
from cyclonedx.validation.json import JsonStrictValidator
3536
from defusedxml import ElementTree as SafeElementTree
@@ -184,10 +185,12 @@ def cyclonedx_component_to_package_data(
184185
affected_by_vulnerabilities = []
185186
if affected_by := vulnerabilities.get(bom_ref):
186187
for cdx_vulnerability in affected_by:
188+
cdx_vulnerability_json = cdx_vulnerability.as_json(view_=BaseSchemaVersion)
187189
affected_by_vulnerabilities.append(
188190
{
189191
"vulnerability_id": str(cdx_vulnerability.id),
190192
"summary": cdx_vulnerability.description,
193+
"cdx_vulnerability_data": json.loads(cdx_vulnerability_json),
191194
}
192195
)
193196

scanpipe/pipes/d2d.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,21 @@ def _map_jvm_to_class_resource(
174174
from/ fully qualified binary files.
175175
"""
176176
for extension in jvm_lang.source_extensions:
177-
normalized_path = jvm_lang.get_normalized_path(
177+
# Perform basic conversion from .class to source file path
178+
source_path = jvm_lang.get_source_path(
178179
path=to_resource.path, extension=extension
179180
)
180-
match = pathmap.find_paths(path=normalized_path, index=from_classes_index)
181+
# Perform basic mapping without normalization for scenarios listed in
182+
# https://github.com/aboutcode-org/scancode.io/issues/1873
183+
match = pathmap.find_paths(path=source_path, index=from_classes_index)
184+
181185
if not match:
182-
return
186+
normalized_path = jvm_lang.get_normalized_path(
187+
path=to_resource.path, extension=extension
188+
)
189+
match = pathmap.find_paths(path=normalized_path, index=from_classes_index)
190+
if not match:
191+
return
183192

184193
for resource_id in match.resource_ids:
185194
from_resource = from_resources.get(id=resource_id)

scanpipe/pipes/jvm.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,27 @@ def get_normalized_path(cls, path, extension):
140140
# https://github.com/aboutcode-org/scancode.io/issues/1994
141141
if class_name.endswith("_$logger.class"):
142142
class_name, _, _ = class_name.partition("_$logger.class")
143-
elif "$" in class_name: # inner class
143+
elif "$" in class_name and not class_name.startswith("$"): # inner class
144144
class_name, _, _ = class_name.partition("$")
145145
else:
146146
class_name, _, _ = class_name.partition(".") # plain .class
147147
return str(path.parent / f"{class_name}{extension}")
148148

149+
@classmethod
150+
def get_source_path(cls, path, extension):
151+
"""
152+
Return a JVM file path for ``path`` .class file path string.
153+
No normalization is performed.
154+
"""
155+
if not path.endswith(cls.binary_extensions):
156+
raise ValueError(
157+
f"Only path ending with {cls.binary_extensions} are supported."
158+
)
159+
path = Path(path.strip("/"))
160+
class_name = path.name
161+
class_name, _, _ = class_name.partition(".") # plain .class
162+
return str(path.parent / f"{class_name}{extension}")
163+
149164

150165
def find_expression(lines, regex):
151166
"""

scanpipe/pipes/ort.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,28 @@ def get_ort_project_type(project):
130130
return "docker"
131131

132132

133+
def sanitize_id_part(value):
134+
"""
135+
Sanitize an identifier part by replacing colons with underscores.
136+
ORT uses colons as separators in the identifier string representation.
137+
"""
138+
if value:
139+
return value.replace(":", "_")
140+
return value
141+
142+
133143
def to_ort_package_list_yml(project):
134144
"""Convert a project object into a YAML string in the ORT package list format."""
135145
project_type = get_ort_project_type(project)
136146

137147
dependencies = []
138148
for package in project.discoveredpackages.all():
149+
type_ = sanitize_id_part(project_type or package.type)
150+
name = sanitize_id_part(package.name)
151+
version = sanitize_id_part(package.version)
152+
139153
dependency = Dependency(
140-
id=f"{project_type or package.type}::{package.name}:{package.version}",
154+
id=f"{type_}::{name}:{version}",
141155
purl=package.purl,
142156
sourceArtifact=SourceArtifact(url=package.download_url),
143157
declaredLicenses=[package.get_declared_license_expression_spdx()],

scanpipe/pipes/pathmap.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,12 @@ def get_reversed_path_segments(path):
164164
Return reversed segments list given a POSIX ``path`` string. We reverse
165165
based on path segments separated by a "/".
166166
167-
Note that the inputh ``path`` is assumed to be normalized, not relative and
167+
Note that the input ``path`` is assumed to be normalized, not relative and
168168
not containing double slash.
169169
170-
For example::
171-
>>> assert get_reversed_path_segments("a/b/c.js") == ["c.js", "b", "a"]
170+
For example:
171+
>>> get_reversed_path_segments("a/b/c.js")
172+
['c.js', 'b', 'a']
172173
"""
173174
# [::-1] does the list reversing
174175
reversed_segments = path.strip("/").split("/")[::-1]
@@ -177,13 +178,14 @@ def get_reversed_path_segments(path):
177178

178179
def convert_segments_to_path(segments):
179180
"""
180-
Return a path string is suitable for indexing or matching given a
181+
Return a path string suitable for indexing or matching given a
181182
``segments`` sequence of path segment strings.
182183
The resulting reversed path is prefixed and suffixed by a "/" irrespective
183184
of whether the original path is a file or directory and had such prefix or
184185
suffix.
185186
186-
For example::
187-
>>> assert convert_segments_to_path(["c.js", "b", "a"]) == "/c.js/b/a/"
187+
For example:
188+
>>> convert_segments_to_path(["c.js", "b", "a"])
189+
'/c.js/b/a/'
188190
"""
189191
return "/" + "/".join(segments) + "/"

scanpipe/templates/scanpipe/tabset/tab_vulnerabilities.html

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
33
<thead>
44
<tr>
5-
<th style="width: 210px;">Affected by</th>
5+
<th style="width: 220px;">Affected by</th>
66
<th>Summary</th>
7-
<th style="width: 210px;">Aliases</th>
7+
<th>Analysis</th>
88
</tr>
99
</thead>
1010
<tbody>
@@ -15,28 +15,43 @@
1515
{{ vulnerability.vulnerability_id }}
1616
<i class="fa-solid fa-up-right-from-square is-small"></i>
1717
</a>
18+
<ul class="list-unstyled mb-0">
19+
{% for alias in aliases %}
20+
<li>
21+
{% if alias|slice:":3" == "CVE" %}
22+
<a href="https://nvd.nist.gov/vuln/detail/{{ alias }}" target="_blank">{{ alias }}
23+
<i class="fa-solid fa-up-right-from-square mini"></i>
24+
</a>
25+
{% elif alias|slice:":4" == "GHSA" %}
26+
<a href="https://github.com/advisories/{{ alias }}" target="_blank">{{ alias }}
27+
<i class="fa-solid fa-up-right-from-square mini"></i>
28+
</a>
29+
{% elif alias|slice:":3" == "NPM" %}
30+
<a href="https://github.com/nodejs/security-wg/blob/main/vuln/npm/{{ alias|slice:"4:" }}.json" target="_blank">{{ alias }}
31+
<i class="fa-solid fa-up-right-from-square mini"></i>
32+
</a>
33+
{% else %}
34+
{{ alias }}
35+
{% endif %}
36+
</li>
37+
{% endfor %}
38+
</ul>
1839
</td>
1940
<td>
20-
{{ vulnerability.summary }}
21-
</td>
22-
<td>
23-
{% for alias in vulnerability.aliases %}
24-
{% if alias|slice:":3" == "CVE" %}
25-
<a href="https://nvd.nist.gov/vuln/detail/{{ alias }}" target="_blank">{{ alias }}
26-
<i class="fa-solid fa-up-right-from-square is-small"></i>
27-
</a>
28-
{% elif alias|slice:":4" == "GHSA" %}
29-
<a href="https://github.com/advisories/{{ alias }}" target="_blank">{{ alias }}
30-
<i class="fa-solid fa-up-right-from-square is-small"></i>
31-
</a>
32-
{% elif alias|slice:":3" == "NPM" %}
33-
<a href="https://github.com/nodejs/security-wg/blob/main/vuln/npm/{{ alias|slice:"4:" }}.json" target="_blank">{{ alias }}
34-
<i class="fa-solid fa-up-right-from-square is-small"></i>
35-
</a>
41+
{% if vulnerability.summary %}
42+
{% if vulnerability.summary|length > 150 %}
43+
<details>
44+
<summary>{{ vulnerability.summary|slice:":150" }}...</summary>
45+
{{ vulnerability.summary|slice:"150:" }}
46+
</details>
3647
{% else %}
37-
{{ alias }}
48+
{{ vulnerability.summary }}
3849
{% endif %}
39-
<br>
50+
{% endif %}
51+
</td>
52+
<td>
53+
{% for key, value in vulnerability.cdx_vulnerability.analysis.items %}
54+
<strong>{{ key }}:</strong> {{ value }}{% if not forloop.last %}<br>{% endif %}
4055
{% endfor %}
4156
</td>
4257
</tr>

scanpipe/tests/pipes/test_cyclonedx.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,24 @@ def test_scanpipe_cyclonedx_resolve_cyclonedx_packages_vulnerabilities(self):
250250
self.assertEqual(1, len(packages))
251251

252252
affected_by = packages[0]["affected_by_vulnerabilities"]
253+
self.assertEqual("CVE-2005-2541", affected_by[0]["vulnerability_id"])
254+
self.assertEqual(
255+
"Tar 1.15.1 does not properly warn the user when...",
256+
affected_by[0]["summary"],
257+
)
258+
self.assertIn("cdx_vulnerability_data", affected_by[0])
259+
cdx_vulnerability_data = affected_by[0]["cdx_vulnerability_data"]
253260
expected = [
254-
{
255-
"vulnerability_id": "CVE-2005-2541",
256-
"summary": "Tar 1.15.1 does not properly warn the user when...",
257-
}
261+
"advisories",
262+
"affects",
263+
"description",
264+
"id",
265+
"published",
266+
"ratings",
267+
"source",
268+
"updated",
258269
]
259-
self.assertEqual(expected, affected_by)
270+
self.assertEqual(expected, sorted(cdx_vulnerability_data.keys()))
260271

261272
def test_scanpipe_cyclonedx_resolve_cyclonedx_packages_pre_validation(self):
262273
# This SBOM includes multiple deserialization issues that are "fixed"

scanpipe/tests/pipes/test_jvm.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ def test_scanpipe_pipes_jvm_get_java_package_too_far_down(self):
8484
package = jvm.JavaLanguage.get_source_package(input_location)
8585
self.assertIsNone(package)
8686

87+
def test_scanpipe_pipes_jvm_get_source_java_path(self):
88+
njp = jvm.JavaLanguage.get_source_path("foo/org/common/Bar.class", ".java")
89+
self.assertEqual("foo/org/common/Bar.java", njp)
90+
91+
def test_scanpipe_pipes_jvm_get_source_java_path_with_inner_class(self):
92+
njp = jvm.JavaLanguage.get_source_path(
93+
"foo/org/common/Bar$inner.class", ".java"
94+
)
95+
self.assertEqual("foo/org/common/Bar$inner.java", njp)
96+
8797
def test_scanpipe_pipes_jvm_get_normalized_java_path(self):
8898
njp = jvm.JavaLanguage.get_normalized_path("foo/org/common/Bar.class", ".java")
8999
self.assertEqual("foo/org/common/Bar.java", njp)

0 commit comments

Comments
 (0)