fosslight-util 2.1.2__py3-none-any.whl → 2.1.4__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.
@@ -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
- success, msg, _ = write_spdx(output_file_without_ext, file_extension, scan_item, spdx_version)
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fosslight-util
3
- Version: 2.1.2
3
+ Version: 2.1.4
4
4
  Summary: FOSSLight Util
5
5
  Home-page: https://github.com/fosslight/fosslight_util
6
6
  Author: LG Electronics
@@ -35,6 +35,7 @@ Requires-Dist: numpy>=1.22.2; python_version >= "3.8"
35
35
  Requires-Dist: pygit2==1.6.1; python_version < "3.7"
36
36
  Requires-Dist: pygit2>=1.10.1; python_version >= "3.7"
37
37
  Requires-Dist: spdx-tools==0.8.*; sys_platform == "linux"
38
+ Requires-Dist: cyclonedx-python-lib==8.5.*; sys_platform == "linux"
38
39
 
39
40
  <!--
40
41
  Copyright (c) 2021 LG Electronics
@@ -4,15 +4,16 @@ fosslight_util/compare_yaml.py,sha256=eLqqCLgERxRHN5vsnpQVMXIEU862Lx66mD_y4uMgQE
4
4
  fosslight_util/constant.py,sha256=Ig3ACm9_QirE4389Wt-IfxOqRkVOUjqGnX1B05z2Byo,2151
5
5
  fosslight_util/correct.py,sha256=3iUipan8ZX8sbyIIGAPtMkAGvZ4YucjeJwx1K1Bx_z4,3897
6
6
  fosslight_util/cover.py,sha256=qqqKzxqFwKimal764FaugRUBcHWdeKt8af6xeK0mH8E,2040
7
- fosslight_util/download.py,sha256=NrAThwiulcWZhV9fBsc8_i7TWLExptmJ_JDnU7TnzuA,16340
7
+ fosslight_util/download.py,sha256=bCKvW76XJTnKMAUW5sJZxg_wBUhiybXovJuL04W4P4c,16364
8
8
  fosslight_util/help.py,sha256=M3_XahUkP794US9Q0NS6ujmGvrFFnKBHsTU95Fg1KpA,2181
9
9
  fosslight_util/oss_item.py,sha256=8W2HlwqGH3l1iPPdvycrRYKsBSBpqAkqYyYtBVPgMtY,6868
10
- fosslight_util/output_format.py,sha256=hELTfwo0PqoRtuSnQLbSrPwoX5bjddB50q-aHErs1YE,8324
10
+ fosslight_util/output_format.py,sha256=AdQVzCpar6n3PCDtijLWbJyFAGKQVE7JhLXlHPtITH4,8678
11
11
  fosslight_util/parsing_yaml.py,sha256=2zx_N5lMkXT1dRmfJMpzlrru-y_2F_CkVbGlba6vQpU,5380
12
12
  fosslight_util/read_excel.py,sha256=-QvrdxaNqYOpIm1H7ZqIEh5NLvFPymZo6BAOZcQmQug,5263
13
13
  fosslight_util/set_log.py,sha256=Xpa94AiOyGEK8ucaYkvkAllvlen1Pq_d6UG6kPYBYBc,3780
14
14
  fosslight_util/spdx_licenses.py,sha256=GvMNe_D4v2meapTVwPu2BJXInnTo3_gIzg669eJhUu0,3691
15
15
  fosslight_util/timer_thread.py,sha256=5VbZENQPD-N0NUmzEktqGr6Am-e7vxD79K05mmr29g0,433
16
+ fosslight_util/write_cyclonedx.py,sha256=V_LFKocErNSwVC8CsLxRcdwlrutVuBSb_3HJ6bO_2J8,9896
16
17
  fosslight_util/write_excel.py,sha256=G0fIslbWoOtWZCJxbBGLCpUKbhmwrrqhI5PHwRw8_44,9931
17
18
  fosslight_util/write_opossum.py,sha256=ltmo6SkugKWdAYupeCqwE4-3lua0GwLpix1XqFC-tT8,11678
18
19
  fosslight_util/write_scancodejson.py,sha256=81n7cWNYoyIKE_V4Kx5YtL2CgjMPIjoKdnSU3inkpJY,2163
@@ -22,9 +23,9 @@ fosslight_util/write_yaml.py,sha256=QlEKoIPQsEaYERfbP53TeKgnllYzhLQWm5wYjnWtVjE,
22
23
  fosslight_util/resources/frequentLicenselist.json,sha256=GUhzK6tu7ok10fekOnmVmUgIGRC-acGABZKTNKfDyYA,4776157
23
24
  fosslight_util/resources/frequent_license_nick_list.json,sha256=ryU2C_6ZxHbz90_sUN9OvI9GXkCMLu7oGcmd9W79YYo,5005
24
25
  fosslight_util/resources/licenses.json,sha256=mK55z-bhY7Mjpj2KsO1crKGGL-X3F6MBFQJ0zLlx010,240843
25
- fosslight_util-2.1.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
26
- fosslight_util-2.1.2.dist-info/METADATA,sha256=_ES9pW6X4xAdZEw7uykDuE1h4R_4n4IR7hO7xMxQfqQ,6431
27
- fosslight_util-2.1.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
28
- fosslight_util-2.1.2.dist-info/entry_points.txt,sha256=bzXX5i7HZ13V8BLKvtu_9KO3ZjtRypH-XszOXT6I3bU,69
29
- fosslight_util-2.1.2.dist-info/top_level.txt,sha256=2qyYWGLakgBRy4BqoBNt-I5C29tBr_e93e5e1pbuTGA,15
30
- fosslight_util-2.1.2.dist-info/RECORD,,
26
+ fosslight_util-2.1.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
27
+ fosslight_util-2.1.4.dist-info/METADATA,sha256=iLIhl1sg0DitSa3xzxABBJf04OUmLwGUX3erMa-CdX8,6499
28
+ fosslight_util-2.1.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
29
+ fosslight_util-2.1.4.dist-info/entry_points.txt,sha256=bzXX5i7HZ13V8BLKvtu_9KO3ZjtRypH-XszOXT6I3bU,69
30
+ fosslight_util-2.1.4.dist-info/top_level.txt,sha256=2qyYWGLakgBRy4BqoBNt-I5C29tBr_e93e5e1pbuTGA,15
31
+ fosslight_util-2.1.4.dist-info/RECORD,,