Skip to content

Commit 84ea3a4

Browse files
committed
Add get crypto hints and versions in range sub-commands
1 parent 75bc9bf commit 84ea3a4

File tree

3 files changed

+234
-9
lines changed

3 files changed

+234
-9
lines changed

src/scanoss/cli.py

Lines changed: 135 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,20 +377,49 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
377377
help='Retrieve cryptographic algorithms for the given components',
378378
)
379379
p_crypto_algorithms.add_argument(
380-
'--range',
381-
'-r',
382-
type=str,
380+
'--with-range',
381+
action='store_true',
383382
help='Returns the list of versions in the specified range that contains cryptographic algorithms',
384383
)
385384
p_crypto_algorithms.set_defaults(func=crypto_algorithms)
386385

386+
# GetEncryptionHints and GetHintsInRange gRPC APIs
387+
p_crypto_hints = crypto_sub.add_parser(
388+
'hints',
389+
description=f'Show Encryption hints: {__version__}',
390+
help='Retrieve encryption hints for the given components',
391+
)
392+
p_crypto_hints.add_argument(
393+
'--with-range',
394+
action='store_true',
395+
help='Returns the list of versions in the specified range that contains encryption hints',
396+
)
397+
p_crypto_hints.set_defaults(func=crypto_hints)
398+
399+
p_crypto_versions_in_range = crypto_sub.add_parser(
400+
'versions-in-range',
401+
aliases=['vr'],
402+
description=f'Show versions in range: {__version__}',
403+
help="Given a list of PURLS and version ranges, get a list of versions that do/don't contain crypto algorithms",
404+
)
405+
p_crypto_versions_in_range.set_defaults(func=crypto_versions_in_range)
406+
387407
# Common purl Component sub-command options
388-
for p in [c_vulns, c_semgrep, c_provenance, p_crypto_algorithms]:
408+
for p in [c_vulns, c_semgrep, c_provenance, p_crypto_algorithms, p_crypto_hints, p_crypto_versions_in_range]:
389409
p.add_argument('--purl', '-p', type=str, nargs='*', help='Package URL - PURL to process.')
390410
p.add_argument('--input', '-i', type=str, help='Input file name')
391411

392412
# Common Component sub-command options
393-
for p in [c_vulns, c_search, c_versions, c_semgrep, c_provenance, p_crypto_algorithms]:
413+
for p in [
414+
c_vulns,
415+
c_search,
416+
c_versions,
417+
c_semgrep,
418+
c_provenance,
419+
p_crypto_algorithms,
420+
p_crypto_hints,
421+
p_crypto_versions_in_range,
422+
]:
394423
p.add_argument(
395424
'--timeout',
396425
'-M',
@@ -620,6 +649,8 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
620649
p_folder_scan,
621650
p_folder_hash,
622651
p_crypto_algorithms,
652+
p_crypto_hints,
653+
p_crypto_versions_in_range,
623654
]:
624655
p.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
625656

@@ -705,6 +736,8 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
705736
p_folder_scan,
706737
p_cs,
707738
p_crypto_algorithms,
739+
p_crypto_hints,
740+
p_crypto_versions_in_range,
708741
]:
709742
p.add_argument(
710743
'--key', '-k', type=str, help='SCANOSS API Key token (optional - not required for default OSSKB URL)'
@@ -731,7 +764,19 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
731764
)
732765

733766
# Global GRPC options
734-
for p in [p_scan, c_vulns, c_search, c_versions, c_semgrep, c_provenance, p_folder_scan, p_cs, p_crypto_algorithms]:
767+
for p in [
768+
p_scan,
769+
c_vulns,
770+
c_search,
771+
c_versions,
772+
c_semgrep,
773+
c_provenance,
774+
p_folder_scan,
775+
p_cs,
776+
p_crypto_algorithms,
777+
p_crypto_hints,
778+
p_crypto_versions_in_range,
779+
]:
735780
p.add_argument(
736781
'--api2url', type=str, help='SCANOSS gRPC API 2.0 URL (optional - default: https://api.osskb.org)'
737782
)
@@ -786,6 +831,8 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
786831
p_folder_hash,
787832
p_cs,
788833
p_crypto_algorithms,
834+
p_crypto_hints,
835+
p_crypto_versions_in_range,
789836
]:
790837
p.add_argument('--debug', '-d', action='store_true', help='Enable debug messages')
791838
p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
@@ -1457,6 +1504,88 @@ def crypto_algorithms(parser, args):
14571504
sys.exit(1)
14581505

14591506

1507+
def crypto_hints(parser, args):
1508+
"""
1509+
Run the "crypto hints" sub-command
1510+
Parameters
1511+
----------
1512+
parser: ArgumentParser
1513+
command line parser object
1514+
args: Namespace
1515+
Parsed arguments
1516+
"""
1517+
if (not args.purl and not args.input) or (args.purl and args.input):
1518+
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
1519+
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
1520+
sys.exit(1)
1521+
if args.ca_cert and not os.path.exists(args.ca_cert):
1522+
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
1523+
sys.exit(1)
1524+
1525+
try:
1526+
config = create_cryptography_config_from_args(args)
1527+
grpc_config = create_grpc_config_from_args(args)
1528+
client = ScanossGrpc(**asdict(grpc_config))
1529+
1530+
# TODO: Add PAC file support
1531+
# pac_file = get_pac_file(config.pac)
1532+
1533+
cryptography = Cryptography(config=config, client=client)
1534+
cryptography.get_encryption_hints()
1535+
cryptography.present(output_file=args.output)
1536+
except ScanossGrpcError as e:
1537+
print_stderr(f'API ERROR: {e}')
1538+
sys.exit(1)
1539+
except Exception as e:
1540+
if args.debug:
1541+
import traceback
1542+
1543+
traceback.print_exc()
1544+
print_stderr(f'ERROR: {e}')
1545+
sys.exit(1)
1546+
1547+
1548+
def crypto_versions_in_range(parser, args):
1549+
"""
1550+
Run the "crypto versions-in-range" sub-command
1551+
Parameters
1552+
----------
1553+
parser: ArgumentParser
1554+
command line parser object
1555+
args: Namespace
1556+
Parsed arguments
1557+
"""
1558+
if (not args.purl and not args.input) or (args.purl and args.input):
1559+
print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
1560+
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
1561+
sys.exit(1)
1562+
if args.ca_cert and not os.path.exists(args.ca_cert):
1563+
print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
1564+
sys.exit(1)
1565+
1566+
try:
1567+
config = create_cryptography_config_from_args(args)
1568+
grpc_config = create_grpc_config_from_args(args)
1569+
client = ScanossGrpc(**asdict(grpc_config))
1570+
1571+
# TODO: Add PAC file support
1572+
# pac_file = get_pac_file(config.pac)
1573+
1574+
cryptography = Cryptography(config=config, client=client)
1575+
cryptography.get_versions_in_range()
1576+
cryptography.present(output_file=args.output)
1577+
except ScanossGrpcError as e:
1578+
print_stderr(f'API ERROR: {e}')
1579+
sys.exit(1)
1580+
except Exception as e:
1581+
if args.debug:
1582+
import traceback
1583+
1584+
traceback.print_exc()
1585+
print_stderr(f'ERROR: {e}')
1586+
sys.exit(1)
1587+
1588+
14601589
def comp_vulns(parser, args):
14611590
"""
14621591
Run the "component vulns" sub-command

src/scanoss/cryptography.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class CryptographyConfig:
1717
debug: bool = False
1818
trace: bool = False
1919
quiet: bool = False
20-
get_range: bool = False
20+
with_range: bool = False
2121
purl: List[str] = None
2222
input_file: str = None
2323
output_file: str = None
@@ -29,7 +29,7 @@ def create_cryptography_config_from_args(args) -> CryptographyConfig:
2929
debug=getattr(args, 'debug', None),
3030
trace=getattr(args, 'trace', None),
3131
quiet=getattr(args, 'quiet', None),
32-
get_range=getattr(args, 'range', None),
32+
with_range=getattr(args, 'with_range', None),
3333
purl=getattr(args, 'purl', None),
3434
input_file=getattr(args, 'input', None),
3535
output_file=getattr(args, 'output', None),
@@ -86,7 +86,7 @@ def get_algorithms(self) -> Optional[Dict]:
8686
self.base.print_stderr(
8787
f'Getting cryptographic algorithms for {", ".join([p["purl"] for p in self.purls_request["purls"]])}'
8888
)
89-
if self.config.get_range:
89+
if self.config.with_range:
9090
response = self.client.get_crypto_algorithms_in_range_for_purl(self.purls_request)
9191
else:
9292
response = self.client.get_crypto_algorithms_for_purl(self.purls_request)
@@ -95,6 +95,51 @@ def get_algorithms(self) -> Optional[Dict]:
9595

9696
return self.results
9797

98+
def get_encryption_hints(self) -> Optional[Dict]:
99+
"""
100+
Get the encryption hints for the provided purl or input file.
101+
102+
Returns:
103+
Optional[Dict]: The encryption hints response from the gRPC client, or None if an error occurs.
104+
"""
105+
106+
if not self.purls_request:
107+
raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
108+
self.base.print_stderr(
109+
f'Getting encryption hints '
110+
f'{"in range" if self.config.with_range else ""} '
111+
f'for {", ".join([p["purl"] for p in self.purls_request["purls"]])}'
112+
)
113+
if self.config.with_range:
114+
response = self.client.get_encryption_hints_in_range_for_purl(self.purls_request)
115+
else:
116+
response = self.client.get_encryption_hints_for_purl(self.purls_request)
117+
if response:
118+
self.results = response
119+
120+
return self.results
121+
122+
def get_versions_in_range(self) -> Optional[Dict]:
123+
"""
124+
Given a list of PURLS and version ranges, get a list of versions that do/do not contain cryptographic algorithms
125+
126+
Returns:
127+
Optional[Dict]: The versions in range response from the gRPC client, or None if an error occurs.
128+
"""
129+
130+
if not self.purls_request:
131+
raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
132+
133+
self.base.print_stderr(
134+
f'Getting versions in range for {", ".join([p["purl"] for p in self.purls_request["purls"]])}'
135+
)
136+
137+
response = self.client.get_versions_in_range_for_purl(self.purls_request)
138+
if response:
139+
self.results = response
140+
141+
return self.results
142+
98143
def _build_purls_request(
99144
self,
100145
) -> Optional[dict]:

src/scanoss/scanossgrpc.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,57 @@ def get_crypto_algorithms_in_range_for_purl(self, request: Dict) -> Optional[Dic
610610
'Sending data for cryptographic algorithms in range decoration (rqId: {rqId})...',
611611
)
612612

613+
def get_encryption_hints_for_purl(self, request: Dict) -> Optional[Dict]:
614+
"""
615+
Client function to call the rpc for GetEncryptionHints for a list of purls
616+
617+
Args:
618+
request (Dict): PurlRequest
619+
620+
Returns:
621+
Optional[Dict]: HintsResponse, or None if the request was not successfull
622+
"""
623+
return self._call_rpc(
624+
self.crypto_stub.GetEncryptionHints,
625+
request,
626+
PurlRequest,
627+
'Sending data for encryption hints decoration (rqId: {rqId})...',
628+
)
629+
630+
def get_encryption_hints_in_range_for_purl(self, request: Dict) -> Optional[Dict]:
631+
"""
632+
Client function to call the rpc for GetHintsInRange for a list of purls
633+
634+
Args:
635+
request (Dict): PurlRequest
636+
637+
Returns:
638+
Optional[Dict]: HintsInRangeResponse, or None if the request was not successfull
639+
"""
640+
return self._call_rpc(
641+
self.crypto_stub.GetHintsInRange,
642+
request,
643+
PurlRequest,
644+
'Sending data for encryption hints in range decoration (rqId: {rqId})...',
645+
)
646+
647+
def get_versions_in_range_for_purl(self, request: Dict) -> Optional[Dict]:
648+
"""
649+
Client function to call the rpc for GetVersionsInRange for a list of purls
650+
651+
Args:
652+
request (Dict): PurlRequest
653+
654+
Returns:
655+
Optional[Dict]: VersionsInRangeResponse, or None if the request was not successfull
656+
"""
657+
return self._call_rpc(
658+
self.crypto_stub.GetVersionsInRange,
659+
request,
660+
PurlRequest,
661+
'Sending data for cryptographic versions in range decoration (rqId: {rqId})...',
662+
)
663+
613664
def load_generic_headers(self):
614665
"""
615666
Adds custom headers from req_headers to metadata.

0 commit comments

Comments
 (0)