fosslight-util 2.1.1__tar.gz → 2.1.3__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.1 → fosslight_util-2.1.3}/PKG-INFO +1 -1
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/requirements.txt +1 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/setup.py +1 -1
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/download.py +95 -61
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/output_format.py +14 -11
- fosslight_util-2.1.3/src/fosslight_util/write_cyclonedx.py +213 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util.egg-info/PKG-INFO +1 -1
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util.egg-info/SOURCES.txt +1 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util.egg-info/requires.txt +1 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/LICENSE +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/MANIFEST.in +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/README.md +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/setup.cfg +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/__init__.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/_get_downloadable_url.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/compare_yaml.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/constant.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/correct.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/cover.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/help.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/oss_item.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/parsing_yaml.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/read_excel.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/resources/frequentLicenselist.json +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/resources/frequent_license_nick_list.json +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/resources/licenses.json +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/set_log.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/spdx_licenses.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/timer_thread.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/write_excel.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/write_opossum.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/write_scancodejson.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/write_spdx.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/write_txt.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util/write_yaml.py +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util.egg-info/dependency_links.txt +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util.egg-info/entry_points.txt +0 -0
- {fosslight_util-2.1.1 → fosslight_util-2.1.3}/src/fosslight_util.egg-info/top_level.txt +0 -0
|
@@ -10,7 +10,7 @@ import zipfile
|
|
|
10
10
|
import logging
|
|
11
11
|
import argparse
|
|
12
12
|
import shutil
|
|
13
|
-
from git import Repo, GitCommandError
|
|
13
|
+
from git import Repo, GitCommandError, Git
|
|
14
14
|
import bz2
|
|
15
15
|
import contextlib
|
|
16
16
|
from datetime import datetime
|
|
@@ -77,7 +77,7 @@ def parse_src_link(src_link):
|
|
|
77
77
|
if src_link.startswith("git://github.com/"):
|
|
78
78
|
src_link_changed = change_src_link_to_https(src_link_split[0])
|
|
79
79
|
elif src_link.startswith("git@github.com:"):
|
|
80
|
-
src_link_changed =
|
|
80
|
+
src_link_changed = src_link_split[0]
|
|
81
81
|
else:
|
|
82
82
|
if "rubygems.org" in src_link:
|
|
83
83
|
src_info["rubygems"] = True
|
|
@@ -92,39 +92,9 @@ def parse_src_link(src_link):
|
|
|
92
92
|
return src_info
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
def main():
|
|
96
|
-
parser = argparse.ArgumentParser(description='FOSSLight Downloader', prog='fosslight_download', add_help=False)
|
|
97
|
-
parser.add_argument('-h', '--help', help='Print help message', action='store_true', dest='help')
|
|
98
|
-
parser.add_argument('-s', '--source', help='Source link to download', type=str, dest='source')
|
|
99
|
-
parser.add_argument('-t', '--target_dir', help='Target directory', type=str, dest='target_dir', default="")
|
|
100
|
-
parser.add_argument('-d', '--log_dir', help='Directory to save log file', type=str, dest='log_dir', default="")
|
|
101
|
-
|
|
102
|
-
src_link = ""
|
|
103
|
-
target_dir = os.getcwd()
|
|
104
|
-
log_dir = os.getcwd()
|
|
105
|
-
|
|
106
|
-
try:
|
|
107
|
-
args = parser.parse_args()
|
|
108
|
-
except SystemExit:
|
|
109
|
-
sys.exit(0)
|
|
110
|
-
|
|
111
|
-
if args.help:
|
|
112
|
-
print_help_msg_download()
|
|
113
|
-
if args.source:
|
|
114
|
-
src_link = args.source
|
|
115
|
-
if args.target_dir:
|
|
116
|
-
target_dir = args.target_dir
|
|
117
|
-
if args.log_dir:
|
|
118
|
-
log_dir = args.log_dir
|
|
119
|
-
|
|
120
|
-
if not src_link:
|
|
121
|
-
print_help_msg_download()
|
|
122
|
-
else:
|
|
123
|
-
cli_download_and_extract(src_link, target_dir, log_dir)
|
|
124
|
-
|
|
125
|
-
|
|
126
95
|
def cli_download_and_extract(link: str, target_dir: str, log_dir: str, checkout_to: str = "",
|
|
127
|
-
compressed_only: bool = False
|
|
96
|
+
compressed_only: bool = False, ssh_key: str = "",
|
|
97
|
+
id: str = "", git_token: str = "") -> Tuple[bool, str, str, str]:
|
|
128
98
|
global logger
|
|
129
99
|
|
|
130
100
|
success = True
|
|
@@ -152,7 +122,9 @@ def cli_download_and_extract(link: str, target_dir: str, log_dir: str, checkout_
|
|
|
152
122
|
is_rubygems = src_info.get("rubygems", False)
|
|
153
123
|
|
|
154
124
|
# General download (git clone, wget)
|
|
155
|
-
success_git, msg, oss_name, oss_version = download_git_clone(link, target_dir, checkout_to,
|
|
125
|
+
success_git, msg, oss_name, oss_version = download_git_clone(link, target_dir, checkout_to,
|
|
126
|
+
tag, branch, ssh_key, id, git_token)
|
|
127
|
+
link = change_ssh_link_to_https(link)
|
|
156
128
|
if (not is_rubygems) and (not success_git):
|
|
157
129
|
if os.path.isfile(target_dir):
|
|
158
130
|
shutil.rmtree(target_dir)
|
|
@@ -229,11 +201,38 @@ def get_github_token(git_url):
|
|
|
229
201
|
return github_token
|
|
230
202
|
|
|
231
203
|
|
|
232
|
-
def
|
|
204
|
+
def download_git_repository(refs_to_checkout, git_url, target_dir, tag):
|
|
205
|
+
success = False
|
|
206
|
+
oss_version = ""
|
|
207
|
+
clone_default_branch_flag = False
|
|
208
|
+
|
|
209
|
+
logger.info(f"Download git url :{git_url}")
|
|
210
|
+
if refs_to_checkout:
|
|
211
|
+
try:
|
|
212
|
+
# gitPython uses the branch argument the same whether you check out to a branch or a tag.
|
|
213
|
+
repo = Repo.clone_from(git_url, target_dir, branch=refs_to_checkout)
|
|
214
|
+
success = True
|
|
215
|
+
except GitCommandError as error:
|
|
216
|
+
logger.debug(f"Git checkout error:{error}")
|
|
217
|
+
success = False
|
|
218
|
+
|
|
219
|
+
if not success:
|
|
220
|
+
repo = Repo.clone_from(git_url, target_dir)
|
|
221
|
+
clone_default_branch_flag = True
|
|
222
|
+
success = True
|
|
223
|
+
|
|
224
|
+
if refs_to_checkout != tag or clone_default_branch_flag:
|
|
225
|
+
oss_version = repo.active_branch.name
|
|
226
|
+
else:
|
|
227
|
+
oss_version = repo.git.describe('--tags')
|
|
228
|
+
return success, oss_version
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch="", ssh_key="", id="", git_token=""):
|
|
233
232
|
oss_name = get_github_ossname(git_url)
|
|
234
233
|
refs_to_checkout = decide_checkout(checkout_to, tag, branch)
|
|
235
|
-
clone_default_branch_flag = False
|
|
236
234
|
msg = ""
|
|
235
|
+
success = True
|
|
237
236
|
|
|
238
237
|
try:
|
|
239
238
|
if platform.system() != "Windows":
|
|
@@ -244,36 +243,40 @@ def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch=""):
|
|
|
244
243
|
alarm.start()
|
|
245
244
|
|
|
246
245
|
Path(target_dir).mkdir(parents=True, exist_ok=True)
|
|
247
|
-
if refs_to_checkout != "":
|
|
248
|
-
try:
|
|
249
|
-
# gitPython uses the branch argument the same whether you check out to a branch or a tag.
|
|
250
|
-
repo = Repo.clone_from(git_url, target_dir, branch=refs_to_checkout)
|
|
251
|
-
except GitCommandError as error:
|
|
252
|
-
error_msg = error.args[2].decode("utf-8")
|
|
253
|
-
if "Remote branch " + refs_to_checkout + " not found in upstream origin" in error_msg:
|
|
254
|
-
# clone default branch, when non-existent branch or tag entered
|
|
255
|
-
repo = Repo.clone_from(git_url, target_dir)
|
|
256
|
-
clone_default_branch_flag = True
|
|
257
|
-
else:
|
|
258
|
-
repo = Repo.clone_from(git_url, target_dir)
|
|
259
|
-
clone_default_branch_flag = True
|
|
260
246
|
|
|
261
|
-
if
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
oss_version = repo.git.describe('--tags')
|
|
265
|
-
logger.info(f"git checkout: {oss_version}")
|
|
266
|
-
|
|
267
|
-
if platform.system() != "Windows":
|
|
268
|
-
signal.alarm(0)
|
|
247
|
+
if git_url.startswith("ssh:") and not ssh_key:
|
|
248
|
+
msg = "Private git needs ssh_key"
|
|
249
|
+
success = False
|
|
269
250
|
else:
|
|
270
|
-
|
|
251
|
+
if ssh_key:
|
|
252
|
+
logger.info(f"Download git with ssh_key:{git_url}")
|
|
253
|
+
git_ssh_cmd = f'ssh -i {ssh_key}'
|
|
254
|
+
with Git().custom_environment(GIT_SSH_COMMAND=git_ssh_cmd):
|
|
255
|
+
success, oss_version = download_git_repository(refs_to_checkout, git_url, target_dir, tag)
|
|
256
|
+
else:
|
|
257
|
+
if id and git_token:
|
|
258
|
+
try:
|
|
259
|
+
m = re.match(r"^(ht|f)tp(s?)\:\/\/", git_url)
|
|
260
|
+
protocol = m.group()
|
|
261
|
+
if protocol:
|
|
262
|
+
git_url = git_url.replace(protocol, f"{protocol}{id}:{git_token}@")
|
|
263
|
+
except Exception as error:
|
|
264
|
+
logger.info(f"Failed to insert id, token to git url:{error}")
|
|
265
|
+
success, oss_version = download_git_repository(refs_to_checkout, git_url, target_dir, tag)
|
|
266
|
+
|
|
267
|
+
logger.info(f"git checkout: {oss_version}")
|
|
268
|
+
refs_to_checkout = oss_version
|
|
269
|
+
|
|
270
|
+
if platform.system() != "Windows":
|
|
271
|
+
signal.alarm(0)
|
|
272
|
+
else:
|
|
273
|
+
del alarm
|
|
271
274
|
except Exception as error:
|
|
275
|
+
success = False
|
|
272
276
|
logger.warning(f"git clone - failed: {error}")
|
|
273
277
|
msg = str(error)
|
|
274
|
-
return False, msg, oss_name, refs_to_checkout
|
|
275
278
|
|
|
276
|
-
return
|
|
279
|
+
return success, msg, oss_name, refs_to_checkout
|
|
277
280
|
|
|
278
281
|
|
|
279
282
|
def download_wget(link, target_dir, compressed_only):
|
|
@@ -444,5 +447,36 @@ def gem_download(link, target_dir, checkout_to):
|
|
|
444
447
|
return success
|
|
445
448
|
|
|
446
449
|
|
|
450
|
+
def main():
|
|
451
|
+
parser = argparse.ArgumentParser(description='FOSSLight Downloader', prog='fosslight_download', add_help=False)
|
|
452
|
+
parser.add_argument('-h', '--help', help='Print help message', action='store_true', dest='help')
|
|
453
|
+
parser.add_argument('-s', '--source', help='Source link to download', type=str, dest='source')
|
|
454
|
+
parser.add_argument('-t', '--target_dir', help='Target directory', type=str, dest='target_dir', default="")
|
|
455
|
+
parser.add_argument('-d', '--log_dir', help='Directory to save log file', type=str, dest='log_dir', default="")
|
|
456
|
+
|
|
457
|
+
src_link = ""
|
|
458
|
+
target_dir = os.getcwd()
|
|
459
|
+
log_dir = os.getcwd()
|
|
460
|
+
|
|
461
|
+
try:
|
|
462
|
+
args = parser.parse_args()
|
|
463
|
+
except SystemExit:
|
|
464
|
+
sys.exit(0)
|
|
465
|
+
|
|
466
|
+
if args.help:
|
|
467
|
+
print_help_msg_download()
|
|
468
|
+
if args.source:
|
|
469
|
+
src_link = args.source
|
|
470
|
+
if args.target_dir:
|
|
471
|
+
target_dir = args.target_dir
|
|
472
|
+
if args.log_dir:
|
|
473
|
+
log_dir = args.log_dir
|
|
474
|
+
|
|
475
|
+
if not src_link:
|
|
476
|
+
print_help_msg_download()
|
|
477
|
+
else:
|
|
478
|
+
cli_download_and_extract(src_link, target_dir, log_dir)
|
|
479
|
+
|
|
480
|
+
|
|
447
481
|
if __name__ == '__main__':
|
|
448
482
|
main()
|
|
@@ -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={}):
|
|
@@ -31,7 +32,7 @@ def check_output_format(output='', format='', customized_format={}):
|
|
|
31
32
|
format = format.lower()
|
|
32
33
|
if format not in list(support_format.keys()):
|
|
33
34
|
success = False
|
|
34
|
-
msg = 'Enter the supported format
|
|
35
|
+
msg = '(-f option) Enter the supported format: ' + ', '.join(list(support_format.keys()))
|
|
35
36
|
else:
|
|
36
37
|
output_extension = support_format[format]
|
|
37
38
|
|
|
@@ -47,11 +48,11 @@ def check_output_format(output='', format='', customized_format={}):
|
|
|
47
48
|
if format:
|
|
48
49
|
if output_extension != basename_extension:
|
|
49
50
|
success = False
|
|
50
|
-
msg = f"Enter the same extension of output file(-o:'{output}') with format(-f:'{format}')."
|
|
51
|
+
msg = f"(-o & -f option) Enter the same extension of output file(-o:'{output}') with format(-f:'{format}')."
|
|
51
52
|
else:
|
|
52
53
|
if basename_extension not in support_format.values():
|
|
53
54
|
success = False
|
|
54
|
-
msg = 'Enter the supported file extension: ' + ', '.join(list(support_format.values()))
|
|
55
|
+
msg = '(-o option) Enter the supported file extension: ' + ', '.join(list(support_format.values()))
|
|
55
56
|
if success:
|
|
56
57
|
output_file = basename_file
|
|
57
58
|
output_extension = basename_extension
|
|
@@ -79,7 +80,7 @@ def check_output_formats(output='', formats=[], customized_format={}):
|
|
|
79
80
|
for format in formats:
|
|
80
81
|
if format not in list(support_format.keys()):
|
|
81
82
|
success = False
|
|
82
|
-
msg = 'Enter the supported format
|
|
83
|
+
msg = '(-f option) Enter the supported format: ' + ', '.join(list(support_format.keys()))
|
|
83
84
|
else:
|
|
84
85
|
output_extensions.append(support_format[format])
|
|
85
86
|
|
|
@@ -95,11 +96,11 @@ def check_output_formats(output='', formats=[], customized_format={}):
|
|
|
95
96
|
if formats:
|
|
96
97
|
if basename_extension not in output_extensions:
|
|
97
98
|
success = False
|
|
98
|
-
msg = f"The format of output file(-o:'{output}') should be in the format list(-f:'{formats}')."
|
|
99
|
+
msg = f"(-o & -f option) The format of output file(-o:'{output}') should be in the format list(-f:'{formats}')."
|
|
99
100
|
else:
|
|
100
101
|
if basename_extension not in support_format.values():
|
|
101
102
|
success = False
|
|
102
|
-
msg = 'Enter the supported file extension: ' + ', '.join(list(support_format.values()))
|
|
103
|
+
msg = '(-o option) Enter the supported file extension: ' + ', '.join(list(support_format.values()))
|
|
103
104
|
output_extensions.append(basename_extension)
|
|
104
105
|
output_files = [basename_file for _ in range(len(output_extensions))]
|
|
105
106
|
else:
|
|
@@ -128,7 +129,7 @@ def check_output_formats_v2(output='', formats=[], customized_format={}):
|
|
|
128
129
|
for format in formats:
|
|
129
130
|
if format not in list(support_format.keys()):
|
|
130
131
|
success = False
|
|
131
|
-
msg = 'Enter the supported format with -f option: ' + ', '.join(list(support_format.keys()))
|
|
132
|
+
msg = '(-f option) Enter the supported format with -f option: ' + ', '.join(list(support_format.keys()))
|
|
132
133
|
else:
|
|
133
134
|
output_extensions.append(support_format[format])
|
|
134
135
|
|
|
@@ -144,11 +145,11 @@ def check_output_formats_v2(output='', formats=[], customized_format={}):
|
|
|
144
145
|
if formats:
|
|
145
146
|
if basename_extension not in output_extensions:
|
|
146
147
|
success = False
|
|
147
|
-
msg = f"The format of output file(-o:'{output}') should be in the format list(-f:'{formats}')."
|
|
148
|
+
msg = f"(-o & -f option) The format of output file(-o:'{output}') should be in the format list(-f:'{formats}')."
|
|
148
149
|
else:
|
|
149
150
|
if basename_extension not in support_format.values():
|
|
150
151
|
success = False
|
|
151
|
-
msg = 'Enter the supported file extension: ' + ', '.join(list(support_format.values()))
|
|
152
|
+
msg = '(-o option) Enter the supported file extension: ' + ', '.join(list(support_format.values()))
|
|
152
153
|
output_extensions.append(basename_extension)
|
|
153
154
|
output_files = [basename_file for _ in range(len(output_extensions))]
|
|
154
155
|
else:
|
|
@@ -188,6 +189,8 @@ def write_output_file(output_file_without_ext: str, file_extension: str, scan_it
|
|
|
188
189
|
msg = f'{platform.system()} not support spdx format.'
|
|
189
190
|
else:
|
|
190
191
|
success, msg, _ = write_spdx(output_file_without_ext, file_extension, scan_item, spdx_version)
|
|
192
|
+
elif format.startswith('cyclonedx'):
|
|
193
|
+
success, msg, _ = write_cyclonedx(output_file_without_ext, file_extension, scan_item)
|
|
191
194
|
else:
|
|
192
195
|
if file_extension == '.xlsx':
|
|
193
196
|
success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
|
|
@@ -199,6 +202,6 @@ def write_output_file(output_file_without_ext: str, file_extension: str, scan_it
|
|
|
199
202
|
success, msg, result_file = write_yaml(result_file, scan_item, False)
|
|
200
203
|
else:
|
|
201
204
|
success = False
|
|
202
|
-
msg = f'Not supported file extension({file_extension})'
|
|
205
|
+
msg = f'(-f option) Not supported file extension({file_extension})'
|
|
203
206
|
|
|
204
207
|
return success, msg, result_file
|
|
@@ -0,0 +1,213 @@
|
|
|
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
|
+
from cyclonedx.builder.this import this_component as cdx_lib_component
|
|
21
|
+
from cyclonedx.exception import MissingOptionalDependencyException
|
|
22
|
+
from cyclonedx.factory.license import LicenseFactory
|
|
23
|
+
from cyclonedx.model import XsUri, ExternalReferenceType
|
|
24
|
+
from cyclonedx.model.bom import Bom
|
|
25
|
+
from cyclonedx.model.component import Component, ComponentType, HashAlgorithm, HashType, ExternalReference
|
|
26
|
+
from cyclonedx.model.contact import OrganizationalEntity
|
|
27
|
+
from cyclonedx.output import make_outputter, BaseOutput
|
|
28
|
+
from cyclonedx.output.json import JsonV1Dot6
|
|
29
|
+
from cyclonedx.schema import OutputFormat, SchemaVersion
|
|
30
|
+
from cyclonedx.validation import make_schemabased_validator
|
|
31
|
+
from cyclonedx.validation.json import JsonStrictValidator
|
|
32
|
+
from cyclonedx.output.json import Json as JsonOutputter
|
|
33
|
+
from cyclonedx.output.xml import Xml as XmlOutputter
|
|
34
|
+
from cyclonedx.validation.xml import XmlValidator
|
|
35
|
+
|
|
36
|
+
logger = logging.getLogger(LOGGER_NAME)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def write_cyclonedx(output_file_without_ext, output_extension, scan_item):
|
|
40
|
+
success = True
|
|
41
|
+
error_msg = ''
|
|
42
|
+
|
|
43
|
+
bom = Bom()
|
|
44
|
+
if scan_item:
|
|
45
|
+
try:
|
|
46
|
+
cover_name = scan_item.cover.get_print_json()["Tool information"].split('(').pop(0).strip()
|
|
47
|
+
match = re.search(r"(.+) v([0-9.]+)", cover_name)
|
|
48
|
+
if match:
|
|
49
|
+
scanner_name = match.group(1)
|
|
50
|
+
else:
|
|
51
|
+
scanner_name = FOSSLIGHT_SCANNER
|
|
52
|
+
except Exception:
|
|
53
|
+
cover_name = FOSSLIGHT_SCANNER
|
|
54
|
+
scanner_name = FOSSLIGHT_SCANNER
|
|
55
|
+
|
|
56
|
+
lc_factory = LicenseFactory()
|
|
57
|
+
bom.metadata.tools.components.add(cdx_lib_component())
|
|
58
|
+
bom.metadata.tools.components.add(Component(name=scanner_name.upper(),
|
|
59
|
+
type=ComponentType.APPLICATION))
|
|
60
|
+
comp_id = 0
|
|
61
|
+
bom.metadata.component = root_component = Component(name='Root Component',
|
|
62
|
+
type=ComponentType.APPLICATION,
|
|
63
|
+
bom_ref=str(comp_id))
|
|
64
|
+
relation_tree = {}
|
|
65
|
+
bom_ref_packages = []
|
|
66
|
+
|
|
67
|
+
output_dir = os.path.dirname(output_file_without_ext)
|
|
68
|
+
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
|
69
|
+
try:
|
|
70
|
+
root_package = False
|
|
71
|
+
for scanner_name, file_items in scan_item.file_items.items():
|
|
72
|
+
for file_item in file_items:
|
|
73
|
+
if file_item.exclude:
|
|
74
|
+
continue
|
|
75
|
+
if scanner_name == FOSSLIGHT_SOURCE:
|
|
76
|
+
comp_type = ComponentType.FILE
|
|
77
|
+
else:
|
|
78
|
+
comp_type = ComponentType.LIBRARY
|
|
79
|
+
|
|
80
|
+
for oss_item in file_item.oss_items:
|
|
81
|
+
if oss_item.name == '':
|
|
82
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY:
|
|
83
|
+
continue
|
|
84
|
+
else:
|
|
85
|
+
comp_name = file_item.source_name_or_path
|
|
86
|
+
else:
|
|
87
|
+
comp_name = oss_item.name
|
|
88
|
+
|
|
89
|
+
comp_id += 1
|
|
90
|
+
comp = Component(type=comp_type,
|
|
91
|
+
name=comp_name,
|
|
92
|
+
bom_ref=str(comp_id))
|
|
93
|
+
|
|
94
|
+
if oss_item.version != '':
|
|
95
|
+
comp.version = oss_item.version
|
|
96
|
+
if oss_item.copyright != '':
|
|
97
|
+
comp.copyright = oss_item.copyright
|
|
98
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY and file_item.purl:
|
|
99
|
+
comp.purl = PackageURL.from_string(file_item.purl)
|
|
100
|
+
if scanner_name != FOSSLIGHT_DEPENDENCY:
|
|
101
|
+
comp.hashes = [HashType(alg=HashAlgorithm.SHA_1, content=file_item.checksum)]
|
|
102
|
+
|
|
103
|
+
if oss_item.download_location != '':
|
|
104
|
+
comp.external_references = [ExternalReference(url=XsUri(oss_item.download_location),
|
|
105
|
+
type=ExternalReferenceType.WEBSITE)]
|
|
106
|
+
|
|
107
|
+
oss_licenses = []
|
|
108
|
+
for ol in oss_item.license:
|
|
109
|
+
try:
|
|
110
|
+
oss_licenses.append(lc_factory.make_from_string(ol))
|
|
111
|
+
except Exception:
|
|
112
|
+
logger.info(f'No spdx license name: {oi}')
|
|
113
|
+
if oss_licenses:
|
|
114
|
+
comp.licenses = oss_licenses
|
|
115
|
+
|
|
116
|
+
root_package = False
|
|
117
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY:
|
|
118
|
+
if oss_item.comment:
|
|
119
|
+
oss_comment = oss_item.comment.split('/')
|
|
120
|
+
for oc in oss_comment:
|
|
121
|
+
if oc in ['direct', 'transitive', 'root package']:
|
|
122
|
+
if oc == 'direct':
|
|
123
|
+
bom.register_dependency(root_component, [comp])
|
|
124
|
+
elif oc == 'root package':
|
|
125
|
+
root_package = True
|
|
126
|
+
root_component.name = comp_name
|
|
127
|
+
root_component.type = comp_type
|
|
128
|
+
comp_id -= 1
|
|
129
|
+
else:
|
|
130
|
+
bom.register_dependency(root_component, [comp])
|
|
131
|
+
if len(file_item.depends_on) > 0:
|
|
132
|
+
purl = file_item.purl
|
|
133
|
+
relation_tree[purl] = []
|
|
134
|
+
relation_tree[purl].extend(file_item.depends_on)
|
|
135
|
+
|
|
136
|
+
if not root_package:
|
|
137
|
+
bom.components.add(comp)
|
|
138
|
+
|
|
139
|
+
if len(bom.components) > 0:
|
|
140
|
+
for comp_purl in relation_tree:
|
|
141
|
+
comp = bom.get_component_by_purl(PackageURL.from_string(comp_purl))
|
|
142
|
+
if comp:
|
|
143
|
+
dep_comp_list = []
|
|
144
|
+
for dep_comp_purl in relation_tree[comp_purl]:
|
|
145
|
+
dep_comp = bom.get_component_by_purl(PackageURL.from_string(dep_comp_purl))
|
|
146
|
+
if dep_comp:
|
|
147
|
+
dep_comp_list.append(dep_comp)
|
|
148
|
+
bom.register_dependency(comp, dep_comp_list)
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
success = False
|
|
152
|
+
error_msg = f'Failed to create CycloneDX document object:{e}, {traceback.format_exc()}'
|
|
153
|
+
else:
|
|
154
|
+
success = False
|
|
155
|
+
error_msg = 'No item to write in output file.'
|
|
156
|
+
|
|
157
|
+
result_file = ''
|
|
158
|
+
if success:
|
|
159
|
+
result_file = output_file_without_ext + output_extension
|
|
160
|
+
try:
|
|
161
|
+
if output_extension == '.json':
|
|
162
|
+
write_cyclonedx_json(bom, result_file)
|
|
163
|
+
elif output_extension == '.xml':
|
|
164
|
+
write_cyclonedx_xml(bom, result_file)
|
|
165
|
+
else:
|
|
166
|
+
success = False
|
|
167
|
+
error_msg = f'Not supported output_extension({output_extension})'
|
|
168
|
+
except Exception as e:
|
|
169
|
+
success = False
|
|
170
|
+
error_msg = f'Failed to write CycloneDX document: {e}'
|
|
171
|
+
if os.path.exists(result_file):
|
|
172
|
+
os.remove(result_file)
|
|
173
|
+
|
|
174
|
+
return success, error_msg, result_file
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def write_cyclonedx_json(bom, result_file):
|
|
178
|
+
success = True
|
|
179
|
+
try:
|
|
180
|
+
my_json_outputter: 'JsonOutputter' = JsonV1Dot6(bom)
|
|
181
|
+
my_json_outputter.output_to_file(result_file)
|
|
182
|
+
serialized_json = my_json_outputter.output_as_string(indent=2)
|
|
183
|
+
my_json_validator = JsonStrictValidator(SchemaVersion.V1_6)
|
|
184
|
+
try:
|
|
185
|
+
validation_errors = my_json_validator.validate_str(serialized_json)
|
|
186
|
+
if validation_errors:
|
|
187
|
+
logger.warning(f'JSON invalid, ValidationError: {repr(validation_errors)}')
|
|
188
|
+
except MissingOptionalDependencyException as error:
|
|
189
|
+
logger.debug(f'JSON-validation was skipped due to {error}')
|
|
190
|
+
except Exception as e:
|
|
191
|
+
success = False
|
|
192
|
+
return success
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def write_cyclonedx_xml(bom, result_file):
|
|
197
|
+
success = True
|
|
198
|
+
try:
|
|
199
|
+
my_xml_outputter: BaseOutput = make_outputter(bom=bom,
|
|
200
|
+
output_format=OutputFormat.XML,
|
|
201
|
+
schema_version=SchemaVersion.V1_6)
|
|
202
|
+
my_xml_outputter.output_to_file(filename=result_file)
|
|
203
|
+
serialized_xml = my_xml_outputter.output_as_string(indent=2)
|
|
204
|
+
my_xml_validator = XmlValidator(SchemaVersion.V1_6)
|
|
205
|
+
try:
|
|
206
|
+
validation_errors = my_xml_validator.validate_str(serialized_xml)
|
|
207
|
+
if validation_errors:
|
|
208
|
+
logger.warning(f'XML invalid, ValidationError: {repr(validation_errors)}')
|
|
209
|
+
except MissingOptionalDependencyException as error:
|
|
210
|
+
logger.debug(f'XML-validation was skipped due to {error}')
|
|
211
|
+
except Exception as e:
|
|
212
|
+
success = False
|
|
213
|
+
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.1 → fosslight_util-2.1.3}/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.1 → fosslight_util-2.1.3}/src/fosslight_util.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|