scanoss 1.12.2__py3-none-any.whl → 1.43.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 +18 -12
- protoc_gen_swagger/options/annotations_pb2.pyi +48 -0
- protoc_gen_swagger/options/annotations_pb2_grpc.py +20 -0
- protoc_gen_swagger/options/openapiv2_pb2.py +110 -99
- protoc_gen_swagger/options/openapiv2_pb2.pyi +1317 -0
- protoc_gen_swagger/options/openapiv2_pb2_grpc.py +20 -0
- 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 +49 -20
- scanoss/api/common/v2/scanoss_common_pb2_grpc.py +25 -0
- scanoss/api/components/__init__.py +17 -17
- scanoss/api/components/v2/__init__.py +17 -17
- scanoss/api/components/v2/scanoss_components_pb2.py +68 -43
- scanoss/api/components/v2/scanoss_components_pb2_grpc.py +83 -22
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +136 -21
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +766 -13
- scanoss/api/dependencies/__init__.py +17 -17
- scanoss/api/dependencies/v2/__init__.py +17 -17
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +56 -29
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +94 -8
- scanoss/api/geoprovenance/__init__.py +23 -0
- scanoss/api/geoprovenance/v2/__init__.py +23 -0
- scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +92 -0
- scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +381 -0
- scanoss/api/licenses/__init__.py +23 -0
- scanoss/api/licenses/v2/__init__.py +23 -0
- scanoss/api/licenses/v2/scanoss_licenses_pb2.py +84 -0
- scanoss/api/licenses/v2/scanoss_licenses_pb2_grpc.py +302 -0
- scanoss/api/scanning/__init__.py +17 -17
- scanoss/api/scanning/v2/__init__.py +17 -17
- scanoss/api/scanning/v2/scanoss_scanning_pb2.py +42 -13
- scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +86 -7
- scanoss/api/semgrep/__init__.py +17 -17
- scanoss/api/semgrep/v2/__init__.py +17 -17
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +50 -23
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +151 -16
- scanoss/api/vulnerabilities/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +78 -31
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +282 -18
- scanoss/cli.py +2359 -370
- scanoss/components.py +187 -94
- scanoss/constants.py +22 -0
- scanoss/cryptography.py +308 -0
- scanoss/csvoutput.py +91 -58
- scanoss/cyclonedx.py +221 -63
- scanoss/data/build_date.txt +1 -1
- scanoss/data/osadl-copyleft.json +133 -0
- scanoss/data/scanoss-settings-schema.json +254 -0
- scanoss/delta.py +197 -0
- scanoss/export/__init__.py +23 -0
- scanoss/export/dependency_track.py +227 -0
- scanoss/file_filters.py +582 -0
- scanoss/filecount.py +75 -69
- scanoss/gitlabqualityreport.py +214 -0
- scanoss/header_filter.py +563 -0
- scanoss/inspection/__init__.py +23 -0
- scanoss/inspection/policy_check/__init__.py +0 -0
- scanoss/inspection/policy_check/dependency_track/__init__.py +0 -0
- scanoss/inspection/policy_check/dependency_track/project_violation.py +479 -0
- scanoss/inspection/policy_check/policy_check.py +222 -0
- scanoss/inspection/policy_check/scanoss/__init__.py +0 -0
- scanoss/inspection/policy_check/scanoss/copyleft.py +243 -0
- scanoss/inspection/policy_check/scanoss/undeclared_component.py +309 -0
- scanoss/inspection/summary/__init__.py +0 -0
- scanoss/inspection/summary/component_summary.py +170 -0
- scanoss/inspection/summary/license_summary.py +191 -0
- scanoss/inspection/summary/match_summary.py +341 -0
- scanoss/inspection/utils/file_utils.py +44 -0
- scanoss/inspection/utils/license_utils.py +123 -0
- scanoss/inspection/utils/markdown_utils.py +63 -0
- scanoss/inspection/utils/scan_result_processor.py +417 -0
- scanoss/osadl.py +125 -0
- scanoss/results.py +275 -0
- scanoss/scancodedeps.py +87 -38
- scanoss/scanner.py +431 -539
- scanoss/scanners/__init__.py +23 -0
- scanoss/scanners/container_scanner.py +476 -0
- scanoss/scanners/folder_hasher.py +358 -0
- scanoss/scanners/scanner_config.py +73 -0
- scanoss/scanners/scanner_hfh.py +252 -0
- scanoss/scanoss_settings.py +337 -0
- scanoss/scanossapi.py +140 -101
- scanoss/scanossbase.py +59 -22
- scanoss/scanossgrpc.py +799 -251
- scanoss/scanpostprocessor.py +294 -0
- scanoss/scantype.py +22 -21
- scanoss/services/dependency_track_service.py +132 -0
- scanoss/spdxlite.py +532 -174
- scanoss/threadeddependencies.py +148 -47
- scanoss/threadedscanning.py +53 -37
- scanoss/utils/__init__.py +23 -0
- scanoss/utils/abstract_presenter.py +103 -0
- scanoss/utils/crc64.py +96 -0
- scanoss/utils/file.py +84 -0
- scanoss/utils/scanoss_scan_results_utils.py +41 -0
- scanoss/utils/simhash.py +198 -0
- scanoss/winnowing.py +241 -63
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/METADATA +18 -9
- scanoss-1.43.1.dist-info/RECORD +110 -0
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/WHEEL +1 -1
- scanoss-1.12.2.dist-info/RECORD +0 -58
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/entry_points.txt +0 -0
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info/licenses}/LICENSE +0 -0
- {scanoss-1.12.2.dist-info → scanoss-1.43.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025, 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
|
+
"""
|
|
24
|
+
|
|
25
|
+
from abc import ABC, abstractmethod
|
|
26
|
+
from enum import Enum
|
|
27
|
+
from typing import Callable, Dict, Generic, List, NamedTuple, TypeVar
|
|
28
|
+
|
|
29
|
+
from ...scanossbase import ScanossBase
|
|
30
|
+
from ..utils.license_utils import LicenseUtil
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class PolicyStatus(Enum):
|
|
34
|
+
"""
|
|
35
|
+
Enumeration representing the status of a policy check.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
POLICY_SUCCESS (int): Indicates that the policy check passed successfully (value: 0).
|
|
39
|
+
POLICY_FAIL (int): Indicates that the policy check failed (value: 2).
|
|
40
|
+
ERROR (int): Indicates that an error occurred during the policy check (value: 1).
|
|
41
|
+
"""
|
|
42
|
+
POLICY_SUCCESS = 0
|
|
43
|
+
POLICY_FAIL = 2
|
|
44
|
+
ERROR = 1
|
|
45
|
+
#
|
|
46
|
+
# End of PolicyStatus Class
|
|
47
|
+
#
|
|
48
|
+
|
|
49
|
+
class PolicyOutput(NamedTuple):
|
|
50
|
+
details: str
|
|
51
|
+
summary: str
|
|
52
|
+
|
|
53
|
+
T = TypeVar('T')
|
|
54
|
+
|
|
55
|
+
class PolicyCheck(ScanossBase, Generic[T], ABC):
|
|
56
|
+
"""
|
|
57
|
+
A base class for implementing various software policy checks.
|
|
58
|
+
|
|
59
|
+
This class provides a framework for policy checking, including methods for
|
|
60
|
+
processing components, generating output in different formats.
|
|
61
|
+
|
|
62
|
+
Attributes:
|
|
63
|
+
VALID_FORMATS (set): A set of valid output formats ('md', 'json').
|
|
64
|
+
|
|
65
|
+
Inherits from:
|
|
66
|
+
InspectBase: A base class providing common functionality for SCANOSS-related operations.
|
|
67
|
+
"""
|
|
68
|
+
VALID_FORMATS = {'md', 'json', 'jira_md'}
|
|
69
|
+
def __init__( # noqa: PLR0913
|
|
70
|
+
self,
|
|
71
|
+
debug: bool = False,
|
|
72
|
+
trace: bool = False,
|
|
73
|
+
quiet: bool = False,
|
|
74
|
+
format_type: str = None,
|
|
75
|
+
status: str = None,
|
|
76
|
+
name: str = None,
|
|
77
|
+
output: str = None,
|
|
78
|
+
):
|
|
79
|
+
super().__init__(debug, trace, quiet)
|
|
80
|
+
self.license_util = LicenseUtil()
|
|
81
|
+
self.name = name
|
|
82
|
+
self.format_type = format_type
|
|
83
|
+
self.status = status
|
|
84
|
+
self.output = output
|
|
85
|
+
|
|
86
|
+
@abstractmethod
|
|
87
|
+
def run(self)-> tuple[int,PolicyOutput]:
|
|
88
|
+
"""
|
|
89
|
+
Execute the policy check process.
|
|
90
|
+
|
|
91
|
+
This abstract method should be implemented by subclasses to perform specific
|
|
92
|
+
policy checks. The general structure of this method typically includes:
|
|
93
|
+
1. Retrieving components
|
|
94
|
+
2. Filtering components based on specific criteria
|
|
95
|
+
3. Formatting the results
|
|
96
|
+
4. Saving the output to files if required
|
|
97
|
+
|
|
98
|
+
:return: A named tuple containing two elements:
|
|
99
|
+
- First element: PolicyStatus enum value (SUCCESS, FAIL, or ERROR)
|
|
100
|
+
- Second element: PolicyOutput A tuple containing the policy results.
|
|
101
|
+
"""
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
def _json(self, data: list[T]) -> PolicyOutput:
|
|
106
|
+
"""
|
|
107
|
+
Format the policy checks results as JSON.
|
|
108
|
+
This method should be implemented by subclasses to create a Markdown representation
|
|
109
|
+
of the policy check results.
|
|
110
|
+
|
|
111
|
+
:param data: List of data to be formatted.
|
|
112
|
+
:return: A dictionary containing two keys:
|
|
113
|
+
- 'results': A JSON-formatted string with the full list of components
|
|
114
|
+
- 'summary': A string summarizing the number of components found
|
|
115
|
+
"""
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
@abstractmethod
|
|
119
|
+
def _markdown(self, data: list[T]) -> PolicyOutput:
|
|
120
|
+
"""
|
|
121
|
+
Generate Markdown output for the policy check results.
|
|
122
|
+
|
|
123
|
+
This method should be implemented by subclasses to create a Markdown representation
|
|
124
|
+
of the policy check results.
|
|
125
|
+
|
|
126
|
+
:param data: List of data to be included in the output.
|
|
127
|
+
:return: A dictionary representing the Markdown output.
|
|
128
|
+
"""
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
@abstractmethod
|
|
132
|
+
def _jira_markdown(self, data: list[T]) -> PolicyOutput:
|
|
133
|
+
"""
|
|
134
|
+
Generate Markdown output for the policy check results.
|
|
135
|
+
|
|
136
|
+
This method should be implemented by subclasses to create a Markdown representation
|
|
137
|
+
of the policy check results.
|
|
138
|
+
|
|
139
|
+
:param data: List of data to be included in the output.
|
|
140
|
+
:return: A dictionary representing the Markdown output.
|
|
141
|
+
"""
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
def _get_formatter(self) -> Callable[[List[dict]], PolicyOutput]:
|
|
145
|
+
"""
|
|
146
|
+
Get the appropriate formatter function based on the specified format.
|
|
147
|
+
|
|
148
|
+
:return: Formatter function (either _json or _markdown)
|
|
149
|
+
"""
|
|
150
|
+
valid_format = self._is_valid_format()
|
|
151
|
+
if not valid_format:
|
|
152
|
+
raise ValueError('Invalid format specified')
|
|
153
|
+
# a map of which format function to return
|
|
154
|
+
function_map = {
|
|
155
|
+
'json': self._json,
|
|
156
|
+
'md': self._markdown,
|
|
157
|
+
'jira_md': self._jira_markdown,
|
|
158
|
+
}
|
|
159
|
+
return function_map[self.format_type]
|
|
160
|
+
|
|
161
|
+
def _debug(self):
|
|
162
|
+
"""
|
|
163
|
+
Print debug information about the policy check.
|
|
164
|
+
|
|
165
|
+
This method prints various attributes of the PolicyCheck instance for debugging purposes.
|
|
166
|
+
"""
|
|
167
|
+
if self.debug:
|
|
168
|
+
self.print_stderr(f'Policy: {self.name}')
|
|
169
|
+
self.print_stderr(f'Format: {self.format_type}')
|
|
170
|
+
self.print_stderr(f'Status: {self.status}')
|
|
171
|
+
self.print_stderr(f'Output: {self.output}')
|
|
172
|
+
|
|
173
|
+
def _is_valid_format(self) -> bool:
|
|
174
|
+
"""
|
|
175
|
+
Validate if the format specified is supported.
|
|
176
|
+
|
|
177
|
+
This method checks if the format stored in format is one of the
|
|
178
|
+
valid formats defined in self.VALID_FORMATS.
|
|
179
|
+
|
|
180
|
+
:return: bool: True if the format is valid, False otherwise.
|
|
181
|
+
"""
|
|
182
|
+
if self.format_type not in self.VALID_FORMATS:
|
|
183
|
+
valid_formats_str = ', '.join(self.VALID_FORMATS)
|
|
184
|
+
self.print_stderr(f'ERROR: Invalid format "{self.format_type}". Valid formats are: {valid_formats_str}')
|
|
185
|
+
return False
|
|
186
|
+
return True
|
|
187
|
+
|
|
188
|
+
def _generate_formatter_report(self, components: list[Dict]):
|
|
189
|
+
"""
|
|
190
|
+
Generates a formatted report for a given component based on the defined formatter.
|
|
191
|
+
|
|
192
|
+
Parameters:
|
|
193
|
+
components (List[dict]): A list of dictionaries representing the components to be
|
|
194
|
+
processed and formatted. Each dictionary contains detailed information that adheres
|
|
195
|
+
to the format requirements for the specified formatter.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
Tuple[int, dict]: A tuple where the first element represents the policy status code
|
|
199
|
+
and the second element is a dictionary containing formatted results information,
|
|
200
|
+
typically with keys 'details' and 'summary'.
|
|
201
|
+
|
|
202
|
+
Raises:
|
|
203
|
+
KeyError: When a required key is missing from the provided component, causing the
|
|
204
|
+
formatter to fail.
|
|
205
|
+
ValueError: If an invalid component is passed and renders unable to process.
|
|
206
|
+
"""
|
|
207
|
+
# Get a formatter for the output results
|
|
208
|
+
formatter = self._get_formatter()
|
|
209
|
+
if formatter is None:
|
|
210
|
+
return PolicyStatus.ERROR.value, {}
|
|
211
|
+
# Format the results
|
|
212
|
+
policy_output = formatter(components)
|
|
213
|
+
## Save outputs if required
|
|
214
|
+
self.print_to_file_or_stdout(policy_output.details, self.output)
|
|
215
|
+
self.print_to_file_or_stderr(policy_output.summary, self.status)
|
|
216
|
+
# Check to see if we have policy violations
|
|
217
|
+
if len(components) > 0:
|
|
218
|
+
return PolicyStatus.POLICY_FAIL.value, policy_output
|
|
219
|
+
return PolicyStatus.POLICY_SUCCESS.value, policy_output
|
|
220
|
+
#
|
|
221
|
+
# End of PolicyCheck Class
|
|
222
|
+
#
|
|
File without changes
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2025, 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
|
+
"""
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
from dataclasses import dataclass
|
|
27
|
+
from typing import Dict, List
|
|
28
|
+
|
|
29
|
+
from scanoss.constants import DEFAULT_COPYLEFT_LICENSE_SOURCES
|
|
30
|
+
|
|
31
|
+
from ...policy_check.policy_check import PolicyCheck, PolicyOutput, PolicyStatus
|
|
32
|
+
from ...utils.markdown_utils import generate_jira_table, generate_table
|
|
33
|
+
from ...utils.scan_result_processor import ScanResultProcessor
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class License:
|
|
38
|
+
spdxid: str
|
|
39
|
+
copyleft: bool
|
|
40
|
+
url: str
|
|
41
|
+
source: str
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class Component:
|
|
45
|
+
purl: str
|
|
46
|
+
version: str
|
|
47
|
+
licenses: List[License]
|
|
48
|
+
status: str
|
|
49
|
+
|
|
50
|
+
class Copyleft(PolicyCheck[Component]):
|
|
51
|
+
"""
|
|
52
|
+
SCANOSS Copyleft class
|
|
53
|
+
Inspects components for copyleft licenses
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__( # noqa: PLR0913
|
|
57
|
+
self,
|
|
58
|
+
debug: bool = False,
|
|
59
|
+
trace: bool = False,
|
|
60
|
+
quiet: bool = False,
|
|
61
|
+
filepath: str = None,
|
|
62
|
+
format_type: str = 'json',
|
|
63
|
+
status: str = None,
|
|
64
|
+
output: str = None,
|
|
65
|
+
include: str = None,
|
|
66
|
+
exclude: str = None,
|
|
67
|
+
explicit: str = None,
|
|
68
|
+
license_sources: list = None,
|
|
69
|
+
):
|
|
70
|
+
"""
|
|
71
|
+
Initialise the Copyleft class.
|
|
72
|
+
|
|
73
|
+
:param debug: Enable debug mode
|
|
74
|
+
:param trace: Enable trace mode (default True)
|
|
75
|
+
:param quiet: Enable quiet mode
|
|
76
|
+
:param filepath: Path to the file containing component data
|
|
77
|
+
:param format_type: Output format ('json' or 'md')
|
|
78
|
+
:param status: Path to save the status output
|
|
79
|
+
:param output: Path to save detailed output
|
|
80
|
+
:param include: Licenses to include in the analysis
|
|
81
|
+
:param exclude: Licenses to exclude from the analysis
|
|
82
|
+
:param explicit: Explicitly defined licenses
|
|
83
|
+
:param license_sources: List of license sources to check
|
|
84
|
+
"""
|
|
85
|
+
super().__init__(
|
|
86
|
+
debug, trace, quiet, format_type, status, name='Copyleft Policy', output=output
|
|
87
|
+
)
|
|
88
|
+
self.license_util.init(include, exclude, explicit)
|
|
89
|
+
self.filepath = filepath
|
|
90
|
+
self.output = output
|
|
91
|
+
self.status = status
|
|
92
|
+
self.license_sources = license_sources or DEFAULT_COPYLEFT_LICENSE_SOURCES
|
|
93
|
+
self.results_processor = ScanResultProcessor(
|
|
94
|
+
self.debug,
|
|
95
|
+
self.trace,
|
|
96
|
+
self.quiet,
|
|
97
|
+
self.filepath,
|
|
98
|
+
include,
|
|
99
|
+
exclude,
|
|
100
|
+
explicit,
|
|
101
|
+
self.license_sources)
|
|
102
|
+
|
|
103
|
+
def _json(self, components: list[Component]) -> PolicyOutput:
|
|
104
|
+
"""
|
|
105
|
+
Format the components with copyleft licenses as JSON.
|
|
106
|
+
|
|
107
|
+
:param components: List of components with copyleft licenses
|
|
108
|
+
:return: Dictionary with formatted JSON details and summary
|
|
109
|
+
"""
|
|
110
|
+
# A component is considered unique by its combination of PURL (Package URL) and license
|
|
111
|
+
component_licenses = self.results_processor.group_components_by_license(components)
|
|
112
|
+
details = {}
|
|
113
|
+
if len(components) > 0:
|
|
114
|
+
details = {'components': components}
|
|
115
|
+
return PolicyOutput(
|
|
116
|
+
details= f'{json.dumps(details, indent=2)}\n',
|
|
117
|
+
summary= f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def _markdown(self, components: list[Component]) -> PolicyOutput:
|
|
121
|
+
"""
|
|
122
|
+
Format the components with copyleft licenses as Markdown.
|
|
123
|
+
|
|
124
|
+
:param components: List of components with copyleft licenses
|
|
125
|
+
:return: Dictionary with formatted Markdown details and summary
|
|
126
|
+
"""
|
|
127
|
+
return self._md_summary_generator(components, generate_table)
|
|
128
|
+
|
|
129
|
+
def _jira_markdown(self, components: list[Component]) -> PolicyOutput:
|
|
130
|
+
"""
|
|
131
|
+
Format the components with copyleft licenses as Markdown.
|
|
132
|
+
|
|
133
|
+
:param components: List of components with copyleft licenses
|
|
134
|
+
:return: Dictionary with formatted Markdown details and summary
|
|
135
|
+
"""
|
|
136
|
+
return self._md_summary_generator(components, generate_jira_table)
|
|
137
|
+
|
|
138
|
+
def _md_summary_generator(self, components: list[Component], table_generator) -> PolicyOutput:
|
|
139
|
+
"""
|
|
140
|
+
Generates a Markdown summary for components with a focus on copyleft licenses.
|
|
141
|
+
|
|
142
|
+
This function processes a list of components and groups them by their licenses.
|
|
143
|
+
For each group, the components are mapped with their license data and a tabular representation is created.
|
|
144
|
+
The generated Markdown summary includes a detailed table and a summary overview.
|
|
145
|
+
|
|
146
|
+
Parameters:
|
|
147
|
+
components: list[Component]
|
|
148
|
+
A list of Component objects to process for generating the summary.
|
|
149
|
+
table_generator
|
|
150
|
+
A callable function to generate tabular data for components.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
PolicyOutput
|
|
154
|
+
"""
|
|
155
|
+
# A component is considered unique by its combination of PURL (Package URL) and license
|
|
156
|
+
component_licenses = self.results_processor.group_components_by_license(components)
|
|
157
|
+
headers = ['Component', 'License', 'URL', 'Copyleft']
|
|
158
|
+
centered_columns = [1, 4]
|
|
159
|
+
rows = []
|
|
160
|
+
for comp_lic_item in component_licenses:
|
|
161
|
+
row = [
|
|
162
|
+
comp_lic_item['purl'],
|
|
163
|
+
comp_lic_item['spdxid'],
|
|
164
|
+
comp_lic_item['url'],
|
|
165
|
+
'YES' if comp_lic_item['copyleft'] else 'NO',
|
|
166
|
+
]
|
|
167
|
+
rows.append(row)
|
|
168
|
+
# End license loop
|
|
169
|
+
# End component loop
|
|
170
|
+
return PolicyOutput(
|
|
171
|
+
details= f'### Copyleft Licenses\n{table_generator(headers, rows, centered_columns)}',
|
|
172
|
+
summary= f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
def _get_components_with_copyleft_licenses(self, components: list) -> list[Dict]:
|
|
176
|
+
"""
|
|
177
|
+
Filter the components list to include only those with copyleft licenses.
|
|
178
|
+
|
|
179
|
+
:param components: List of all components
|
|
180
|
+
:return: List of components with copyleft licenses
|
|
181
|
+
"""
|
|
182
|
+
filtered_components = []
|
|
183
|
+
for component in components:
|
|
184
|
+
copyleft_licenses = [lic for lic in component['licenses'] if lic['copyleft']]
|
|
185
|
+
if copyleft_licenses:
|
|
186
|
+
# Remove unused keys
|
|
187
|
+
del component['count']
|
|
188
|
+
del component['declared']
|
|
189
|
+
del component['undeclared']
|
|
190
|
+
filtered_component = component
|
|
191
|
+
# Remove 'count' from each license using pop
|
|
192
|
+
for lic in copyleft_licenses:
|
|
193
|
+
lic.pop('count', None) # None is default value if key doesn't exist
|
|
194
|
+
|
|
195
|
+
filtered_component['licenses'] = copyleft_licenses
|
|
196
|
+
filtered_components.append(filtered_component)
|
|
197
|
+
# End component loop
|
|
198
|
+
self.print_debug(f'Copyleft components: {filtered_components}')
|
|
199
|
+
return filtered_components
|
|
200
|
+
|
|
201
|
+
def _get_components(self):
|
|
202
|
+
"""
|
|
203
|
+
Extract and process components from results and their dependencies.
|
|
204
|
+
|
|
205
|
+
This method performs the following steps:
|
|
206
|
+
1. Validates that `self.results` is loaded. Returns `None` if not.
|
|
207
|
+
2. Extracts file, snippet, and dependency components into a dictionary.
|
|
208
|
+
3. Converts components to a list and processes their licenses.
|
|
209
|
+
|
|
210
|
+
:return: A list of processed components with license data, or `None` if `self.results` is not set.
|
|
211
|
+
"""
|
|
212
|
+
if self.results_processor.get_results() is None:
|
|
213
|
+
return None
|
|
214
|
+
components: dict = {}
|
|
215
|
+
# Extract component and license data from file and dependency results. Both helpers mutate `components`
|
|
216
|
+
self.results_processor.get_components_data(components)
|
|
217
|
+
self.results_processor.get_dependencies_data(components)
|
|
218
|
+
return self.results_processor.convert_components_to_list(components)
|
|
219
|
+
|
|
220
|
+
def run(self):
|
|
221
|
+
"""
|
|
222
|
+
Run the copyleft license inspection process.
|
|
223
|
+
|
|
224
|
+
This method performs the following steps:
|
|
225
|
+
1. Get all components
|
|
226
|
+
2. Filter components with copyleft licenses
|
|
227
|
+
3. Format the results
|
|
228
|
+
4. Save the output to files if required
|
|
229
|
+
|
|
230
|
+
:return: Dictionary containing the inspection results
|
|
231
|
+
"""
|
|
232
|
+
self._debug()
|
|
233
|
+
# Get the components from the results
|
|
234
|
+
components = self._get_components()
|
|
235
|
+
if components is None:
|
|
236
|
+
return PolicyStatus.ERROR.value, {}
|
|
237
|
+
# Get a list of copyleft components if they exist
|
|
238
|
+
copyleft_components = self._get_components_with_copyleft_licenses(components)
|
|
239
|
+
# Format the results and save to files if required
|
|
240
|
+
return self._generate_formatter_report(copyleft_components)
|
|
241
|
+
#
|
|
242
|
+
# End of Copyleft Class
|
|
243
|
+
#
|