scanoss 1.20.5__py3-none-any.whl → 1.22.0__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/options/annotations_pb2.py +9 -12
- protoc_gen_swagger/options/annotations_pb2_grpc.py +1 -1
- protoc_gen_swagger/options/openapiv2_pb2.py +96 -98
- protoc_gen_swagger/options/openapiv2_pb2_grpc.py +1 -1
- scanoss/__init__.py +1 -1
- scanoss/api/common/v2/scanoss_common_pb2.py +20 -18
- scanoss/api/common/v2/scanoss_common_pb2_grpc.py +1 -1
- scanoss/api/components/v2/scanoss_components_pb2.py +38 -48
- scanoss/api/components/v2/scanoss_components_pb2_grpc.py +96 -142
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +42 -22
- scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +185 -75
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +32 -30
- scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +83 -75
- scanoss/api/provenance/v2/scanoss_provenance_pb2.py +20 -21
- scanoss/api/provenance/v2/scanoss_provenance_pb2_grpc.py +1 -1
- scanoss/api/scanning/v2/scanoss_scanning_pb2.py +20 -10
- scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +70 -40
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +18 -22
- scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +49 -71
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +27 -37
- scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +72 -109
- scanoss/cli.py +417 -74
- scanoss/components.py +5 -3
- scanoss/constants.py +12 -0
- scanoss/data/build_date.txt +1 -1
- scanoss/file_filters.py +272 -57
- scanoss/results.py +92 -109
- scanoss/scanner.py +25 -20
- scanoss/scanners/__init__.py +23 -0
- scanoss/scanners/container_scanner.py +474 -0
- scanoss/scanners/folder_hasher.py +302 -0
- scanoss/scanners/scanner_config.py +73 -0
- scanoss/scanners/scanner_hfh.py +172 -0
- scanoss/scanoss_settings.py +9 -5
- scanoss/scanossapi.py +29 -7
- scanoss/scanossbase.py +9 -3
- scanoss/scanossgrpc.py +145 -13
- scanoss/threadedscanning.py +6 -6
- scanoss/utils/abstract_presenter.py +103 -0
- scanoss/utils/crc64.py +96 -0
- scanoss/utils/simhash.py +198 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info}/METADATA +4 -2
- scanoss-1.22.0.dist-info/RECORD +83 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info}/WHEEL +1 -1
- scanoss-1.20.5.dist-info/RECORD +0 -74
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info}/entry_points.txt +0 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info/licenses}/LICENSE +0 -0
- {scanoss-1.20.5.dist-info → scanoss-1.22.0.dist-info}/top_level.txt +0 -0
scanoss/cli.py
CHANGED
|
@@ -25,12 +25,37 @@ SPDX-License-Identifier: MIT
|
|
|
25
25
|
import argparse
|
|
26
26
|
import os
|
|
27
27
|
import sys
|
|
28
|
+
from dataclasses import asdict
|
|
28
29
|
from pathlib import Path
|
|
30
|
+
from typing import List
|
|
29
31
|
|
|
30
32
|
import pypac
|
|
31
33
|
|
|
34
|
+
from scanoss.scanners.container_scanner import (
|
|
35
|
+
DEFAULT_SYFT_COMMAND,
|
|
36
|
+
DEFAULT_SYFT_TIMEOUT,
|
|
37
|
+
ContainerScanner,
|
|
38
|
+
create_container_scanner_config_from_args,
|
|
39
|
+
)
|
|
40
|
+
from scanoss.scanners.folder_hasher import (
|
|
41
|
+
FolderHasher,
|
|
42
|
+
create_folder_hasher_config_from_args,
|
|
43
|
+
)
|
|
44
|
+
from scanoss.scanossgrpc import (
|
|
45
|
+
ScanossGrpc,
|
|
46
|
+
ScanossGrpcError,
|
|
47
|
+
create_grpc_config_from_args,
|
|
48
|
+
)
|
|
49
|
+
|
|
32
50
|
from . import __version__
|
|
33
51
|
from .components import Components
|
|
52
|
+
from .constants import (
|
|
53
|
+
DEFAULT_POST_SIZE,
|
|
54
|
+
DEFAULT_RETRY,
|
|
55
|
+
DEFAULT_TIMEOUT,
|
|
56
|
+
MIN_TIMEOUT,
|
|
57
|
+
PYTHON_MAJOR_VERSION,
|
|
58
|
+
)
|
|
34
59
|
from .csvoutput import CsvOutput
|
|
35
60
|
from .cyclonedx import CycloneDx
|
|
36
61
|
from .filecount import FileCount
|
|
@@ -39,17 +64,16 @@ from .inspection.undeclared_component import UndeclaredComponent
|
|
|
39
64
|
from .results import Results
|
|
40
65
|
from .scancodedeps import ScancodeDeps
|
|
41
66
|
from .scanner import FAST_WINNOWING, Scanner
|
|
67
|
+
from .scanners.scanner_config import create_scanner_config_from_args
|
|
68
|
+
from .scanners.scanner_hfh import ScannerHFH
|
|
42
69
|
from .scanoss_settings import ScanossSettings, ScanossSettingsError
|
|
43
70
|
from .scantype import ScanType
|
|
44
71
|
from .spdxlite import SpdxLite
|
|
45
72
|
from .threadeddependencies import SCOPE
|
|
46
73
|
from .utils.file import validate_json_file
|
|
47
74
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
MIN_TIMEOUT_VALUE = 5
|
|
51
|
-
DEFAULT_RETRY = 5
|
|
52
|
-
PYTHON3_OR_LATER = 3
|
|
75
|
+
HEADER_PARTS_COUNT = 2
|
|
76
|
+
|
|
53
77
|
|
|
54
78
|
def print_stderr(*args, **kwargs):
|
|
55
79
|
"""
|
|
@@ -58,7 +82,7 @@ def print_stderr(*args, **kwargs):
|
|
|
58
82
|
print(*args, file=sys.stderr, **kwargs)
|
|
59
83
|
|
|
60
84
|
|
|
61
|
-
def setup_args() -> None: # noqa: PLR0915
|
|
85
|
+
def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
62
86
|
"""
|
|
63
87
|
Setup all the command line arguments for processing
|
|
64
88
|
"""
|
|
@@ -93,14 +117,6 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
93
117
|
p_scan.add_argument('--files', '-e', type=str, nargs='*', help='List of files to scan.')
|
|
94
118
|
p_scan.add_argument('--identify', '-i', type=str, help='Scan and identify components in SBOM file')
|
|
95
119
|
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
120
|
p_scan.add_argument(
|
|
105
121
|
'--threads', '-T', type=int, default=5, help='Number of threads to use while scanning (optional - default 5)'
|
|
106
122
|
)
|
|
@@ -130,15 +146,17 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
130
146
|
help='Timeout (in seconds) for API communication (optional - default 180)',
|
|
131
147
|
)
|
|
132
148
|
p_scan.add_argument(
|
|
133
|
-
'--retry',
|
|
134
|
-
|
|
149
|
+
'--retry',
|
|
150
|
+
'-R',
|
|
151
|
+
type=int,
|
|
152
|
+
default=DEFAULT_RETRY,
|
|
153
|
+
help='Retry limit for API communication (optional - default 5)',
|
|
135
154
|
)
|
|
136
155
|
p_scan.add_argument('--no-wfp-output', action='store_true', help='Skip WFP file generation')
|
|
137
156
|
p_scan.add_argument('--dependencies', '-D', action='store_true', help='Add Dependency scanning')
|
|
138
157
|
p_scan.add_argument('--dependencies-only', action='store_true', help='Run Dependency scanning only')
|
|
139
158
|
p_scan.add_argument(
|
|
140
|
-
'--sc-command', type=str,
|
|
141
|
-
help='Scancode command and path if required (optional - default scancode).'
|
|
159
|
+
'--sc-command', type=str, help='Scancode command and path if required (optional - default scancode).'
|
|
142
160
|
)
|
|
143
161
|
p_scan.add_argument(
|
|
144
162
|
'--sc-timeout',
|
|
@@ -151,18 +169,6 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
151
169
|
)
|
|
152
170
|
p_scan.add_argument('--dep-scope-inc', '-dsi', type=str, help='Include dependencies with declared scopes')
|
|
153
171
|
p_scan.add_argument('--dep-scope-exc', '-dse', type=str, help='Exclude dependencies with declared scopes')
|
|
154
|
-
p_scan.add_argument(
|
|
155
|
-
'--settings',
|
|
156
|
-
'-st',
|
|
157
|
-
type=str,
|
|
158
|
-
help='Settings file to use for scanning (optional - default scanoss.json)',
|
|
159
|
-
)
|
|
160
|
-
p_scan.add_argument(
|
|
161
|
-
'--skip-settings-file',
|
|
162
|
-
'-stf',
|
|
163
|
-
action='store_true',
|
|
164
|
-
help='Skip default settings file (scanoss.json) if it exists',
|
|
165
|
-
)
|
|
166
172
|
|
|
167
173
|
# Sub-command: fingerprint
|
|
168
174
|
p_wfp = subparsers.add_parser(
|
|
@@ -180,19 +186,6 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
180
186
|
type=str,
|
|
181
187
|
help='Fingerprint the file contents supplied via STDIN (optional)',
|
|
182
188
|
)
|
|
183
|
-
p_wfp.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
184
|
-
p_wfp.add_argument(
|
|
185
|
-
'--settings',
|
|
186
|
-
'-st',
|
|
187
|
-
type=str,
|
|
188
|
-
help='Settings file to use for fingerprinting (optional - default scanoss.json)',
|
|
189
|
-
)
|
|
190
|
-
p_wfp.add_argument(
|
|
191
|
-
'--skip-settings-file',
|
|
192
|
-
'-stf',
|
|
193
|
-
action='store_true',
|
|
194
|
-
help='Skip default settings file (scanoss.json) if it exists',
|
|
195
|
-
)
|
|
196
189
|
|
|
197
190
|
# Sub-command: dependency
|
|
198
191
|
p_dep = subparsers.add_parser(
|
|
@@ -201,9 +194,13 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
201
194
|
description=f'Produce dependency file summary: {__version__}',
|
|
202
195
|
help='Scan source code for dependencies, but do not decorate them',
|
|
203
196
|
)
|
|
204
|
-
p_dep.
|
|
205
|
-
p_dep.add_argument(
|
|
206
|
-
|
|
197
|
+
p_dep.add_argument('scan_loc', metavar='FILE/DIR', type=str, nargs='?', help='A file or folder to scan')
|
|
198
|
+
p_dep.add_argument(
|
|
199
|
+
'--container',
|
|
200
|
+
type=str,
|
|
201
|
+
help='Container image to scan. Supports yourrepo/yourimage:tag, Docker tar, '
|
|
202
|
+
'OCI tar, OCI directory, SIF Container, or generic filesystem directory.',
|
|
203
|
+
)
|
|
207
204
|
p_dep.add_argument(
|
|
208
205
|
'--sc-command', type=str, help='Scancode command and path if required (optional - default scancode).'
|
|
209
206
|
)
|
|
@@ -213,6 +210,40 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
213
210
|
default=600,
|
|
214
211
|
help='Timeout (in seconds) for scancode to complete (optional - default 600)',
|
|
215
212
|
)
|
|
213
|
+
p_dep.set_defaults(func=dependency)
|
|
214
|
+
|
|
215
|
+
# Container scan sub-command
|
|
216
|
+
p_cs = subparsers.add_parser(
|
|
217
|
+
'container-scan',
|
|
218
|
+
aliases=['cs'],
|
|
219
|
+
description=f'Analyse/scan the given container image: {__version__}',
|
|
220
|
+
help='Scan container image',
|
|
221
|
+
)
|
|
222
|
+
p_cs.add_argument(
|
|
223
|
+
'scan_loc',
|
|
224
|
+
metavar='IMAGE',
|
|
225
|
+
type=str,
|
|
226
|
+
nargs='?',
|
|
227
|
+
help=(
|
|
228
|
+
'Container image to scan. Supports yourrepo/yourimage:tag, Docker tar, '
|
|
229
|
+
'OCI tar, OCI directory, SIF Container, or generic filesystem directory.'
|
|
230
|
+
),
|
|
231
|
+
)
|
|
232
|
+
p_cs.add_argument(
|
|
233
|
+
'--retry',
|
|
234
|
+
'-R',
|
|
235
|
+
type=int,
|
|
236
|
+
default=DEFAULT_RETRY,
|
|
237
|
+
help='Retry limit for API communication (optional - default 5)',
|
|
238
|
+
)
|
|
239
|
+
p_cs.add_argument(
|
|
240
|
+
'--timeout',
|
|
241
|
+
'-M',
|
|
242
|
+
type=int,
|
|
243
|
+
default=DEFAULT_TIMEOUT,
|
|
244
|
+
help='Timeout (in seconds) for API communication (optional - default 180)',
|
|
245
|
+
)
|
|
246
|
+
p_cs.set_defaults(func=container_scan)
|
|
216
247
|
|
|
217
248
|
# Sub-command: file_count
|
|
218
249
|
p_fc = subparsers.add_parser(
|
|
@@ -223,7 +254,6 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
223
254
|
)
|
|
224
255
|
p_fc.set_defaults(func=file_count)
|
|
225
256
|
p_fc.add_argument('scan_dir', metavar='DIR', type=str, nargs='?', help='A folder to search')
|
|
226
|
-
p_fc.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
227
257
|
p_fc.add_argument('--all-hidden', action='store_true', help='Scan all hidden files/folders')
|
|
228
258
|
|
|
229
259
|
# Sub-command: convert
|
|
@@ -235,7 +265,6 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
235
265
|
)
|
|
236
266
|
p_cnv.set_defaults(func=convert)
|
|
237
267
|
p_cnv.add_argument('--input', '-i', type=str, required=True, help='Input file name')
|
|
238
|
-
p_cnv.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
239
268
|
p_cnv.add_argument(
|
|
240
269
|
'--format',
|
|
241
270
|
'-f',
|
|
@@ -331,9 +360,9 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
331
360
|
for p in [c_crypto, c_vulns, c_semgrep, c_provenance]:
|
|
332
361
|
p.add_argument('--purl', '-p', type=str, nargs='*', help='Package URL - PURL to process.')
|
|
333
362
|
p.add_argument('--input', '-i', type=str, help='Input file name')
|
|
363
|
+
|
|
334
364
|
# Common Component sub-command options
|
|
335
365
|
for p in [c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance]:
|
|
336
|
-
p.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
337
366
|
p.add_argument(
|
|
338
367
|
'--timeout',
|
|
339
368
|
'-M',
|
|
@@ -381,7 +410,6 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
381
410
|
p_c_dwnld.add_argument(
|
|
382
411
|
'--port', '-p', required=False, type=int, default=443, help='Server port number (default: 443).'
|
|
383
412
|
)
|
|
384
|
-
p_c_dwnld.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
385
413
|
|
|
386
414
|
# Utils Sub-command: utils pac-proxy
|
|
387
415
|
p_p_proxy = utils_sub.add_parser(
|
|
@@ -489,6 +517,114 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
489
517
|
)
|
|
490
518
|
p_undeclared.set_defaults(func=inspect_undeclared)
|
|
491
519
|
|
|
520
|
+
# Sub-command: folder-scan
|
|
521
|
+
p_folder_scan = subparsers.add_parser(
|
|
522
|
+
'folder-scan',
|
|
523
|
+
aliases=['fs'],
|
|
524
|
+
description=f'Scan the given directory using folder hashing: {__version__}',
|
|
525
|
+
help='Scan the given directory using folder hashing',
|
|
526
|
+
)
|
|
527
|
+
p_folder_scan.add_argument('scan_dir', metavar='FILE/DIR', type=str, nargs='?', help='The root directory to scan')
|
|
528
|
+
p_folder_scan.add_argument(
|
|
529
|
+
'--timeout',
|
|
530
|
+
'-M',
|
|
531
|
+
type=int,
|
|
532
|
+
default=600,
|
|
533
|
+
help='Timeout (in seconds) for API communication (optional - default 600)',
|
|
534
|
+
)
|
|
535
|
+
p_folder_scan.add_argument(
|
|
536
|
+
'--format',
|
|
537
|
+
'-f',
|
|
538
|
+
type=str,
|
|
539
|
+
choices=['json'],
|
|
540
|
+
default='json',
|
|
541
|
+
help='Result output format (optional - default: json)',
|
|
542
|
+
)
|
|
543
|
+
p_folder_scan.add_argument(
|
|
544
|
+
'--best-match',
|
|
545
|
+
'-bm',
|
|
546
|
+
action='store_true',
|
|
547
|
+
default=False,
|
|
548
|
+
help='Enable best match mode (optional - default: False)',
|
|
549
|
+
)
|
|
550
|
+
p_folder_scan.add_argument(
|
|
551
|
+
'--threshold',
|
|
552
|
+
type=int,
|
|
553
|
+
choices=range(1, 101),
|
|
554
|
+
metavar='1-100',
|
|
555
|
+
default=100,
|
|
556
|
+
help='Threshold for result matching (optional - default: 100)',
|
|
557
|
+
)
|
|
558
|
+
p_folder_scan.set_defaults(func=folder_hashing_scan)
|
|
559
|
+
|
|
560
|
+
# Sub-command: folder-hash
|
|
561
|
+
p_folder_hash = subparsers.add_parser(
|
|
562
|
+
'folder-hash',
|
|
563
|
+
aliases=['fh'],
|
|
564
|
+
description=f'Produce a folder hash for the given directory: {__version__}',
|
|
565
|
+
help='Produce a folder hash for the given directory',
|
|
566
|
+
)
|
|
567
|
+
p_folder_hash.add_argument('scan_dir', metavar='FILE/DIR', type=str, nargs='?', help='A file or folder to scan')
|
|
568
|
+
p_folder_hash.add_argument(
|
|
569
|
+
'--format',
|
|
570
|
+
'-f',
|
|
571
|
+
type=str,
|
|
572
|
+
choices=['json'],
|
|
573
|
+
default='json',
|
|
574
|
+
help='Result output format (optional - default: json)',
|
|
575
|
+
)
|
|
576
|
+
p_folder_hash.set_defaults(func=folder_hash)
|
|
577
|
+
|
|
578
|
+
# Output options
|
|
579
|
+
for p in [
|
|
580
|
+
p_scan,
|
|
581
|
+
p_cs,
|
|
582
|
+
p_wfp,
|
|
583
|
+
p_dep,
|
|
584
|
+
p_fc,
|
|
585
|
+
p_cnv,
|
|
586
|
+
c_crypto,
|
|
587
|
+
c_vulns,
|
|
588
|
+
c_search,
|
|
589
|
+
c_versions,
|
|
590
|
+
c_semgrep,
|
|
591
|
+
c_provenance,
|
|
592
|
+
p_c_dwnld,
|
|
593
|
+
p_folder_scan,
|
|
594
|
+
p_folder_hash,
|
|
595
|
+
]:
|
|
596
|
+
p.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
|
|
597
|
+
|
|
598
|
+
# Format options
|
|
599
|
+
for p in [p_scan, p_cs]:
|
|
600
|
+
choices = ['plain', 'cyclonedx', 'spdxlite', 'csv']
|
|
601
|
+
if p is p_cs:
|
|
602
|
+
choices.append('raw')
|
|
603
|
+
|
|
604
|
+
p.add_argument(
|
|
605
|
+
'--format',
|
|
606
|
+
'-f',
|
|
607
|
+
type=str,
|
|
608
|
+
choices=choices,
|
|
609
|
+
default='plain',
|
|
610
|
+
help='Result output format (optional - default: plain)',
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
# Scanoss settings options
|
|
614
|
+
for p in [p_folder_scan, p_scan, p_wfp, p_folder_hash]:
|
|
615
|
+
p.add_argument(
|
|
616
|
+
'--settings',
|
|
617
|
+
'-st',
|
|
618
|
+
type=str,
|
|
619
|
+
help='Settings file to use for scanning (optional - default scanoss.json)',
|
|
620
|
+
)
|
|
621
|
+
p.add_argument(
|
|
622
|
+
'--skip-settings-file',
|
|
623
|
+
'-stf',
|
|
624
|
+
action='store_true',
|
|
625
|
+
help='Skip default settings file (scanoss.json) if it exists',
|
|
626
|
+
)
|
|
627
|
+
|
|
492
628
|
for p in [p_copyleft, p_undeclared]:
|
|
493
629
|
p.add_argument('-i', '--input', nargs='?', help='Path to results file')
|
|
494
630
|
p.add_argument(
|
|
@@ -503,7 +639,7 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
503
639
|
p.add_argument('-s', '--status', type=str, help='Save summary data into Markdown file')
|
|
504
640
|
|
|
505
641
|
# Global Scan command options
|
|
506
|
-
for p in [p_scan]:
|
|
642
|
+
for p in [p_scan, p_cs]:
|
|
507
643
|
p.add_argument(
|
|
508
644
|
'--apiurl', type=str, help='SCANOSS API URL (optional - default: https://api.osskb.org/scan/direct)'
|
|
509
645
|
)
|
|
@@ -512,9 +648,9 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
512
648
|
# Global Scan/Fingerprint filter options
|
|
513
649
|
for p in [p_scan, p_wfp]:
|
|
514
650
|
p.add_argument('--obfuscate', action='store_true', help='Obfuscate fingerprints')
|
|
515
|
-
p.add_argument('--all-extensions', action='store_true', help='Fingerprint all file extensions')
|
|
516
|
-
p.add_argument('--all-folders', action='store_true', help='Fingerprint all folders')
|
|
517
|
-
p.add_argument('--all-hidden', action='store_true', help='Fingerprint all hidden files/folders')
|
|
651
|
+
p.add_argument('--all-extensions', action='store_true', help='Fingerprint all file extensions/types...')
|
|
652
|
+
p.add_argument('--all-folders', action='store_true', help='Fingerprint all folders...')
|
|
653
|
+
p.add_argument('--all-hidden', action='store_true', help='Fingerprint all hidden files/folders...')
|
|
518
654
|
p.add_argument('--hpsm', '-H', action='store_true', help='Use High Precision Snippet Matching algorithm.')
|
|
519
655
|
p.add_argument('--skip-snippets', '-S', action='store_true', help='Skip the generation of snippets')
|
|
520
656
|
p.add_argument('--skip-extension', '-E', type=str, action='append', help='File Extension to skip.')
|
|
@@ -531,7 +667,17 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
531
667
|
p.add_argument('--strip-snippet', '-N', type=str, action='append', help='Strip Snippet ID string from WFP.')
|
|
532
668
|
|
|
533
669
|
# Global Scan/GRPC options
|
|
534
|
-
for p in [
|
|
670
|
+
for p in [
|
|
671
|
+
p_scan,
|
|
672
|
+
c_crypto,
|
|
673
|
+
c_vulns,
|
|
674
|
+
c_search,
|
|
675
|
+
c_versions,
|
|
676
|
+
c_semgrep,
|
|
677
|
+
c_provenance,
|
|
678
|
+
p_folder_scan,
|
|
679
|
+
p_cs,
|
|
680
|
+
]:
|
|
535
681
|
p.add_argument(
|
|
536
682
|
'--key', '-k', type=str, help='SCANOSS API Key token (optional - not required for default OSSKB URL)'
|
|
537
683
|
)
|
|
@@ -557,7 +703,7 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
557
703
|
)
|
|
558
704
|
|
|
559
705
|
# Global GRPC options
|
|
560
|
-
for p in [p_scan, c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance]:
|
|
706
|
+
for p in [p_scan, c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance, p_folder_scan, p_cs]:
|
|
561
707
|
p.add_argument(
|
|
562
708
|
'--api2url', type=str, help='SCANOSS gRPC API 2.0 URL (optional - default: https://api.osskb.org)'
|
|
563
709
|
)
|
|
@@ -567,6 +713,28 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
567
713
|
help='GRPC Proxy URL to use for connections (optional). '
|
|
568
714
|
'Can also use the environment variable "grcp_proxy=<ip>:<port>"',
|
|
569
715
|
)
|
|
716
|
+
p.add_argument(
|
|
717
|
+
'--header',
|
|
718
|
+
'-hdr',
|
|
719
|
+
action='append', # This allows multiple -H flags
|
|
720
|
+
type=str,
|
|
721
|
+
help='Headers to be sent on request (e.g., -hdr "Name: Value") - can be used multiple times',
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
# Syft options
|
|
725
|
+
for p in [p_cs, p_dep]:
|
|
726
|
+
p.add_argument(
|
|
727
|
+
'--syft-command',
|
|
728
|
+
type=str,
|
|
729
|
+
help='Syft command and path if required (optional - default syft).',
|
|
730
|
+
default=DEFAULT_SYFT_COMMAND,
|
|
731
|
+
)
|
|
732
|
+
p.add_argument(
|
|
733
|
+
'--syft-timeout',
|
|
734
|
+
type=int,
|
|
735
|
+
default=DEFAULT_SYFT_TIMEOUT,
|
|
736
|
+
help='Timeout (in seconds) for syft to complete (optional - default 600)',
|
|
737
|
+
)
|
|
570
738
|
|
|
571
739
|
# Help/Trace command options
|
|
572
740
|
for p in [
|
|
@@ -586,7 +754,10 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
586
754
|
p_results,
|
|
587
755
|
p_undeclared,
|
|
588
756
|
p_copyleft,
|
|
589
|
-
c_provenance
|
|
757
|
+
c_provenance,
|
|
758
|
+
p_folder_scan,
|
|
759
|
+
p_folder_hash,
|
|
760
|
+
p_cs,
|
|
590
761
|
]:
|
|
591
762
|
p.add_argument('--debug', '-d', action='store_true', help='Enable debug messages')
|
|
592
763
|
p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
|
|
@@ -599,8 +770,7 @@ def setup_args() -> None: # noqa: PLR0915
|
|
|
599
770
|
if not args.subparser:
|
|
600
771
|
parser.print_help() # No sub command subcommand, print general help
|
|
601
772
|
sys.exit(1)
|
|
602
|
-
elif (
|
|
603
|
-
args.subparser in {'utils', 'ut', 'component', 'comp', 'inspect', 'insp', 'ins'} and not args.subparsercmd):
|
|
773
|
+
elif (args.subparser in ('utils', 'ut', 'component', 'comp', 'inspect', 'insp', 'ins')) and not args.subparsercmd:
|
|
604
774
|
parser.parse_args([args.subparser, '--help']) # Force utils helps to be displayed
|
|
605
775
|
sys.exit(1)
|
|
606
776
|
args.func(parser, args) # Execute the function associated with the sub-command
|
|
@@ -684,7 +854,7 @@ def wfp(parser, args):
|
|
|
684
854
|
if not args.skip_settings_file:
|
|
685
855
|
scan_settings = ScanossSettings(debug=args.debug, trace=args.trace, quiet=args.quiet)
|
|
686
856
|
try:
|
|
687
|
-
scan_settings.load_json_file(args.settings)
|
|
857
|
+
scan_settings.load_json_file(args.settings, args.scan_dir)
|
|
688
858
|
except ScanossSettingsError as e:
|
|
689
859
|
print_stderr(f'Error: {e}')
|
|
690
860
|
sys.exit(1)
|
|
@@ -759,7 +929,7 @@ def get_scan_options(args):
|
|
|
759
929
|
return scan_options
|
|
760
930
|
|
|
761
931
|
|
|
762
|
-
def scan(parser, args):
|
|
932
|
+
def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
763
933
|
"""
|
|
764
934
|
Run the "scan" sub-command
|
|
765
935
|
Parameters
|
|
@@ -854,7 +1024,7 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
|
854
1024
|
if flags:
|
|
855
1025
|
print_stderr(f'Using flags {flags}...')
|
|
856
1026
|
elif not args.quiet:
|
|
857
|
-
if args.timeout <
|
|
1027
|
+
if args.timeout < MIN_TIMEOUT:
|
|
858
1028
|
print_stderr(f'POST timeout (--timeout) too small: {args.timeout}. Reverting to default.')
|
|
859
1029
|
if args.retry < 0:
|
|
860
1030
|
print_stderr(f'POST retry (--retry) too small: {args.retry}. Reverting to default.')
|
|
@@ -903,6 +1073,7 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
|
903
1073
|
strip_hpsm_ids=args.strip_hpsm,
|
|
904
1074
|
strip_snippet_ids=args.strip_snippet,
|
|
905
1075
|
scan_settings=scan_settings,
|
|
1076
|
+
req_headers=process_req_headers(args.header),
|
|
906
1077
|
)
|
|
907
1078
|
if args.wfp:
|
|
908
1079
|
if not scanner.is_file_or_snippet_scan():
|
|
@@ -972,12 +1143,18 @@ def dependency(parser, args):
|
|
|
972
1143
|
args: Namespace
|
|
973
1144
|
Parsed arguments
|
|
974
1145
|
"""
|
|
975
|
-
if not args.
|
|
976
|
-
print_stderr('Please specify a file/folder')
|
|
1146
|
+
if not args.scan_loc and not args.container:
|
|
1147
|
+
print_stderr('Please specify a file/folder or container image')
|
|
977
1148
|
parser.parse_args([args.subparser, '-h'])
|
|
978
1149
|
sys.exit(1)
|
|
979
|
-
|
|
980
|
-
|
|
1150
|
+
|
|
1151
|
+
# Workaround to return syft scan results converted to our dependency output format
|
|
1152
|
+
if args.container:
|
|
1153
|
+
args.scan_loc = args.container
|
|
1154
|
+
return container_scan(parser, args, only_interim_results=True)
|
|
1155
|
+
|
|
1156
|
+
if not os.path.exists(args.scan_loc):
|
|
1157
|
+
print_stderr(f'Error: File or folder specified does not exist: {args.scan_loc}.')
|
|
981
1158
|
sys.exit(1)
|
|
982
1159
|
scan_output: str = None
|
|
983
1160
|
if args.output:
|
|
@@ -987,7 +1164,7 @@ def dependency(parser, args):
|
|
|
987
1164
|
sc_deps = ScancodeDeps(
|
|
988
1165
|
debug=args.debug, quiet=args.quiet, trace=args.trace, sc_command=args.sc_command, timeout=args.sc_timeout
|
|
989
1166
|
)
|
|
990
|
-
if not sc_deps.get_dependencies(what_to_scan=args.
|
|
1167
|
+
if not sc_deps.get_dependencies(what_to_scan=args.scan_loc, result_output=scan_output):
|
|
991
1168
|
sys.exit(1)
|
|
992
1169
|
|
|
993
1170
|
|
|
@@ -1114,7 +1291,7 @@ def utils_certloc(*_):
|
|
|
1114
1291
|
print(f'CA Cert File: {certifi.where()}')
|
|
1115
1292
|
|
|
1116
1293
|
|
|
1117
|
-
def utils_cert_download(_, args):
|
|
1294
|
+
def utils_cert_download(_, args): # pylint: disable=PLR0912 # noqa: PLR0912
|
|
1118
1295
|
"""
|
|
1119
1296
|
Run the "utils cert-download" sub-command
|
|
1120
1297
|
:param _: ignore/unused
|
|
@@ -1141,13 +1318,14 @@ def utils_cert_download(_, args): # pylint: disable=PLR0912 # noqa: PLR0912
|
|
|
1141
1318
|
certs = conn.get_peer_cert_chain()
|
|
1142
1319
|
for index, cert in enumerate(certs):
|
|
1143
1320
|
cert_components = dict(cert.get_subject().get_components())
|
|
1144
|
-
if sys.version_info[0] >=
|
|
1321
|
+
if sys.version_info[0] >= PYTHON_MAJOR_VERSION:
|
|
1145
1322
|
cn = cert_components.get(b'CN')
|
|
1146
1323
|
else:
|
|
1324
|
+
# Fallback for Python versions less than PYTHON_MAJOR_VERSION
|
|
1147
1325
|
cn = cert_components.get('CN')
|
|
1148
1326
|
if not args.quiet:
|
|
1149
1327
|
print_stderr(f'Certificate {index} - CN: {cn}')
|
|
1150
|
-
if sys.version_info[0] >=
|
|
1328
|
+
if sys.version_info[0] >= PYTHON_MAJOR_VERSION:
|
|
1151
1329
|
print(
|
|
1152
1330
|
(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8')).strip(), file=file
|
|
1153
1331
|
) # Print the downloaded PEM certificate
|
|
@@ -1196,7 +1374,7 @@ def get_pac_file(pac: str):
|
|
|
1196
1374
|
if pac == 'auto':
|
|
1197
1375
|
pac_file = pypac.get_pac() # try to determine the PAC file
|
|
1198
1376
|
elif pac.startswith('file://'):
|
|
1199
|
-
pac_local = pac
|
|
1377
|
+
pac_local = pac[7:] # Remove 'file://' prefix (7 characters)
|
|
1200
1378
|
if not os.path.exists(pac_local):
|
|
1201
1379
|
print_stderr(f'Error: PAC file does not exist: {pac_local}.')
|
|
1202
1380
|
sys.exit(1)
|
|
@@ -1228,6 +1406,7 @@ def comp_crypto(parser, args):
|
|
|
1228
1406
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
1229
1407
|
sys.exit(1)
|
|
1230
1408
|
pac_file = get_pac_file(args.pac)
|
|
1409
|
+
|
|
1231
1410
|
comps = Components(
|
|
1232
1411
|
debug=args.debug,
|
|
1233
1412
|
trace=args.trace,
|
|
@@ -1239,6 +1418,7 @@ def comp_crypto(parser, args):
|
|
|
1239
1418
|
grpc_proxy=args.grpc_proxy,
|
|
1240
1419
|
pac=pac_file,
|
|
1241
1420
|
timeout=args.timeout,
|
|
1421
|
+
req_headers=process_req_headers(args.header),
|
|
1242
1422
|
)
|
|
1243
1423
|
if not comps.get_crypto_details(args.input, args.purl, args.output):
|
|
1244
1424
|
sys.exit(1)
|
|
@@ -1273,6 +1453,7 @@ def comp_vulns(parser, args):
|
|
|
1273
1453
|
grpc_proxy=args.grpc_proxy,
|
|
1274
1454
|
pac=pac_file,
|
|
1275
1455
|
timeout=args.timeout,
|
|
1456
|
+
req_headers=process_req_headers(args.header),
|
|
1276
1457
|
)
|
|
1277
1458
|
if not comps.get_vulnerabilities(args.input, args.purl, args.output):
|
|
1278
1459
|
sys.exit(1)
|
|
@@ -1307,6 +1488,7 @@ def comp_semgrep(parser, args):
|
|
|
1307
1488
|
grpc_proxy=args.grpc_proxy,
|
|
1308
1489
|
pac=pac_file,
|
|
1309
1490
|
timeout=args.timeout,
|
|
1491
|
+
req_headers=process_req_headers(args.header),
|
|
1310
1492
|
)
|
|
1311
1493
|
if not comps.get_semgrep_details(args.input, args.purl, args.output):
|
|
1312
1494
|
sys.exit(1)
|
|
@@ -1344,6 +1526,7 @@ def comp_search(parser, args):
|
|
|
1344
1526
|
grpc_proxy=args.grpc_proxy,
|
|
1345
1527
|
pac=pac_file,
|
|
1346
1528
|
timeout=args.timeout,
|
|
1529
|
+
req_headers=process_req_headers(args.header),
|
|
1347
1530
|
)
|
|
1348
1531
|
if not comps.search_components(
|
|
1349
1532
|
args.output,
|
|
@@ -1388,10 +1571,12 @@ def comp_versions(parser, args):
|
|
|
1388
1571
|
grpc_proxy=args.grpc_proxy,
|
|
1389
1572
|
pac=pac_file,
|
|
1390
1573
|
timeout=args.timeout,
|
|
1574
|
+
req_headers=process_req_headers(args.header),
|
|
1391
1575
|
)
|
|
1392
1576
|
if not comps.get_component_versions(args.output, json_file=args.input, purl=args.purl, limit=args.limit):
|
|
1393
1577
|
sys.exit(1)
|
|
1394
1578
|
|
|
1579
|
+
|
|
1395
1580
|
def comp_provenance(parser, args):
|
|
1396
1581
|
"""
|
|
1397
1582
|
Run the "component semgrep" sub-command
|
|
@@ -1410,12 +1595,23 @@ def comp_provenance(parser, args):
|
|
|
1410
1595
|
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
|
|
1411
1596
|
sys.exit(1)
|
|
1412
1597
|
pac_file = get_pac_file(args.pac)
|
|
1413
|
-
comps = Components(
|
|
1414
|
-
|
|
1415
|
-
|
|
1598
|
+
comps = Components(
|
|
1599
|
+
debug=args.debug,
|
|
1600
|
+
trace=args.trace,
|
|
1601
|
+
quiet=args.quiet,
|
|
1602
|
+
grpc_url=args.api2url,
|
|
1603
|
+
api_key=args.key,
|
|
1604
|
+
ca_cert=args.ca_cert,
|
|
1605
|
+
proxy=args.proxy,
|
|
1606
|
+
grpc_proxy=args.grpc_proxy,
|
|
1607
|
+
pac=pac_file,
|
|
1608
|
+
timeout=args.timeout,
|
|
1609
|
+
req_headers=process_req_headers(args.header),
|
|
1610
|
+
)
|
|
1416
1611
|
if not comps.get_provenance_details(args.input, args.purl, args.output):
|
|
1417
1612
|
sys.exit(1)
|
|
1418
1613
|
|
|
1614
|
+
|
|
1419
1615
|
def results(parser, args):
|
|
1420
1616
|
"""
|
|
1421
1617
|
Run the "results" sub-command
|
|
@@ -1456,6 +1652,153 @@ def results(parser, args):
|
|
|
1456
1652
|
results.apply_filters().present()
|
|
1457
1653
|
|
|
1458
1654
|
|
|
1655
|
+
def process_req_headers(headers_array: List[str]) -> dict:
|
|
1656
|
+
"""
|
|
1657
|
+
Process a list of header strings in the format "Name: Value" into a dictionary.
|
|
1658
|
+
|
|
1659
|
+
Args:
|
|
1660
|
+
headers_array (list): List of header strings from command line args
|
|
1661
|
+
|
|
1662
|
+
Returns:
|
|
1663
|
+
dict: Dictionary of header name-value pairs
|
|
1664
|
+
"""
|
|
1665
|
+
# Check if headers_array is empty
|
|
1666
|
+
if not headers_array:
|
|
1667
|
+
# Array is empty
|
|
1668
|
+
return {}
|
|
1669
|
+
|
|
1670
|
+
dict_headers = {}
|
|
1671
|
+
for header_str in headers_array:
|
|
1672
|
+
# Split each "Name: Value" header
|
|
1673
|
+
parts = header_str.split(':', 1)
|
|
1674
|
+
if len(parts) == HEADER_PARTS_COUNT:
|
|
1675
|
+
name = parts[0].strip()
|
|
1676
|
+
value = parts[1].strip()
|
|
1677
|
+
dict_headers[name] = value
|
|
1678
|
+
return dict_headers
|
|
1679
|
+
|
|
1680
|
+
|
|
1681
|
+
def folder_hashing_scan(parser, args):
|
|
1682
|
+
"""Run the "folder-scan" sub-command
|
|
1683
|
+
|
|
1684
|
+
Args:
|
|
1685
|
+
parser (ArgumentParser): command line parser object
|
|
1686
|
+
args (Namespace): Parsed arguments
|
|
1687
|
+
"""
|
|
1688
|
+
try:
|
|
1689
|
+
if not args.scan_dir:
|
|
1690
|
+
print_stderr('ERROR: Please specify a directory to scan')
|
|
1691
|
+
parser.parse_args([args.subparser, '-h'])
|
|
1692
|
+
sys.exit(1)
|
|
1693
|
+
|
|
1694
|
+
if not os.path.exists(args.scan_dir) or not os.path.isdir(args.scan_dir):
|
|
1695
|
+
print_stderr(f'ERROR: The specified directory {args.scan_dir} does not exist')
|
|
1696
|
+
sys.exit(1)
|
|
1697
|
+
|
|
1698
|
+
scanner_config = create_scanner_config_from_args(args)
|
|
1699
|
+
scanoss_settings = get_scanoss_settings_from_args(args)
|
|
1700
|
+
grpc_config = create_grpc_config_from_args(args)
|
|
1701
|
+
|
|
1702
|
+
client = ScanossGrpc(**asdict(grpc_config))
|
|
1703
|
+
|
|
1704
|
+
scanner = ScannerHFH(
|
|
1705
|
+
scan_dir=args.scan_dir,
|
|
1706
|
+
config=scanner_config,
|
|
1707
|
+
client=client,
|
|
1708
|
+
scanoss_settings=scanoss_settings,
|
|
1709
|
+
)
|
|
1710
|
+
|
|
1711
|
+
scanner.best_match = args.best_match
|
|
1712
|
+
scanner.threshold = args.threshold
|
|
1713
|
+
|
|
1714
|
+
scanner.scan()
|
|
1715
|
+
scanner.present(output_file=args.output, output_format=args.format)
|
|
1716
|
+
except ScanossGrpcError as e:
|
|
1717
|
+
print_stderr(f'ERROR: {e}')
|
|
1718
|
+
sys.exit(1)
|
|
1719
|
+
|
|
1720
|
+
|
|
1721
|
+
def folder_hash(parser, args):
|
|
1722
|
+
"""Run the "folder-hash" sub-command
|
|
1723
|
+
|
|
1724
|
+
Args:
|
|
1725
|
+
parser (ArgumentParser): command line parser object
|
|
1726
|
+
args (Namespace): Parsed arguments
|
|
1727
|
+
"""
|
|
1728
|
+
try:
|
|
1729
|
+
if not args.scan_dir:
|
|
1730
|
+
print_stderr('ERROR: Please specify a directory to scan')
|
|
1731
|
+
parser.parse_args([args.subparser, '-h'])
|
|
1732
|
+
sys.exit(1)
|
|
1733
|
+
|
|
1734
|
+
if not os.path.exists(args.scan_dir) or not os.path.isdir(args.scan_dir):
|
|
1735
|
+
print_stderr(f'ERROR: The specified directory {args.scan_dir} does not exist')
|
|
1736
|
+
sys.exit(1)
|
|
1737
|
+
|
|
1738
|
+
folder_hasher_config = create_folder_hasher_config_from_args(args)
|
|
1739
|
+
scanoss_settings = get_scanoss_settings_from_args(args)
|
|
1740
|
+
|
|
1741
|
+
folder_hasher = FolderHasher(
|
|
1742
|
+
scan_dir=args.scan_dir,
|
|
1743
|
+
config=folder_hasher_config,
|
|
1744
|
+
scanoss_settings=scanoss_settings,
|
|
1745
|
+
)
|
|
1746
|
+
|
|
1747
|
+
folder_hasher.hash_directory(args.scan_dir)
|
|
1748
|
+
folder_hasher.present(output_file=args.output, output_format=args.format)
|
|
1749
|
+
except Exception as e:
|
|
1750
|
+
print_stderr(f'ERROR: {e}')
|
|
1751
|
+
sys.exit(1)
|
|
1752
|
+
|
|
1753
|
+
|
|
1754
|
+
def container_scan(parser, args, only_interim_results: bool = False):
|
|
1755
|
+
"""
|
|
1756
|
+
Run the "container-scan" sub-command
|
|
1757
|
+
Parameters
|
|
1758
|
+
----------
|
|
1759
|
+
parser: ArgumentParser
|
|
1760
|
+
command line parser object
|
|
1761
|
+
args: Namespace
|
|
1762
|
+
Parsed arguments
|
|
1763
|
+
"""
|
|
1764
|
+
if not args.scan_loc:
|
|
1765
|
+
print_stderr(
|
|
1766
|
+
'Please specify a container image, Docker tar, OCI tar, OCI directory, SIF Container, or directory to scan'
|
|
1767
|
+
)
|
|
1768
|
+
parser.parse_args([args.subparser, '-h'])
|
|
1769
|
+
sys.exit(1)
|
|
1770
|
+
|
|
1771
|
+
try:
|
|
1772
|
+
config = create_container_scanner_config_from_args(args)
|
|
1773
|
+
config.only_interim_results = only_interim_results
|
|
1774
|
+
container_scanner = ContainerScanner(
|
|
1775
|
+
config=config,
|
|
1776
|
+
what_to_scan=args.scan_loc,
|
|
1777
|
+
)
|
|
1778
|
+
|
|
1779
|
+
container_scanner.scan()
|
|
1780
|
+
if only_interim_results:
|
|
1781
|
+
container_scanner.present(output_file=config.output, output_format='raw')
|
|
1782
|
+
else:
|
|
1783
|
+
container_scanner.decorate_scan_results_with_dependencies()
|
|
1784
|
+
container_scanner.present(output_file=config.output, output_format=config.format)
|
|
1785
|
+
except Exception as e:
|
|
1786
|
+
print_stderr(f'ERROR: {e}')
|
|
1787
|
+
sys.exit(1)
|
|
1788
|
+
|
|
1789
|
+
|
|
1790
|
+
def get_scanoss_settings_from_args(args):
|
|
1791
|
+
scanoss_settings = None
|
|
1792
|
+
if not args.skip_settings_file:
|
|
1793
|
+
scanoss_settings = ScanossSettings(debug=args.debug, trace=args.trace, quiet=args.quiet)
|
|
1794
|
+
try:
|
|
1795
|
+
scanoss_settings.load_json_file(args.settings, args.scan_dir).set_file_type('new').set_scan_type('identify')
|
|
1796
|
+
except ScanossSettingsError as e:
|
|
1797
|
+
print_stderr(f'Error: {e}')
|
|
1798
|
+
sys.exit(1)
|
|
1799
|
+
return scanoss_settings
|
|
1800
|
+
|
|
1801
|
+
|
|
1459
1802
|
def main():
|
|
1460
1803
|
"""
|
|
1461
1804
|
Run the ScanOSS CLI
|