fosslight-util 2.1.2__tar.gz → 2.1.4__tar.gz
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.
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/PKG-INFO +1 -1
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/requirements.txt +1 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/setup.py +1 -1
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/download.py +1 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/output_format.py +7 -3
- fosslight_util-2.1.4/src/fosslight_util/write_cyclonedx.py +215 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util.egg-info/PKG-INFO +1 -1
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util.egg-info/SOURCES.txt +1 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util.egg-info/requires.txt +1 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/LICENSE +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/MANIFEST.in +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/README.md +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/setup.cfg +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/__init__.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/_get_downloadable_url.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/compare_yaml.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/constant.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/correct.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/cover.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/help.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/oss_item.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/parsing_yaml.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/read_excel.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/resources/frequentLicenselist.json +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/resources/frequent_license_nick_list.json +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/resources/licenses.json +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/set_log.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/spdx_licenses.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/timer_thread.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/write_excel.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/write_opossum.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/write_scancodejson.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/write_spdx.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/write_txt.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/write_yaml.py +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util.egg-info/dependency_links.txt +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util.egg-info/entry_points.txt +0 -0
- {fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util.egg-info/top_level.txt +0 -0
|
@@ -106,6 +106,7 @@ def cli_download_and_extract(link: str, target_dir: str, log_dir: str, checkout_
|
|
|
106
106
|
datetime.now().strftime('%Y%m%d_%H-%M-%S')+".txt"
|
|
107
107
|
logger, log_item = init_log(os.path.join(log_dir, log_file_name))
|
|
108
108
|
link = link.strip()
|
|
109
|
+
is_rubygems = False
|
|
109
110
|
|
|
110
111
|
try:
|
|
111
112
|
if not link:
|
|
@@ -8,11 +8,12 @@ from fosslight_util.write_excel import write_result_to_excel, write_result_to_cs
|
|
|
8
8
|
from fosslight_util.write_opossum import write_opossum
|
|
9
9
|
from fosslight_util.write_yaml import write_yaml
|
|
10
10
|
from fosslight_util.write_spdx import write_spdx
|
|
11
|
+
from fosslight_util.write_cyclonedx import write_cyclonedx
|
|
11
12
|
from typing import Tuple
|
|
12
13
|
|
|
13
14
|
SUPPORT_FORMAT = {'excel': '.xlsx', 'csv': '.csv', 'opossum': '.json', 'yaml': '.yaml',
|
|
14
15
|
'spdx-yaml': '.yaml', 'spdx-json': '.json', 'spdx-xml': '.xml',
|
|
15
|
-
'spdx-tag': '.tag'}
|
|
16
|
+
'spdx-tag': '.tag', 'cyclonedx-json': '.json', 'cyclonedx-xml': '.xml'}
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def check_output_format(output='', format='', customized_format={}):
|
|
@@ -182,12 +183,15 @@ def write_output_file(output_file_without_ext: str, file_extension: str, scan_it
|
|
|
182
183
|
success, msg = write_opossum(result_file, scan_item)
|
|
183
184
|
elif format == 'yaml':
|
|
184
185
|
success, msg, _ = write_yaml(result_file, scan_item, False)
|
|
185
|
-
elif format.startswith('spdx'):
|
|
186
|
+
elif format.startswith('spdx') or format.startswith('cyclonedx'):
|
|
186
187
|
if platform.system() == 'Windows' or platform.system() == 'Darwin':
|
|
187
188
|
success = False
|
|
188
189
|
msg = f'{platform.system()} not support spdx format.'
|
|
189
190
|
else:
|
|
190
|
-
|
|
191
|
+
if format.startswith('spdx'):
|
|
192
|
+
success, msg, _ = write_spdx(output_file_without_ext, file_extension, scan_item, spdx_version)
|
|
193
|
+
elif format.startswith('cyclonedx'):
|
|
194
|
+
success, msg, _ = write_cyclonedx(output_file_without_ext, file_extension, scan_item)
|
|
191
195
|
else:
|
|
192
196
|
if file_extension == '.xlsx':
|
|
193
197
|
success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Copyright (c) 2024 LG Electronics Inc.
|
|
4
|
+
# Copyright (c) OWASP Foundation.
|
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import logging
|
|
10
|
+
import re
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from fosslight_util.spdx_licenses import get_spdx_licenses_json, get_license_from_nick
|
|
15
|
+
from fosslight_util.constant import (LOGGER_NAME, FOSSLIGHT_DEPENDENCY, FOSSLIGHT_SCANNER,
|
|
16
|
+
FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE)
|
|
17
|
+
from fosslight_util.oss_item import CHECKSUM_NULL, get_checksum_sha1
|
|
18
|
+
from packageurl import PackageURL
|
|
19
|
+
import traceback
|
|
20
|
+
try:
|
|
21
|
+
from cyclonedx.builder.this import this_component as cdx_lib_component
|
|
22
|
+
from cyclonedx.exception import MissingOptionalDependencyException
|
|
23
|
+
from cyclonedx.factory.license import LicenseFactory
|
|
24
|
+
from cyclonedx.model import XsUri, ExternalReferenceType
|
|
25
|
+
from cyclonedx.model.bom import Bom
|
|
26
|
+
from cyclonedx.model.component import Component, ComponentType, HashAlgorithm, HashType, ExternalReference
|
|
27
|
+
from cyclonedx.model.contact import OrganizationalEntity
|
|
28
|
+
from cyclonedx.output import make_outputter, BaseOutput
|
|
29
|
+
from cyclonedx.output.json import JsonV1Dot6
|
|
30
|
+
from cyclonedx.schema import OutputFormat, SchemaVersion
|
|
31
|
+
from cyclonedx.validation import make_schemabased_validator
|
|
32
|
+
from cyclonedx.validation.json import JsonStrictValidator
|
|
33
|
+
from cyclonedx.output.json import Json as JsonOutputter
|
|
34
|
+
from cyclonedx.output.xml import Xml as XmlOutputter
|
|
35
|
+
from cyclonedx.validation.xml import XmlValidator
|
|
36
|
+
except Exception:
|
|
37
|
+
logger.info('No import cyclonedx-python-lib')
|
|
38
|
+
logger = logging.getLogger(LOGGER_NAME)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def write_cyclonedx(output_file_without_ext, output_extension, scan_item):
|
|
42
|
+
success = True
|
|
43
|
+
error_msg = ''
|
|
44
|
+
|
|
45
|
+
bom = Bom()
|
|
46
|
+
if scan_item:
|
|
47
|
+
try:
|
|
48
|
+
cover_name = scan_item.cover.get_print_json()["Tool information"].split('(').pop(0).strip()
|
|
49
|
+
match = re.search(r"(.+) v([0-9.]+)", cover_name)
|
|
50
|
+
if match:
|
|
51
|
+
scanner_name = match.group(1)
|
|
52
|
+
else:
|
|
53
|
+
scanner_name = FOSSLIGHT_SCANNER
|
|
54
|
+
except Exception:
|
|
55
|
+
cover_name = FOSSLIGHT_SCANNER
|
|
56
|
+
scanner_name = FOSSLIGHT_SCANNER
|
|
57
|
+
|
|
58
|
+
lc_factory = LicenseFactory()
|
|
59
|
+
bom.metadata.tools.components.add(cdx_lib_component())
|
|
60
|
+
bom.metadata.tools.components.add(Component(name=scanner_name.upper(),
|
|
61
|
+
type=ComponentType.APPLICATION))
|
|
62
|
+
comp_id = 0
|
|
63
|
+
bom.metadata.component = root_component = Component(name='Root Component',
|
|
64
|
+
type=ComponentType.APPLICATION,
|
|
65
|
+
bom_ref=str(comp_id))
|
|
66
|
+
relation_tree = {}
|
|
67
|
+
bom_ref_packages = []
|
|
68
|
+
|
|
69
|
+
output_dir = os.path.dirname(output_file_without_ext)
|
|
70
|
+
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
|
71
|
+
try:
|
|
72
|
+
root_package = False
|
|
73
|
+
for scanner_name, file_items in scan_item.file_items.items():
|
|
74
|
+
for file_item in file_items:
|
|
75
|
+
if file_item.exclude:
|
|
76
|
+
continue
|
|
77
|
+
if scanner_name == FOSSLIGHT_SOURCE:
|
|
78
|
+
comp_type = ComponentType.FILE
|
|
79
|
+
else:
|
|
80
|
+
comp_type = ComponentType.LIBRARY
|
|
81
|
+
|
|
82
|
+
for oss_item in file_item.oss_items:
|
|
83
|
+
if oss_item.name == '':
|
|
84
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY:
|
|
85
|
+
continue
|
|
86
|
+
else:
|
|
87
|
+
comp_name = file_item.source_name_or_path
|
|
88
|
+
else:
|
|
89
|
+
comp_name = oss_item.name
|
|
90
|
+
|
|
91
|
+
comp_id += 1
|
|
92
|
+
comp = Component(type=comp_type,
|
|
93
|
+
name=comp_name,
|
|
94
|
+
bom_ref=str(comp_id))
|
|
95
|
+
|
|
96
|
+
if oss_item.version != '':
|
|
97
|
+
comp.version = oss_item.version
|
|
98
|
+
if oss_item.copyright != '':
|
|
99
|
+
comp.copyright = oss_item.copyright
|
|
100
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY and file_item.purl:
|
|
101
|
+
comp.purl = PackageURL.from_string(file_item.purl)
|
|
102
|
+
if scanner_name != FOSSLIGHT_DEPENDENCY:
|
|
103
|
+
comp.hashes = [HashType(alg=HashAlgorithm.SHA_1, content=file_item.checksum)]
|
|
104
|
+
|
|
105
|
+
if oss_item.download_location != '':
|
|
106
|
+
comp.external_references = [ExternalReference(url=XsUri(oss_item.download_location),
|
|
107
|
+
type=ExternalReferenceType.WEBSITE)]
|
|
108
|
+
|
|
109
|
+
oss_licenses = []
|
|
110
|
+
for ol in oss_item.license:
|
|
111
|
+
try:
|
|
112
|
+
oss_licenses.append(lc_factory.make_from_string(ol))
|
|
113
|
+
except Exception:
|
|
114
|
+
logger.info(f'No spdx license name: {oi}')
|
|
115
|
+
if oss_licenses:
|
|
116
|
+
comp.licenses = oss_licenses
|
|
117
|
+
|
|
118
|
+
root_package = False
|
|
119
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY:
|
|
120
|
+
if oss_item.comment:
|
|
121
|
+
oss_comment = oss_item.comment.split('/')
|
|
122
|
+
for oc in oss_comment:
|
|
123
|
+
if oc in ['direct', 'transitive', 'root package']:
|
|
124
|
+
if oc == 'direct':
|
|
125
|
+
bom.register_dependency(root_component, [comp])
|
|
126
|
+
elif oc == 'root package':
|
|
127
|
+
root_package = True
|
|
128
|
+
root_component.name = comp_name
|
|
129
|
+
root_component.type = comp_type
|
|
130
|
+
comp_id -= 1
|
|
131
|
+
else:
|
|
132
|
+
bom.register_dependency(root_component, [comp])
|
|
133
|
+
if len(file_item.depends_on) > 0:
|
|
134
|
+
purl = file_item.purl
|
|
135
|
+
relation_tree[purl] = []
|
|
136
|
+
relation_tree[purl].extend(file_item.depends_on)
|
|
137
|
+
|
|
138
|
+
if not root_package:
|
|
139
|
+
bom.components.add(comp)
|
|
140
|
+
|
|
141
|
+
if len(bom.components) > 0:
|
|
142
|
+
for comp_purl in relation_tree:
|
|
143
|
+
comp = bom.get_component_by_purl(PackageURL.from_string(comp_purl))
|
|
144
|
+
if comp:
|
|
145
|
+
dep_comp_list = []
|
|
146
|
+
for dep_comp_purl in relation_tree[comp_purl]:
|
|
147
|
+
dep_comp = bom.get_component_by_purl(PackageURL.from_string(dep_comp_purl))
|
|
148
|
+
if dep_comp:
|
|
149
|
+
dep_comp_list.append(dep_comp)
|
|
150
|
+
bom.register_dependency(comp, dep_comp_list)
|
|
151
|
+
|
|
152
|
+
except Exception as e:
|
|
153
|
+
success = False
|
|
154
|
+
error_msg = f'Failed to create CycloneDX document object:{e}, {traceback.format_exc()}'
|
|
155
|
+
else:
|
|
156
|
+
success = False
|
|
157
|
+
error_msg = 'No item to write in output file.'
|
|
158
|
+
|
|
159
|
+
result_file = ''
|
|
160
|
+
if success:
|
|
161
|
+
result_file = output_file_without_ext + output_extension
|
|
162
|
+
try:
|
|
163
|
+
if output_extension == '.json':
|
|
164
|
+
write_cyclonedx_json(bom, result_file)
|
|
165
|
+
elif output_extension == '.xml':
|
|
166
|
+
write_cyclonedx_xml(bom, result_file)
|
|
167
|
+
else:
|
|
168
|
+
success = False
|
|
169
|
+
error_msg = f'Not supported output_extension({output_extension})'
|
|
170
|
+
except Exception as e:
|
|
171
|
+
success = False
|
|
172
|
+
error_msg = f'Failed to write CycloneDX document: {e}'
|
|
173
|
+
if os.path.exists(result_file):
|
|
174
|
+
os.remove(result_file)
|
|
175
|
+
|
|
176
|
+
return success, error_msg, result_file
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def write_cyclonedx_json(bom, result_file):
|
|
180
|
+
success = True
|
|
181
|
+
try:
|
|
182
|
+
my_json_outputter: 'JsonOutputter' = JsonV1Dot6(bom)
|
|
183
|
+
my_json_outputter.output_to_file(result_file)
|
|
184
|
+
serialized_json = my_json_outputter.output_as_string(indent=2)
|
|
185
|
+
my_json_validator = JsonStrictValidator(SchemaVersion.V1_6)
|
|
186
|
+
try:
|
|
187
|
+
validation_errors = my_json_validator.validate_str(serialized_json)
|
|
188
|
+
if validation_errors:
|
|
189
|
+
logger.warning(f'JSON invalid, ValidationError: {repr(validation_errors)}')
|
|
190
|
+
except MissingOptionalDependencyException as error:
|
|
191
|
+
logger.debug(f'JSON-validation was skipped due to {error}')
|
|
192
|
+
except Exception as e:
|
|
193
|
+
success = False
|
|
194
|
+
return success
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def write_cyclonedx_xml(bom, result_file):
|
|
199
|
+
success = True
|
|
200
|
+
try:
|
|
201
|
+
my_xml_outputter: BaseOutput = make_outputter(bom=bom,
|
|
202
|
+
output_format=OutputFormat.XML,
|
|
203
|
+
schema_version=SchemaVersion.V1_6)
|
|
204
|
+
my_xml_outputter.output_to_file(filename=result_file)
|
|
205
|
+
serialized_xml = my_xml_outputter.output_as_string(indent=2)
|
|
206
|
+
my_xml_validator = XmlValidator(SchemaVersion.V1_6)
|
|
207
|
+
try:
|
|
208
|
+
validation_errors = my_xml_validator.validate_str(serialized_xml)
|
|
209
|
+
if validation_errors:
|
|
210
|
+
logger.warning(f'XML invalid, ValidationError: {repr(validation_errors)}')
|
|
211
|
+
except MissingOptionalDependencyException as error:
|
|
212
|
+
logger.debug(f'XML-validation was skipped due to {error}')
|
|
213
|
+
except Exception as e:
|
|
214
|
+
success = False
|
|
215
|
+
return success
|
|
@@ -18,6 +18,7 @@ src/fosslight_util/read_excel.py
|
|
|
18
18
|
src/fosslight_util/set_log.py
|
|
19
19
|
src/fosslight_util/spdx_licenses.py
|
|
20
20
|
src/fosslight_util/timer_thread.py
|
|
21
|
+
src/fosslight_util/write_cyclonedx.py
|
|
21
22
|
src/fosslight_util/write_excel.py
|
|
22
23
|
src/fosslight_util/write_opossum.py
|
|
23
24
|
src/fosslight_util/write_scancodejson.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util/resources/frequentLicenselist.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fosslight_util-2.1.2 → fosslight_util-2.1.4}/src/fosslight_util.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|