Skip to content

feat: [SP-2400] - Create crypto sub command #117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 190 additions & 33 deletions src/scanoss/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import pypac

from scanoss.cryptography import Cryptography, create_cryptography_config_from_args
from scanoss.scanners.container_scanner import (
DEFAULT_SYFT_COMMAND,
DEFAULT_SYFT_TIMEOUT,
Expand All @@ -50,6 +51,7 @@
from . import __version__
from .components import Components
from .constants import (
DEFAULT_API_TIMEOUT,
DEFAULT_POST_SIZE,
DEFAULT_RETRY,
DEFAULT_TIMEOUT,
Expand Down Expand Up @@ -292,15 +294,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
help='component sub-commands',
)

# Component Sub-command: component crypto
c_crypto = comp_sub.add_parser(
'crypto',
aliases=['cr'],
description=f'Show Cryptographic algorithms: {__version__}',
help='Retrieve cryptographic algorithms for the given components',
)
c_crypto.set_defaults(func=comp_crypto)

# Component Sub-command: component vulns
c_vulns = comp_sub.add_parser(
'vulns',
Expand Down Expand Up @@ -361,18 +354,77 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
c_versions.add_argument('--limit', '-l', type=int, help='Generic component search')
c_versions.set_defaults(func=comp_versions)

# Sub-command: crypto
p_crypto = subparsers.add_parser(
'crypto',
aliases=['cr'],
description=f'SCANOSS Crypto commands: {__version__}',
help='Crypto support commands',
)
crypto_sub = p_crypto.add_subparsers(
title='Crypto Commands',
dest='subparsercmd',
description='crypto sub-commands',
help='crypto sub-commands',
required=True,
)

# GetAlgorithms and GetAlgorithmsInRange gRPC APIs
p_crypto_algorithms = crypto_sub.add_parser(
'algorithms',
aliases=['alg'],
description=f'Show Cryptographic algorithms: {__version__}',
help='Retrieve cryptographic algorithms for the given components',
)
p_crypto_algorithms.add_argument(
'--with-range',
action='store_true',
help='Returns the list of versions in the specified range that contains cryptographic algorithms',
)
p_crypto_algorithms.set_defaults(func=crypto_algorithms)

# GetEncryptionHints and GetHintsInRange gRPC APIs
p_crypto_hints = crypto_sub.add_parser(
'hints',
description=f'Show Encryption hints: {__version__}',
help='Retrieve encryption hints for the given components',
)
p_crypto_hints.add_argument(
'--with-range',
action='store_true',
help='Returns the list of versions in the specified range that contains encryption hints',
)
p_crypto_hints.set_defaults(func=crypto_hints)

p_crypto_versions_in_range = crypto_sub.add_parser(
'versions-in-range',
aliases=['vr'],
description=f'Show versions in range: {__version__}',
help="Given a list of PURLS and version ranges, get a list of versions that do/don't contain crypto algorithms",
)
p_crypto_versions_in_range.set_defaults(func=crypto_versions_in_range)

# Common purl Component sub-command options
for p in [c_crypto, c_vulns, c_semgrep, c_provenance]:
for p in [c_vulns, c_semgrep, c_provenance, p_crypto_algorithms, p_crypto_hints, p_crypto_versions_in_range]:
p.add_argument('--purl', '-p', type=str, nargs='*', help='Package URL - PURL to process.')
p.add_argument('--input', '-i', type=str, help='Input file name')

# Common Component sub-command options
for p in [c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance]:
for p in [
c_vulns,
c_search,
c_versions,
c_semgrep,
c_provenance,
p_crypto_algorithms,
p_crypto_hints,
p_crypto_versions_in_range,
]:
p.add_argument(
'--timeout',
'-M',
type=int,
default=600,
default=DEFAULT_API_TIMEOUT,
help='Timeout (in seconds) for API communication (optional - default 600)',
)

Expand Down Expand Up @@ -588,7 +640,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
p_dep,
p_fc,
p_cnv,
c_crypto,
c_vulns,
c_search,
c_versions,
Expand All @@ -597,6 +648,9 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
p_c_dwnld,
p_folder_scan,
p_folder_hash,
p_crypto_algorithms,
p_crypto_hints,
p_crypto_versions_in_range,
]:
p.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')

Expand Down Expand Up @@ -674,14 +728,16 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
# Global Scan/GRPC options
for p in [
p_scan,
c_crypto,
c_vulns,
c_search,
c_versions,
c_semgrep,
c_provenance,
p_folder_scan,
p_cs,
p_crypto_algorithms,
p_crypto_hints,
p_crypto_versions_in_range,
]:
p.add_argument(
'--key', '-k', type=str, help='SCANOSS API Key token (optional - not required for default OSSKB URL)'
Expand All @@ -708,7 +764,19 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
)

# Global GRPC options
for p in [p_scan, c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance, p_folder_scan, p_cs]:
for p in [
p_scan,
c_vulns,
c_search,
c_versions,
c_semgrep,
c_provenance,
p_folder_scan,
p_cs,
p_crypto_algorithms,
p_crypto_hints,
p_crypto_versions_in_range,
]:
p.add_argument(
'--api2url', type=str, help='SCANOSS gRPC API 2.0 URL (optional - default: https://api.osskb.org)'
)
Expand Down Expand Up @@ -751,7 +819,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
p_c_loc,
p_c_dwnld,
p_p_proxy,
c_crypto,
c_vulns,
c_search,
c_versions,
Expand All @@ -763,6 +830,9 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
p_folder_scan,
p_folder_hash,
p_cs,
p_crypto_algorithms,
p_crypto_hints,
p_crypto_versions_in_range,
]:
p.add_argument('--debug', '-d', action='store_true', help='Enable debug messages')
p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
Expand Down Expand Up @@ -1393,9 +1463,9 @@ def get_pac_file(pac: str):
return pac_file


def comp_crypto(parser, args):
def crypto_algorithms(parser, args):
"""
Run the "component crypto" sub-command
Run the "crypto algorithms" sub-command
Parameters
----------
parser: ArgumentParser
Expand All @@ -1410,22 +1480,109 @@ def comp_crypto(parser, args):
if args.ca_cert and not os.path.exists(args.ca_cert):
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
sys.exit(1)
pac_file = get_pac_file(args.pac)

comps = Components(
debug=args.debug,
trace=args.trace,
quiet=args.quiet,
grpc_url=args.api2url,
api_key=args.key,
ca_cert=args.ca_cert,
proxy=args.proxy,
grpc_proxy=args.grpc_proxy,
pac=pac_file,
timeout=args.timeout,
req_headers=process_req_headers(args.header),
)
if not comps.get_crypto_details(args.input, args.purl, args.output):
try:
config = create_cryptography_config_from_args(args)
grpc_config = create_grpc_config_from_args(args)
client = ScanossGrpc(**asdict(grpc_config))

# TODO: Add PAC file support
# pac_file = get_pac_file(config.pac)

cryptography = Cryptography(config=config, client=client)
cryptography.get_algorithms()
cryptography.present(output_file=args.output)
except ScanossGrpcError as e:
print_stderr(f'API ERROR: {e}')
sys.exit(1)
except Exception as e:
if args.debug:
import traceback

traceback.print_exc()
print_stderr(f'ERROR: {e}')
sys.exit(1)


def crypto_hints(parser, args):
"""
Run the "crypto hints" sub-command
Parameters
----------
parser: ArgumentParser
command line parser object
args: Namespace
Parsed arguments
"""
if (not args.purl and not args.input) or (args.purl and args.input):
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
sys.exit(1)
if args.ca_cert and not os.path.exists(args.ca_cert):
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
sys.exit(1)

try:
config = create_cryptography_config_from_args(args)
grpc_config = create_grpc_config_from_args(args)
client = ScanossGrpc(**asdict(grpc_config))

# TODO: Add PAC file support
# pac_file = get_pac_file(config.pac)

cryptography = Cryptography(config=config, client=client)
cryptography.get_encryption_hints()
cryptography.present(output_file=args.output)
except ScanossGrpcError as e:
print_stderr(f'API ERROR: {e}')
sys.exit(1)
except Exception as e:
if args.debug:
import traceback

traceback.print_exc()
print_stderr(f'ERROR: {e}')
sys.exit(1)


def crypto_versions_in_range(parser, args):
"""
Run the "crypto versions-in-range" sub-command
Parameters
----------
parser: ArgumentParser
command line parser object
args: Namespace
Parsed arguments
"""
if (not args.purl and not args.input) or (args.purl and args.input):
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
sys.exit(1)
if args.ca_cert and not os.path.exists(args.ca_cert):
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
sys.exit(1)

try:
config = create_cryptography_config_from_args(args)
grpc_config = create_grpc_config_from_args(args)
client = ScanossGrpc(**asdict(grpc_config))

# TODO: Add PAC file support
# pac_file = get_pac_file(config.pac)

cryptography = Cryptography(config=config, client=client)
cryptography.get_versions_in_range()
cryptography.present(output_file=args.output)
except ScanossGrpcError as e:
print_stderr(f'API ERROR: {e}')
sys.exit(1)
except Exception as e:
if args.debug:
import traceback

traceback.print_exc()
print_stderr(f'ERROR: {e}')
sys.exit(1)


Expand Down
2 changes: 2 additions & 0 deletions src/scanoss/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@

DEFAULT_URL = 'https://api.osskb.org' # default free service URL
DEFAULT_URL2 = 'https://api.scanoss.com' # default premium service URL

DEFAULT_API_TIMEOUT = 600
Loading