Skip to content

Commit 404f7e7

Browse files
committed
added convert, utils commands and proxy/cert support
1 parent f8432a3 commit 404f7e7

File tree

3 files changed

+120
-5
lines changed

3 files changed

+120
-5
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
### Added
1010
- Upcoming changes...
1111

12+
## [1.3.0] - 2022-12-02
13+
### Added
14+
- Added support for proxy (--proxy) and certificates (--ca-certs) while scanning
15+
- Certificates can also be supplied using environment variables: REQUESTS_CA_BUNDLE & GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
16+
- Proxies can be supplied using: grpc_proxy, https_proxy, http_proxy, HTTPS_PROXY, HTTP_PROXY
17+
- Added snippet match fields to CSV output
18+
- Added `convert` command to convert raw JSON reports into CSV, CycloneDX and SPDXLite
19+
- Added `utils certloc` sub-command to print the location of Python's CA Cert file
20+
- This is useful to know where to append custom certificates to if needed
21+
1222
## [1.2.3] - 2022-11-22
1323
### Added
1424
- Added Max Threaded scanning override env var (SCANOSS_MAX_ALLOWED_THREADS)
@@ -148,3 +158,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
148158
[1.2.1]: https://github.com/scanoss/scanoss.py/compare/v1.2.0...v1.2.1
149159
[1.2.2]: https://github.com/scanoss/scanoss.py/compare/v1.2.1...v1.2.2
150160
[1.2.3]: https://github.com/scanoss/scanoss.py/compare/v1.2.2...v1.2.3
161+
[1.3.0]: https://github.com/scanoss/scanoss.py/compare/v1.2.3...v1.3.0

src/scanoss/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@
2222
THE SOFTWARE.
2323
"""
2424

25-
__version__ = '1.2.3'
25+
__version__ = '1.3.0'

src/scanoss/cli.py

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
from .scancodedeps import ScancodeDeps
3232
from .scantype import ScanType
3333
from .filecount import FileCount
34+
from .cyclonedx import CycloneDx
35+
from .spdxlite import SpdxLite
36+
from .csvoutput import CsvOutput
3437
from . import __version__
3538

3639

@@ -46,6 +49,8 @@ def setup_args() -> None:
4649
Setup all the command line arguments for processing
4750
"""
4851
parser = argparse.ArgumentParser(description=f'SCANOSS Python CLI. Ver: {__version__}, License: MIT')
52+
parser.add_argument('--version', '-v', action='store_true', help='Display version details')
53+
4954
subparsers = parser.add_subparsers(title='Sub Commands', dest='subparser', description='valid subcommands',
5055
help='sub-command help'
5156
)
@@ -131,6 +136,35 @@ def setup_args() -> None:
131136
p_fc.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).' )
132137
p_fc.add_argument('--all-hidden', action='store_true', help='Scan all hidden files/folders')
133138

139+
# Sub-command: convert
140+
p_cnv = subparsers.add_parser('convert', aliases=['cv', 'cnv', 'cvrt'],
141+
description=f'Convert results files between formats: {__version__}',
142+
help='Convert file format')
143+
p_cnv.set_defaults(func=convert)
144+
p_cnv.add_argument('--input', '-i', type=str, required=True, help='Input file name')
145+
p_cnv.add_argument('--output','-o', type=str, help='Output result file name (optional - default stdout).' )
146+
p_cnv.add_argument('--format','-f', type=str, choices=['cyclonedx', 'spdxlite', 'csv'], default='spdxlite',
147+
help='Output format (optional - default: spdxlite)'
148+
)
149+
p_cnv.add_argument('--input-format', type=str, choices=['plain'], default='plain',
150+
help='Input format (optional - default: plain)'
151+
)
152+
153+
# Sub-command: utils
154+
p_util = subparsers.add_parser('utils', aliases=['ut', 'util'],
155+
description=f'SCANOSS Utility commands: {__version__}',
156+
help='General utility support commands')
157+
158+
utils_sub = p_util.add_subparsers(title='Utils Commands', dest='utilsubparser', description='utils sub-commands',
159+
help='utils sub-commands'
160+
)
161+
162+
# Utils Sub-command: utils certloc
163+
p_c_loc = utils_sub.add_parser('certloc', aliases=['cl'],
164+
description=f'Show location of Python CA Certs: {__version__}',
165+
help='Display the location of Python CA Certs')
166+
p_c_loc.set_defaults(func=utils_certloc)
167+
134168
# Global command options
135169
for p in [p_scan]:
136170
p.add_argument('--key', '-k', type=str,
@@ -142,16 +176,31 @@ def setup_args() -> None:
142176
p.add_argument('--api2url', type=str,
143177
help='SCANOSS gRPC API 2.0 URL (optional - default: https://api.osskb.org)'
144178
)
179+
p.add_argument('--proxy', type=str, help='Proxy URL to use for connections (optional). '
180+
'Can also use the environment variable "HTTPS_PROXY=<ip>:<port>" '
181+
'and "grcp_proxy=<ip>:<port>" for gRPC'
182+
)
183+
p.add_argument('--ca-cert', type=str, help='Alternative certificate PEM file (optional). '
184+
'Can also use the environment variable '
185+
'"REQUESTS_CA_BUNDLE=/path/to/cacert.pem" and '
186+
'"GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/path/to/cacert.pem" for gRPC'
187+
)
145188
p.add_argument('--ignore-cert-errors', action='store_true', help='Ignore certificate errors')
146189

147-
for p in [p_scan, p_wfp, p_dep, p_fc]:
190+
for p in [p_scan, p_wfp, p_dep, p_fc, p_cnv, p_c_loc]:
148191
p.add_argument('--debug', '-d', action='store_true', help='Enable debug messages')
149192
p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
150193
p.add_argument('--quiet', '-q', action='store_true', help='Enable quiet mode')
151194

152195
args = parser.parse_args()
196+
if args.version:
197+
ver(parser, args)
198+
exit(0)
153199
if not args.subparser:
154-
parser.print_help()
200+
parser.print_help() # No sub command subcommand, print general help
201+
exit(1)
202+
elif args.subparser == 'utils' and not args.utilsubparser: # No utils sub command supplied
203+
parser.parse_args([args.subparser, '--help']) # Force utils helps to be displayed
155204
exit(1)
156205
args.func(parser, args) # Execute the function associated with the sub-command
157206

@@ -326,14 +375,20 @@ def scan(parser, args):
326375
print_stderr(f'Changing scanning POST timeout to: {args.timeout}...')
327376
if args.obfuscate:
328377
print_stderr("Obfuscating file fingerprints...")
378+
if args.proxy:
379+
print_stderr(f'Using Proxy {arg.proxy}...')
380+
if args.ca_cert:
381+
print_stderr(f'Using Certificate {arg.ca_cert}...')
329382
elif not args.quiet:
330383
if args.timeout < 5:
331384
print_stderr(f'POST timeout (--timeout) too small: {args.timeout}. Reverting to default.')
332385

333386
if not os.access( os.getcwd(), os.W_OK ): # Make sure the current directory is writable. If not disable saving WFP
334387
print_stderr(f'Warning: Current directory is not writable: {os.getcwd()}')
335388
args.no_wfp_output = True
336-
389+
if args.ca_cert and not os.path.exists(args.ca_cert):
390+
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
391+
exit(1)
337392
scan_options = get_scan_options(args) # Figure out what scanning options we have
338393

339394
scanner = Scanner(debug=args.debug, trace=args.trace, quiet=args.quiet, api_key=args.key, url=args.apiurl,
@@ -342,7 +397,8 @@ def scan(parser, args):
342397
timeout=args.timeout, no_wfp_file=args.no_wfp_output, all_extensions=args.all_extensions,
343398
all_folders=args.all_folders, hidden_files_folders=args.all_hidden,
344399
scan_options=scan_options, sc_timeout=args.sc_timeout, sc_command=args.sc_command,
345-
grpc_url=args.api2url, obfuscate=args.obfuscate, ignore_cert_errors=args.ignore_cert_errors
400+
grpc_url=args.api2url, obfuscate=args.obfuscate,
401+
ignore_cert_errors=args.ignore_cert_errors, proxy=args.proxy, ca_cert=args.ca_cert
346402
)
347403
if args.wfp:
348404
if not scanner.is_file_or_snippet_scan():
@@ -397,6 +453,54 @@ def dependency(parser, args):
397453
if not sc_deps.get_dependencies(what_to_scan=args.scan_dir, result_output=scan_output):
398454
exit(1)
399455

456+
def convert(parser, args):
457+
"""
458+
Run the "convert" sub-command
459+
Parameters
460+
----------
461+
parser: ArgumentParser
462+
command line parser object
463+
args: Namespace
464+
Parsed arguments
465+
"""
466+
if not args.input:
467+
print_stderr('Please specify an input file to convert')
468+
parser.parse_args([args.subparser, '-h'])
469+
exit(1)
470+
success = False
471+
if args.format == 'cyclonedx':
472+
if not args.quiet:
473+
print_stderr(f'Producing CycloneDX report...')
474+
cdx = CycloneDx(debug=args.debug, output_file=args.output)
475+
success = cdx.produce_from_file(args.input)
476+
elif args.format == 'spdxlite':
477+
if not args.quiet:
478+
print_stderr(f'Producing SPDX Lite report...')
479+
spdxlite = SpdxLite(debug=args.debug, output_file=args.output)
480+
success = spdxlite.produce_from_file(args.input)
481+
elif args.format == 'csv':
482+
if not args.quiet:
483+
print_stderr(f'Producing CSV report...')
484+
csvo = CsvOutput(debug=args.debug, output_file=args.output)
485+
success = csvo.produce_from_file(args.input)
486+
else:
487+
print_stderr(f'ERROR: Unknown output format (--format): {args.format}')
488+
if not success:
489+
exit(1)
490+
491+
def utils_certloc(parser, args):
492+
"""
493+
Run the "utils certloc" sub-command
494+
Parameters
495+
----------
496+
parser: ArgumentParser
497+
command line parser object
498+
args: Namespace
499+
Parsed arguments
500+
"""
501+
import certifi
502+
print(f'CA Cert File: {certifi.where()}')
503+
400504
def main():
401505
"""
402506
Run the ScanOSS CLI

0 commit comments

Comments
 (0)