3131from .scancodedeps import ScancodeDeps
3232from .scantype import ScanType
3333from .filecount import FileCount
34+ from .cyclonedx import CycloneDx
35+ from .spdxlite import SpdxLite
36+ from .csvoutput import CsvOutput
3437from . 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+
400504def main ():
401505 """
402506 Run the ScanOSS CLI
0 commit comments