scanoss 1.23.0__tar.gz → 1.25.0__tar.gz

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.
Files changed (98) hide show
  1. {scanoss-1.23.0/src/scanoss.egg-info → scanoss-1.25.0}/PKG-INFO +1 -1
  2. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/__init__.py +1 -1
  3. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/cli.py +195 -34
  4. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/constants.py +2 -0
  5. scanoss-1.25.0/src/scanoss/cryptography.py +274 -0
  6. scanoss-1.25.0/src/scanoss/data/build_date.txt +1 -0
  7. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/inspection/policy_check.py +77 -47
  8. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanossgrpc.py +87 -33
  9. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/utils/file.py +2 -2
  10. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/winnowing.py +64 -7
  11. {scanoss-1.23.0 → scanoss-1.25.0/src/scanoss.egg-info}/PKG-INFO +1 -1
  12. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss.egg-info/SOURCES.txt +1 -0
  13. scanoss-1.25.0/tests/test_winnowing.py +393 -0
  14. scanoss-1.23.0/src/scanoss/data/build_date.txt +0 -1
  15. scanoss-1.23.0/tests/test_winnowing.py +0 -82
  16. {scanoss-1.23.0 → scanoss-1.25.0}/LICENSE +0 -0
  17. {scanoss-1.23.0 → scanoss-1.25.0}/PACKAGE.md +0 -0
  18. {scanoss-1.23.0 → scanoss-1.25.0}/README.md +0 -0
  19. {scanoss-1.23.0 → scanoss-1.25.0}/pyproject.toml +0 -0
  20. {scanoss-1.23.0 → scanoss-1.25.0}/setup.cfg +0 -0
  21. {scanoss-1.23.0 → scanoss-1.25.0}/src/protoc_gen_swagger/__init__.py +0 -0
  22. {scanoss-1.23.0 → scanoss-1.25.0}/src/protoc_gen_swagger/options/__init__.py +0 -0
  23. {scanoss-1.23.0 → scanoss-1.25.0}/src/protoc_gen_swagger/options/annotations_pb2.py +0 -0
  24. {scanoss-1.23.0 → scanoss-1.25.0}/src/protoc_gen_swagger/options/annotations_pb2_grpc.py +0 -0
  25. {scanoss-1.23.0 → scanoss-1.25.0}/src/protoc_gen_swagger/options/openapiv2_pb2.py +0 -0
  26. {scanoss-1.23.0 → scanoss-1.25.0}/src/protoc_gen_swagger/options/openapiv2_pb2_grpc.py +0 -0
  27. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/__init__.py +0 -0
  28. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/common/__init__.py +0 -0
  29. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/common/v2/__init__.py +0 -0
  30. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/common/v2/scanoss_common_pb2.py +0 -0
  31. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/common/v2/scanoss_common_pb2_grpc.py +0 -0
  32. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/components/__init__.py +0 -0
  33. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/components/v2/__init__.py +0 -0
  34. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/components/v2/scanoss_components_pb2.py +0 -0
  35. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/components/v2/scanoss_components_pb2_grpc.py +0 -0
  36. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2.py +0 -0
  37. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/cryptography/v2/scanoss_cryptography_pb2_grpc.py +0 -0
  38. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/dependencies/__init__.py +0 -0
  39. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/dependencies/v2/__init__.py +0 -0
  40. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2.py +0 -0
  41. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/dependencies/v2/scanoss_dependencies_pb2_grpc.py +0 -0
  42. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/geoprovenance/__init__.py +0 -0
  43. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/geoprovenance/v2/__init__.py +0 -0
  44. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2.py +0 -0
  45. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/geoprovenance/v2/scanoss_geoprovenance_pb2_grpc.py +0 -0
  46. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/scanning/__init__.py +0 -0
  47. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/scanning/v2/__init__.py +0 -0
  48. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2.py +0 -0
  49. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/scanning/v2/scanoss_scanning_pb2_grpc.py +0 -0
  50. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/semgrep/__init__.py +0 -0
  51. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/semgrep/v2/__init__.py +0 -0
  52. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2.py +0 -0
  53. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/semgrep/v2/scanoss_semgrep_pb2_grpc.py +0 -0
  54. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/vulnerabilities/__init__.py +0 -0
  55. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/vulnerabilities/v2/__init__.py +0 -0
  56. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2.py +0 -0
  57. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/api/vulnerabilities/v2/scanoss_vulnerabilities_pb2_grpc.py +0 -0
  58. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/components.py +0 -0
  59. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/csvoutput.py +0 -0
  60. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/cyclonedx.py +0 -0
  61. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/data/scanoss-settings-schema.json +0 -0
  62. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/data/spdx-exceptions.json +0 -0
  63. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/data/spdx-licenses.json +0 -0
  64. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/file_filters.py +0 -0
  65. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/filecount.py +0 -0
  66. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/inspection/__init__.py +0 -0
  67. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/inspection/copyleft.py +0 -0
  68. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/inspection/undeclared_component.py +0 -0
  69. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/inspection/utils/license_utils.py +0 -0
  70. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/results.py +0 -0
  71. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scancodedeps.py +0 -0
  72. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanner.py +0 -0
  73. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanners/__init__.py +0 -0
  74. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanners/container_scanner.py +0 -0
  75. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanners/folder_hasher.py +0 -0
  76. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanners/scanner_config.py +0 -0
  77. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanners/scanner_hfh.py +0 -0
  78. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanoss_settings.py +0 -0
  79. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanossapi.py +0 -0
  80. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanossbase.py +0 -0
  81. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scanpostprocessor.py +0 -0
  82. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/scantype.py +0 -0
  83. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/spdxlite.py +0 -0
  84. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/threadeddependencies.py +0 -0
  85. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/threadedscanning.py +0 -0
  86. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/utils/__init__.py +0 -0
  87. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/utils/abstract_presenter.py +0 -0
  88. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/utils/crc64.py +0 -0
  89. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss/utils/simhash.py +0 -0
  90. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss.egg-info/dependency_links.txt +0 -0
  91. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss.egg-info/entry_points.txt +0 -0
  92. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss.egg-info/requires.txt +0 -0
  93. {scanoss-1.23.0 → scanoss-1.25.0}/src/scanoss.egg-info/top_level.txt +0 -0
  94. {scanoss-1.23.0 → scanoss-1.25.0}/tests/test_csv_output.py +0 -0
  95. {scanoss-1.23.0 → scanoss-1.25.0}/tests/test_file_filters.py +0 -0
  96. {scanoss-1.23.0 → scanoss-1.25.0}/tests/test_policy_inspect.py +0 -0
  97. {scanoss-1.23.0 → scanoss-1.25.0}/tests/test_scan_post_processor.py +0 -0
  98. {scanoss-1.23.0 → scanoss-1.25.0}/tests/test_spdxlite.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scanoss
3
- Version: 1.23.0
3
+ Version: 1.25.0
4
4
  Summary: Simple Python library to leverage the SCANOSS APIs
5
5
  Home-page: https://scanoss.com
6
6
  Author: SCANOSS
@@ -22,4 +22,4 @@ SPDX-License-Identifier: MIT
22
22
  THE SOFTWARE.
23
23
  """
24
24
 
25
- __version__ = '1.23.0'
25
+ __version__ = '1.25.0'
@@ -31,6 +31,7 @@ from typing import List
31
31
 
32
32
  import pypac
33
33
 
34
+ from scanoss.cryptography import Cryptography, create_cryptography_config_from_args
34
35
  from scanoss.scanners.container_scanner import (
35
36
  DEFAULT_SYFT_COMMAND,
36
37
  DEFAULT_SYFT_TIMEOUT,
@@ -50,6 +51,7 @@ from scanoss.scanossgrpc import (
50
51
  from . import __version__
51
52
  from .components import Components
52
53
  from .constants import (
54
+ DEFAULT_API_TIMEOUT,
53
55
  DEFAULT_POST_SIZE,
54
56
  DEFAULT_RETRY,
55
57
  DEFAULT_TIMEOUT,
@@ -292,15 +294,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
292
294
  help='component sub-commands',
293
295
  )
294
296
 
295
- # Component Sub-command: component crypto
296
- c_crypto = comp_sub.add_parser(
297
- 'crypto',
298
- aliases=['cr'],
299
- description=f'Show Cryptographic algorithms: {__version__}',
300
- help='Retrieve cryptographic algorithms for the given components',
301
- )
302
- c_crypto.set_defaults(func=comp_crypto)
303
-
304
297
  # Component Sub-command: component vulns
305
298
  c_vulns = comp_sub.add_parser(
306
299
  'vulns',
@@ -361,18 +354,76 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
361
354
  c_versions.add_argument('--limit', '-l', type=int, help='Generic component search')
362
355
  c_versions.set_defaults(func=comp_versions)
363
356
 
357
+ # Sub-command: crypto
358
+ p_crypto = subparsers.add_parser(
359
+ 'crypto',
360
+ aliases=['cr'],
361
+ description=f'SCANOSS Crypto commands: {__version__}',
362
+ help='Crypto support commands',
363
+ )
364
+ crypto_sub = p_crypto.add_subparsers(
365
+ title='Crypto Commands',
366
+ dest='subparsercmd',
367
+ description='crypto sub-commands',
368
+ help='crypto sub-commands',
369
+ )
370
+
371
+ # GetAlgorithms and GetAlgorithmsInRange gRPC APIs
372
+ p_crypto_algorithms = crypto_sub.add_parser(
373
+ 'algorithms',
374
+ aliases=['alg'],
375
+ description=f'Show Cryptographic algorithms: {__version__}',
376
+ help='Retrieve cryptographic algorithms for the given components',
377
+ )
378
+ p_crypto_algorithms.add_argument(
379
+ '--with-range',
380
+ action='store_true',
381
+ help='Returns the list of versions in the specified range that contains cryptographic algorithms',
382
+ )
383
+ p_crypto_algorithms.set_defaults(func=crypto_algorithms)
384
+
385
+ # GetEncryptionHints and GetHintsInRange gRPC APIs
386
+ p_crypto_hints = crypto_sub.add_parser(
387
+ 'hints',
388
+ description=f'Show Encryption hints: {__version__}',
389
+ help='Retrieve encryption hints for the given components',
390
+ )
391
+ p_crypto_hints.add_argument(
392
+ '--with-range',
393
+ action='store_true',
394
+ help='Returns the list of versions in the specified range that contains encryption hints',
395
+ )
396
+ p_crypto_hints.set_defaults(func=crypto_hints)
397
+
398
+ p_crypto_versions_in_range = crypto_sub.add_parser(
399
+ 'versions-in-range',
400
+ aliases=['vr'],
401
+ description=f'Show versions in range: {__version__}',
402
+ help="Given a list of PURLS and version ranges, get a list of versions that do/don't contain crypto algorithms",
403
+ )
404
+ p_crypto_versions_in_range.set_defaults(func=crypto_versions_in_range)
405
+
364
406
  # Common purl Component sub-command options
365
- for p in [c_crypto, c_vulns, c_semgrep, c_provenance]:
407
+ for p in [c_vulns, c_semgrep, c_provenance, p_crypto_algorithms, p_crypto_hints, p_crypto_versions_in_range]:
366
408
  p.add_argument('--purl', '-p', type=str, nargs='*', help='Package URL - PURL to process.')
367
409
  p.add_argument('--input', '-i', type=str, help='Input file name')
368
410
 
369
411
  # Common Component sub-command options
370
- for p in [c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance]:
412
+ for p in [
413
+ c_vulns,
414
+ c_search,
415
+ c_versions,
416
+ c_semgrep,
417
+ c_provenance,
418
+ p_crypto_algorithms,
419
+ p_crypto_hints,
420
+ p_crypto_versions_in_range,
421
+ ]:
371
422
  p.add_argument(
372
423
  '--timeout',
373
424
  '-M',
374
425
  type=int,
375
- default=600,
426
+ default=DEFAULT_API_TIMEOUT,
376
427
  help='Timeout (in seconds) for API communication (optional - default 600)',
377
428
  )
378
429
 
@@ -588,7 +639,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
588
639
  p_dep,
589
640
  p_fc,
590
641
  p_cnv,
591
- c_crypto,
592
642
  c_vulns,
593
643
  c_search,
594
644
  c_versions,
@@ -597,6 +647,9 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
597
647
  p_c_dwnld,
598
648
  p_folder_scan,
599
649
  p_folder_hash,
650
+ p_crypto_algorithms,
651
+ p_crypto_hints,
652
+ p_crypto_versions_in_range,
600
653
  ]:
601
654
  p.add_argument('--output', '-o', type=str, help='Output result file name (optional - default stdout).')
602
655
 
@@ -674,7 +727,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
674
727
  # Global Scan/GRPC options
675
728
  for p in [
676
729
  p_scan,
677
- c_crypto,
678
730
  c_vulns,
679
731
  c_search,
680
732
  c_versions,
@@ -682,6 +734,9 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
682
734
  c_provenance,
683
735
  p_folder_scan,
684
736
  p_cs,
737
+ p_crypto_algorithms,
738
+ p_crypto_hints,
739
+ p_crypto_versions_in_range,
685
740
  ]:
686
741
  p.add_argument(
687
742
  '--key', '-k', type=str, help='SCANOSS API Key token (optional - not required for default OSSKB URL)'
@@ -708,7 +763,19 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
708
763
  )
709
764
 
710
765
  # Global GRPC options
711
- for p in [p_scan, c_crypto, c_vulns, c_search, c_versions, c_semgrep, c_provenance, p_folder_scan, p_cs]:
766
+ for p in [
767
+ p_scan,
768
+ c_vulns,
769
+ c_search,
770
+ c_versions,
771
+ c_semgrep,
772
+ c_provenance,
773
+ p_folder_scan,
774
+ p_cs,
775
+ p_crypto_algorithms,
776
+ p_crypto_hints,
777
+ p_crypto_versions_in_range,
778
+ ]:
712
779
  p.add_argument(
713
780
  '--api2url', type=str, help='SCANOSS gRPC API 2.0 URL (optional - default: https://api.osskb.org)'
714
781
  )
@@ -751,7 +818,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
751
818
  p_c_loc,
752
819
  p_c_dwnld,
753
820
  p_p_proxy,
754
- c_crypto,
755
821
  c_vulns,
756
822
  c_search,
757
823
  c_versions,
@@ -763,6 +829,9 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
763
829
  p_folder_scan,
764
830
  p_folder_hash,
765
831
  p_cs,
832
+ p_crypto_algorithms,
833
+ p_crypto_hints,
834
+ p_crypto_versions_in_range,
766
835
  ]:
767
836
  p.add_argument('--debug', '-d', action='store_true', help='Enable debug messages')
768
837
  p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
@@ -775,7 +844,9 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
775
844
  if not args.subparser:
776
845
  parser.print_help() # No sub command subcommand, print general help
777
846
  sys.exit(1)
778
- elif (args.subparser in ('utils', 'ut', 'component', 'comp', 'inspect', 'insp', 'ins')) and not args.subparsercmd:
847
+ elif (
848
+ args.subparser in ('utils', 'ut', 'component', 'comp', 'inspect', 'insp', 'ins', 'crypto', 'cr')
849
+ ) and not args.subparsercmd:
779
850
  parser.parse_args([args.subparser, '--help']) # Force utils helps to be displayed
780
851
  sys.exit(1)
781
852
  args.func(parser, args) # Execute the function associated with the sub-command
@@ -1393,9 +1464,9 @@ def get_pac_file(pac: str):
1393
1464
  return pac_file
1394
1465
 
1395
1466
 
1396
- def comp_crypto(parser, args):
1467
+ def crypto_algorithms(parser, args):
1397
1468
  """
1398
- Run the "component crypto" sub-command
1469
+ Run the "crypto algorithms" sub-command
1399
1470
  Parameters
1400
1471
  ----------
1401
1472
  parser: ArgumentParser
@@ -1410,22 +1481,112 @@ def comp_crypto(parser, args):
1410
1481
  if args.ca_cert and not os.path.exists(args.ca_cert):
1411
1482
  print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
1412
1483
  sys.exit(1)
1413
- pac_file = get_pac_file(args.pac)
1414
1484
 
1415
- comps = Components(
1416
- debug=args.debug,
1417
- trace=args.trace,
1418
- quiet=args.quiet,
1419
- grpc_url=args.api2url,
1420
- api_key=args.key,
1421
- ca_cert=args.ca_cert,
1422
- proxy=args.proxy,
1423
- grpc_proxy=args.grpc_proxy,
1424
- pac=pac_file,
1425
- timeout=args.timeout,
1426
- req_headers=process_req_headers(args.header),
1427
- )
1428
- if not comps.get_crypto_details(args.input, args.purl, args.output):
1485
+ try:
1486
+ config = create_cryptography_config_from_args(args)
1487
+ grpc_config = create_grpc_config_from_args(args)
1488
+ if args.pac:
1489
+ grpc_config.pac = get_pac_file(args.pac)
1490
+ if args.header:
1491
+ grpc_config.req_headers = process_req_headers(args.header)
1492
+ client = ScanossGrpc(**asdict(grpc_config))
1493
+
1494
+ cryptography = Cryptography(config=config, client=client)
1495
+ cryptography.get_algorithms()
1496
+ cryptography.present(output_file=args.output)
1497
+ except ScanossGrpcError as e:
1498
+ print_stderr(f'API ERROR: {e}')
1499
+ sys.exit(1)
1500
+ except Exception as e:
1501
+ if args.debug:
1502
+ import traceback
1503
+
1504
+ traceback.print_exc()
1505
+ print_stderr(f'ERROR: {e}')
1506
+ sys.exit(1)
1507
+
1508
+
1509
+ def crypto_hints(parser, args):
1510
+ """
1511
+ Run the "crypto hints" sub-command
1512
+ Parameters
1513
+ ----------
1514
+ parser: ArgumentParser
1515
+ command line parser object
1516
+ args: Namespace
1517
+ Parsed arguments
1518
+ """
1519
+ if (not args.purl and not args.input) or (args.purl and args.input):
1520
+ print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
1521
+ parser.parse_args([args.subparser, args.subparsercmd, '-h'])
1522
+ sys.exit(1)
1523
+ if args.ca_cert and not os.path.exists(args.ca_cert):
1524
+ print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
1525
+ sys.exit(1)
1526
+
1527
+ try:
1528
+ config = create_cryptography_config_from_args(args)
1529
+ grpc_config = create_grpc_config_from_args(args)
1530
+ if args.pac:
1531
+ grpc_config.pac = get_pac_file(args.pac)
1532
+ if args.header:
1533
+ grpc_config.req_headers = process_req_headers(args.header)
1534
+ client = ScanossGrpc(**asdict(grpc_config))
1535
+
1536
+ cryptography = Cryptography(config=config, client=client)
1537
+ cryptography.get_encryption_hints()
1538
+ cryptography.present(output_file=args.output)
1539
+ except ScanossGrpcError as e:
1540
+ print_stderr(f'API ERROR: {e}')
1541
+ sys.exit(1)
1542
+ except Exception as e:
1543
+ if args.debug:
1544
+ import traceback
1545
+
1546
+ traceback.print_exc()
1547
+ print_stderr(f'ERROR: {e}')
1548
+ sys.exit(1)
1549
+
1550
+
1551
+ def crypto_versions_in_range(parser, args):
1552
+ """
1553
+ Run the "crypto versions-in-range" sub-command
1554
+ Parameters
1555
+ ----------
1556
+ parser: ArgumentParser
1557
+ command line parser object
1558
+ args: Namespace
1559
+ Parsed arguments
1560
+ """
1561
+ if (not args.purl and not args.input) or (args.purl and args.input):
1562
+ print_stderr('Please specify an input file or purl to decorate (--purl or --input)')
1563
+ parser.parse_args([args.subparser, args.subparsercmd, '-h'])
1564
+ sys.exit(1)
1565
+ if args.ca_cert and not os.path.exists(args.ca_cert):
1566
+ print_stderr(f'Error: Certificate file does not exist: {args.ca_cert}.')
1567
+ sys.exit(1)
1568
+
1569
+ try:
1570
+ config = create_cryptography_config_from_args(args)
1571
+ grpc_config = create_grpc_config_from_args(args)
1572
+ if args.pac:
1573
+ grpc_config.pac = get_pac_file(args.pac)
1574
+ if args.header:
1575
+ grpc_config.req_headers = process_req_headers(args.header)
1576
+ client = ScanossGrpc(**asdict(grpc_config))
1577
+
1578
+ cryptography = Cryptography(config=config, client=client)
1579
+ cryptography.get_versions_in_range()
1580
+ cryptography.present(output_file=args.output)
1581
+ except ScanossGrpcError as e:
1582
+ print_stderr(f'API ERROR: {e}')
1583
+ sys.exit(1)
1584
+ except Exception as e:
1585
+ if args.debug:
1586
+ import traceback
1587
+
1588
+ traceback.print_exc()
1589
+ print_stderr(f'ERROR: {e}')
1429
1590
  sys.exit(1)
1430
1591
 
1431
1592
 
@@ -10,3 +10,5 @@ DEFAULT_NB_THREADS = 5
10
10
 
11
11
  DEFAULT_URL = 'https://api.osskb.org' # default free service URL
12
12
  DEFAULT_URL2 = 'https://api.scanoss.com' # default premium service URL
13
+
14
+ DEFAULT_API_TIMEOUT = 600
@@ -0,0 +1,274 @@
1
+ import json
2
+ from dataclasses import dataclass
3
+ from typing import Dict, List, Optional
4
+
5
+ from scanoss.scanossbase import ScanossBase
6
+ from scanoss.scanossgrpc import ScanossGrpc
7
+ from scanoss.utils.abstract_presenter import AbstractPresenter
8
+ from scanoss.utils.file import validate_json_file
9
+
10
+
11
+ class ScanossCryptographyError(Exception):
12
+ pass
13
+
14
+
15
+ MIN_SPLIT_PARTS = 2
16
+
17
+
18
+ @dataclass
19
+ class CryptographyConfig:
20
+ purl: List[str]
21
+ input_file: Optional[str] = None
22
+ output_file: Optional[str] = None
23
+ header: Optional[str] = None
24
+ debug: bool = False
25
+ trace: bool = False
26
+ quiet: bool = False
27
+ with_range: bool = False
28
+
29
+ def __post_init__(self):
30
+ """
31
+ Validate that the configuration is valid.
32
+ """
33
+ if self.purl:
34
+ if self.with_range:
35
+ for purl in self.purl:
36
+ parts = purl.split('@')
37
+ if not (len(parts) >= MIN_SPLIT_PARTS and parts[1]):
38
+ raise ScanossCryptographyError(
39
+ f'Invalid PURL format: "{purl}".' f'It must include a version (e.g., pkg:type/name@version)'
40
+ )
41
+ if self.input_file:
42
+ input_file_validation = validate_json_file(self.input_file)
43
+ if not input_file_validation.is_valid:
44
+ raise ScanossCryptographyError(
45
+ f'There was a problem with the purl input file. {input_file_validation.error}'
46
+ )
47
+ if (
48
+ not isinstance(input_file_validation.data, dict)
49
+ or 'purls' not in input_file_validation.data
50
+ or not isinstance(input_file_validation.data['purls'], list)
51
+ or not all(isinstance(p, dict) and 'purl' in p for p in input_file_validation.data['purls'])
52
+ ):
53
+ raise ScanossCryptographyError('The supplied input file is not in the correct PurlRequest format.')
54
+ purls = input_file_validation.data['purls']
55
+ purls_with_requirement = []
56
+ if self.with_range:
57
+ if any('requirement' not in p for p in purls):
58
+ raise ScanossCryptographyError(
59
+ f'One or more PURLs in "{self.input_file}" are missing the "requirement" field.'
60
+ )
61
+ else:
62
+ for purl in purls:
63
+ purls_with_requirement.append(f'{purl["purl"]}@{purl["requirement"]}')
64
+ else:
65
+ purls_with_requirement = purls
66
+ self.purl = purls_with_requirement
67
+
68
+
69
+ def create_cryptography_config_from_args(args) -> CryptographyConfig:
70
+ return CryptographyConfig(
71
+ debug=getattr(args, 'debug', False),
72
+ trace=getattr(args, 'trace', False),
73
+ quiet=getattr(args, 'quiet', False),
74
+ with_range=getattr(args, 'with_range', False),
75
+ purl=getattr(args, 'purl', []),
76
+ input_file=getattr(args, 'input', None),
77
+ output_file=getattr(args, 'output', None),
78
+ header=getattr(args, 'header', None),
79
+ )
80
+
81
+
82
+ class Cryptography:
83
+ """
84
+ Cryptography Class
85
+
86
+ This class is used to decorate purls with cryptography information.
87
+ """
88
+
89
+ def __init__(
90
+ self,
91
+ config: CryptographyConfig,
92
+ client: ScanossGrpc,
93
+ ):
94
+ """
95
+ Initialize the Cryptography.
96
+
97
+ Args:
98
+ config (CryptographyConfig): Configuration parameters for the cryptography.
99
+ client (ScanossGrpc): gRPC client for communicating with the scanning service.
100
+ """
101
+ self.base = ScanossBase(
102
+ debug=config.debug,
103
+ trace=config.trace,
104
+ quiet=config.quiet,
105
+ )
106
+ self.presenter = CryptographyPresenter(
107
+ self,
108
+ debug=config.debug,
109
+ trace=config.trace,
110
+ quiet=config.quiet,
111
+ )
112
+
113
+ self.client = client
114
+ self.config = config
115
+ self.purls_request = self._build_purls_request()
116
+ self.results = None
117
+
118
+ def get_algorithms(self) -> Optional[Dict]:
119
+ """
120
+ Get the cryptographic algorithms for the provided purl or input file.
121
+
122
+ Returns:
123
+ Optional[Dict]: The folder hash response from the gRPC client, or None if an error occurs.
124
+ """
125
+
126
+ if not self.purls_request:
127
+ raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
128
+ self.base.print_stderr(
129
+ f'Getting cryptographic algorithms for {", ".join([p["purl"] for p in self.purls_request["purls"]])}'
130
+ )
131
+ if self.config.with_range:
132
+ response = self.client.get_crypto_algorithms_in_range_for_purl(self.purls_request)
133
+ else:
134
+ response = self.client.get_crypto_algorithms_for_purl(self.purls_request)
135
+ if response:
136
+ self.results = response
137
+
138
+ return self.results
139
+
140
+ def get_encryption_hints(self) -> Optional[Dict]:
141
+ """
142
+ Get the encryption hints for the provided purl or input file.
143
+
144
+ Returns:
145
+ Optional[Dict]: The encryption hints response from the gRPC client, or None if an error occurs.
146
+ """
147
+
148
+ if not self.purls_request:
149
+ raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
150
+ self.base.print_stderr(
151
+ f'Getting encryption hints '
152
+ f'{"in range" if self.config.with_range else ""} '
153
+ f'for {", ".join([p["purl"] for p in self.purls_request["purls"]])}'
154
+ )
155
+ if self.config.with_range:
156
+ response = self.client.get_encryption_hints_in_range_for_purl(self.purls_request)
157
+ else:
158
+ response = self.client.get_encryption_hints_for_purl(self.purls_request)
159
+ if response:
160
+ self.results = response
161
+
162
+ return self.results
163
+
164
+ def get_versions_in_range(self) -> Optional[Dict]:
165
+ """
166
+ Given a list of PURLS and version ranges, get a list of versions that do/do not contain cryptographic algorithms
167
+
168
+ Returns:
169
+ Optional[Dict]: The versions in range response from the gRPC client, or None if an error occurs.
170
+ """
171
+
172
+ if not self.purls_request:
173
+ raise ScanossCryptographyError('No PURLs supplied. Provide --purl or --input.')
174
+
175
+ self.base.print_stderr(
176
+ f'Getting versions in range for {", ".join([p["purl"] for p in self.purls_request["purls"]])}'
177
+ )
178
+
179
+ response = self.client.get_versions_in_range_for_purl(self.purls_request)
180
+ if response:
181
+ self.results = response
182
+
183
+ return self.results
184
+
185
+ def _build_purls_request(
186
+ self,
187
+ ) -> Optional[dict]:
188
+ """
189
+ Load the specified purls from a JSON file or a list of PURLs and return a dictionary
190
+
191
+ Args:
192
+ json_file (Optional[str], optional): The JSON file containing the PURLs. Defaults to None.
193
+ purls (Optional[List[str]], optional): The list of PURLs. Defaults to None.
194
+
195
+ Returns:
196
+ Optional[dict]: The dictionary containing the PURLs
197
+ """
198
+ return {
199
+ 'purls': [
200
+ {
201
+ 'purl': p,
202
+ 'requirement': self._extract_version_from_purl(p),
203
+ }
204
+ for p in self.config.purl
205
+ ]
206
+ }
207
+
208
+ def _extract_version_from_purl(self, purl: str) -> str:
209
+ """
210
+ Extract version from purl
211
+
212
+ Args:
213
+ purl (str): The purl string to extract the version from
214
+
215
+ Returns:
216
+ str: The extracted version
217
+
218
+ Raises:
219
+ ScanossCryptographyError: If the purl is not in the correct format
220
+ """
221
+ try:
222
+ return purl.split('@')[-1]
223
+ except IndexError:
224
+ raise ScanossCryptographyError(f'Invalid purl format: {purl}')
225
+
226
+ def present(
227
+ self,
228
+ output_format: Optional[str] = None,
229
+ output_file: Optional[str] = None,
230
+ ):
231
+ """Present the results in the selected format"""
232
+ self.presenter.present(output_format=output_format, output_file=output_file)
233
+
234
+
235
+ class CryptographyPresenter(AbstractPresenter):
236
+ """
237
+ Cryptography presenter class
238
+ Handles the presentation of the cryptography results
239
+ """
240
+
241
+ def __init__(self, cryptography: Cryptography, **kwargs):
242
+ super().__init__(**kwargs)
243
+ self.cryptography = cryptography
244
+
245
+ def _format_json_output(self) -> str:
246
+ """
247
+ Format the scan output data into a JSON object
248
+
249
+ Returns:
250
+ str: The formatted JSON string
251
+ """
252
+ return json.dumps(self.cryptography.results, indent=2)
253
+
254
+ def _format_plain_output(self) -> str:
255
+ """
256
+ Format the scan output data into a plain text string
257
+ """
258
+ return (
259
+ json.dumps(self.cryptography.results, indent=2)
260
+ if isinstance(self.cryptography.results, dict)
261
+ else str(self.cryptography.results)
262
+ )
263
+
264
+ def _format_cyclonedx_output(self) -> str:
265
+ raise NotImplementedError('CycloneDX output is not implemented')
266
+
267
+ def _format_spdxlite_output(self) -> str:
268
+ raise NotImplementedError('SPDXlite output is not implemented')
269
+
270
+ def _format_csv_output(self) -> str:
271
+ raise NotImplementedError('CSV output is not implemented')
272
+
273
+ def _format_raw_output(self) -> str:
274
+ raise NotImplementedError('Raw output is not implemented')
@@ -0,0 +1 @@
1
+ date: 20250610161304, utime: 1749571984