scanoss 1.20.0__py3-none-any.whl → 1.20.2__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.
- protoc_gen_swagger/__init__.py +13 -13
- protoc_gen_swagger/options/__init__.py +13 -13
- protoc_gen_swagger/options/annotations_pb2.py +12 -9
- protoc_gen_swagger/options/annotations_pb2_grpc.py +1 -1
- protoc_gen_swagger/options/openapiv2_pb2.py +98 -96
- protoc_gen_swagger/options/openapiv2_pb2_grpc.py +1 -1
- scanoss/__init__.py +18 -18
- scanoss/api/__init__.py +17 -17
- scanoss/api/common/__init__.py +17 -17
- scanoss/api/common/v2/__init__.py +17 -17
- scanoss/api/common/v2/scanoss_common_pb2.py +18 -18
- scanoss/api/common/v2/scanoss_common_pb2_grpc.py +1 -1
- scanoss/api/components/__init__.py +17 -17
- scanoss/api/components/v2/__init__.py +17 -17
- scanoss/api/components/v2/scanoss_components_pb2.py +48 -38
- scanoss/api/components/v2/scanoss_components_pb2_grpc.py +142 -96
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +22 -16
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +75 -49
- scanoss/api/dependencies/__init__.py +17 -17
- scanoss/api/dependencies/v2/__init__.py +17 -17
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +30 -24
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +75 -49
- scanoss/api/scanning/__init__.py +17 -17
- scanoss/api/scanning/v2/__init__.py +17 -17
- scanoss/api/scanning/v2/scanoss_scanning_pb2.py +10 -8
- scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +40 -32
- scanoss/api/semgrep/__init__.py +17 -17
- scanoss/api/semgrep/v2/__init__.py +17 -17
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +22 -18
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +71 -49
- scanoss/api/vulnerabilities/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/__init__.py +17 -17
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +37 -27
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +109 -72
- scanoss/cli.py +664 -356
- scanoss/components.py +67 -45
- scanoss/csvoutput.py +83 -56
- scanoss/cyclonedx.py +48 -46
- scanoss/data/build_date.txt +1 -1
- scanoss/file_filters.py +13 -15
- scanoss/filecount.py +43 -36
- scanoss/inspection/__init__.py +17 -17
- scanoss/inspection/copyleft.py +71 -58
- scanoss/inspection/policy_check.py +76 -53
- scanoss/inspection/undeclared_component.py +98 -75
- scanoss/inspection/utils/license_utils.py +66 -44
- scanoss/results.py +51 -60
- scanoss/scancodedeps.py +61 -38
- scanoss/scanner.py +203 -135
- scanoss/scanoss_settings.py +5 -3
- scanoss/scanossapi.py +98 -69
- scanoss/scanossbase.py +19 -19
- scanoss/scanossgrpc.py +73 -51
- scanoss/scanpostprocessor.py +9 -6
- scanoss/scantype.py +22 -21
- scanoss/spdxlite.py +265 -171
- scanoss/threadeddependencies.py +91 -61
- scanoss/threadedscanning.py +37 -31
- scanoss/utils/file.py +4 -4
- scanoss/winnowing.py +111 -47
- {scanoss-1.20.0.dist-info → scanoss-1.20.2.dist-info}/METADATA +1 -1
- scanoss-1.20.2.dist-info/RECORD +74 -0
- {scanoss-1.20.0.dist-info → scanoss-1.20.2.dist-info}/WHEEL +1 -1
- scanoss-1.20.0.dist-info/RECORD +0 -74
- {scanoss-1.20.0.dist-info → scanoss-1.20.2.dist-info}/LICENSE +0 -0
- {scanoss-1.20.0.dist-info → scanoss-1.20.2.dist-info}/entry_points.txt +0 -0
- {scanoss-1.20.0.dist-info → scanoss-1.20.2.dist-info}/top_level.txt +0 -0
scanoss/cli.py
CHANGED
|
@@ -1,49 +1,55 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2021, 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
23
|
"""
|
|
24
|
+
|
|
24
25
|
import argparse
|
|
25
26
|
import os
|
|
26
|
-
from pathlib import Path
|
|
27
27
|
import sys
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
28
30
|
import pypac
|
|
29
31
|
|
|
32
|
+
from . import __version__
|
|
33
|
+
from .components import Components
|
|
34
|
+
from .csvoutput import CsvOutput
|
|
35
|
+
from .cyclonedx import CycloneDx
|
|
36
|
+
from .filecount import FileCount
|
|
30
37
|
from .inspection.copyleft import Copyleft
|
|
31
38
|
from .inspection.undeclared_component import UndeclaredComponent
|
|
32
|
-
from .
|
|
33
|
-
from .scanoss_settings import ScanossSettings, ScanossSettingsError
|
|
39
|
+
from .results import Results
|
|
34
40
|
from .scancodedeps import ScancodeDeps
|
|
35
|
-
from .scanner import Scanner
|
|
41
|
+
from .scanner import FAST_WINNOWING, Scanner
|
|
42
|
+
from .scanoss_settings import ScanossSettings, ScanossSettingsError
|
|
36
43
|
from .scantype import ScanType
|
|
37
|
-
from .filecount import FileCount
|
|
38
|
-
from .cyclonedx import CycloneDx
|
|
39
44
|
from .spdxlite import SpdxLite
|
|
40
|
-
from .
|
|
41
|
-
from .components import Components
|
|
42
|
-
from . import __version__
|
|
43
|
-
from .scanner import FAST_WINNOWING
|
|
44
|
-
from .results import Results
|
|
45
|
+
from .threadeddependencies import SCOPE
|
|
45
46
|
from .utils.file import validate_json_file
|
|
46
47
|
|
|
48
|
+
DEFAULT_POST_SIZE = 32
|
|
49
|
+
DEFAULT_TIMEOUT = 180
|
|
50
|
+
MIN_TIMEOUT_VALUE = 5
|
|
51
|
+
DEFAULT_RETRY = 5
|
|
52
|
+
PYTHON3_OR_LATER = 3
|
|
47
53
|
|
|
48
54
|
def print_stderr(*args, **kwargs):
|
|
49
55
|
"""
|
|
@@ -52,163 +58,254 @@ def print_stderr(*args, **kwargs):
|
|
|
52
58
|
print(*args, file=sys.stderr, **kwargs)
|
|
53
59
|
|
|
54
60
|
|
|
55
|
-
def setup_args() -> None:
|
|
61
|
+
def setup_args() -> None: # noqa: PLR0915
|
|
56
62
|
"""
|
|
57
63
|
Setup all the command line arguments for processing
|
|
58
64
|
"""
|
|
59
|
-
parser = argparse.ArgumentParser(
|
|
65
|
+
parser = argparse.ArgumentParser(
|
|
66
|
+
description=f'SCANOSS Python CLI. Ver: {__version__}, License: MIT, Fast Winnowing: {FAST_WINNOWING}'
|
|
67
|
+
)
|
|
60
68
|
parser.add_argument('--version', '-v', action='store_true', help='Display version details')
|
|
61
69
|
|
|
62
|
-
subparsers = parser.add_subparsers(
|
|
63
|
-
|
|
70
|
+
subparsers = parser.add_subparsers(
|
|
71
|
+
title='Sub Commands', dest='subparser', description='valid subcommands', help='sub-command help'
|
|
72
|
+
)
|
|
64
73
|
# Sub-command: version
|
|
65
|
-
p_ver = subparsers.add_parser(
|
|
66
|
-
|
|
74
|
+
p_ver = subparsers.add_parser(
|
|
75
|
+
'version', aliases=['ver'], description=f'Version of SCANOSS CLI: {__version__}', help='SCANOSS version'
|
|
76
|
+
)
|
|
67
77
|
p_ver.set_defaults(func=ver)
|
|
68
78
|
|
|
69
79
|
# Sub-command: scan
|
|
70
|
-
p_scan = subparsers.add_parser(
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
p_scan = subparsers.add_parser(
|
|
81
|
+
'scan',
|
|
82
|
+
aliases=['sc'],
|
|
83
|
+
description=f'Analyse/scan the given source base: {__version__}',
|
|
84
|
+
help='Scan source code',
|
|
85
|
+
)
|
|
73
86
|
p_scan.set_defaults(func=scan)
|
|
74
87
|
p_scan.add_argument('scan_dir', metavar='FILE/DIR', type=str, nargs='?', help='A file or folder to scan')
|
|
75
|
-
p_scan.add_argument('--wfp', '-w',
|
|
76
|
-
|
|
77
|
-
p_scan.add_argument(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
p_scan.add_argument('--files', '-e', type=str, nargs="*", help='List of files to scan.')
|
|
88
|
+
p_scan.add_argument('--wfp', '-w', type=str, help='Scan a WFP File instead of a folder (optional)')
|
|
89
|
+
p_scan.add_argument('--dep', '-p', type=str, help='Use a dependency file instead of a folder (optional)')
|
|
90
|
+
p_scan.add_argument(
|
|
91
|
+
'--stdin', '-s', metavar='STDIN-FILENAME', type=str, help='Scan the file contents supplied via STDIN (optional)'
|
|
92
|
+
)
|
|
93
|
+
p_scan.add_argument('--files', '-e', type=str, nargs='*', help='List of files to scan.')
|
|
82
94
|
p_scan.add_argument('--identify', '-i', type=str, help='Scan and identify components in SBOM file')
|
|
83
|
-
p_scan.add_argument('--ignore',
|
|
84
|
-
p_scan.add_argument('--output',
|
|
85
|
-
p_scan.add_argument(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
p_scan.add_argument('--ignore', '-n', type=str, help='Ignore components specified in the SBOM file')
|
|
96
|
+
p_scan.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
97
|
+
p_scan.add_argument(
|
|
98
|
+
'--format',
|
|
99
|
+
'-f',
|
|
100
|
+
type=str,
|
|
101
|
+
choices=['plain', 'cyclonedx', 'spdxlite', 'csv'],
|
|
102
|
+
help='Result output format (optional - default: plain)',
|
|
103
|
+
)
|
|
104
|
+
p_scan.add_argument(
|
|
105
|
+
'--threads', '-T', type=int, default=5, help='Number of threads to use while scanning (optional - default 5)'
|
|
106
|
+
)
|
|
107
|
+
p_scan.add_argument(
|
|
108
|
+
'--flags',
|
|
109
|
+
'-F',
|
|
110
|
+
type=int,
|
|
111
|
+
help='Scanning engine flags (1: disable snippet matching, 2 enable snippet ids, '
|
|
112
|
+
'4: disable dependencies, 8: disable licenses, 16: disable copyrights,'
|
|
113
|
+
'32: disable vulnerabilities, 64: disable quality, 128: disable cryptography,'
|
|
114
|
+
'256: disable best match only, 512: hide identified files, '
|
|
115
|
+
'1024: enable download_url, 2048: enable GitHub full path, '
|
|
116
|
+
'4096: disable extended server stats)',
|
|
117
|
+
)
|
|
118
|
+
p_scan.add_argument(
|
|
119
|
+
'--post-size',
|
|
120
|
+
'-P',
|
|
121
|
+
type=int,
|
|
122
|
+
default=DEFAULT_POST_SIZE,
|
|
123
|
+
help='Number of kilobytes to limit the post to while scanning (optional - default 32)',
|
|
124
|
+
)
|
|
125
|
+
p_scan.add_argument(
|
|
126
|
+
'--timeout',
|
|
127
|
+
'-M',
|
|
128
|
+
type=int,
|
|
129
|
+
default=DEFAULT_TIMEOUT,
|
|
130
|
+
help='Timeout (in seconds) for API communication (optional - default 180)',
|
|
131
|
+
)
|
|
132
|
+
p_scan.add_argument(
|
|
133
|
+
'--retry', '-R', type=int, default=DEFAULT_RETRY,
|
|
134
|
+
help='Retry limit for API communication (optional - default 5)'
|
|
135
|
+
)
|
|
102
136
|
p_scan.add_argument('--no-wfp-output', action='store_true', help='Skip WFP file generation')
|
|
103
137
|
p_scan.add_argument('--dependencies', '-D', action='store_true', help='Add Dependency scanning')
|
|
104
138
|
p_scan.add_argument('--dependencies-only', action='store_true', help='Run Dependency scanning only')
|
|
105
|
-
p_scan.add_argument(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
p_scan.add_argument(
|
|
110
|
-
|
|
139
|
+
p_scan.add_argument(
|
|
140
|
+
'--sc-command', type=str,
|
|
141
|
+
help='Scancode command and path if required (optional - default scancode).'
|
|
142
|
+
)
|
|
143
|
+
p_scan.add_argument(
|
|
144
|
+
'--sc-timeout',
|
|
145
|
+
type=int,
|
|
146
|
+
default=600,
|
|
147
|
+
help='Timeout (in seconds) for scancode to complete (optional - default 600)',
|
|
148
|
+
)
|
|
149
|
+
p_scan.add_argument(
|
|
150
|
+
'--dep-scope', '-ds', type=SCOPE, help='Filter dependencies by scope - default all (options: dev/prod)'
|
|
151
|
+
)
|
|
152
|
+
p_scan.add_argument('--dep-scope-inc', '-dsi', type=str, help='Include dependencies with declared scopes')
|
|
111
153
|
p_scan.add_argument('--dep-scope-exc', '-dse', type=str, help='Exclude dependencies with declared scopes')
|
|
112
154
|
p_scan.add_argument(
|
|
113
|
-
'--settings',
|
|
155
|
+
'--settings',
|
|
156
|
+
'-st',
|
|
114
157
|
type=str,
|
|
115
158
|
help='Settings file to use for scanning (optional - default scanoss.json)',
|
|
116
159
|
)
|
|
117
160
|
p_scan.add_argument(
|
|
118
|
-
'--skip-settings-file',
|
|
161
|
+
'--skip-settings-file',
|
|
162
|
+
'-stf',
|
|
163
|
+
action='store_true',
|
|
119
164
|
help='Skip default settings file (scanoss.json) if it exists',
|
|
120
165
|
)
|
|
121
166
|
|
|
122
167
|
# Sub-command: fingerprint
|
|
123
|
-
p_wfp = subparsers.add_parser(
|
|
124
|
-
|
|
125
|
-
|
|
168
|
+
p_wfp = subparsers.add_parser(
|
|
169
|
+
'fingerprint',
|
|
170
|
+
aliases=['fp', 'wfp'],
|
|
171
|
+
description=f'Fingerprint the given source base: {__version__}',
|
|
172
|
+
help='Fingerprint source code',
|
|
173
|
+
)
|
|
126
174
|
p_wfp.set_defaults(func=wfp)
|
|
127
|
-
p_wfp.add_argument('scan_dir', metavar='FILE/DIR', type=str, nargs='?',
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
175
|
+
p_wfp.add_argument('scan_dir', metavar='FILE/DIR', type=str, nargs='?', help='A file or folder to scan')
|
|
176
|
+
p_wfp.add_argument(
|
|
177
|
+
'--stdin',
|
|
178
|
+
'-s',
|
|
179
|
+
metavar='STDIN-FILENAME',
|
|
180
|
+
type=str,
|
|
181
|
+
help='Fingerprint the file contents supplied via STDIN (optional)',
|
|
182
|
+
)
|
|
131
183
|
p_wfp.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
132
184
|
p_wfp.add_argument(
|
|
133
|
-
'--settings',
|
|
185
|
+
'--settings',
|
|
186
|
+
'-st',
|
|
134
187
|
type=str,
|
|
135
188
|
help='Settings file to use for fingerprinting (optional - default scanoss.json)',
|
|
136
189
|
)
|
|
137
190
|
p_wfp.add_argument(
|
|
138
|
-
'--skip-settings-file',
|
|
191
|
+
'--skip-settings-file',
|
|
192
|
+
'-stf',
|
|
193
|
+
action='store_true',
|
|
139
194
|
help='Skip default settings file (scanoss.json) if it exists',
|
|
140
195
|
)
|
|
141
196
|
|
|
142
197
|
# Sub-command: dependency
|
|
143
|
-
p_dep = subparsers.add_parser(
|
|
144
|
-
|
|
145
|
-
|
|
198
|
+
p_dep = subparsers.add_parser(
|
|
199
|
+
'dependencies',
|
|
200
|
+
aliases=['dp', 'dep'],
|
|
201
|
+
description=f'Produce dependency file summary: {__version__}',
|
|
202
|
+
help='Scan source code for dependencies, but do not decorate them',
|
|
203
|
+
)
|
|
146
204
|
p_dep.set_defaults(func=dependency)
|
|
147
205
|
p_dep.add_argument('scan_dir', metavar='FILE/DIR', type=str, nargs='?', help='A file or folder to scan')
|
|
148
206
|
p_dep.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
149
|
-
p_dep.add_argument(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
207
|
+
p_dep.add_argument(
|
|
208
|
+
'--sc-command', type=str, help='Scancode command and path if required (optional - default scancode).'
|
|
209
|
+
)
|
|
210
|
+
p_dep.add_argument(
|
|
211
|
+
'--sc-timeout',
|
|
212
|
+
type=int,
|
|
213
|
+
default=600,
|
|
214
|
+
help='Timeout (in seconds) for scancode to complete (optional - default 600)',
|
|
215
|
+
)
|
|
153
216
|
|
|
154
217
|
# Sub-command: file_count
|
|
155
|
-
p_fc = subparsers.add_parser(
|
|
156
|
-
|
|
157
|
-
|
|
218
|
+
p_fc = subparsers.add_parser(
|
|
219
|
+
'file_count',
|
|
220
|
+
aliases=['fc'],
|
|
221
|
+
description=f'Produce a file type count summary: {__version__}',
|
|
222
|
+
help='Search the source tree and produce a file type summary',
|
|
223
|
+
)
|
|
158
224
|
p_fc.set_defaults(func=file_count)
|
|
159
225
|
p_fc.add_argument('scan_dir', metavar='DIR', type=str, nargs='?', help='A folder to search')
|
|
160
226
|
p_fc.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
161
227
|
p_fc.add_argument('--all-hidden', action='store_true', help='Scan all hidden files/folders')
|
|
162
228
|
|
|
163
229
|
# Sub-command: convert
|
|
164
|
-
p_cnv = subparsers.add_parser(
|
|
165
|
-
|
|
166
|
-
|
|
230
|
+
p_cnv = subparsers.add_parser(
|
|
231
|
+
'convert',
|
|
232
|
+
aliases=['cv', 'cnv', 'cvrt'],
|
|
233
|
+
description=f'Convert results files between formats: {__version__}',
|
|
234
|
+
help='Convert file format',
|
|
235
|
+
)
|
|
167
236
|
p_cnv.set_defaults(func=convert)
|
|
168
237
|
p_cnv.add_argument('--input', '-i', type=str, required=True, help='Input file name')
|
|
169
238
|
p_cnv.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
170
|
-
p_cnv.add_argument(
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
239
|
+
p_cnv.add_argument(
|
|
240
|
+
'--format',
|
|
241
|
+
'-f',
|
|
242
|
+
type=str,
|
|
243
|
+
choices=['cyclonedx', 'spdxlite', 'csv'],
|
|
244
|
+
default='spdxlite',
|
|
245
|
+
help='Output format (optional - default: spdxlite)',
|
|
246
|
+
)
|
|
247
|
+
p_cnv.add_argument(
|
|
248
|
+
'--input-format', type=str, choices=['plain'], default='plain', help='Input format (optional - default: plain)'
|
|
249
|
+
)
|
|
174
250
|
|
|
175
251
|
# Sub-command: component
|
|
176
|
-
p_comp = subparsers.add_parser(
|
|
177
|
-
|
|
178
|
-
|
|
252
|
+
p_comp = subparsers.add_parser(
|
|
253
|
+
'component',
|
|
254
|
+
aliases=['comp'],
|
|
255
|
+
description=f'SCANOSS Component commands: {__version__}',
|
|
256
|
+
help='Component support commands',
|
|
257
|
+
)
|
|
179
258
|
|
|
180
|
-
comp_sub = p_comp.add_subparsers(
|
|
181
|
-
|
|
259
|
+
comp_sub = p_comp.add_subparsers(
|
|
260
|
+
title='Component Commands',
|
|
261
|
+
dest='subparsercmd',
|
|
262
|
+
description='component sub-commands',
|
|
263
|
+
help='component sub-commands',
|
|
264
|
+
)
|
|
182
265
|
|
|
183
266
|
# Component Sub-command: component crypto
|
|
184
|
-
c_crypto = comp_sub.add_parser(
|
|
185
|
-
|
|
186
|
-
|
|
267
|
+
c_crypto = comp_sub.add_parser(
|
|
268
|
+
'crypto',
|
|
269
|
+
aliases=['cr'],
|
|
270
|
+
description=f'Show Cryptographic algorithms: {__version__}',
|
|
271
|
+
help='Retrieve cryptographic algorithms for the given components',
|
|
272
|
+
)
|
|
187
273
|
c_crypto.set_defaults(func=comp_crypto)
|
|
188
274
|
|
|
189
275
|
# Component Sub-command: component vulns
|
|
190
|
-
c_vulns = comp_sub.add_parser(
|
|
191
|
-
|
|
192
|
-
|
|
276
|
+
c_vulns = comp_sub.add_parser(
|
|
277
|
+
'vulns',
|
|
278
|
+
aliases=['vulnerabilities', 'vu'],
|
|
279
|
+
description=f'Show Vulnerability details: {__version__}',
|
|
280
|
+
help='Retrieve vulnerabilities for the given components',
|
|
281
|
+
)
|
|
193
282
|
c_vulns.set_defaults(func=comp_vulns)
|
|
194
283
|
|
|
195
284
|
# Component Sub-command: component semgrep
|
|
196
|
-
c_semgrep = comp_sub.add_parser(
|
|
197
|
-
|
|
198
|
-
|
|
285
|
+
c_semgrep = comp_sub.add_parser(
|
|
286
|
+
'semgrep',
|
|
287
|
+
aliases=['sp'],
|
|
288
|
+
description=f'Show Semgrep findings: {__version__}',
|
|
289
|
+
help='Retrieve semgrep issues/findings for the given components',
|
|
290
|
+
)
|
|
199
291
|
c_semgrep.set_defaults(func=comp_semgrep)
|
|
200
292
|
|
|
201
293
|
# Component Sub-command: component provenance
|
|
202
|
-
c_provenance = comp_sub.add_parser(
|
|
203
|
-
|
|
204
|
-
|
|
294
|
+
c_provenance = comp_sub.add_parser(
|
|
295
|
+
'provenance',
|
|
296
|
+
aliases=['prov', 'prv'],
|
|
297
|
+
description=f'Show Provenance findings: {__version__}',
|
|
298
|
+
help='Retrieve provenance for the given components',
|
|
299
|
+
)
|
|
205
300
|
c_provenance.set_defaults(func=comp_provenance)
|
|
206
301
|
|
|
207
|
-
|
|
208
302
|
# Component Sub-command: component search
|
|
209
|
-
c_search = comp_sub.add_parser(
|
|
210
|
-
|
|
211
|
-
|
|
303
|
+
c_search = comp_sub.add_parser(
|
|
304
|
+
'search',
|
|
305
|
+
aliases=['sc'],
|
|
306
|
+
description=f'Search component details: {__version__}',
|
|
307
|
+
help='Search for a KB component',
|
|
308
|
+
)
|
|
212
309
|
c_search.add_argument('--input', '-i', type=str, help='Input file name')
|
|
213
310
|
c_search.add_argument('--search', '-s', type=str, help='Generic component search')
|
|
214
311
|
c_search.add_argument('--vendor', '-v', type=str, help='Generic component search')
|
|
@@ -219,9 +316,12 @@ def setup_args() -> None:
|
|
|
219
316
|
c_search.set_defaults(func=comp_search)
|
|
220
317
|
|
|
221
318
|
# Component Sub-command: component versions
|
|
222
|
-
c_versions = comp_sub.add_parser(
|
|
223
|
-
|
|
224
|
-
|
|
319
|
+
c_versions = comp_sub.add_parser(
|
|
320
|
+
'versions',
|
|
321
|
+
aliases=['vs'],
|
|
322
|
+
description=f'Get component version details: {__version__}',
|
|
323
|
+
help='Search for component versions',
|
|
324
|
+
)
|
|
225
325
|
c_versions.add_argument('--input', '-i', type=str, help='Input file name')
|
|
226
326
|
c_versions.add_argument('--purl', '-p', type=str, help='Generic component search')
|
|
227
327
|
c_versions.add_argument('--limit', '-l', type=int, help='Generic component search')
|
|
@@ -229,58 +329,87 @@ def setup_args() -> None:
|
|
|
229
329
|
|
|
230
330
|
# Common purl Component sub-command options
|
|
231
331
|
for p in [c_crypto, c_vulns, c_semgrep, c_provenance]:
|
|
232
|
-
p.add_argument('--purl',
|
|
332
|
+
p.add_argument('--purl', '-p', type=str, nargs='*', help='Package URL - PURL to process.')
|
|
233
333
|
p.add_argument('--input', '-i', type=str, help='Input file name')
|
|
234
334
|
# Common Component sub-command options
|
|
235
335
|
for p in [c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance]:
|
|
236
336
|
p.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
237
|
-
p.add_argument(
|
|
238
|
-
|
|
337
|
+
p.add_argument(
|
|
338
|
+
'--timeout',
|
|
339
|
+
'-M',
|
|
340
|
+
type=int,
|
|
341
|
+
default=600,
|
|
342
|
+
help='Timeout (in seconds) for API communication (optional - default 600)',
|
|
343
|
+
)
|
|
239
344
|
|
|
240
345
|
# Sub-command: utils
|
|
241
|
-
p_util = subparsers.add_parser(
|
|
242
|
-
|
|
243
|
-
|
|
346
|
+
p_util = subparsers.add_parser(
|
|
347
|
+
'utils',
|
|
348
|
+
aliases=['ut'],
|
|
349
|
+
description=f'SCANOSS Utility commands: {__version__}',
|
|
350
|
+
help='General utility support commands',
|
|
351
|
+
)
|
|
244
352
|
|
|
245
|
-
utils_sub = p_util.add_subparsers(
|
|
246
|
-
|
|
353
|
+
utils_sub = p_util.add_subparsers(
|
|
354
|
+
title='Utils Commands', dest='subparsercmd', description='utils sub-commands', help='utils sub-commands'
|
|
355
|
+
)
|
|
247
356
|
|
|
248
357
|
# Utils Sub-command: utils fast
|
|
249
|
-
p_f_f = utils_sub.add_parser(
|
|
250
|
-
|
|
358
|
+
p_f_f = utils_sub.add_parser(
|
|
359
|
+
'fast', description=f'Is fast winnowing enabled: {__version__}', help='SCANOSS fast winnowing'
|
|
360
|
+
)
|
|
251
361
|
p_f_f.set_defaults(func=fast)
|
|
252
362
|
|
|
253
363
|
# Utils Sub-command: utils certloc
|
|
254
|
-
p_c_loc = utils_sub.add_parser(
|
|
255
|
-
|
|
256
|
-
|
|
364
|
+
p_c_loc = utils_sub.add_parser(
|
|
365
|
+
'certloc',
|
|
366
|
+
aliases=['cl'],
|
|
367
|
+
description=f'Show location of Python CA Certs: {__version__}',
|
|
368
|
+
help='Display the location of Python CA Certs',
|
|
369
|
+
)
|
|
257
370
|
p_c_loc.set_defaults(func=utils_certloc)
|
|
258
371
|
|
|
259
372
|
# Utils Sub-command: utils cert-download
|
|
260
|
-
p_c_dwnld = utils_sub.add_parser(
|
|
261
|
-
|
|
262
|
-
|
|
373
|
+
p_c_dwnld = utils_sub.add_parser(
|
|
374
|
+
'cert-download',
|
|
375
|
+
aliases=['cdl', 'cert-dl'],
|
|
376
|
+
description=f'Download Server SSL Cert: {__version__}',
|
|
377
|
+
help="Download the specified server's SSL PEM certificate",
|
|
378
|
+
)
|
|
263
379
|
p_c_dwnld.set_defaults(func=utils_cert_download)
|
|
264
380
|
p_c_dwnld.add_argument('--hostname', '-n', required=True, type=str, help='Server hostname to download cert from.')
|
|
265
|
-
p_c_dwnld.add_argument(
|
|
266
|
-
|
|
381
|
+
p_c_dwnld.add_argument(
|
|
382
|
+
'--port', '-p', required=False, type=int, default=443, help='Server port number (default: 443).'
|
|
383
|
+
)
|
|
267
384
|
p_c_dwnld.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
268
385
|
|
|
269
386
|
# Utils Sub-command: utils pac-proxy
|
|
270
|
-
p_p_proxy = utils_sub.add_parser(
|
|
271
|
-
|
|
272
|
-
|
|
387
|
+
p_p_proxy = utils_sub.add_parser(
|
|
388
|
+
'pac-proxy',
|
|
389
|
+
aliases=['pac'],
|
|
390
|
+
description=f'Determine Proxy from PAC: {__version__}',
|
|
391
|
+
help='Use Proxy Auto-Config to determine proxy configuration',
|
|
392
|
+
)
|
|
273
393
|
p_p_proxy.set_defaults(func=utils_pac_proxy)
|
|
274
|
-
p_p_proxy.add_argument(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
394
|
+
p_p_proxy.add_argument(
|
|
395
|
+
'--pac',
|
|
396
|
+
required=False,
|
|
397
|
+
type=str,
|
|
398
|
+
default='auto',
|
|
399
|
+
help='Proxy auto configuration. Specify a file, http url or "auto" to try to discover it.',
|
|
400
|
+
)
|
|
401
|
+
p_p_proxy.add_argument(
|
|
402
|
+
'--url',
|
|
403
|
+
required=False,
|
|
404
|
+
type=str,
|
|
405
|
+
default='https://api.osskb.org',
|
|
406
|
+
help='URL to test (default: https://api.osskb.org).',
|
|
407
|
+
)
|
|
279
408
|
|
|
280
409
|
p_results = subparsers.add_parser(
|
|
281
410
|
'results',
|
|
282
411
|
aliases=['res'],
|
|
283
|
-
description=f
|
|
412
|
+
description=f'SCANOSS Results commands: {__version__}',
|
|
284
413
|
help='Process scan results',
|
|
285
414
|
)
|
|
286
415
|
p_results.add_argument(
|
|
@@ -318,37 +447,66 @@ def setup_args() -> None:
|
|
|
318
447
|
)
|
|
319
448
|
p_results.set_defaults(func=results)
|
|
320
449
|
|
|
321
|
-
|
|
322
450
|
# Sub-command: inspect
|
|
323
|
-
p_inspect = subparsers.add_parser(
|
|
324
|
-
|
|
325
|
-
|
|
451
|
+
p_inspect = subparsers.add_parser(
|
|
452
|
+
'inspect', aliases=['insp', 'ins'], description=f'Inspect results: {__version__}', help='Inspect results'
|
|
453
|
+
)
|
|
326
454
|
# Sub-parser: inspect
|
|
327
|
-
p_inspect_sub = p_inspect.add_subparsers(
|
|
328
|
-
|
|
455
|
+
p_inspect_sub = p_inspect.add_subparsers(
|
|
456
|
+
title='Inspect Commands', dest='subparsercmd', description='Inspect sub-commands', help='Inspect sub-commands'
|
|
457
|
+
)
|
|
329
458
|
# Inspect Sub-command: inspect copyleft
|
|
330
|
-
p_copyleft = p_inspect_sub.add_parser(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
p_copyleft.add_argument(
|
|
459
|
+
p_copyleft = p_inspect_sub.add_parser(
|
|
460
|
+
'copyleft', aliases=['cp'], description='Inspect for copyleft licenses', help='Inspect for copyleft licenses'
|
|
461
|
+
)
|
|
462
|
+
p_copyleft.add_argument(
|
|
463
|
+
'--include',
|
|
464
|
+
help='List of Copyleft licenses to append to the default list. Provide licenses as a comma-separated list.',
|
|
465
|
+
)
|
|
466
|
+
p_copyleft.add_argument(
|
|
467
|
+
'--exclude',
|
|
468
|
+
help='List of Copyleft licenses to remove from default list. Provide licenses as a comma-separated list.',
|
|
469
|
+
)
|
|
470
|
+
p_copyleft.add_argument(
|
|
471
|
+
'--explicit',
|
|
472
|
+
help='Explicit list of Copyleft licenses to consider. Provide licenses as a comma-separated list.s',
|
|
473
|
+
)
|
|
334
474
|
p_copyleft.set_defaults(func=inspect_copyleft)
|
|
335
475
|
|
|
336
476
|
# Inspect Sub-command: inspect undeclared
|
|
337
|
-
p_undeclared = p_inspect_sub.add_parser(
|
|
338
|
-
|
|
339
|
-
|
|
477
|
+
p_undeclared = p_inspect_sub.add_parser(
|
|
478
|
+
'undeclared',
|
|
479
|
+
aliases=['un'],
|
|
480
|
+
description='Inspect for undeclared components',
|
|
481
|
+
help='Inspect for undeclared components',
|
|
482
|
+
)
|
|
483
|
+
p_undeclared.add_argument(
|
|
484
|
+
'--sbom-format',
|
|
485
|
+
required=False,
|
|
486
|
+
choices=['legacy', 'settings'],
|
|
487
|
+
default='settings',
|
|
488
|
+
help='Sbom format for status output',
|
|
489
|
+
)
|
|
340
490
|
p_undeclared.set_defaults(func=inspect_undeclared)
|
|
341
491
|
|
|
342
492
|
for p in [p_copyleft, p_undeclared]:
|
|
343
493
|
p.add_argument('-i', '--input', nargs='?', help='Path to results file')
|
|
344
|
-
p.add_argument(
|
|
494
|
+
p.add_argument(
|
|
495
|
+
'-f',
|
|
496
|
+
'--format',
|
|
497
|
+
required=False,
|
|
498
|
+
choices=['json', 'md', 'jira_md'],
|
|
499
|
+
default='json',
|
|
500
|
+
help='Output format (default: json)',
|
|
501
|
+
)
|
|
345
502
|
p.add_argument('-o', '--output', type=str, help='Save details into a file')
|
|
346
503
|
p.add_argument('-s', '--status', type=str, help='Save summary data into Markdown file')
|
|
347
504
|
|
|
348
505
|
# Global Scan command options
|
|
349
506
|
for p in [p_scan]:
|
|
350
|
-
p.add_argument(
|
|
351
|
-
|
|
507
|
+
p.add_argument(
|
|
508
|
+
'--apiurl', type=str, help='SCANOSS API URL (optional - default: https://api.osskb.org/scan/direct)'
|
|
509
|
+
)
|
|
352
510
|
p.add_argument('--ignore-cert-errors', action='store_true', help='Ignore certificate errors')
|
|
353
511
|
|
|
354
512
|
# Global Scan/Fingerprint filter options
|
|
@@ -361,36 +519,75 @@ def setup_args() -> None:
|
|
|
361
519
|
p.add_argument('--skip-snippets', '-S', action='store_true', help='Skip the generation of snippets')
|
|
362
520
|
p.add_argument('--skip-extension', '-E', type=str, action='append', help='File Extension to skip.')
|
|
363
521
|
p.add_argument('--skip-folder', '-O', type=str, action='append', help='Folder to skip.')
|
|
364
|
-
p.add_argument(
|
|
365
|
-
|
|
522
|
+
p.add_argument(
|
|
523
|
+
'--skip-size',
|
|
524
|
+
'-Z',
|
|
525
|
+
type=int,
|
|
526
|
+
default=0,
|
|
527
|
+
help='Minimum file size to consider for fingerprinting (optional - default 0 bytes [unlimited])',
|
|
528
|
+
)
|
|
366
529
|
p.add_argument('--skip-md5', '-5', type=str, action='append', help='Skip files matching MD5.')
|
|
367
530
|
p.add_argument('--strip-hpsm', '-G', type=str, action='append', help='Strip HPSM string from WFP.')
|
|
368
531
|
p.add_argument('--strip-snippet', '-N', type=str, action='append', help='Strip Snippet ID string from WFP.')
|
|
369
532
|
|
|
370
533
|
# Global Scan/GRPC options
|
|
371
534
|
for p in [p_scan, c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance]:
|
|
372
|
-
p.add_argument(
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
535
|
+
p.add_argument(
|
|
536
|
+
'--key', '-k', type=str, help='SCANOSS API Key token (optional - not required for default OSSKB URL)'
|
|
537
|
+
)
|
|
538
|
+
p.add_argument(
|
|
539
|
+
'--proxy',
|
|
540
|
+
type=str,
|
|
541
|
+
help='Proxy URL to use for connections (optional). '
|
|
542
|
+
'Can also use the environment variable "HTTPS_PROXY=<ip>:<port>" '
|
|
543
|
+
'and "grcp_proxy=<ip>:<port>" for gRPC',
|
|
544
|
+
)
|
|
545
|
+
p.add_argument(
|
|
546
|
+
'--pac',
|
|
547
|
+
type=str,
|
|
548
|
+
help='Proxy auto configuration (optional). Specify a file, http url or "auto" to try to discover it.',
|
|
549
|
+
)
|
|
550
|
+
p.add_argument(
|
|
551
|
+
'--ca-cert',
|
|
552
|
+
type=str,
|
|
553
|
+
help='Alternative certificate PEM file (optional). '
|
|
554
|
+
'Can also use the environment variable '
|
|
555
|
+
'"REQUESTS_CA_BUNDLE=/path/to/cacert.pem" and '
|
|
556
|
+
'"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/path/to/cacert.pem" for gRPC',
|
|
557
|
+
)
|
|
383
558
|
|
|
384
559
|
# Global GRPC options
|
|
385
560
|
for p in [p_scan, c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance]:
|
|
386
|
-
p.add_argument(
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
561
|
+
p.add_argument(
|
|
562
|
+
'--api2url', type=str, help='SCANOSS gRPC API 2.0 URL (optional - default: https://api.osskb.org)'
|
|
563
|
+
)
|
|
564
|
+
p.add_argument(
|
|
565
|
+
'--grpc-proxy',
|
|
566
|
+
type=str,
|
|
567
|
+
help='GRPC Proxy URL to use for connections (optional). '
|
|
568
|
+
'Can also use the environment variable "grcp_proxy=<ip>:<port>"',
|
|
569
|
+
)
|
|
390
570
|
|
|
391
571
|
# Help/Trace command options
|
|
392
|
-
for p in [
|
|
393
|
-
|
|
572
|
+
for p in [
|
|
573
|
+
p_scan,
|
|
574
|
+
p_wfp,
|
|
575
|
+
p_dep,
|
|
576
|
+
p_fc,
|
|
577
|
+
p_cnv,
|
|
578
|
+
p_c_loc,
|
|
579
|
+
p_c_dwnld,
|
|
580
|
+
p_p_proxy,
|
|
581
|
+
c_crypto,
|
|
582
|
+
c_vulns,
|
|
583
|
+
c_search,
|
|
584
|
+
c_versions,
|
|
585
|
+
c_semgrep,
|
|
586
|
+
p_results,
|
|
587
|
+
p_undeclared,
|
|
588
|
+
p_copyleft,
|
|
589
|
+
c_provenance
|
|
590
|
+
]:
|
|
394
591
|
p.add_argument('--debug', '-d', action='store_true', help='Enable debug messages')
|
|
395
592
|
p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
|
|
396
593
|
p.add_argument('--quiet', '-q', action='store_true', help='Enable quiet mode')
|
|
@@ -398,17 +595,14 @@ def setup_args() -> None:
|
|
|
398
595
|
args = parser.parse_args()
|
|
399
596
|
if args.version:
|
|
400
597
|
ver(parser, args)
|
|
401
|
-
exit(0)
|
|
598
|
+
sys.sys.exit(0)
|
|
402
599
|
if not args.subparser:
|
|
403
600
|
parser.print_help() # No sub command subcommand, print general help
|
|
404
|
-
exit(1)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
and not args.subparsercmd):
|
|
410
|
-
parser.parse_args([args.subparser, '--help']) # Force utils helps to be displayed
|
|
411
|
-
exit(1)
|
|
601
|
+
sys.exit(1)
|
|
602
|
+
elif (
|
|
603
|
+
args.subparser in {'utils', 'ut', 'component', 'comp', 'inspect', 'insp', 'ins'} and not args.subparsercmd):
|
|
604
|
+
parser.parse_args([args.subparser, '--help']) # Force utils helps to be displayed
|
|
605
|
+
sys.exit(1)
|
|
412
606
|
args.func(parser, args) # Execute the function associated with the sub-command
|
|
413
607
|
|
|
414
608
|
|
|
@@ -441,23 +635,27 @@ def file_count(parser, args):
|
|
|
441
635
|
if not args.scan_dir:
|
|
442
636
|
print_stderr('Please specify a folder')
|
|
443
637
|
parser.parse_args([args.subparser, '-h'])
|
|
444
|
-
exit(1)
|
|
638
|
+
sys.exit(1)
|
|
445
639
|
scan_output: str = None
|
|
446
640
|
if args.output:
|
|
447
641
|
scan_output = args.output
|
|
448
642
|
open(scan_output, 'w').close()
|
|
449
643
|
|
|
450
|
-
counter = FileCount(
|
|
451
|
-
|
|
452
|
-
|
|
644
|
+
counter = FileCount(
|
|
645
|
+
debug=args.debug,
|
|
646
|
+
quiet=args.quiet,
|
|
647
|
+
trace=args.trace,
|
|
648
|
+
scan_output=scan_output,
|
|
649
|
+
hidden_files_folders=args.all_hidden,
|
|
650
|
+
)
|
|
453
651
|
if not os.path.exists(args.scan_dir):
|
|
454
652
|
print_stderr(f'Error: Folder specified does not exist: {args.scan_dir}.')
|
|
455
|
-
exit(1)
|
|
653
|
+
sys.exit(1)
|
|
456
654
|
if os.path.isdir(args.scan_dir):
|
|
457
655
|
counter.count_files(args.scan_dir)
|
|
458
656
|
else:
|
|
459
657
|
print_stderr(f'Error: Path specified is not a folder: {args.scan_dir}.')
|
|
460
|
-
exit(1)
|
|
658
|
+
sys.exit(1)
|
|
461
659
|
|
|
462
660
|
|
|
463
661
|
def wfp(parser, args):
|
|
@@ -473,9 +671,9 @@ def wfp(parser, args):
|
|
|
473
671
|
if not args.scan_dir and not args.stdin:
|
|
474
672
|
print_stderr('Please specify a file/folder or STDIN (--stdin)')
|
|
475
673
|
parser.parse_args([args.subparser, '-h'])
|
|
476
|
-
exit(1)
|
|
674
|
+
sys.exit(1)
|
|
477
675
|
if args.strip_hpsm and not args.hpsm and not args.quiet:
|
|
478
|
-
print_stderr(
|
|
676
|
+
print_stderr('Warning: --strip-hpsm option supplied without enabling HPSM (--hpsm). Ignoring.')
|
|
479
677
|
scan_output: str = None
|
|
480
678
|
if args.output:
|
|
481
679
|
scan_output = args.output
|
|
@@ -489,33 +687,44 @@ def wfp(parser, args):
|
|
|
489
687
|
scan_settings.load_json_file(args.settings)
|
|
490
688
|
except ScanossSettingsError as e:
|
|
491
689
|
print_stderr(f'Error: {e}')
|
|
492
|
-
exit(1)
|
|
690
|
+
sys.exit(1)
|
|
493
691
|
|
|
494
692
|
scan_options = 0 if args.skip_snippets else ScanType.SCAN_SNIPPETS.value # Skip snippet generation or not
|
|
495
|
-
scanner = Scanner(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
693
|
+
scanner = Scanner(
|
|
694
|
+
debug=args.debug,
|
|
695
|
+
trace=args.trace,
|
|
696
|
+
quiet=args.quiet,
|
|
697
|
+
obfuscate=args.obfuscate,
|
|
698
|
+
scan_options=scan_options,
|
|
699
|
+
all_extensions=args.all_extensions,
|
|
700
|
+
all_folders=args.all_folders,
|
|
701
|
+
hidden_files_folders=args.all_hidden,
|
|
702
|
+
hpsm=args.hpsm,
|
|
703
|
+
skip_size=args.skip_size,
|
|
704
|
+
skip_extensions=args.skip_extension,
|
|
705
|
+
skip_folders=args.skip_folder,
|
|
706
|
+
skip_md5_ids=args.skip_md5,
|
|
707
|
+
strip_hpsm_ids=args.strip_hpsm,
|
|
708
|
+
strip_snippet_ids=args.strip_snippet,
|
|
709
|
+
scan_settings=scan_settings,
|
|
710
|
+
)
|
|
502
711
|
if args.stdin:
|
|
503
712
|
contents = sys.stdin.buffer.read()
|
|
504
713
|
scanner.wfp_contents(args.stdin, contents, scan_output)
|
|
505
714
|
elif args.scan_dir:
|
|
506
715
|
if not os.path.exists(args.scan_dir):
|
|
507
716
|
print_stderr(f'Error: File or folder specified does not exist: {args.scan_dir}.')
|
|
508
|
-
exit(1)
|
|
717
|
+
sys.exit(1)
|
|
509
718
|
if os.path.isdir(args.scan_dir):
|
|
510
719
|
scanner.wfp_folder(args.scan_dir, scan_output)
|
|
511
720
|
elif os.path.isfile(args.scan_dir):
|
|
512
721
|
scanner.wfp_file(args.scan_dir, scan_output)
|
|
513
722
|
else:
|
|
514
723
|
print_stderr(f'Error: Path specified is neither a file or a folder: {args.scan_dir}.')
|
|
515
|
-
exit(1)
|
|
724
|
+
sys.exit(1)
|
|
516
725
|
else:
|
|
517
726
|
print_stderr('No action found to process')
|
|
518
|
-
exit(1)
|
|
727
|
+
sys.exit(1)
|
|
519
728
|
|
|
520
729
|
|
|
521
730
|
def get_scan_options(args):
|
|
@@ -539,18 +748,18 @@ def get_scan_options(args):
|
|
|
539
748
|
|
|
540
749
|
if args.debug:
|
|
541
750
|
if ScanType.SCAN_FILES.value & scan_options:
|
|
542
|
-
print_stderr(
|
|
751
|
+
print_stderr('Scan Files')
|
|
543
752
|
if ScanType.SCAN_SNIPPETS.value & scan_options:
|
|
544
|
-
print_stderr(
|
|
753
|
+
print_stderr('Scan Snippets')
|
|
545
754
|
if ScanType.SCAN_DEPENDENCIES.value & scan_options:
|
|
546
|
-
print_stderr(
|
|
755
|
+
print_stderr('Scan Dependencies')
|
|
547
756
|
if scan_options <= 0:
|
|
548
757
|
print_stderr(f'Error: No valid scan options configured: {scan_options}')
|
|
549
|
-
exit(1)
|
|
758
|
+
sys.exit(1)
|
|
550
759
|
return scan_options
|
|
551
760
|
|
|
552
761
|
|
|
553
|
-
def scan(parser, args):
|
|
762
|
+
def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
554
763
|
"""
|
|
555
764
|
Run the "scan" sub-command
|
|
556
765
|
Parameters
|
|
@@ -565,39 +774,45 @@ def scan(parser, args):
|
|
|
565
774
|
'Please specify a file/folder, files (--files), fingerprint (--wfp), dependency (--dep), or STDIN (--stdin)'
|
|
566
775
|
)
|
|
567
776
|
parser.parse_args([args.subparser, '-h'])
|
|
568
|
-
exit(1)
|
|
777
|
+
sys.exit(1)
|
|
569
778
|
if args.pac and args.proxy:
|
|
570
779
|
print_stderr('Please specify one of --proxy or --pac, not both')
|
|
571
780
|
parser.parse_args([args.subparser, '-h'])
|
|
572
|
-
exit(1)
|
|
781
|
+
sys.exit(1)
|
|
573
782
|
if args.identify and args.settings:
|
|
574
783
|
print_stderr('ERROR: Cannot specify both --identify and --settings options.')
|
|
575
|
-
exit(1)
|
|
784
|
+
sys.exit(1)
|
|
576
785
|
if args.settings and args.skip_settings_file:
|
|
577
786
|
print_stderr('ERROR: Cannot specify both --settings and --skip-file-settings options.')
|
|
578
|
-
exit(1)
|
|
787
|
+
sys.exit(1)
|
|
579
788
|
# Figure out which settings (if any) to load before processing
|
|
580
789
|
scan_settings = None
|
|
581
790
|
if not args.skip_settings_file:
|
|
582
791
|
scan_settings = ScanossSettings(debug=args.debug, trace=args.trace, quiet=args.quiet)
|
|
583
792
|
try:
|
|
584
793
|
if args.identify:
|
|
585
|
-
scan_settings.load_json_file(args.identify, args.scan_dir).set_file_type('legacy').set_scan_type(
|
|
794
|
+
scan_settings.load_json_file(args.identify, args.scan_dir).set_file_type('legacy').set_scan_type(
|
|
795
|
+
'identify'
|
|
796
|
+
)
|
|
586
797
|
elif args.ignore:
|
|
587
|
-
scan_settings.load_json_file(args.ignore, args.scan_dir).set_file_type('legacy').set_scan_type(
|
|
798
|
+
scan_settings.load_json_file(args.ignore, args.scan_dir).set_file_type('legacy').set_scan_type(
|
|
799
|
+
'blacklist'
|
|
800
|
+
)
|
|
588
801
|
else:
|
|
589
|
-
scan_settings.load_json_file(args.settings, args.scan_dir).set_file_type('new').set_scan_type(
|
|
802
|
+
scan_settings.load_json_file(args.settings, args.scan_dir).set_file_type('new').set_scan_type(
|
|
803
|
+
'identify'
|
|
804
|
+
)
|
|
590
805
|
except ScanossSettingsError as e:
|
|
591
806
|
print_stderr(f'Error: {e}')
|
|
592
|
-
exit(1)
|
|
807
|
+
sys.exit(1)
|
|
593
808
|
if args.dep:
|
|
594
809
|
if not os.path.exists(args.dep) or not os.path.isfile(args.dep):
|
|
595
810
|
print_stderr(f'Specified --dep file does not exist or is not a file: {args.dep}')
|
|
596
|
-
exit(1)
|
|
811
|
+
sys.exit(1)
|
|
597
812
|
result = validate_json_file(args.dep)
|
|
598
813
|
if not result.is_valid:
|
|
599
814
|
print_stderr(f'Error: Dependency file is not valid: {result.error}')
|
|
600
|
-
exit(1)
|
|
815
|
+
sys.exit(1)
|
|
601
816
|
if args.strip_hpsm and not args.hpsm and not args.quiet:
|
|
602
817
|
print_stderr('Warning: --strip-hpsm option supplied without enabling HPSM (--hpsm). Ignoring.')
|
|
603
818
|
|
|
@@ -611,21 +826,21 @@ def scan(parser, args):
|
|
|
611
826
|
if args.skip_settings_file:
|
|
612
827
|
print_stderr('Skipping Settings file...')
|
|
613
828
|
if args.all_extensions:
|
|
614
|
-
print_stderr(
|
|
829
|
+
print_stderr('Scanning all file extensions/types...')
|
|
615
830
|
if args.all_folders:
|
|
616
|
-
print_stderr(
|
|
831
|
+
print_stderr('Scanning all folders...')
|
|
617
832
|
if args.all_hidden:
|
|
618
|
-
print_stderr(
|
|
833
|
+
print_stderr('Scanning all hidden files/folders...')
|
|
619
834
|
if args.skip_snippets:
|
|
620
|
-
print_stderr(
|
|
621
|
-
if args.post_size !=
|
|
835
|
+
print_stderr('Skipping snippets...')
|
|
836
|
+
if args.post_size != DEFAULT_POST_SIZE:
|
|
622
837
|
print_stderr(f'Changing scanning POST size to: {args.post_size}k...')
|
|
623
|
-
if args.timeout !=
|
|
838
|
+
if args.timeout != DEFAULT_TIMEOUT:
|
|
624
839
|
print_stderr(f'Changing scanning POST timeout to: {args.timeout}...')
|
|
625
|
-
if args.retry !=
|
|
840
|
+
if args.retry != DEFAULT_RETRY:
|
|
626
841
|
print_stderr(f'Changing scanning POST retry to: {args.retry}...')
|
|
627
842
|
if args.obfuscate:
|
|
628
|
-
print_stderr(
|
|
843
|
+
print_stderr('Obfuscating file fingerprints...')
|
|
629
844
|
if args.proxy:
|
|
630
845
|
print_stderr(f'Using Proxy {args.proxy}...')
|
|
631
846
|
if args.grpc_proxy:
|
|
@@ -635,11 +850,11 @@ def scan(parser, args):
|
|
|
635
850
|
if args.ca_cert:
|
|
636
851
|
print_stderr(f'Using Certificate {args.ca_cert}...')
|
|
637
852
|
if args.hpsm:
|
|
638
|
-
print_stderr(
|
|
853
|
+
print_stderr('Setting HPSM mode...')
|
|
639
854
|
if flags:
|
|
640
855
|
print_stderr(f'Using flags {flags}...')
|
|
641
856
|
elif not args.quiet:
|
|
642
|
-
if args.timeout <
|
|
857
|
+
if args.timeout < MIN_TIMEOUT_VALUE:
|
|
643
858
|
print_stderr(f'POST timeout (--timeout) too small: {args.timeout}. Reverting to default.')
|
|
644
859
|
if args.retry < 0:
|
|
645
860
|
print_stderr(f'POST retry (--retry) too small: {args.retry}. Reverting to default.')
|
|
@@ -649,13 +864,16 @@ def scan(parser, args):
|
|
|
649
864
|
args.no_wfp_output = True
|
|
650
865
|
if args.ca_cert and not os.path.exists(args.ca_cert):
|
|
651
866
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
652
|
-
exit(1)
|
|
867
|
+
sys.exit(1)
|
|
653
868
|
pac_file = get_pac_file(args.pac)
|
|
654
869
|
scan_options = get_scan_options(args) # Figure out what scanning options we have
|
|
655
870
|
|
|
656
871
|
scanner = Scanner(
|
|
657
|
-
debug=args.debug,
|
|
658
|
-
|
|
872
|
+
debug=args.debug,
|
|
873
|
+
trace=args.trace,
|
|
874
|
+
quiet=args.quiet,
|
|
875
|
+
api_key=args.key,
|
|
876
|
+
url=args.apiurl,
|
|
659
877
|
scan_output=scan_output,
|
|
660
878
|
output_format=output_format,
|
|
661
879
|
flags=flags,
|
|
@@ -689,47 +907,59 @@ def scan(parser, args):
|
|
|
689
907
|
if args.wfp:
|
|
690
908
|
if not scanner.is_file_or_snippet_scan():
|
|
691
909
|
print_stderr(f'Error: Cannot specify WFP scanning if file/snippet options are disabled ({scan_options})')
|
|
692
|
-
exit(1)
|
|
910
|
+
sys.exit(1)
|
|
693
911
|
if scanner.is_dependency_scan() and not args.dep:
|
|
694
|
-
print_stderr(
|
|
695
|
-
exit(1)
|
|
912
|
+
print_stderr('Error: Cannot specify WFP & Dependency scanning without a dependency file (--dep)')
|
|
913
|
+
sys.exit(1)
|
|
696
914
|
scanner.scan_wfp_with_options(args.wfp, args.dep)
|
|
697
915
|
elif args.stdin:
|
|
698
916
|
contents = sys.stdin.buffer.read()
|
|
699
917
|
if not scanner.scan_contents(args.stdin, contents):
|
|
700
|
-
exit(1)
|
|
918
|
+
sys.exit(1)
|
|
701
919
|
elif args.files:
|
|
702
|
-
if not scanner.scan_files_with_options(
|
|
703
|
-
|
|
704
|
-
):
|
|
705
|
-
exit(1)
|
|
920
|
+
if not scanner.scan_files_with_options(args.files, args.dep, scanner.winnowing.file_map):
|
|
921
|
+
sys.exit(1)
|
|
706
922
|
elif args.scan_dir:
|
|
707
923
|
if not os.path.exists(args.scan_dir):
|
|
708
924
|
print_stderr(f'Error: File or folder specified does not exist: {args.scan_dir}.')
|
|
709
|
-
exit(1)
|
|
925
|
+
sys.exit(1)
|
|
710
926
|
if os.path.isdir(args.scan_dir):
|
|
711
|
-
if not scanner.scan_folder_with_options(
|
|
712
|
-
|
|
713
|
-
|
|
927
|
+
if not scanner.scan_folder_with_options(
|
|
928
|
+
args.scan_dir,
|
|
929
|
+
args.dep,
|
|
930
|
+
scanner.winnowing.file_map,
|
|
931
|
+
args.dep_scope,
|
|
932
|
+
args.dep_scope_inc,
|
|
933
|
+
args.dep_scope_exc,
|
|
934
|
+
):
|
|
935
|
+
sys.exit(1)
|
|
714
936
|
elif os.path.isfile(args.scan_dir):
|
|
715
|
-
if not scanner.scan_file_with_options(
|
|
716
|
-
|
|
717
|
-
|
|
937
|
+
if not scanner.scan_file_with_options(
|
|
938
|
+
args.scan_dir,
|
|
939
|
+
args.dep,
|
|
940
|
+
scanner.winnowing.file_map,
|
|
941
|
+
args.dep_scope,
|
|
942
|
+
args.dep_scope_inc,
|
|
943
|
+
args.dep_scope_exc,
|
|
944
|
+
):
|
|
945
|
+
sys.exit(1)
|
|
718
946
|
else:
|
|
719
947
|
print_stderr(f'Error: Path specified is neither a file or a folder: {args.scan_dir}.')
|
|
720
|
-
exit(1)
|
|
948
|
+
sys.exit(1)
|
|
721
949
|
elif args.dep:
|
|
722
950
|
if not args.dependencies_only:
|
|
723
951
|
print_stderr(
|
|
724
|
-
|
|
952
|
+
'Error: No file or folder specified to scan.'
|
|
953
|
+
' Please add --dependencies-only to decorate dependency file only.'
|
|
725
954
|
)
|
|
726
|
-
exit(1)
|
|
727
|
-
if not scanner.scan_folder_with_options(
|
|
728
|
-
|
|
729
|
-
|
|
955
|
+
sys.exit(1)
|
|
956
|
+
if not scanner.scan_folder_with_options(
|
|
957
|
+
'.', args.dep, scanner.winnowing.file_map, args.dep_scope, args.dep_scope_inc, args.dep_scope_exc
|
|
958
|
+
):
|
|
959
|
+
sys.exit(1)
|
|
730
960
|
else:
|
|
731
961
|
print_stderr('No action found to process')
|
|
732
|
-
exit(1)
|
|
962
|
+
sys.exit(1)
|
|
733
963
|
|
|
734
964
|
|
|
735
965
|
def dependency(parser, args):
|
|
@@ -745,20 +975,20 @@ def dependency(parser, args):
|
|
|
745
975
|
if not args.scan_dir:
|
|
746
976
|
print_stderr('Please specify a file/folder')
|
|
747
977
|
parser.parse_args([args.subparser, '-h'])
|
|
748
|
-
exit(1)
|
|
978
|
+
sys.exit(1)
|
|
749
979
|
if not os.path.exists(args.scan_dir):
|
|
750
980
|
print_stderr(f'Error: File or folder specified does not exist: {args.scan_dir}.')
|
|
751
|
-
exit(1)
|
|
981
|
+
sys.exit(1)
|
|
752
982
|
scan_output: str = None
|
|
753
983
|
if args.output:
|
|
754
984
|
scan_output = args.output
|
|
755
985
|
open(scan_output, 'w').close()
|
|
756
986
|
|
|
757
|
-
sc_deps = ScancodeDeps(
|
|
758
|
-
|
|
759
|
-
|
|
987
|
+
sc_deps = ScancodeDeps(
|
|
988
|
+
debug=args.debug, quiet=args.quiet, trace=args.trace, sc_command=args.sc_command, timeout=args.sc_timeout
|
|
989
|
+
)
|
|
760
990
|
if not sc_deps.get_dependencies(what_to_scan=args.scan_dir, result_output=scan_output):
|
|
761
|
-
exit(1)
|
|
991
|
+
sys.exit(1)
|
|
762
992
|
|
|
763
993
|
|
|
764
994
|
def convert(parser, args):
|
|
@@ -774,27 +1004,28 @@ def convert(parser, args):
|
|
|
774
1004
|
if not args.input:
|
|
775
1005
|
print_stderr('Please specify an input file to convert')
|
|
776
1006
|
parser.parse_args([args.subparser, '-h'])
|
|
777
|
-
exit(1)
|
|
1007
|
+
sys.exit(1)
|
|
778
1008
|
success = False
|
|
779
1009
|
if args.format == 'cyclonedx':
|
|
780
1010
|
if not args.quiet:
|
|
781
|
-
print_stderr(
|
|
1011
|
+
print_stderr('Producing CycloneDX report...')
|
|
782
1012
|
cdx = CycloneDx(debug=args.debug, output_file=args.output)
|
|
783
1013
|
success = cdx.produce_from_file(args.input)
|
|
784
1014
|
elif args.format == 'spdxlite':
|
|
785
1015
|
if not args.quiet:
|
|
786
|
-
print_stderr(
|
|
1016
|
+
print_stderr('Producing SPDX Lite report...')
|
|
787
1017
|
spdxlite = SpdxLite(debug=args.debug, output_file=args.output)
|
|
788
1018
|
success = spdxlite.produce_from_file(args.input)
|
|
789
1019
|
elif args.format == 'csv':
|
|
790
1020
|
if not args.quiet:
|
|
791
|
-
print_stderr(
|
|
1021
|
+
print_stderr('Producing CSV report...')
|
|
792
1022
|
csvo = CsvOutput(debug=args.debug, output_file=args.output)
|
|
793
1023
|
success = csvo.produce_from_file(args.input)
|
|
794
1024
|
else:
|
|
795
1025
|
print_stderr(f'ERROR: Unknown output format (--format): {args.format}')
|
|
796
1026
|
if not success:
|
|
797
|
-
exit(1)
|
|
1027
|
+
sys.exit(1)
|
|
1028
|
+
|
|
798
1029
|
|
|
799
1030
|
def inspect_copyleft(parser, args):
|
|
800
1031
|
"""
|
|
@@ -809,7 +1040,7 @@ def inspect_copyleft(parser, args):
|
|
|
809
1040
|
if args.input is None:
|
|
810
1041
|
print_stderr('Please specify an input file to inspect')
|
|
811
1042
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
812
|
-
exit(1)
|
|
1043
|
+
sys.exit(1)
|
|
813
1044
|
output: str = None
|
|
814
1045
|
if args.output:
|
|
815
1046
|
output = args.output
|
|
@@ -820,11 +1051,21 @@ def inspect_copyleft(parser, args):
|
|
|
820
1051
|
status_output = args.status
|
|
821
1052
|
open(status_output, 'w').close()
|
|
822
1053
|
|
|
823
|
-
i_copyleft = Copyleft(
|
|
824
|
-
|
|
825
|
-
|
|
1054
|
+
i_copyleft = Copyleft(
|
|
1055
|
+
debug=args.debug,
|
|
1056
|
+
trace=args.trace,
|
|
1057
|
+
quiet=args.quiet,
|
|
1058
|
+
filepath=args.input,
|
|
1059
|
+
format_type=args.format,
|
|
1060
|
+
status=status_output,
|
|
1061
|
+
output=output,
|
|
1062
|
+
include=args.include,
|
|
1063
|
+
exclude=args.exclude,
|
|
1064
|
+
explicit=args.explicit,
|
|
1065
|
+
)
|
|
826
1066
|
status, _ = i_copyleft.run()
|
|
827
|
-
sys.exit(status)
|
|
1067
|
+
sys.sys.exit(status)
|
|
1068
|
+
|
|
828
1069
|
|
|
829
1070
|
def inspect_undeclared(parser, args):
|
|
830
1071
|
"""
|
|
@@ -839,7 +1080,7 @@ def inspect_undeclared(parser, args):
|
|
|
839
1080
|
if args.input is None:
|
|
840
1081
|
print_stderr('Please specify an input file to inspect')
|
|
841
1082
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
842
|
-
exit(1)
|
|
1083
|
+
sys.exit(1)
|
|
843
1084
|
output: str = None
|
|
844
1085
|
if args.output:
|
|
845
1086
|
output = args.output
|
|
@@ -849,11 +1090,19 @@ def inspect_undeclared(parser, args):
|
|
|
849
1090
|
if args.status:
|
|
850
1091
|
status_output = args.status
|
|
851
1092
|
open(status_output, 'w').close()
|
|
852
|
-
i_undeclared = UndeclaredComponent(
|
|
853
|
-
|
|
854
|
-
|
|
1093
|
+
i_undeclared = UndeclaredComponent(
|
|
1094
|
+
debug=args.debug,
|
|
1095
|
+
trace=args.trace,
|
|
1096
|
+
quiet=args.quiet,
|
|
1097
|
+
filepath=args.input,
|
|
1098
|
+
format_type=args.format,
|
|
1099
|
+
status=status_output,
|
|
1100
|
+
output=output,
|
|
1101
|
+
sbom_format=args.sbom_format,
|
|
1102
|
+
)
|
|
855
1103
|
status, _ = i_undeclared.run()
|
|
856
|
-
sys.exit(status)
|
|
1104
|
+
sys.sys.exit(status)
|
|
1105
|
+
|
|
857
1106
|
|
|
858
1107
|
def utils_certloc(*_):
|
|
859
1108
|
"""
|
|
@@ -861,9 +1110,11 @@ def utils_certloc(*_):
|
|
|
861
1110
|
:param _: ignored/unused
|
|
862
1111
|
"""
|
|
863
1112
|
import certifi
|
|
1113
|
+
|
|
864
1114
|
print(f'CA Cert File: {certifi.where()}')
|
|
865
1115
|
|
|
866
|
-
|
|
1116
|
+
|
|
1117
|
+
def utils_cert_download(_, args): # pylint: disable=PLR0912 # noqa: PLR0912
|
|
867
1118
|
"""
|
|
868
1119
|
Run the "utils cert-download" sub-command
|
|
869
1120
|
:param _: ignore/unused
|
|
@@ -890,21 +1141,23 @@ def utils_cert_download(_, args):
|
|
|
890
1141
|
certs = conn.get_peer_cert_chain()
|
|
891
1142
|
for index, cert in enumerate(certs):
|
|
892
1143
|
cert_components = dict(cert.get_subject().get_components())
|
|
893
|
-
if sys.version_info[0] >=
|
|
1144
|
+
if sys.version_info[0] >= PYTHON3_OR_LATER:
|
|
894
1145
|
cn = cert_components.get(b'CN')
|
|
895
1146
|
else:
|
|
896
1147
|
cn = cert_components.get('CN')
|
|
897
1148
|
if not args.quiet:
|
|
898
1149
|
print_stderr(f'Certificate {index} - CN: {cn}')
|
|
899
|
-
if sys.version_info[0] >=
|
|
900
|
-
print(
|
|
1150
|
+
if sys.version_info[0] >= PYTHON3_OR_LATER:
|
|
1151
|
+
print(
|
|
1152
|
+
(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8')).strip(), file=file
|
|
1153
|
+
) # Print the downloaded PEM certificate
|
|
901
1154
|
else:
|
|
902
1155
|
print((crypto.dump_certificate(crypto.FILETYPE_PEM, cert)).strip(), file=file)
|
|
903
1156
|
except SSL.Error as e:
|
|
904
1157
|
print_stderr(f'ERROR: Exception ({e.__class__.__name__}) Downloading certificate from {hostname}:{port} - {e}.')
|
|
905
1158
|
if args.debug:
|
|
906
1159
|
traceback.print_exc()
|
|
907
|
-
exit(1)
|
|
1160
|
+
sys.exit(1)
|
|
908
1161
|
else:
|
|
909
1162
|
if args.output:
|
|
910
1163
|
if args.debug:
|
|
@@ -919,13 +1172,14 @@ def utils_pac_proxy(_, args):
|
|
|
919
1172
|
:param args: Parsed arguments
|
|
920
1173
|
"""
|
|
921
1174
|
from pypac.resolver import ProxyResolver
|
|
1175
|
+
|
|
922
1176
|
if not args.pac:
|
|
923
|
-
print_stderr(
|
|
924
|
-
exit(1)
|
|
1177
|
+
print_stderr('Error: No pac file option specified.')
|
|
1178
|
+
sys.exit(1)
|
|
925
1179
|
pac_file = get_pac_file(args.pac)
|
|
926
1180
|
if pac_file is None:
|
|
927
1181
|
print_stderr(f'No proxy configuration for: {args.pac}')
|
|
928
|
-
exit(1)
|
|
1182
|
+
sys.exit(1)
|
|
929
1183
|
resolver = ProxyResolver(pac_file)
|
|
930
1184
|
proxies = resolver.get_proxy_for_requests(args.url)
|
|
931
1185
|
print(f'Proxies: {proxies}\n')
|
|
@@ -945,14 +1199,14 @@ def get_pac_file(pac: str):
|
|
|
945
1199
|
pac_local = pac.strip('file://')
|
|
946
1200
|
if not os.path.exists(pac_local):
|
|
947
1201
|
print_stderr(f'Error: PAC file does not exist: {pac_local}.')
|
|
948
|
-
exit(1)
|
|
1202
|
+
sys.exit(1)
|
|
949
1203
|
with open(pac_local) as pf:
|
|
950
1204
|
pac_file = pypac.get_pac(js=pf.read())
|
|
951
1205
|
elif pac.startswith('http'):
|
|
952
1206
|
pac_file = pypac.get_pac(url=pac)
|
|
953
1207
|
else:
|
|
954
1208
|
print_stderr(f'Error: Unknown PAC file option: {pac}. Should be one of "auto", "file://", "https://"')
|
|
955
|
-
exit(1)
|
|
1209
|
+
sys.exit(1)
|
|
956
1210
|
return pac_file
|
|
957
1211
|
|
|
958
1212
|
|
|
@@ -969,16 +1223,25 @@ def comp_crypto(parser, args):
|
|
|
969
1223
|
if (not args.purl and not args.input) or (args.purl and args.input):
|
|
970
1224
|
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
|
|
971
1225
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
972
|
-
exit(1)
|
|
1226
|
+
sys.exit(1)
|
|
973
1227
|
if args.ca_cert and not os.path.exists(args.ca_cert):
|
|
974
1228
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
975
|
-
exit(1)
|
|
1229
|
+
sys.exit(1)
|
|
976
1230
|
pac_file = get_pac_file(args.pac)
|
|
977
|
-
comps = Components(
|
|
978
|
-
|
|
979
|
-
|
|
1231
|
+
comps = Components(
|
|
1232
|
+
debug=args.debug,
|
|
1233
|
+
trace=args.trace,
|
|
1234
|
+
quiet=args.quiet,
|
|
1235
|
+
grpc_url=args.api2url,
|
|
1236
|
+
api_key=args.key,
|
|
1237
|
+
ca_cert=args.ca_cert,
|
|
1238
|
+
proxy=args.proxy,
|
|
1239
|
+
grpc_proxy=args.grpc_proxy,
|
|
1240
|
+
pac=pac_file,
|
|
1241
|
+
timeout=args.timeout,
|
|
1242
|
+
)
|
|
980
1243
|
if not comps.get_crypto_details(args.input, args.purl, args.output):
|
|
981
|
-
exit(1)
|
|
1244
|
+
sys.exit(1)
|
|
982
1245
|
|
|
983
1246
|
|
|
984
1247
|
def comp_vulns(parser, args):
|
|
@@ -994,16 +1257,26 @@ def comp_vulns(parser, args):
|
|
|
994
1257
|
if (not args.purl and not args.input) or (args.purl and args.input):
|
|
995
1258
|
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
|
|
996
1259
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
997
|
-
exit(1)
|
|
1260
|
+
sys.exit(1)
|
|
998
1261
|
if args.ca_cert and not os.path.exists(args.ca_cert):
|
|
999
1262
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
1000
|
-
exit(1)
|
|
1263
|
+
sys.exit(1)
|
|
1001
1264
|
pac_file = get_pac_file(args.pac)
|
|
1002
|
-
comps = Components(
|
|
1003
|
-
|
|
1004
|
-
|
|
1265
|
+
comps = Components(
|
|
1266
|
+
debug=args.debug,
|
|
1267
|
+
trace=args.trace,
|
|
1268
|
+
quiet=args.quiet,
|
|
1269
|
+
grpc_url=args.api2url,
|
|
1270
|
+
api_key=args.key,
|
|
1271
|
+
ca_cert=args.ca_cert,
|
|
1272
|
+
proxy=args.proxy,
|
|
1273
|
+
grpc_proxy=args.grpc_proxy,
|
|
1274
|
+
pac=pac_file,
|
|
1275
|
+
timeout=args.timeout,
|
|
1276
|
+
)
|
|
1005
1277
|
if not comps.get_vulnerabilities(args.input, args.purl, args.output):
|
|
1006
|
-
exit(1)
|
|
1278
|
+
sys.exit(1)
|
|
1279
|
+
|
|
1007
1280
|
|
|
1008
1281
|
def comp_semgrep(parser, args):
|
|
1009
1282
|
"""
|
|
@@ -1018,20 +1291,30 @@ def comp_semgrep(parser, args):
|
|
|
1018
1291
|
if (not args.purl and not args.input) or (args.purl and args.input):
|
|
1019
1292
|
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
|
|
1020
1293
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1021
|
-
exit(1)
|
|
1294
|
+
sys.exit(1)
|
|
1022
1295
|
if args.ca_cert and not os.path.exists(args.ca_cert):
|
|
1023
1296
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
1024
|
-
exit(1)
|
|
1297
|
+
sys.exit(1)
|
|
1025
1298
|
pac_file = get_pac_file(args.pac)
|
|
1026
|
-
comps = Components(
|
|
1027
|
-
|
|
1028
|
-
|
|
1299
|
+
comps = Components(
|
|
1300
|
+
debug=args.debug,
|
|
1301
|
+
trace=args.trace,
|
|
1302
|
+
quiet=args.quiet,
|
|
1303
|
+
grpc_url=args.api2url,
|
|
1304
|
+
api_key=args.key,
|
|
1305
|
+
ca_cert=args.ca_cert,
|
|
1306
|
+
proxy=args.proxy,
|
|
1307
|
+
grpc_proxy=args.grpc_proxy,
|
|
1308
|
+
pac=pac_file,
|
|
1309
|
+
timeout=args.timeout,
|
|
1310
|
+
)
|
|
1029
1311
|
if not comps.get_semgrep_details(args.input, args.purl, args.output):
|
|
1030
|
-
exit(1)
|
|
1312
|
+
sys.exit(1)
|
|
1031
1313
|
|
|
1032
|
-
|
|
1314
|
+
|
|
1315
|
+
def comp_search(parser, args):
|
|
1033
1316
|
"""
|
|
1034
|
-
Run the "component
|
|
1317
|
+
Run the "component search" sub-command
|
|
1035
1318
|
Parameters
|
|
1036
1319
|
----------
|
|
1037
1320
|
parser: ArgumentParser
|
|
@@ -1039,23 +1322,45 @@ def comp_provenance(parser, args):
|
|
|
1039
1322
|
args: Namespace
|
|
1040
1323
|
Parsed arguments
|
|
1041
1324
|
"""
|
|
1042
|
-
if (not args.
|
|
1043
|
-
|
|
1325
|
+
if (not args.input and not args.search and not args.vendor and not args.comp) or (
|
|
1326
|
+
args.input and (args.search or args.vendor or args.comp)
|
|
1327
|
+
):
|
|
1328
|
+
print_stderr('Please specify an input file or search terms (--input or --search, or --vendor or --comp.)')
|
|
1044
1329
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1045
|
-
exit(1)
|
|
1330
|
+
sys.exit(1)
|
|
1331
|
+
|
|
1046
1332
|
if args.ca_cert and not os.path.exists(args.ca_cert):
|
|
1047
1333
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
1048
|
-
exit(1)
|
|
1334
|
+
sys.exit(1)
|
|
1049
1335
|
pac_file = get_pac_file(args.pac)
|
|
1050
|
-
comps = Components(
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1336
|
+
comps = Components(
|
|
1337
|
+
debug=args.debug,
|
|
1338
|
+
trace=args.trace,
|
|
1339
|
+
quiet=args.quiet,
|
|
1340
|
+
grpc_url=args.api2url,
|
|
1341
|
+
api_key=args.key,
|
|
1342
|
+
ca_cert=args.ca_cert,
|
|
1343
|
+
proxy=args.proxy,
|
|
1344
|
+
grpc_proxy=args.grpc_proxy,
|
|
1345
|
+
pac=pac_file,
|
|
1346
|
+
timeout=args.timeout,
|
|
1347
|
+
)
|
|
1348
|
+
if not comps.search_components(
|
|
1349
|
+
args.output,
|
|
1350
|
+
json_file=args.input,
|
|
1351
|
+
search=args.search,
|
|
1352
|
+
vendor=args.vendor,
|
|
1353
|
+
comp=args.comp,
|
|
1354
|
+
package=args.package,
|
|
1355
|
+
limit=args.limit,
|
|
1356
|
+
offset=args.offset,
|
|
1357
|
+
):
|
|
1358
|
+
sys.exit(1)
|
|
1055
1359
|
|
|
1056
|
-
|
|
1360
|
+
|
|
1361
|
+
def comp_versions(parser, args):
|
|
1057
1362
|
"""
|
|
1058
|
-
Run the "component
|
|
1363
|
+
Run the "component versions" sub-command
|
|
1059
1364
|
Parameters
|
|
1060
1365
|
----------
|
|
1061
1366
|
parser: ArgumentParser
|
|
@@ -1063,28 +1368,33 @@ def comp_search(parser, args):
|
|
|
1063
1368
|
args: Namespace
|
|
1064
1369
|
Parsed arguments
|
|
1065
1370
|
"""
|
|
1066
|
-
if (
|
|
1067
|
-
|
|
1068
|
-
print_stderr('Please specify an input file or search terms (--input or --search, or --vendor or --comp.)')
|
|
1371
|
+
if (not args.input and not args.purl) or (args.input and args.purl):
|
|
1372
|
+
print_stderr('Please specify an input file or search terms (--input or --purl.)')
|
|
1069
1373
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1070
|
-
exit(1)
|
|
1374
|
+
sys.exit(1)
|
|
1071
1375
|
|
|
1072
1376
|
if args.ca_cert and not os.path.exists(args.ca_cert):
|
|
1073
1377
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
1074
|
-
exit(1)
|
|
1378
|
+
sys.exit(1)
|
|
1075
1379
|
pac_file = get_pac_file(args.pac)
|
|
1076
|
-
comps = Components(
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1380
|
+
comps = Components(
|
|
1381
|
+
debug=args.debug,
|
|
1382
|
+
trace=args.trace,
|
|
1383
|
+
quiet=args.quiet,
|
|
1384
|
+
grpc_url=args.api2url,
|
|
1385
|
+
api_key=args.key,
|
|
1386
|
+
ca_cert=args.ca_cert,
|
|
1387
|
+
proxy=args.proxy,
|
|
1388
|
+
grpc_proxy=args.grpc_proxy,
|
|
1389
|
+
pac=pac_file,
|
|
1390
|
+
timeout=args.timeout,
|
|
1391
|
+
)
|
|
1392
|
+
if not comps.get_component_versions(args.output, json_file=args.input, purl=args.purl, limit=args.limit):
|
|
1393
|
+
sys.exit(1)
|
|
1084
1394
|
|
|
1085
|
-
def
|
|
1395
|
+
def comp_provenance(parser, args):
|
|
1086
1396
|
"""
|
|
1087
|
-
Run the "component
|
|
1397
|
+
Run the "component semgrep" sub-command
|
|
1088
1398
|
Parameters
|
|
1089
1399
|
----------
|
|
1090
1400
|
parser: ArgumentParser
|
|
@@ -1092,21 +1402,19 @@ def comp_versions(parser, args):
|
|
|
1092
1402
|
args: Namespace
|
|
1093
1403
|
Parsed arguments
|
|
1094
1404
|
"""
|
|
1095
|
-
if (not args.
|
|
1096
|
-
print_stderr('Please specify an input file or
|
|
1405
|
+
if (not args.purl and not args.input) or (args.purl and args.input):
|
|
1406
|
+
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
|
|
1097
1407
|
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1098
|
-
exit(1)
|
|
1099
|
-
|
|
1408
|
+
sys.exit(1)
|
|
1100
1409
|
if args.ca_cert and not os.path.exists(args.ca_cert):
|
|
1101
1410
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
1102
|
-
exit(1)
|
|
1411
|
+
sys.exit(1)
|
|
1103
1412
|
pac_file = get_pac_file(args.pac)
|
|
1104
1413
|
comps = Components(debug=args.debug, trace=args.trace, quiet=args.quiet, grpc_url=args.api2url, api_key=args.key,
|
|
1105
1414
|
ca_cert=args.ca_cert, proxy=args.proxy, grpc_proxy=args.grpc_proxy, pac=pac_file,
|
|
1106
1415
|
timeout=args.timeout)
|
|
1107
|
-
if not comps.
|
|
1108
|
-
exit(1)
|
|
1109
|
-
|
|
1416
|
+
if not comps.get_provenance_details(args.input, args.purl, args.output):
|
|
1417
|
+
sys.exit(1)
|
|
1110
1418
|
|
|
1111
1419
|
def results(parser, args):
|
|
1112
1420
|
"""
|
|
@@ -1120,14 +1428,14 @@ def results(parser, args):
|
|
|
1120
1428
|
"""
|
|
1121
1429
|
if not args.filepath:
|
|
1122
1430
|
print_stderr('ERROR: Please specify a file containing the results')
|
|
1123
|
-
parser.parse_args([args.subparser,
|
|
1124
|
-
exit(1)
|
|
1431
|
+
parser.parse_args([args.subparser, '-h'])
|
|
1432
|
+
sys.exit(1)
|
|
1125
1433
|
|
|
1126
1434
|
file_path = Path(args.filepath).resolve()
|
|
1127
1435
|
|
|
1128
1436
|
if not file_path.is_file():
|
|
1129
|
-
print_stderr(f
|
|
1130
|
-
exit(1)
|
|
1437
|
+
print_stderr(f'The specified file {args.filepath} does not exist')
|
|
1438
|
+
sys.exit(1)
|
|
1131
1439
|
|
|
1132
1440
|
results = Results(
|
|
1133
1441
|
debug=args.debug,
|
|
@@ -1143,7 +1451,7 @@ def results(parser, args):
|
|
|
1143
1451
|
if args.has_pending:
|
|
1144
1452
|
results.get_pending_identifications().present()
|
|
1145
1453
|
if results.has_results():
|
|
1146
|
-
exit(1)
|
|
1454
|
+
sys.exit(1)
|
|
1147
1455
|
else:
|
|
1148
1456
|
results.apply_filters().present()
|
|
1149
1457
|
|
|
@@ -1155,5 +1463,5 @@ def main():
|
|
|
1155
1463
|
setup_args()
|
|
1156
1464
|
|
|
1157
1465
|
|
|
1158
|
-
if __name__ ==
|
|
1466
|
+
if __name__ == '__main__':
|
|
1159
1467
|
main()
|