scanoss 1.25.2__py3-none-any.whl → 1.26.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.
- scanoss/__init__.py +1 -1
- scanoss/cli.py +114 -21
- scanoss/data/build_date.txt +1 -1
- scanoss/inspection/__init__.py +1 -1
- scanoss/inspection/component_summary.py +94 -0
- scanoss/inspection/copyleft.py +30 -21
- scanoss/inspection/inspect_base.py +412 -0
- scanoss/inspection/license_summary.py +141 -0
- scanoss/inspection/policy_check.py +16 -273
- scanoss/inspection/undeclared_component.py +21 -13
- {scanoss-1.25.2.dist-info → scanoss-1.26.1.dist-info}/METADATA +1 -1
- {scanoss-1.25.2.dist-info → scanoss-1.26.1.dist-info}/RECORD +16 -13
- {scanoss-1.25.2.dist-info → scanoss-1.26.1.dist-info}/WHEEL +0 -0
- {scanoss-1.25.2.dist-info → scanoss-1.26.1.dist-info}/entry_points.txt +0 -0
- {scanoss-1.25.2.dist-info → scanoss-1.26.1.dist-info}/licenses/LICENSE +0 -0
- {scanoss-1.25.2.dist-info → scanoss-1.26.1.dist-info}/top_level.txt +0 -0
scanoss/__init__.py
CHANGED
scanoss/cli.py
CHANGED
|
@@ -32,6 +32,8 @@ from typing import List
|
|
|
32
32
|
import pypac
|
|
33
33
|
|
|
34
34
|
from scanoss.cryptography import Cryptography, create_cryptography_config_from_args
|
|
35
|
+
from scanoss.inspection.component_summary import ComponentSummary
|
|
36
|
+
from scanoss.inspection.license_summary import LicenseSummary
|
|
35
37
|
from scanoss.scanners.container_scanner import (
|
|
36
38
|
DEFAULT_SYFT_COMMAND,
|
|
37
39
|
DEFAULT_SYFT_TIMEOUT,
|
|
@@ -531,6 +533,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
531
533
|
)
|
|
532
534
|
p_results.set_defaults(func=results)
|
|
533
535
|
|
|
536
|
+
########################################### INSPECT SUBCOMMAND ###########################################
|
|
534
537
|
# Sub-command: inspect
|
|
535
538
|
p_inspect = subparsers.add_parser(
|
|
536
539
|
'inspect', aliases=['insp', 'ins'], description=f'Inspect results: {__version__}', help='Inspect results'
|
|
@@ -539,24 +542,26 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
539
542
|
p_inspect_sub = p_inspect.add_subparsers(
|
|
540
543
|
title='Inspect Commands', dest='subparsercmd', description='Inspect sub-commands', help='Inspect sub-commands'
|
|
541
544
|
)
|
|
545
|
+
|
|
546
|
+
####### INSPECT: Copyleft ######
|
|
542
547
|
# Inspect Sub-command: inspect copyleft
|
|
543
548
|
p_copyleft = p_inspect_sub.add_parser(
|
|
544
549
|
'copyleft', aliases=['cp'], description='Inspect for copyleft licenses', help='Inspect for copyleft licenses'
|
|
545
550
|
)
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
'
|
|
552
|
-
help='List of Copyleft licenses to remove from default list. Provide licenses as a comma-separated list.',
|
|
551
|
+
|
|
552
|
+
####### INSPECT: License Summary ######
|
|
553
|
+
# Inspect Sub-command: inspect license summary
|
|
554
|
+
p_license_summary = p_inspect_sub.add_parser(
|
|
555
|
+
'license-summary', aliases=['lic-summary', 'licsum'], description='Get license summary',
|
|
556
|
+
help='Get detected license summary from scan results'
|
|
553
557
|
)
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
558
|
+
|
|
559
|
+
p_component_summary = p_inspect_sub.add_parser(
|
|
560
|
+
'component-summary', aliases=['comp-summary', 'compsum'], description='Get component summary',
|
|
561
|
+
help='Get detected component summary from scan results'
|
|
557
562
|
)
|
|
558
|
-
p_copyleft.set_defaults(func=inspect_copyleft)
|
|
559
563
|
|
|
564
|
+
####### INSPECT: Undeclared components ######
|
|
560
565
|
# Inspect Sub-command: inspect undeclared
|
|
561
566
|
p_undeclared = p_inspect_sub.add_parser(
|
|
562
567
|
'undeclared',
|
|
@@ -571,7 +576,33 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
571
576
|
default='settings',
|
|
572
577
|
help='Sbom format for status output',
|
|
573
578
|
)
|
|
579
|
+
|
|
580
|
+
# Add common commands for inspect copyleft and license summary
|
|
581
|
+
for p in [p_copyleft, p_license_summary]:
|
|
582
|
+
p.add_argument(
|
|
583
|
+
'--include',
|
|
584
|
+
help='List of Copyleft licenses to append to the default list. Provide licenses as a comma-separated list.',
|
|
585
|
+
)
|
|
586
|
+
p.add_argument(
|
|
587
|
+
'--exclude',
|
|
588
|
+
help='List of Copyleft licenses to remove from default list. Provide licenses as a comma-separated list.',
|
|
589
|
+
)
|
|
590
|
+
p.add_argument(
|
|
591
|
+
'--explicit',
|
|
592
|
+
help='Explicit list of Copyleft licenses to consider. Provide licenses as a comma-separated list.s',
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
# Add common commands for inspect copyleft and license summary
|
|
596
|
+
for p in [p_license_summary, p_component_summary]:
|
|
597
|
+
p.add_argument('-i', '--input', nargs='?', help='Path to results file')
|
|
598
|
+
p.add_argument('-o', '--output', type=str, help='Save summary into a file')
|
|
599
|
+
|
|
574
600
|
p_undeclared.set_defaults(func=inspect_undeclared)
|
|
601
|
+
p_copyleft.set_defaults(func=inspect_copyleft)
|
|
602
|
+
p_license_summary.set_defaults(func=inspect_license_summary)
|
|
603
|
+
p_component_summary.set_defaults(func=inspect_component_summary)
|
|
604
|
+
|
|
605
|
+
########################################### END INSPECT SUBCOMMAND ###########################################
|
|
575
606
|
|
|
576
607
|
# Sub-command: folder-scan
|
|
577
608
|
p_folder_scan = subparsers.add_parser(
|
|
@@ -825,6 +856,8 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
825
856
|
p_results,
|
|
826
857
|
p_undeclared,
|
|
827
858
|
p_copyleft,
|
|
859
|
+
p_license_summary,
|
|
860
|
+
p_component_summary,
|
|
828
861
|
c_provenance,
|
|
829
862
|
p_folder_scan,
|
|
830
863
|
p_folder_hash,
|
|
@@ -1279,7 +1312,7 @@ def convert(parser, args):
|
|
|
1279
1312
|
if not success:
|
|
1280
1313
|
sys.exit(1)
|
|
1281
1314
|
|
|
1282
|
-
|
|
1315
|
+
################################ INSPECT handlers ################################
|
|
1283
1316
|
def inspect_copyleft(parser, args):
|
|
1284
1317
|
"""
|
|
1285
1318
|
Run the "inspect" sub-command
|
|
@@ -1356,13 +1389,73 @@ def inspect_undeclared(parser, args):
|
|
|
1356
1389
|
status, _ = i_undeclared.run()
|
|
1357
1390
|
sys.exit(status)
|
|
1358
1391
|
|
|
1392
|
+
def inspect_license_summary(parser, args):
|
|
1393
|
+
"""
|
|
1394
|
+
Run the "inspect" sub-command
|
|
1395
|
+
Parameters
|
|
1396
|
+
----------
|
|
1397
|
+
parser: ArgumentParser
|
|
1398
|
+
command line parser object
|
|
1399
|
+
args: Namespace
|
|
1400
|
+
Parsed arguments
|
|
1401
|
+
"""
|
|
1402
|
+
if args.input is None:
|
|
1403
|
+
print_stderr('Please specify an input file to inspect')
|
|
1404
|
+
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1405
|
+
sys.exit(1)
|
|
1406
|
+
output: str = None
|
|
1407
|
+
if args.output:
|
|
1408
|
+
output = args.output
|
|
1409
|
+
open(output, 'w').close()
|
|
1410
|
+
|
|
1411
|
+
i_license_summary = LicenseSummary(
|
|
1412
|
+
debug=args.debug,
|
|
1413
|
+
trace=args.trace,
|
|
1414
|
+
quiet=args.quiet,
|
|
1415
|
+
filepath=args.input,
|
|
1416
|
+
output=output,
|
|
1417
|
+
include=args.include,
|
|
1418
|
+
exclude=args.exclude,
|
|
1419
|
+
explicit=args.explicit,
|
|
1420
|
+
)
|
|
1421
|
+
i_license_summary.run()
|
|
1422
|
+
|
|
1423
|
+
def inspect_component_summary(parser, args):
|
|
1424
|
+
"""
|
|
1425
|
+
Run the "inspect" sub-command
|
|
1426
|
+
Parameters
|
|
1427
|
+
----------
|
|
1428
|
+
parser: ArgumentParser
|
|
1429
|
+
command line parser object
|
|
1430
|
+
args: Namespace
|
|
1431
|
+
Parsed arguments
|
|
1432
|
+
"""
|
|
1433
|
+
if args.input is None:
|
|
1434
|
+
print_stderr('Please specify an input file to inspect')
|
|
1435
|
+
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1436
|
+
sys.exit(1)
|
|
1437
|
+
output: str = None
|
|
1438
|
+
if args.output:
|
|
1439
|
+
output = args.output
|
|
1440
|
+
open(output, 'w').close()
|
|
1441
|
+
|
|
1442
|
+
i_component_summary = ComponentSummary(
|
|
1443
|
+
debug=args.debug,
|
|
1444
|
+
trace=args.trace,
|
|
1445
|
+
quiet=args.quiet,
|
|
1446
|
+
filepath=args.input,
|
|
1447
|
+
output=output,
|
|
1448
|
+
)
|
|
1449
|
+
i_component_summary.run()
|
|
1450
|
+
|
|
1451
|
+
################################ End inspect handlers ################################
|
|
1359
1452
|
|
|
1360
1453
|
def utils_certloc(*_):
|
|
1361
1454
|
"""
|
|
1362
1455
|
Run the "utils certloc" sub-command
|
|
1363
1456
|
:param _: ignored/unused
|
|
1364
1457
|
"""
|
|
1365
|
-
import certifi
|
|
1458
|
+
import certifi # noqa: PLC0415,I001
|
|
1366
1459
|
|
|
1367
1460
|
print(f'CA Cert File: {certifi.where()}')
|
|
1368
1461
|
|
|
@@ -1373,11 +1466,11 @@ def utils_cert_download(_, args): # pylint: disable=PLR0912 # noqa: PLR0912
|
|
|
1373
1466
|
:param _: ignore/unused
|
|
1374
1467
|
:param args: Parsed arguments
|
|
1375
1468
|
"""
|
|
1376
|
-
import socket
|
|
1377
|
-
import traceback
|
|
1378
|
-
from urllib.parse import urlparse
|
|
1469
|
+
import socket # noqa: PLC0415,I001
|
|
1470
|
+
import traceback # noqa: PLC0415,I001
|
|
1471
|
+
from urllib.parse import urlparse # noqa: PLC0415,I001
|
|
1379
1472
|
|
|
1380
|
-
from OpenSSL import SSL, crypto
|
|
1473
|
+
from OpenSSL import SSL, crypto # noqa: PLC0415,I001
|
|
1381
1474
|
|
|
1382
1475
|
file = sys.stdout
|
|
1383
1476
|
if args.output:
|
|
@@ -1425,7 +1518,7 @@ def utils_pac_proxy(_, args):
|
|
|
1425
1518
|
:param _: ignore/unused
|
|
1426
1519
|
:param args: Parsed arguments
|
|
1427
1520
|
"""
|
|
1428
|
-
from pypac.resolver import ProxyResolver
|
|
1521
|
+
from pypac.resolver import ProxyResolver # noqa: PLC0415,I001
|
|
1429
1522
|
|
|
1430
1523
|
if not args.pac:
|
|
1431
1524
|
print_stderr('Error: No pac file option specified.')
|
|
@@ -1499,7 +1592,7 @@ def crypto_algorithms(parser, args):
|
|
|
1499
1592
|
sys.exit(1)
|
|
1500
1593
|
except Exception as e:
|
|
1501
1594
|
if args.debug:
|
|
1502
|
-
import traceback
|
|
1595
|
+
import traceback # noqa: PLC0415,I001
|
|
1503
1596
|
|
|
1504
1597
|
traceback.print_exc()
|
|
1505
1598
|
print_stderr(f'ERROR: {e}')
|
|
@@ -1541,7 +1634,7 @@ def crypto_hints(parser, args):
|
|
|
1541
1634
|
sys.exit(1)
|
|
1542
1635
|
except Exception as e:
|
|
1543
1636
|
if args.debug:
|
|
1544
|
-
import traceback
|
|
1637
|
+
import traceback # noqa: PLC0415,I001
|
|
1545
1638
|
|
|
1546
1639
|
traceback.print_exc()
|
|
1547
1640
|
print_stderr(f'ERROR: {e}')
|
|
@@ -1583,7 +1676,7 @@ def crypto_versions_in_range(parser, args):
|
|
|
1583
1676
|
sys.exit(1)
|
|
1584
1677
|
except Exception as e:
|
|
1585
1678
|
if args.debug:
|
|
1586
|
-
import traceback
|
|
1679
|
+
import traceback # noqa: PLC0415,I001
|
|
1587
1680
|
|
|
1588
1681
|
traceback.print_exc()
|
|
1589
1682
|
print_stderr(f'ERROR: {e}')
|
scanoss/data/build_date.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
date:
|
|
1
|
+
date: 20250623123500, utime: 1750682100
|
scanoss/inspection/__init__.py
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
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
|
+
|
|
27
|
+
from .inspect_base import InspectBase
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ComponentSummary(InspectBase):
|
|
31
|
+
def _get_component_summary_from_components(self, scan_components: list)-> dict:
|
|
32
|
+
"""
|
|
33
|
+
Get a component summary from detected components.
|
|
34
|
+
|
|
35
|
+
:param components: List of all components
|
|
36
|
+
:return: Dict with license summary information
|
|
37
|
+
"""
|
|
38
|
+
# A component is considered unique by its combination of PURL (Package URL) and license
|
|
39
|
+
component_licenses = self._group_components_by_license(scan_components)
|
|
40
|
+
total_components = len(component_licenses)
|
|
41
|
+
# Get undeclared components
|
|
42
|
+
undeclared_components = len([c for c in component_licenses if c['status'] == 'pending'])
|
|
43
|
+
|
|
44
|
+
components: list = []
|
|
45
|
+
total_undeclared_files = 0
|
|
46
|
+
total_files_detected = 0
|
|
47
|
+
for component in scan_components:
|
|
48
|
+
total_files_detected += component['count']
|
|
49
|
+
total_undeclared_files += component['undeclared']
|
|
50
|
+
components.append({
|
|
51
|
+
'purl': component['purl'],
|
|
52
|
+
'version': component['version'],
|
|
53
|
+
'count': component['count'],
|
|
54
|
+
'undeclared': component['undeclared'],
|
|
55
|
+
'declared': component['count'] - component['undeclared'],
|
|
56
|
+
})
|
|
57
|
+
## End for loop components
|
|
58
|
+
return {
|
|
59
|
+
"components": component_licenses,
|
|
60
|
+
'totalComponents': total_components,
|
|
61
|
+
'undeclaredComponents': undeclared_components,
|
|
62
|
+
'declaredComponents': total_components - undeclared_components,
|
|
63
|
+
'totalFilesDetected': total_files_detected,
|
|
64
|
+
'totalFilesUndeclared': total_undeclared_files,
|
|
65
|
+
'totalFilesDeclared': total_files_detected - total_undeclared_files,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
def _get_components(self):
|
|
69
|
+
"""
|
|
70
|
+
Extract and process components from results and their dependencies.
|
|
71
|
+
|
|
72
|
+
This method performs the following steps:
|
|
73
|
+
1. Validates that `self.results` is loaded. Returns `None` if not.
|
|
74
|
+
2. Extracts file, snippet, and dependency components into a dictionary.
|
|
75
|
+
3. Converts components to a list and processes their licenses.
|
|
76
|
+
|
|
77
|
+
:return: A list of processed components with license data, or `None` if `self.results` is not set.
|
|
78
|
+
"""
|
|
79
|
+
if self.results is None:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
components: dict = {}
|
|
83
|
+
# Extract component and license data from file and dependency results. Both helpers mutate `components`
|
|
84
|
+
self._get_components_data(self.results, components)
|
|
85
|
+
return self._convert_components_to_list(components)
|
|
86
|
+
|
|
87
|
+
def run(self):
|
|
88
|
+
components = self._get_components()
|
|
89
|
+
component_summary = self._get_component_summary_from_components(components)
|
|
90
|
+
self.print_to_file_or_stdout(json.dumps(component_summary, indent=2), self.output)
|
|
91
|
+
return component_summary
|
|
92
|
+
#
|
|
93
|
+
# End of ComponentSummary Class
|
|
94
|
+
#
|
scanoss/inspection/copyleft.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
SPDX-License-Identifier: MIT
|
|
3
3
|
|
|
4
|
-
Copyright (c)
|
|
4
|
+
Copyright (c) 2025, SCANOSS
|
|
5
5
|
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -78,12 +78,14 @@ class Copyleft(PolicyCheck):
|
|
|
78
78
|
:param components: List of components with copyleft licenses
|
|
79
79
|
:return: Dictionary with formatted JSON details and summary
|
|
80
80
|
"""
|
|
81
|
+
# A component is considered unique by its combination of PURL (Package URL) and license
|
|
82
|
+
component_licenses = self._group_components_by_license(components)
|
|
81
83
|
details = {}
|
|
82
84
|
if len(components) > 0:
|
|
83
85
|
details = {'components': components}
|
|
84
86
|
return {
|
|
85
87
|
'details': f'{json.dumps(details, indent=2)}\n',
|
|
86
|
-
'summary': f'{len(
|
|
88
|
+
'summary': f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
def _markdown(self, components: list) -> Dict[str, Any]:
|
|
@@ -93,24 +95,24 @@ class Copyleft(PolicyCheck):
|
|
|
93
95
|
:param components: List of components with copyleft licenses
|
|
94
96
|
:return: Dictionary with formatted Markdown details and summary
|
|
95
97
|
"""
|
|
96
|
-
|
|
98
|
+
# A component is considered unique by its combination of PURL (Package URL) and license
|
|
99
|
+
component_licenses = self._group_components_by_license(components)
|
|
100
|
+
headers = ['Component', 'License', 'URL', 'Copyleft']
|
|
97
101
|
centered_columns = [1, 4]
|
|
98
102
|
rows: [[]] = []
|
|
99
|
-
for
|
|
100
|
-
for lic in component['licenses']:
|
|
103
|
+
for comp_lic_item in component_licenses:
|
|
101
104
|
row = [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
'YES' if lic['copyleft'] else 'NO',
|
|
105
|
+
comp_lic_item['purl'],
|
|
106
|
+
comp_lic_item['spdxid'],
|
|
107
|
+
comp_lic_item['url'],
|
|
108
|
+
'YES' if comp_lic_item['copyleft'] else 'NO',
|
|
107
109
|
]
|
|
108
110
|
rows.append(row)
|
|
109
111
|
# End license loop
|
|
110
112
|
# End component loop
|
|
111
113
|
return {
|
|
112
114
|
'details': f'### Copyleft licenses\n{self.generate_table(headers, rows, centered_columns)}\n',
|
|
113
|
-
'summary': f'{len(
|
|
115
|
+
'summary': f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
def _jira_markdown(self, components: list) -> Dict[str, Any]:
|
|
@@ -120,24 +122,24 @@ class Copyleft(PolicyCheck):
|
|
|
120
122
|
:param components: List of components with copyleft licenses
|
|
121
123
|
:return: Dictionary with formatted Markdown details and summary
|
|
122
124
|
"""
|
|
123
|
-
|
|
125
|
+
# A component is considered unique by its combination of PURL (Package URL) and license
|
|
126
|
+
component_licenses = self._group_components_by_license(components)
|
|
127
|
+
headers = ['Component', 'License', 'URL', 'Copyleft']
|
|
124
128
|
centered_columns = [1, 4]
|
|
125
129
|
rows: [[]] = []
|
|
126
|
-
for
|
|
127
|
-
for lic in component['licenses']:
|
|
130
|
+
for comp_lic_item in component_licenses:
|
|
128
131
|
row = [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
'YES' if lic['copyleft'] else 'NO',
|
|
132
|
+
comp_lic_item['purl'],
|
|
133
|
+
comp_lic_item['spdxid'],
|
|
134
|
+
comp_lic_item['url'],
|
|
135
|
+
'YES' if comp_lic_item['copyleft'] else 'NO',
|
|
134
136
|
]
|
|
135
137
|
rows.append(row)
|
|
136
138
|
# End license loop
|
|
137
139
|
# End component loop
|
|
138
140
|
return {
|
|
139
141
|
'details': f'{self.generate_jira_table(headers, rows, centered_columns)}',
|
|
140
|
-
'summary': f'{len(
|
|
142
|
+
'summary': f'{len(component_licenses)} component(s) with copyleft licenses were found.\n',
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
def _filter_components_with_copyleft_licenses(self, components: list) -> list:
|
|
@@ -151,9 +153,16 @@ class Copyleft(PolicyCheck):
|
|
|
151
153
|
for component in components:
|
|
152
154
|
copyleft_licenses = [lic for lic in component['licenses'] if lic['copyleft']]
|
|
153
155
|
if copyleft_licenses:
|
|
156
|
+
# Remove unused keys
|
|
157
|
+
del component['count']
|
|
158
|
+
del component['declared']
|
|
159
|
+
del component['undeclared']
|
|
154
160
|
filtered_component = component
|
|
161
|
+
# Remove 'count' from each license using pop
|
|
162
|
+
for lic in copyleft_licenses:
|
|
163
|
+
lic.pop('count', None) # None is default value if key doesn't exist
|
|
164
|
+
|
|
155
165
|
filtered_component['licenses'] = copyleft_licenses
|
|
156
|
-
del filtered_component['status']
|
|
157
166
|
filtered_components.append(filtered_component)
|
|
158
167
|
# End component loop
|
|
159
168
|
self.print_debug(f'Copyleft components: {filtered_components}')
|