scanoss 1.19.6__py3-none-any.whl → 1.20.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- protoc_gen_swagger/__init__.py +13 -13
- protoc_gen_swagger/options/__init__.py +13 -13
- protoc_gen_swagger/options/annotations_pb2.py +12 -9
- protoc_gen_swagger/options/annotations_pb2_grpc.py +1 -1
- protoc_gen_swagger/options/openapiv2_pb2.py +98 -96
- protoc_gen_swagger/options/openapiv2_pb2_grpc.py +1 -1
- scanoss/__init__.py +18 -18
- scanoss/api/__init__.py +17 -17
- scanoss/api/common/__init__.py +17 -17
- scanoss/api/common/v2/__init__.py +17 -17
- scanoss/api/common/v2/scanoss_common_pb2.py +18 -18
- scanoss/api/common/v2/scanoss_common_pb2_grpc.py +1 -1
- scanoss/api/components/__init__.py +17 -17
- scanoss/api/components/v2/__init__.py +17 -17
- scanoss/api/components/v2/scanoss_components_pb2.py +48 -38
- scanoss/api/components/v2/scanoss_components_pb2_grpc.py +142 -96
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +22 -16
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +75 -49
- scanoss/api/dependencies/__init__.py +17 -17
- scanoss/api/dependencies/v2/__init__.py +17 -17
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +30 -24
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +75 -49
- scanoss/api/provenance/__init__.py +23 -0
- scanoss/api/provenance/v2/__init__.py +23 -0
- scanoss/api/provenance/v2/scanoss_provenance_pb2.py +42 -0
- scanoss/api/provenance/v2/scanoss_provenance_pb2_grpc.py +108 -0
- scanoss/api/scanning/__init__.py +17 -17
- scanoss/api/scanning/v2/__init__.py +17 -17
- scanoss/api/scanning/v2/scanoss_scanning_pb2.py +10 -8
- scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +40 -32
- scanoss/api/semgrep/__init__.py +17 -17
- scanoss/api/semgrep/v2/__init__.py +17 -17
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +22 -18
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +71 -49
- scanoss/api/vulnerabilities/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +37 -27
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +109 -72
- scanoss/cli.py +578 -264
- scanoss/components.py +99 -48
- scanoss/csvoutput.py +83 -56
- scanoss/cyclonedx.py +48 -46
- scanoss/data/build_date.txt +1 -1
- scanoss/file_filters.py +13 -15
- scanoss/filecount.py +43 -36
- scanoss/inspection/__init__.py +17 -17
- scanoss/inspection/copyleft.py +71 -58
- scanoss/inspection/policy_check.py +76 -53
- scanoss/inspection/undeclared_component.py +98 -75
- scanoss/inspection/utils/license_utils.py +66 -44
- scanoss/results.py +51 -60
- scanoss/scancodedeps.py +61 -38
- scanoss/scanner.py +203 -135
- scanoss/scanoss_settings.py +5 -3
- scanoss/scanossapi.py +98 -69
- scanoss/scanossbase.py +19 -19
- scanoss/scanossgrpc.py +107 -51
- scanoss/scanpostprocessor.py +9 -6
- scanoss/scantype.py +22 -21
- scanoss/spdxlite.py +265 -171
- scanoss/threadeddependencies.py +91 -61
- scanoss/threadedscanning.py +37 -31
- scanoss/utils/file.py +4 -4
- scanoss/winnowing.py +111 -47
- {scanoss-1.19.6.dist-info → scanoss-1.20.1.dist-info}/METADATA +1 -1
- scanoss-1.20.1.dist-info/RECORD +74 -0
- scanoss-1.19.6.dist-info/RECORD +0 -70
- {scanoss-1.19.6.dist-info → scanoss-1.20.1.dist-info}/LICENSE +0 -0
- {scanoss-1.19.6.dist-info → scanoss-1.20.1.dist-info}/WHEEL +0 -0
- {scanoss-1.19.6.dist-info → scanoss-1.20.1.dist-info}/entry_points.txt +0 -0
- {scanoss-1.19.6.dist-info → scanoss-1.20.1.dist-info}/top_level.txt +0 -0
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024, SCANOSS
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
|
23
23
|
"""
|
|
24
|
+
|
|
24
25
|
import json
|
|
25
26
|
import os.path
|
|
26
27
|
from abc import abstractmethod
|
|
@@ -39,13 +40,17 @@ class PolicyStatus(Enum):
|
|
|
39
40
|
FAIL (int): Indicates that the policy check failed (value: 1).
|
|
40
41
|
ERROR (int): Indicates that an error occurred during the policy check (value: 2).
|
|
41
42
|
"""
|
|
43
|
+
|
|
42
44
|
SUCCESS = 0
|
|
43
45
|
FAIL = 1
|
|
44
46
|
ERROR = 2
|
|
47
|
+
|
|
48
|
+
|
|
45
49
|
#
|
|
46
50
|
# End of PolicyStatus Class
|
|
47
51
|
#
|
|
48
52
|
|
|
53
|
+
|
|
49
54
|
class ComponentID(Enum):
|
|
50
55
|
"""
|
|
51
56
|
Enumeration representing different types of software components.
|
|
@@ -55,13 +60,17 @@ class ComponentID(Enum):
|
|
|
55
60
|
SNIPPET (str): Represents a code snippet component (value: "snippet").
|
|
56
61
|
DEPENDENCY (str): Represents a dependency component (value: "dependency").
|
|
57
62
|
"""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
|
|
64
|
+
FILE = 'file'
|
|
65
|
+
SNIPPET = 'snippet'
|
|
66
|
+
DEPENDENCY = 'dependency'
|
|
67
|
+
|
|
68
|
+
|
|
61
69
|
#
|
|
62
70
|
# End of ComponentID Class
|
|
63
71
|
#
|
|
64
72
|
|
|
73
|
+
|
|
65
74
|
class PolicyCheck(ScanossBase):
|
|
66
75
|
"""
|
|
67
76
|
A base class for implementing various software policy checks.
|
|
@@ -78,8 +87,17 @@ class PolicyCheck(ScanossBase):
|
|
|
78
87
|
|
|
79
88
|
VALID_FORMATS = {'md', 'json', 'jira_md'}
|
|
80
89
|
|
|
81
|
-
def __init__(
|
|
82
|
-
|
|
90
|
+
def __init__(
|
|
91
|
+
self,
|
|
92
|
+
debug: bool = False,
|
|
93
|
+
trace: bool = True,
|
|
94
|
+
quiet: bool = False,
|
|
95
|
+
filepath: str = None,
|
|
96
|
+
format_type: str = None,
|
|
97
|
+
status: str = None,
|
|
98
|
+
output: str = None,
|
|
99
|
+
name: str = None,
|
|
100
|
+
):
|
|
83
101
|
super().__init__(debug, trace, quiet)
|
|
84
102
|
self.license_util = LicenseUtil()
|
|
85
103
|
self.filepath = filepath
|
|
@@ -110,14 +128,14 @@ class PolicyCheck(ScanossBase):
|
|
|
110
128
|
@abstractmethod
|
|
111
129
|
def _json(self, components: list) -> Dict[str, Any]:
|
|
112
130
|
"""
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
131
|
+
Format the policy checks results as JSON.
|
|
132
|
+
This method should be implemented by subclasses to create a Markdown representation
|
|
133
|
+
of the policy check results.
|
|
134
|
+
|
|
135
|
+
:param components: List of components to be formatted.
|
|
136
|
+
:return: A dictionary containing two keys:
|
|
137
|
+
- 'details': A JSON-formatted string with the full list of components
|
|
138
|
+
- 'summary': A string summarizing the number of components found
|
|
121
139
|
"""
|
|
122
140
|
pass
|
|
123
141
|
|
|
@@ -147,8 +165,9 @@ class PolicyCheck(ScanossBase):
|
|
|
147
165
|
"""
|
|
148
166
|
pass
|
|
149
167
|
|
|
150
|
-
def _append_component(
|
|
151
|
-
|
|
168
|
+
def _append_component(
|
|
169
|
+
self, components: Dict[str, Any], new_component: Dict[str, Any], id: str, status: str
|
|
170
|
+
) -> Dict[str, Any]:
|
|
152
171
|
"""
|
|
153
172
|
Append a new component to the component's dictionary.
|
|
154
173
|
|
|
@@ -169,12 +188,12 @@ class PolicyCheck(ScanossBase):
|
|
|
169
188
|
else:
|
|
170
189
|
purl = new_component['purl']
|
|
171
190
|
|
|
172
|
-
component_key = f
|
|
191
|
+
component_key = f'{purl}@{new_component["version"]}'
|
|
173
192
|
components[component_key] = {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
'purl': purl,
|
|
194
|
+
'version': new_component['version'],
|
|
195
|
+
'licenses': {},
|
|
196
|
+
'status': status,
|
|
178
197
|
}
|
|
179
198
|
|
|
180
199
|
if not new_component.get('licenses'):
|
|
@@ -191,16 +210,16 @@ class PolicyCheck(ScanossBase):
|
|
|
191
210
|
}
|
|
192
211
|
return components
|
|
193
212
|
|
|
194
|
-
def _get_components_from_results(self,results: Dict[str, Any]) -> list or None:
|
|
213
|
+
def _get_components_from_results(self, results: Dict[str, Any]) -> list or None:
|
|
195
214
|
"""
|
|
196
|
-
|
|
215
|
+
Process the results dictionary to extract and format component information.
|
|
197
216
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
217
|
+
This function iterates through the results dictionary, identifying components from
|
|
218
|
+
different sources (files, snippets, and dependencies). It consolidates this information
|
|
219
|
+
into a list of unique components, each with its associated licenses and other details.
|
|
201
220
|
|
|
202
|
-
|
|
203
|
-
|
|
221
|
+
:param results: A dictionary containing the raw results of a component scan
|
|
222
|
+
:return: A list of dictionaries, each representing a unique component with its details
|
|
204
223
|
"""
|
|
205
224
|
if results is None:
|
|
206
225
|
self.print_stderr(f'ERROR: Results cannot be empty')
|
|
@@ -226,7 +245,7 @@ class PolicyCheck(ScanossBase):
|
|
|
226
245
|
if not c.get('version'):
|
|
227
246
|
self.print_stderr(f'WARNING: Result missing version. Skipping.')
|
|
228
247
|
continue
|
|
229
|
-
component_key = f
|
|
248
|
+
component_key = f'{c["purl"][0]}@{c["version"]}'
|
|
230
249
|
# Initialize or update the component entry
|
|
231
250
|
if component_key not in components:
|
|
232
251
|
components = self._append_component(components, c, component_id, status)
|
|
@@ -244,7 +263,7 @@ class PolicyCheck(ScanossBase):
|
|
|
244
263
|
if not d.get('version'):
|
|
245
264
|
self.print_stderr(f'WARNING: Result missing version. Skipping.')
|
|
246
265
|
continue
|
|
247
|
-
component_key = f
|
|
266
|
+
component_key = f'{d["purl"]}@{d["version"]}'
|
|
248
267
|
if component_key not in components:
|
|
249
268
|
components = self._append_component(components, d, component_id, status)
|
|
250
269
|
# End of dependencies loop
|
|
@@ -271,11 +290,13 @@ class PolicyCheck(ScanossBase):
|
|
|
271
290
|
if headers is None:
|
|
272
291
|
self.print_stderr('ERROR: Header are no set')
|
|
273
292
|
return None
|
|
293
|
+
|
|
274
294
|
# Decide which separator to use
|
|
275
295
|
def create_separator(index):
|
|
276
296
|
if centered_columns is None:
|
|
277
297
|
return '-'
|
|
278
298
|
return ':-:' if index in centered_column_set else '-'
|
|
299
|
+
|
|
279
300
|
# Build the row separator
|
|
280
301
|
row_separator = col_sep + col_sep.join(create_separator(index) for index, _ in enumerate(headers)) + col_sep
|
|
281
302
|
# build table rows
|
|
@@ -297,7 +318,7 @@ class PolicyCheck(ScanossBase):
|
|
|
297
318
|
|
|
298
319
|
return table
|
|
299
320
|
|
|
300
|
-
def _get_formatter(self)-> Callable[[List[dict]], Dict[str,Any]] or None:
|
|
321
|
+
def _get_formatter(self) -> Callable[[List[dict]], Dict[str, Any]] or None:
|
|
301
322
|
"""
|
|
302
323
|
Get the appropriate formatter function based on the specified format.
|
|
303
324
|
|
|
@@ -348,11 +369,11 @@ class PolicyCheck(ScanossBase):
|
|
|
348
369
|
|
|
349
370
|
Returns:
|
|
350
371
|
Dict[str, Any]: The parsed JSON data
|
|
351
|
-
|
|
372
|
+
"""
|
|
352
373
|
if not os.path.exists(self.filepath):
|
|
353
374
|
self.print_stderr(f'ERROR: The file "{self.filepath}" does not exist.')
|
|
354
375
|
return None
|
|
355
|
-
with open(self.filepath,
|
|
376
|
+
with open(self.filepath, 'r') as jsonfile:
|
|
356
377
|
try:
|
|
357
378
|
return json.load(jsonfile)
|
|
358
379
|
except Exception as e:
|
|
@@ -381,6 +402,8 @@ class PolicyCheck(ScanossBase):
|
|
|
381
402
|
return None
|
|
382
403
|
components = self._get_components_from_results(self.results)
|
|
383
404
|
return components
|
|
405
|
+
|
|
406
|
+
|
|
384
407
|
#
|
|
385
408
|
# End of PolicyCheck Class
|
|
386
409
|
#
|
|
@@ -1,38 +1,49 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024, SCANOSS
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
|
23
23
|
"""
|
|
24
|
+
|
|
24
25
|
import json
|
|
25
26
|
from typing import Dict, Any
|
|
26
27
|
from .policy_check import PolicyCheck, PolicyStatus
|
|
27
28
|
|
|
29
|
+
|
|
28
30
|
class UndeclaredComponent(PolicyCheck):
|
|
29
31
|
"""
|
|
30
32
|
SCANOSS UndeclaredComponent class
|
|
31
33
|
Inspects for undeclared components
|
|
32
34
|
"""
|
|
33
35
|
|
|
34
|
-
def __init__(
|
|
35
|
-
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
debug: bool = False,
|
|
39
|
+
trace: bool = True,
|
|
40
|
+
quiet: bool = False,
|
|
41
|
+
filepath: str = None,
|
|
42
|
+
format_type: str = 'json',
|
|
43
|
+
status: str = None,
|
|
44
|
+
output: str = None,
|
|
45
|
+
sbom_format: str = 'settings',
|
|
46
|
+
):
|
|
36
47
|
"""
|
|
37
48
|
Initialize the UndeclaredComponent class.
|
|
38
49
|
|
|
@@ -45,20 +56,21 @@ class UndeclaredComponent(PolicyCheck):
|
|
|
45
56
|
:param output: Path to save detailed output
|
|
46
57
|
:param sbom_format: Sbom format for status output (default 'settings')
|
|
47
58
|
"""
|
|
48
|
-
super().__init__(
|
|
49
|
-
|
|
59
|
+
super().__init__(
|
|
60
|
+
debug, trace, quiet, filepath, format_type, status, output, name='Undeclared Components Policy'
|
|
61
|
+
)
|
|
50
62
|
self.filepath = filepath
|
|
51
63
|
self.format = format
|
|
52
64
|
self.output = output
|
|
53
65
|
self.status = status
|
|
54
66
|
self.sbom_format = sbom_format
|
|
55
67
|
|
|
56
|
-
def _get_undeclared_component(self, components: list)-> list or None:
|
|
68
|
+
def _get_undeclared_component(self, components: list) -> list or None:
|
|
57
69
|
"""
|
|
58
|
-
|
|
70
|
+
Filter the components list to include only undeclared components.
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
:param components: List of all components
|
|
73
|
+
:return: List of undeclared components
|
|
62
74
|
"""
|
|
63
75
|
if components is None:
|
|
64
76
|
self.print_debug(f'WARNING: No components provided!')
|
|
@@ -73,24 +85,29 @@ class UndeclaredComponent(PolicyCheck):
|
|
|
73
85
|
|
|
74
86
|
def _get_jira_summary(self, components: list) -> str:
|
|
75
87
|
"""
|
|
76
|
-
|
|
88
|
+
Get a summary of the undeclared components.
|
|
77
89
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
90
|
+
:param components: List of all components
|
|
91
|
+
:return: Component summary markdown
|
|
92
|
+
"""
|
|
81
93
|
if len(components) > 0:
|
|
82
94
|
if self.sbom_format == 'settings':
|
|
83
|
-
json_str = (
|
|
84
|
-
|
|
95
|
+
json_str = (
|
|
96
|
+
json.dumps(self._generate_scanoss_file(components), indent=2)
|
|
97
|
+
.replace('\n', '\\n')
|
|
98
|
+
.replace('"', '\\"')
|
|
99
|
+
)
|
|
85
100
|
return f'{len(components)} undeclared component(s) were found.\nAdd the following snippet into your `scanoss.json` file\n{{code:json}}\n{json.dumps(self._generate_scanoss_file(components), indent=2)}\n{{code}}\n'
|
|
86
101
|
else:
|
|
87
|
-
json_str = (
|
|
88
|
-
|
|
102
|
+
json_str = (
|
|
103
|
+
json.dumps(self._generate_scanoss_file(components), indent=2)
|
|
104
|
+
.replace('\n', '\\n')
|
|
105
|
+
.replace('"', '\\"')
|
|
106
|
+
)
|
|
89
107
|
return f'{len(components)} undeclared component(s) were found.\nAdd the following snippet into your `sbom.json` file\n{{code:json}}\n{json.dumps(self._generate_scanoss_file(components), indent=2)}\n{{code}}\n'
|
|
90
108
|
|
|
91
109
|
return f'{len(components)} undeclared component(s) were found.\\n'
|
|
92
110
|
|
|
93
|
-
|
|
94
111
|
def _get_summary(self, components: list) -> str:
|
|
95
112
|
"""
|
|
96
113
|
Get a summary of the undeclared components.
|
|
@@ -101,11 +118,15 @@ class UndeclaredComponent(PolicyCheck):
|
|
|
101
118
|
summary = f'{len(components)} undeclared component(s) were found.\n'
|
|
102
119
|
if len(components) > 0:
|
|
103
120
|
if self.sbom_format == 'settings':
|
|
104
|
-
summary += (
|
|
105
|
-
|
|
121
|
+
summary += (
|
|
122
|
+
f'Add the following snippet into your `scanoss.json` file\n'
|
|
123
|
+
f'\n```json\n{json.dumps(self._generate_scanoss_file(components), indent=2)}\n```\n'
|
|
124
|
+
)
|
|
106
125
|
else:
|
|
107
|
-
summary += (
|
|
108
|
-
|
|
126
|
+
summary += (
|
|
127
|
+
f'Add the following snippet into your `sbom.json` file\n'
|
|
128
|
+
f'\n```json\n{json.dumps(self._generate_sbom_file(components), indent=2)}\n```\n'
|
|
129
|
+
)
|
|
109
130
|
|
|
110
131
|
return summary
|
|
111
132
|
|
|
@@ -120,71 +141,71 @@ class UndeclaredComponent(PolicyCheck):
|
|
|
120
141
|
if len(components) > 0:
|
|
121
142
|
details = {'components': components}
|
|
122
143
|
return {
|
|
123
|
-
'details':
|
|
144
|
+
'details': f'{json.dumps(details, indent=2)}\n',
|
|
124
145
|
'summary': self._get_summary(components),
|
|
125
146
|
}
|
|
126
147
|
|
|
127
|
-
def _markdown(self, components: list) -> Dict[str,Any]:
|
|
148
|
+
def _markdown(self, components: list) -> Dict[str, Any]:
|
|
128
149
|
"""
|
|
129
|
-
|
|
150
|
+
Format the undeclared components as Markdown.
|
|
130
151
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
152
|
+
:param components: List of undeclared components
|
|
153
|
+
:return: Dictionary with formatted Markdown details and summary
|
|
154
|
+
"""
|
|
134
155
|
headers = ['Component', 'Version', 'License']
|
|
135
|
-
rows: [[]]= []
|
|
156
|
+
rows: [[]] = []
|
|
136
157
|
# TODO look at using SpdxLite license name lookup method
|
|
137
158
|
for component in components:
|
|
138
|
-
licenses =
|
|
159
|
+
licenses = ' - '.join(lic.get('spdxid', 'Unknown') for lic in component['licenses'])
|
|
139
160
|
rows.append([component['purl'], component['version'], licenses])
|
|
140
|
-
return
|
|
141
|
-
'details': f'### Undeclared components\n{self.generate_table(headers,rows)}\n',
|
|
161
|
+
return {
|
|
162
|
+
'details': f'### Undeclared components\n{self.generate_table(headers, rows)}\n',
|
|
142
163
|
'summary': self._get_summary(components),
|
|
143
164
|
}
|
|
144
165
|
|
|
145
|
-
def _jira_markdown(self, components: list) -> Dict[str,Any]:
|
|
166
|
+
def _jira_markdown(self, components: list) -> Dict[str, Any]:
|
|
146
167
|
"""
|
|
147
|
-
|
|
168
|
+
Format the undeclared components as Markdown.
|
|
148
169
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
170
|
+
:param components: List of undeclared components
|
|
171
|
+
:return: Dictionary with formatted Markdown details and summary
|
|
172
|
+
"""
|
|
152
173
|
headers = ['Component', 'Version', 'License']
|
|
153
|
-
rows: [[]]= []
|
|
174
|
+
rows: [[]] = []
|
|
154
175
|
# TODO look at using SpdxLite license name lookup method
|
|
155
176
|
for component in components:
|
|
156
|
-
licenses =
|
|
177
|
+
licenses = ' - '.join(lic.get('spdxid', 'Unknown') for lic in component['licenses'])
|
|
157
178
|
rows.append([component['purl'], component['version'], licenses])
|
|
158
|
-
return
|
|
159
|
-
'details': f'{self.generate_jira_table(headers,rows)}',
|
|
179
|
+
return {
|
|
180
|
+
'details': f'{self.generate_jira_table(headers, rows)}',
|
|
160
181
|
'summary': self._get_jira_summary(components),
|
|
161
182
|
}
|
|
162
183
|
|
|
163
184
|
def _get_unique_components(self, components: list) -> list:
|
|
164
185
|
"""
|
|
165
|
-
|
|
186
|
+
Generate a list of unique components.
|
|
166
187
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
188
|
+
:param components: List of undeclared components
|
|
189
|
+
:return: list of unique components
|
|
190
|
+
"""
|
|
170
191
|
unique_components = {}
|
|
171
192
|
if components is None:
|
|
172
193
|
self.print_stderr(f'WARNING: No components provided!')
|
|
173
194
|
return []
|
|
174
195
|
|
|
175
196
|
for component in components:
|
|
176
|
-
|
|
197
|
+
unique_components[component['purl']] = {'purl': component['purl']}
|
|
177
198
|
return list(unique_components.values())
|
|
178
199
|
|
|
179
200
|
def _generate_scanoss_file(self, components: list) -> dict:
|
|
180
201
|
"""
|
|
181
|
-
|
|
202
|
+
Generate a list of PURLs for the scanoss.json file.
|
|
182
203
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
204
|
+
:param components: List of undeclared components
|
|
205
|
+
:return: scanoss.json Dictionary
|
|
206
|
+
"""
|
|
186
207
|
scanoss_settings = {
|
|
187
|
-
'bom':{
|
|
208
|
+
'bom': {
|
|
188
209
|
'include': self._get_unique_components(components),
|
|
189
210
|
}
|
|
190
211
|
}
|
|
@@ -193,11 +214,11 @@ class UndeclaredComponent(PolicyCheck):
|
|
|
193
214
|
|
|
194
215
|
def _generate_sbom_file(self, components: list) -> dict:
|
|
195
216
|
"""
|
|
196
|
-
|
|
217
|
+
Generate a list of PURLs for the SBOM file.
|
|
197
218
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
219
|
+
:param components: List of undeclared components
|
|
220
|
+
:return: SBOM Dictionary with components
|
|
221
|
+
"""
|
|
201
222
|
sbom = {
|
|
202
223
|
'components': self._get_unique_components(components),
|
|
203
224
|
}
|
|
@@ -236,6 +257,8 @@ class UndeclaredComponent(PolicyCheck):
|
|
|
236
257
|
if len(undeclared_components) <= 0:
|
|
237
258
|
return PolicyStatus.FAIL.value, results
|
|
238
259
|
return PolicyStatus.SUCCESS.value, results
|
|
260
|
+
|
|
261
|
+
|
|
239
262
|
#
|
|
240
263
|
# End of UndeclaredComponent Class
|
|
241
264
|
#
|