scanoss 1.17.1__py3-none-any.whl → 1.17.3__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.
- scanoss/__init__.py +1 -1
- scanoss/cli.py +3 -2
- scanoss/data/build_date.txt +1 -1
- scanoss/inspection/copyleft.py +1 -1
- scanoss/inspection/policy_check.py +29 -12
- scanoss/inspection/undeclared_component.py +12 -6
- scanoss/inspection/utils/license_utils.py +1 -1
- scanoss/scanoss_settings.py +28 -23
- scanoss/spdxlite.py +4 -1
- {scanoss-1.17.1.dist-info → scanoss-1.17.3.dist-info}/METADATA +1 -1
- {scanoss-1.17.1.dist-info → scanoss-1.17.3.dist-info}/RECORD +15 -17
- {scanoss-1.17.1.dist-info → scanoss-1.17.3.dist-info}/WHEEL +1 -1
- scanoss/inspection/utils/markdown_utils.py +0 -23
- scanoss/inspection/utils/result_utils.py +0 -79
- {scanoss-1.17.1.dist-info → scanoss-1.17.3.dist-info}/LICENSE +0 -0
- {scanoss-1.17.1.dist-info → scanoss-1.17.3.dist-info}/entry_points.txt +0 -0
- {scanoss-1.17.1.dist-info → scanoss-1.17.3.dist-info}/top_level.txt +0 -0
scanoss/__init__.py
CHANGED
scanoss/cli.py
CHANGED
|
@@ -26,8 +26,9 @@ import os
|
|
|
26
26
|
from pathlib import Path
|
|
27
27
|
import sys
|
|
28
28
|
import pypac
|
|
29
|
-
|
|
30
|
-
from
|
|
29
|
+
|
|
30
|
+
from .inspection.copyleft import Copyleft
|
|
31
|
+
from .inspection.undeclared_component import UndeclaredComponent
|
|
31
32
|
from .threadeddependencies import SCOPE
|
|
32
33
|
from .scanoss_settings import ScanossSettings
|
|
33
34
|
from .scancodedeps import ScancodeDeps
|
scanoss/data/build_date.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
date:
|
|
1
|
+
date: 20241105131130, utime: 1730812290
|
scanoss/inspection/copyleft.py
CHANGED
|
@@ -26,8 +26,9 @@ import os.path
|
|
|
26
26
|
from abc import abstractmethod
|
|
27
27
|
from enum import Enum
|
|
28
28
|
from typing import Callable, List, Dict, Any
|
|
29
|
-
from
|
|
30
|
-
from
|
|
29
|
+
from .utils.license_utils import LicenseUtil
|
|
30
|
+
from ..scanossbase import ScanossBase
|
|
31
|
+
|
|
31
32
|
|
|
32
33
|
class PolicyStatus(Enum):
|
|
33
34
|
"""
|
|
@@ -133,7 +134,8 @@ class PolicyCheck(ScanossBase):
|
|
|
133
134
|
"""
|
|
134
135
|
pass
|
|
135
136
|
|
|
136
|
-
def _append_component(self,components: Dict[str, Any], new_component: Dict[str, Any]
|
|
137
|
+
def _append_component(self,components: Dict[str, Any], new_component: Dict[str, Any],
|
|
138
|
+
id: str, status: str) -> Dict[str, Any]:
|
|
137
139
|
"""
|
|
138
140
|
Append a new component to the component's dictionary.
|
|
139
141
|
|
|
@@ -143,15 +145,25 @@ class PolicyCheck(ScanossBase):
|
|
|
143
145
|
|
|
144
146
|
:param components: The existing dictionary of components
|
|
145
147
|
:param new_component: The new component to be added or updated
|
|
148
|
+
:param id: The new component ID
|
|
149
|
+
:param status: The new component status
|
|
146
150
|
:return: The updated components dictionary
|
|
147
151
|
"""
|
|
148
|
-
|
|
152
|
+
|
|
153
|
+
# Determine the component key and purl based on component type
|
|
154
|
+
if id in [ComponentID.FILE.value, ComponentID.SNIPPET.value]:
|
|
155
|
+
purl = new_component['purl'][0] # Take first purl for these component types
|
|
156
|
+
else:
|
|
157
|
+
purl = new_component['purl']
|
|
158
|
+
|
|
159
|
+
component_key = f"{purl}@{new_component['version']}"
|
|
149
160
|
components[component_key] = {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
161
|
+
'purl': purl,
|
|
162
|
+
'version': new_component['version'],
|
|
163
|
+
'licenses': {},
|
|
164
|
+
'status': status,
|
|
154
165
|
}
|
|
166
|
+
|
|
155
167
|
if not new_component.get('licenses'):
|
|
156
168
|
self.print_stderr(f'WARNING: Results missing licenses. Skipping.')
|
|
157
169
|
return components
|
|
@@ -187,6 +199,10 @@ class PolicyCheck(ScanossBase):
|
|
|
187
199
|
if not component_id:
|
|
188
200
|
self.print_stderr(f'WARNING: Result missing id. Skipping.')
|
|
189
201
|
continue
|
|
202
|
+
status = c.get('status')
|
|
203
|
+
if not component_id:
|
|
204
|
+
self.print_stderr(f'WARNING: Result missing status. Skipping.')
|
|
205
|
+
continue
|
|
190
206
|
if component_id in [ComponentID.FILE.value, ComponentID.SNIPPET.value]:
|
|
191
207
|
if not c.get('purl'):
|
|
192
208
|
self.print_stderr(f'WARNING: Result missing purl. Skipping.')
|
|
@@ -200,9 +216,10 @@ class PolicyCheck(ScanossBase):
|
|
|
200
216
|
component_key = f"{c['purl'][0]}@{c['version']}"
|
|
201
217
|
# Initialize or update the component entry
|
|
202
218
|
if component_key not in components:
|
|
203
|
-
components = self._append_component(components, c)
|
|
219
|
+
components = self._append_component(components, c, component_id, status)
|
|
220
|
+
|
|
204
221
|
if c['id'] == ComponentID.DEPENDENCY.value:
|
|
205
|
-
if c.get('
|
|
222
|
+
if c.get('dependencies') is None:
|
|
206
223
|
continue
|
|
207
224
|
for d in c['dependencies']:
|
|
208
225
|
if not d.get('purl'):
|
|
@@ -214,9 +231,9 @@ class PolicyCheck(ScanossBase):
|
|
|
214
231
|
if not d.get('version'):
|
|
215
232
|
self.print_stderr(f'WARNING: Result missing version. Skipping.')
|
|
216
233
|
continue
|
|
217
|
-
component_key = f"{d['purl']
|
|
234
|
+
component_key = f"{d['purl']}@{d['version']}"
|
|
218
235
|
if component_key not in components:
|
|
219
|
-
components = self._append_component(components, d)
|
|
236
|
+
components = self._append_component(components, d, component_id, status)
|
|
220
237
|
# End of dependencies loop
|
|
221
238
|
# End if
|
|
222
239
|
# End of component loop
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"""
|
|
24
24
|
import json
|
|
25
25
|
from typing import Dict, Any
|
|
26
|
-
from
|
|
26
|
+
from .policy_check import PolicyCheck, PolicyStatus
|
|
27
27
|
|
|
28
28
|
class UndeclaredComponent(PolicyCheck):
|
|
29
29
|
"""
|
|
@@ -115,20 +115,26 @@ class UndeclaredComponent(PolicyCheck):
|
|
|
115
115
|
'summary': self._get_summary(components),
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
def _generate_sbom_file(self, components: list) ->
|
|
118
|
+
def _generate_sbom_file(self, components: list) -> dict:
|
|
119
119
|
"""
|
|
120
120
|
Generate a list of PURLs for the SBOM file.
|
|
121
121
|
|
|
122
122
|
:param components: List of undeclared components
|
|
123
|
-
:return:
|
|
123
|
+
:return: SBOM Dictionary with components
|
|
124
124
|
"""
|
|
125
|
-
|
|
125
|
+
|
|
126
|
+
unique_components = {}
|
|
126
127
|
if components is None:
|
|
127
128
|
self.print_stderr(f'WARNING: No components provided!')
|
|
128
129
|
else:
|
|
129
130
|
for component in components:
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
unique_components[component['purl']] = { 'purl': component['purl'] }
|
|
132
|
+
|
|
133
|
+
sbom = {
|
|
134
|
+
'components': list(unique_components.values())
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return sbom
|
|
132
138
|
|
|
133
139
|
def run(self):
|
|
134
140
|
"""
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
22
|
THE SOFTWARE.
|
|
23
23
|
"""
|
|
24
|
-
from
|
|
24
|
+
from ...scanossbase import ScanossBase
|
|
25
25
|
|
|
26
26
|
DEFAULT_COPYLEFT_LICENSES = {
|
|
27
27
|
'agpl-3.0-only', 'artistic-1.0', 'artistic-2.0', 'cc-by-sa-4.0', 'cddl-1.0', 'cddl-1.1', 'cecill-2.1',
|
scanoss/scanoss_settings.py
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
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
25
|
import json
|
|
26
26
|
from pathlib import Path
|
|
27
|
-
from typing import
|
|
27
|
+
from typing import List, TypedDict
|
|
28
28
|
|
|
29
29
|
from .scanossbase import ScanossBase
|
|
30
30
|
|
|
@@ -123,7 +123,12 @@ class ScanossSettings(ScanossBase):
|
|
|
123
123
|
list: If using SBOM.json
|
|
124
124
|
"""
|
|
125
125
|
if self.settings_file_type == "legacy":
|
|
126
|
-
|
|
126
|
+
if isinstance(self.data, list):
|
|
127
|
+
return self.data
|
|
128
|
+
elif isinstance(self.data, dict) and self.data.get("components"):
|
|
129
|
+
return self.data.get("components")
|
|
130
|
+
else:
|
|
131
|
+
return []
|
|
127
132
|
return self.data.get("bom", {})
|
|
128
133
|
|
|
129
134
|
def get_bom_include(self) -> List[BomEntry]:
|
scanoss/spdxlite.py
CHANGED
|
@@ -180,7 +180,7 @@ class SpdxLite:
|
|
|
180
180
|
data = {
|
|
181
181
|
'spdxVersion': 'SPDX-2.2',
|
|
182
182
|
'dataLicense': 'CC0-1.0',
|
|
183
|
-
'SPDXID': f'SPDXRef-
|
|
183
|
+
'SPDXID': f'SPDXRef-DOCUMENT',
|
|
184
184
|
'name': 'SCANOSS-SBOM',
|
|
185
185
|
'creationInfo': {
|
|
186
186
|
'created': now.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
|
@@ -214,6 +214,8 @@ class SpdxLite:
|
|
|
214
214
|
comp_name = comp.get('component')
|
|
215
215
|
comp_ver = comp.get('version')
|
|
216
216
|
purl_ver = f'{purl}@{comp_ver}'
|
|
217
|
+
vendor = comp.get('vendor', 'NOASSERTION')
|
|
218
|
+
supplier = f"Organization: {vendor}" if vendor != 'NOASSERTION' else vendor
|
|
217
219
|
purl_hash = hashlib.md5(f'{purl_ver}'.encode('utf-8')).hexdigest()
|
|
218
220
|
purl_spdx = f'SPDXRef-{purl_hash}'
|
|
219
221
|
data['documentDescribes'].append(purl_spdx)
|
|
@@ -227,6 +229,7 @@ class SpdxLite:
|
|
|
227
229
|
'licenseConcluded': 'NOASSERTION',
|
|
228
230
|
'filesAnalyzed': False,
|
|
229
231
|
'copyrightText': 'NOASSERTION',
|
|
232
|
+
'supplier': supplier,
|
|
230
233
|
'externalRefs': [{
|
|
231
234
|
'referenceCategory': 'PACKAGE-MANAGER',
|
|
232
235
|
'referenceLocator': purl_ver,
|
|
@@ -4,8 +4,8 @@ protoc_gen_swagger/options/annotations_pb2.py,sha256=b25EDD6gssUWnFby9gxgcpLIROT
|
|
|
4
4
|
protoc_gen_swagger/options/annotations_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
|
5
5
|
protoc_gen_swagger/options/openapiv2_pb2.py,sha256=vYElGp8E1vGHszvWqX97zNG9GFJ7u2QcdK9ouq0XdyI,14939
|
|
6
6
|
protoc_gen_swagger/options/openapiv2_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
|
7
|
-
scanoss/__init__.py,sha256=
|
|
8
|
-
scanoss/cli.py,sha256=
|
|
7
|
+
scanoss/__init__.py,sha256=1NiSw2lXM_aNTdlVVTT7y0u5plLKheHEs83ftzzggNc,1163
|
|
8
|
+
scanoss/cli.py,sha256=LSe8D3whEiDXgVyAtw2dsVqBd9BwQyB6POz4cH7kVf8,50652
|
|
9
9
|
scanoss/components.py,sha256=ZHZ1KA69shxOASZK7USD9yPTITpAc_RXL5q5zpDK23o,12590
|
|
10
10
|
scanoss/csvoutput.py,sha256=hBwr_Fc6mBdOdXgyQcdFrockYH-PJ0jblowlExJ6OPg,9925
|
|
11
11
|
scanoss/cyclonedx.py,sha256=JVBYeR3D-i4yP9cVSyWvm0_7Y8Kr2MC5GxMgRGAf8R0,12585
|
|
@@ -13,13 +13,13 @@ scanoss/filecount.py,sha256=o7xb6m387ucnsU4H1OXGzf_AdWsudhAHe49T8uX4Ieo,6660
|
|
|
13
13
|
scanoss/results.py,sha256=7G33QAYYI9qI61TCzXjSLYXMmg5CDtZS5e2QhnQfE74,9883
|
|
14
14
|
scanoss/scancodedeps.py,sha256=_9d7MAV20-FrET7mF7gW-BZiz2eHrtwudgrEcSX0oZQ,11321
|
|
15
15
|
scanoss/scanner.py,sha256=Boxk0A-AuS0DMB4UYArU0PWZ0yJlK4v1YgdeVnKmJck,52023
|
|
16
|
-
scanoss/scanoss_settings.py,sha256=
|
|
16
|
+
scanoss/scanoss_settings.py,sha256=QOpBDfu6vYL-K3WxkujPbXWwut1BHWpN2mJTm7yMD9c,6162
|
|
17
17
|
scanoss/scanossapi.py,sha256=TJxPctr-0DTn_26LfM__OAMfntaXzvheFTbdmU-5pnM,11953
|
|
18
18
|
scanoss/scanossbase.py,sha256=zMDRCLbrcoRvYEKQRuZXnBiVY4_Vsplmg_APbB65oaU,3084
|
|
19
19
|
scanoss/scanossgrpc.py,sha256=ythZkr6F0P0hl_KPYoHkos_IL97TxLKeYfAouX_CUnM,20491
|
|
20
20
|
scanoss/scanpostprocessor.py,sha256=tfQk6GBmW1Yd2rqHHp6QKiYVdmTkBAcpoE4HHN__oKo,5899
|
|
21
21
|
scanoss/scantype.py,sha256=R2-ExLGOrYxaJFtIK2AEo2caD0XrN1zpF5q1qT9Zsyc,1326
|
|
22
|
-
scanoss/spdxlite.py,sha256=
|
|
22
|
+
scanoss/spdxlite.py,sha256=REChAWV-6qhp16jc4X2lMb1v7VvYiDH5nN9VDV3fDaQ,15828
|
|
23
23
|
scanoss/threadeddependencies.py,sha256=sOIAjiPTmxybKz2yhT4-ixXBeC4K8UQVq6JQj4e8mLc,9906
|
|
24
24
|
scanoss/threadedscanning.py,sha256=T0tL8W1IEX_hLY5ksrAl_iQqtxT_KbyDhTDHo6a7xFE,9387
|
|
25
25
|
scanoss/winnowing.py,sha256=HzMWRYh1XB4so71br-DUPpV6OlmymDfsnU-EOCCObJM,18734
|
|
@@ -50,19 +50,17 @@ scanoss/api/vulnerabilities/__init__.py,sha256=FLQtiDiv85Q1Chk-sJ9ky9WOV1mulZhEK
|
|
|
50
50
|
scanoss/api/vulnerabilities/v2/__init__.py,sha256=FLQtiDiv85Q1Chk-sJ9ky9WOV1mulZhEKjiBihlwiaM,1139
|
|
51
51
|
scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py,sha256=CFhF80av8tenGvn9AIsGEtRJPuV2dC_syA5JLZb2lDw,5464
|
|
52
52
|
scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py,sha256=HlS4k4Zmx6RIAqaO9I96jD-eyF5yU6Xx04pVm7pdqOg,6864
|
|
53
|
-
scanoss/data/build_date.txt,sha256=
|
|
53
|
+
scanoss/data/build_date.txt,sha256=iecgeD6VIUUJDqEOmZ76jXpADPg08oJD7N5i8Acxrd8,40
|
|
54
54
|
scanoss/data/spdx-exceptions.json,sha256=s7UTYxC7jqQXr11YBlIWYCNwN6lRDFTR33Y8rpN_dA4,17953
|
|
55
55
|
scanoss/data/spdx-licenses.json,sha256=A6Z0q82gaTLtnopBfzeIVZjJFxkdRW1g2TuumQc-lII,228794
|
|
56
56
|
scanoss/inspection/__init__.py,sha256=z62680zKq4OmBOugSODvgpSwdsloZL7bvcaMbnx3xgU,1139
|
|
57
|
-
scanoss/inspection/copyleft.py,sha256=
|
|
58
|
-
scanoss/inspection/policy_check.py,sha256=
|
|
59
|
-
scanoss/inspection/undeclared_component.py,sha256=
|
|
60
|
-
scanoss/inspection/utils/license_utils.py,sha256=
|
|
61
|
-
scanoss/
|
|
62
|
-
scanoss/
|
|
63
|
-
scanoss-1.17.
|
|
64
|
-
scanoss-1.17.
|
|
65
|
-
scanoss-1.17.
|
|
66
|
-
scanoss-1.17.
|
|
67
|
-
scanoss-1.17.1.dist-info/top_level.txt,sha256=V11PrQ6Pnrc-nDF9xnisnJ8e6-i7HqSIKVNqduRWcL8,27
|
|
68
|
-
scanoss-1.17.1.dist-info/RECORD,,
|
|
57
|
+
scanoss/inspection/copyleft.py,sha256=dkiLkgNYz7cbIQZCzy6zThiIyHkqrper_xruZ9PQhAI,6563
|
|
58
|
+
scanoss/inspection/policy_check.py,sha256=eo5VfEBwKoDSqIwRi0xwaVLy6EUR29HlH5Bl0Kpvx7I,14752
|
|
59
|
+
scanoss/inspection/undeclared_component.py,sha256=BxFhRrI_b_Ulu7cArm5ySphAXT7DfMmbrrGy121cz14,6808
|
|
60
|
+
scanoss/inspection/utils/license_utils.py,sha256=mIaoVWXMA6shkRQmgmiP2mWchjxX4ex8LWs91Nf6rq4,5093
|
|
61
|
+
scanoss-1.17.3.dist-info/LICENSE,sha256=LLUaXoiyOroIbr5ubAyrxBOwSRLTm35ETO2FmLpy8QQ,1074
|
|
62
|
+
scanoss-1.17.3.dist-info/METADATA,sha256=b62_P5hYfA_3m9WoZg87MXMwvO2KXzYuxeoQ_yxGkTw,5936
|
|
63
|
+
scanoss-1.17.3.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
64
|
+
scanoss-1.17.3.dist-info/entry_points.txt,sha256=Uy28xnaDL5KQ7V77sZD5VLDXPNxYYzSr5tsqtiXVzAs,48
|
|
65
|
+
scanoss-1.17.3.dist-info/top_level.txt,sha256=V11PrQ6Pnrc-nDF9xnisnJ8e6-i7HqSIKVNqduRWcL8,27
|
|
66
|
+
scanoss-1.17.3.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
def generate_table(headers, rows, centered_columns=None):
|
|
2
|
-
"""
|
|
3
|
-
Generate Markdown table
|
|
4
|
-
:param headers: List of headers
|
|
5
|
-
:param rows: Rows
|
|
6
|
-
:param centered_columns: List with centered columns
|
|
7
|
-
"""
|
|
8
|
-
COL_SEP = ' | '
|
|
9
|
-
centered_column_set = set(centered_columns or [])
|
|
10
|
-
def create_separator(header, index):
|
|
11
|
-
if centered_columns is None:
|
|
12
|
-
return '-'
|
|
13
|
-
return ':-:' if index in centered_column_set else '-'
|
|
14
|
-
|
|
15
|
-
row_separator = COL_SEP + COL_SEP.join(
|
|
16
|
-
create_separator(header, index) for index, header in enumerate(headers)
|
|
17
|
-
) + COL_SEP
|
|
18
|
-
|
|
19
|
-
table_rows = [COL_SEP + COL_SEP.join(headers) + COL_SEP]
|
|
20
|
-
table_rows.append(row_separator)
|
|
21
|
-
table_rows.extend(COL_SEP + COL_SEP.join(row) + COL_SEP for row in rows)
|
|
22
|
-
|
|
23
|
-
return '\n'.join(table_rows)
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
from typing import Dict, Any
|
|
3
|
-
|
|
4
|
-
from scanoss.inspection.utils.license_utils import license_util
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ComponentID(Enum):
|
|
8
|
-
FILE = "file"
|
|
9
|
-
SNIPPET = "snippet"
|
|
10
|
-
DEPENDENCY = "dependency"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def _append_component(components: Dict[str, Any], new_component: Dict[str, Any]) -> Dict[str, Any]:
|
|
14
|
-
"""
|
|
15
|
-
Append a new component to the components dictionary.
|
|
16
|
-
|
|
17
|
-
This function creates a new entry in the components dictionary for the given component,
|
|
18
|
-
or updates an existing entry if the component already exists. It also processes the
|
|
19
|
-
licenses associated with the component.
|
|
20
|
-
|
|
21
|
-
:param components: The existing dictionary of components
|
|
22
|
-
:param new_component: The new component to be added or updated
|
|
23
|
-
:return: The updated components dictionary
|
|
24
|
-
"""
|
|
25
|
-
component_key = f"{new_component['purl'][0]}@{new_component['version']}"
|
|
26
|
-
components[component_key] = {
|
|
27
|
-
'purl': new_component['purl'][0],
|
|
28
|
-
'version': new_component['version'],
|
|
29
|
-
'licenses': {},
|
|
30
|
-
'status': new_component['status'],
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
# Process licenses for this component
|
|
34
|
-
for l in new_component['licenses']:
|
|
35
|
-
spdxid = l['name']
|
|
36
|
-
components[component_key]['licenses'][spdxid] = {
|
|
37
|
-
'spdxid': spdxid,
|
|
38
|
-
'copyleft': license_util.is_copyleft(spdxid),
|
|
39
|
-
'url': l.get('url')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return components
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def get_components(results: Dict[str, Any]) -> list:
|
|
46
|
-
"""
|
|
47
|
-
Process the results dictionary to extract and format component information.
|
|
48
|
-
|
|
49
|
-
This function iterates through the results dictionary, identifying components from
|
|
50
|
-
different sources (files, snippets, and dependencies). It consolidates this information
|
|
51
|
-
into a list of unique components, each with its associated licenses and other details.
|
|
52
|
-
|
|
53
|
-
:param results: A dictionary containing the raw results of a component scan
|
|
54
|
-
:return: A list of dictionaries, each representing a unique component with its details
|
|
55
|
-
"""
|
|
56
|
-
components = {}
|
|
57
|
-
for component in results.values():
|
|
58
|
-
for c in component:
|
|
59
|
-
if c['id'] in [ComponentID.FILE.value, ComponentID.SNIPPET.value]:
|
|
60
|
-
component_key = f"{c['purl'][0]}@{c['version']}"
|
|
61
|
-
|
|
62
|
-
# Initialize or update the component entry
|
|
63
|
-
if component_key not in components:
|
|
64
|
-
components = _append_component(components, c)
|
|
65
|
-
|
|
66
|
-
if c['id'] == ComponentID.DEPENDENCY.value:
|
|
67
|
-
for d in c['dependencies']:
|
|
68
|
-
component_key = f"{d['purl'][0]}@{d['version']}"
|
|
69
|
-
|
|
70
|
-
if component_key not in components:
|
|
71
|
-
components = _append_component(components, d)
|
|
72
|
-
# End of for loop
|
|
73
|
-
# End if
|
|
74
|
-
# End if
|
|
75
|
-
results = list(components.values())
|
|
76
|
-
for component in results:
|
|
77
|
-
component['licenses'] = list(component['licenses'].values())
|
|
78
|
-
|
|
79
|
-
return results
|
|
File without changes
|
|
File without changes
|
|
File without changes
|