10 from datetime
import datetime
11 from typing
import List, Set, Dict, Tuple
13 from license_expression
import get_spdx_licensing
14 from spdx_tools.spdx.model
import (
24 PackageVerificationCode,
29 from spdx_tools.spdx.validation.document_validator
import \
30 validate_full_spdx_document
31 from spdx_tools.spdx.validation.validation_message
import ValidationMessage
32 from spdx_tools.spdx.writer.write_anything
import write_file
34 from .ApiConfig
import ApiConfig
35 from .CliOptions
import CliOptions
36 from .Scanners
import ScanResult, Scanners
43 :ivar cli_options: CliOptions object
44 :ivar report_files: Dictionary of SPDX files with SPDX ID as key
45 :ivar license_package_set: Set of licenses found in package
46 :ivar creation_info: Report creation info
47 :ivar document: Report document
48 :ivar package: Report package
51 def __init__(self, cli_options: CliOptions, api_config: ApiConfig):
53 :param cli_options: CliOptions to use
54 :param api_config: ApiConfig to use
57 self.report_files: Dict[str, File] = {}
58 self.license_package_set: Set[str] = set()
59 self.creation_info: CreationInfo = CreationInfo(
60 spdx_version=
"SPDX-2.3",
61 spdx_id=
"SPDXRef-DOCUMENT",
62 name=
"FOSSology CI Report",
63 data_license=
"CC0-1.0",
64 document_namespace=
"https://fossology.org",
65 creators=[Actor(ActorType.ORGANIZATION,
"FOSSology",
66 "fossology@fossology.org")],
67 created=datetime.now(),
69 self.document: Document = Document(self.creation_info)
71 self.package: Package = Package(
72 name=api_config.project_name,
73 spdx_id=
"SPDXRef-Package",
75 download_location=SpdxNoAssertion(),
76 release_date=datetime.now(),
78 if api_config.project_desc
is not None:
79 self.package.description = api_config.project_desc
80 if api_config.project_orig
is not None and api_config.project_orig !=
"":
81 self.package.originator = Actor(ActorType.ORGANIZATION,
82 api_config.project_orig)
84 self.package.originator = SpdxNoAssertion()
85 if api_config.project_url
is not None and api_config.project_url !=
"":
86 self.package.download_location = api_config.project_url
88 self.package.download_location = SpdxNoAssertion()
90 self.document.packages = [self.package]
92 describes_relationship = Relationship(
"SPDXRef-DOCUMENT",
93 RelationshipType.DESCRIBES,
95 self.document.relationships = [describes_relationship]
99 Add scan result from license scanner to report.
101 :param scan_result: Scan result from license scanner.
103 all_allowed_licenses = all([lic
in self.
cli_optionscli_options.allowlist[
'licenses']
104 for lic
in scan_result.result])
is True
107 if spdx_id
in self.report_files:
108 file = self.report_files[spdx_id]
112 file.file_types = [FileType.SOURCE]
113 if all_allowed_licenses:
114 file.license_concluded = get_spdx_licensing().parse(
" AND ".join([
115 lic
for lic
in scan_result.result
118 file.license_concluded = SpdxNoAssertion()
119 file.license_info_in_file = [
120 get_spdx_licensing().parse(lic)
for lic
in scan_result.result
122 self.report_files[spdx_id] = file
123 self.license_package_set.
update(scan_result.result)
127 Create a new SPDX File for given scan result and populate common fields.
129 :param scan_result: Scan result from scanner.
130 :param spdx_id: SPDX ID to use for file.
131 :return: New SPDX File
133 md5_hash, sha1_hash, sha256_hash = self.
__get_file_info__get_file_info(scan_result)
135 name=scan_result.file,
138 Checksum(ChecksumAlgorithm.MD5, md5_hash.hexdigest()),
139 Checksum(ChecksumAlgorithm.SHA1, sha1_hash.hexdigest()),
140 Checksum(ChecksumAlgorithm.SHA256, sha256_hash.hexdigest()),
142 file_types=[FileType.SOURCE],
143 license_concluded=SpdxNoAssertion()
149 Add scan result from copyright agent. If the file does not exist, creates a
152 :param copyright_result: Scan result from copyright scanner.
155 if spdx_id
in self.report_files:
156 file = self.report_files[spdx_id]
159 file.copyright_text =
"\n".join([
160 cpy
for cpy
in copyright_result.result
166 Get different hash for the file in scan result.
168 :param scan_result: Scan result from scanners.
169 :return: Tuple of md5, sha1 and sha256 checksums.
171 md5_hash = hashlib.md5()
172 sha1_hash = hashlib.sha1()
173 sha256_hash = hashlib.sha256()
174 with open(scan_result.path,
"rb")
as f:
175 for byte_block
in iter(
lambda: f.read(4096), b
""):
176 md5_hash.update(byte_block)
177 sha1_hash.update(byte_block)
178 sha256_hash.update(byte_block)
179 return md5_hash, sha1_hash, sha256_hash
184 Generate SPDX ID for file in scan result.
186 :param scan_result: Scan result from scanner.
187 :return: SPDX ID for the file.
189 spdx_id =
"SPDXRef-File" + hashlib.md5(
190 scan_result.file.encode()).hexdigest()
195 Validate the document and write the SPDX file.
197 :param file_name: Location to store the report.
199 validation_messages: List[ValidationMessage] = \
200 validate_full_spdx_document(self.document)
201 for message
in validation_messages:
202 logging.warning(message.validation_message)
203 logging.warning(message.context)
204 assert validation_messages == []
205 write_file(self.document, file_name)
209 Finalize the document by setting relations between packages and files.
210 At the same time, add all the licenses from files to the package and
211 calculate the verification code, without the excluded files.
213 for spdx_id, file
in self.report_files.items():
214 contains_relationship = Relationship(
"SPDXRef-Package",
215 RelationshipType.CONTAINS, spdx_id)
216 self.document.relationships += [contains_relationship]
217 self.document.files += [file]
219 self.package.license_info_from_files = [
220 get_spdx_licensing().parse(lic)
for lic
in self.license_package_set
223 all_allowed_licenses = all([lic
in self.
cli_optionscli_options.allowlist[
'licenses']
224 for lic
in self.license_package_set])
is True
225 if all_allowed_licenses:
226 self.package.license_concluded = get_spdx_licensing().parse(
" AND ".join([
227 lic
for lic
in self.license_package_set
230 self.package.license_concluded = SpdxNoAssertion()
233 excluded_files: list[str] = []
234 for f
in self.document.files:
235 if scanner_obj.is_excluded_path(f.name):
236 excluded_files.append(f.name)
238 for sum
in f.checksums:
239 if sum.algorithm == ChecksumAlgorithm.SHA1:
240 templist.append(sum.value)
243 verificationcode = hashlib.sha1(
"".join(templist).encode()).hexdigest()
245 self.package.verification_code = PackageVerificationCode(
246 value=verificationcode, excluded_files=excluded_files
251 Helper function to add scan results to the report from license scanners.
253 :param scan_results: List of scan results from the license scanners.
255 for result
in scan_results:
260 Helper function to add scan results to the report from copyright scanner.
262 :param copyright_results: List of scan results from the copyright scanner.
264 for result
in copyright_results:
static int update(int *pid_ptr, agent_t *agent, gpointer unused)
def finalize_document(self)
Tuple __get_file_info(ScanResult scan_result)
def add_copyright_results(self, List[ScanResult] copyright_results)
def add_copyright_file(self, ScanResult copyright_result)
def add_license_results(self, List[ScanResult] scan_results)
File __get_new_spdx_file(self, ScanResult scan_result, str spdx_id)
str __get_file_spdx_id(ScanResult scan_result)
def add_license_file(self, ScanResult scan_result)
def __init__(self, CliOptions cli_options, ApiConfig api_config)
def write_report(self, str file_name)