scanoss 1.29.0__py3-none-any.whl → 1.31.0__py3-none-any.whl
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.
- scanoss/__init__.py +1 -1
- scanoss/cli.py +630 -167
- scanoss/cyclonedx.py +41 -24
- scanoss/data/build_date.txt +1 -1
- scanoss/export/__init__.py +23 -0
- scanoss/export/dependency_track.py +222 -0
- scanoss/file_filters.py +1 -5
- scanoss/inspection/dependency_track/project_violation.py +443 -0
- scanoss/inspection/policy_check.py +54 -23
- scanoss/inspection/{component_summary.py → raw/component_summary.py} +3 -3
- scanoss/inspection/{copyleft.py → raw/copyleft.py} +63 -54
- scanoss/inspection/{license_summary.py → raw/license_summary.py} +5 -4
- scanoss/inspection/{inspect_base.py → raw/raw_base.py} +9 -6
- scanoss/inspection/{undeclared_component.py → raw/undeclared_component.py} +29 -25
- scanoss/services/dependency_track_service.py +131 -0
- {scanoss-1.29.0.dist-info → scanoss-1.31.0.dist-info}/METADATA +2 -1
- {scanoss-1.29.0.dist-info → scanoss-1.31.0.dist-info}/RECORD +21 -17
- {scanoss-1.29.0.dist-info → scanoss-1.31.0.dist-info}/WHEEL +0 -0
- {scanoss-1.29.0.dist-info → scanoss-1.31.0.dist-info}/entry_points.txt +0 -0
- {scanoss-1.29.0.dist-info → scanoss-1.31.0.dist-info}/licenses/LICENSE +0 -0
- {scanoss-1.29.0.dist-info → scanoss-1.31.0.dist-info}/top_level.txt +0 -0
scanoss/cli.py
CHANGED
|
@@ -25,6 +25,7 @@ SPDX-License-Identifier: MIT
|
|
|
25
25
|
import argparse
|
|
26
26
|
import os
|
|
27
27
|
import sys
|
|
28
|
+
import traceback
|
|
28
29
|
from dataclasses import asdict
|
|
29
30
|
from pathlib import Path
|
|
30
31
|
from typing import List
|
|
@@ -32,8 +33,10 @@ from typing import List
|
|
|
32
33
|
import pypac
|
|
33
34
|
|
|
34
35
|
from scanoss.cryptography import Cryptography, create_cryptography_config_from_args
|
|
35
|
-
from scanoss.
|
|
36
|
-
from scanoss.inspection.
|
|
36
|
+
from scanoss.export.dependency_track import DependencyTrackExporter
|
|
37
|
+
from scanoss.inspection.dependency_track.project_violation import DependencyTrackProjectViolationPolicyCheck
|
|
38
|
+
from scanoss.inspection.raw.component_summary import ComponentSummary
|
|
39
|
+
from scanoss.inspection.raw.license_summary import LicenseSummary
|
|
37
40
|
from scanoss.scanners.container_scanner import (
|
|
38
41
|
DEFAULT_SYFT_COMMAND,
|
|
39
42
|
DEFAULT_SYFT_TIMEOUT,
|
|
@@ -64,8 +67,8 @@ from .constants import (
|
|
|
64
67
|
from .csvoutput import CsvOutput
|
|
65
68
|
from .cyclonedx import CycloneDx
|
|
66
69
|
from .filecount import FileCount
|
|
67
|
-
from .inspection.copyleft import Copyleft
|
|
68
|
-
from .inspection.undeclared_component import UndeclaredComponent
|
|
70
|
+
from .inspection.raw.copyleft import Copyleft
|
|
71
|
+
from .inspection.raw.undeclared_component import UndeclaredComponent
|
|
69
72
|
from .results import Results
|
|
70
73
|
from .scancodedeps import ScancodeDeps
|
|
71
74
|
from .scanner import FAST_WINNOWING, Scanner
|
|
@@ -534,76 +537,324 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
534
537
|
)
|
|
535
538
|
p_results.set_defaults(func=results)
|
|
536
539
|
|
|
537
|
-
|
|
538
|
-
#
|
|
540
|
+
# =========================================================================
|
|
541
|
+
# INSPECT SUBCOMMAND - Analysis and validation of scan results
|
|
542
|
+
# =========================================================================
|
|
543
|
+
|
|
544
|
+
# Main inspect parser - provides tools for analyzing scan results
|
|
539
545
|
p_inspect = subparsers.add_parser(
|
|
540
|
-
'inspect',
|
|
546
|
+
'inspect',
|
|
547
|
+
aliases=['insp', 'ins'],
|
|
548
|
+
description=f'Inspect and analyse scan results: {__version__}',
|
|
549
|
+
help='Inspect and analyse scan results'
|
|
541
550
|
)
|
|
542
|
-
|
|
551
|
+
|
|
552
|
+
# Inspect sub-commands parser
|
|
543
553
|
p_inspect_sub = p_inspect.add_subparsers(
|
|
544
|
-
title='Inspect Commands',
|
|
554
|
+
title='Inspect Commands',
|
|
555
|
+
dest='subparsercmd',
|
|
556
|
+
description='Available inspection sub-commands',
|
|
557
|
+
help='Choose an inspection type'
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
# -------------------------------------------------------------------------
|
|
561
|
+
# RAW RESULTS INSPECTION - Analyse raw scan output
|
|
562
|
+
# -------------------------------------------------------------------------
|
|
563
|
+
|
|
564
|
+
# Raw results parser - handles inspection of unprocessed scan results
|
|
565
|
+
p_inspect_raw = p_inspect_sub.add_parser(
|
|
566
|
+
'raw',
|
|
567
|
+
description='Inspect and analyse SCANOSS raw scan results',
|
|
568
|
+
help='Analyse raw scan results for various compliance issues'
|
|
545
569
|
)
|
|
546
570
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
571
|
+
# Raw results sub-commands parser
|
|
572
|
+
p_inspect_raw_sub = p_inspect_raw.add_subparsers(
|
|
573
|
+
title='Raw Results Inspection Commands',
|
|
574
|
+
dest='subparser_subcmd',
|
|
575
|
+
description='Tools for analyzing raw scan results',
|
|
576
|
+
help='Choose a raw results analysis type'
|
|
551
577
|
)
|
|
552
578
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
579
|
+
# Copyleft license inspection - identifies copyleft license violations
|
|
580
|
+
p_inspect_raw_copyleft = p_inspect_raw_sub.add_parser(
|
|
581
|
+
'copyleft',
|
|
582
|
+
aliases=['cp'],
|
|
583
|
+
description='Identify components with copyleft licenses that may require compliance action',
|
|
584
|
+
help='Find copyleft license violations'
|
|
558
585
|
)
|
|
559
586
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
587
|
+
# License summary inspection - provides overview of all detected licenses
|
|
588
|
+
p_inspect_raw_license_summary = p_inspect_raw_sub.add_parser(
|
|
589
|
+
'license-summary',
|
|
590
|
+
aliases=['lic-summary', 'licsum'],
|
|
591
|
+
description='Generate comprehensive summary of all licenses found in scan results',
|
|
592
|
+
help='Generate license summary report'
|
|
563
593
|
)
|
|
564
594
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
595
|
+
# Component summary inspection - provides overview of all detected components
|
|
596
|
+
p_inspect_raw_component_summary = p_inspect_raw_sub.add_parser(
|
|
597
|
+
'component-summary',
|
|
598
|
+
aliases=['comp-summary', 'compsum'],
|
|
599
|
+
description='Generate comprehensive summary of all components found in scan results',
|
|
600
|
+
help='Generate component summary report'
|
|
601
|
+
)
|
|
602
|
+
|
|
603
|
+
# Undeclared components inspection - finds components not declared in SBOM
|
|
604
|
+
p_inspect_raw_undeclared = p_inspect_raw_sub.add_parser(
|
|
568
605
|
'undeclared',
|
|
569
606
|
aliases=['un'],
|
|
570
|
-
description='
|
|
571
|
-
help='
|
|
607
|
+
description='Identify components present in code but not declared in SBOM files',
|
|
608
|
+
help='Find undeclared components'
|
|
572
609
|
)
|
|
573
|
-
|
|
610
|
+
# SBOM format option for undeclared components inspection
|
|
611
|
+
p_inspect_raw_undeclared.add_argument(
|
|
574
612
|
'--sbom-format',
|
|
575
613
|
required=False,
|
|
576
614
|
choices=['legacy', 'settings'],
|
|
577
615
|
default='settings',
|
|
578
|
-
help='
|
|
616
|
+
help='SBOM format type for comparison: legacy or settings (default)'
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
# -------------------------------------------------------------------------
|
|
620
|
+
# BACKWARD COMPATIBILITY - Support old inspect command format
|
|
621
|
+
# -------------------------------------------------------------------------
|
|
622
|
+
|
|
623
|
+
# Legacy copyleft inspection - backward compatibility for 'scanoss-py inspect copyleft'
|
|
624
|
+
p_inspect_legacy_copyleft = p_inspect_sub.add_parser(
|
|
625
|
+
'copyleft',
|
|
626
|
+
aliases=['cp'],
|
|
627
|
+
description='Identify components with copyleft licenses that may require compliance action',
|
|
628
|
+
help='Find copyleft license violations (legacy format)'
|
|
579
629
|
)
|
|
580
630
|
|
|
581
|
-
#
|
|
582
|
-
|
|
631
|
+
# Legacy undeclared components inspection - backward compatibility for 'scanoss-py inspect undeclared'
|
|
632
|
+
p_inspect_legacy_undeclared = p_inspect_sub.add_parser(
|
|
633
|
+
'undeclared',
|
|
634
|
+
aliases=['un'],
|
|
635
|
+
description='Identify components present in code but not declared in SBOM files',
|
|
636
|
+
help='Find undeclared components (legacy format)'
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
# SBOM format option for legacy undeclared components inspection
|
|
640
|
+
p_inspect_legacy_undeclared.add_argument(
|
|
641
|
+
'--sbom-format',
|
|
642
|
+
required=False,
|
|
643
|
+
choices=['legacy', 'settings'],
|
|
644
|
+
default='settings',
|
|
645
|
+
help='SBOM format type for comparison: legacy or settings (default)'
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
# Legacy license summary inspection - backward compatibility for 'scanoss-py inspect license-summary'
|
|
649
|
+
p_inspect_legacy_license_summary = p_inspect_sub.add_parser(
|
|
650
|
+
'license-summary',
|
|
651
|
+
aliases=['lic-summary', 'licsum'],
|
|
652
|
+
description='Generate comprehensive summary of all licenses found in scan results',
|
|
653
|
+
help='Generate license summary report (legacy format)'
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
# Legacy component summary inspection - backward compatibility for 'scanoss-py inspect component-summary'
|
|
657
|
+
p_inspect_legacy_component_summary = p_inspect_sub.add_parser(
|
|
658
|
+
'component-summary',
|
|
659
|
+
aliases=['comp-summary', 'compsum'],
|
|
660
|
+
description='Generate comprehensive summary of all components found in scan results',
|
|
661
|
+
help='Generate component summary report (legacy format)'
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
# Applies the same configuration to both legacy and raw versions
|
|
665
|
+
# License filtering options - common to (legacy) copyleft and license summary commands
|
|
666
|
+
for p in [p_inspect_raw_copyleft, p_inspect_raw_license_summary,
|
|
667
|
+
p_inspect_legacy_copyleft, p_inspect_legacy_license_summary]:
|
|
583
668
|
p.add_argument(
|
|
584
669
|
'--include',
|
|
585
|
-
help='
|
|
670
|
+
help='Additional licenses to include in analysis (comma-separated list)'
|
|
586
671
|
)
|
|
587
672
|
p.add_argument(
|
|
588
673
|
'--exclude',
|
|
589
|
-
help='
|
|
674
|
+
help='Licenses to exclude from analysis (comma-separated list)'
|
|
590
675
|
)
|
|
591
676
|
p.add_argument(
|
|
592
677
|
'--explicit',
|
|
593
|
-
help='
|
|
678
|
+
help='Use only these specific licenses for analysis (comma-separated list)'
|
|
594
679
|
)
|
|
595
680
|
|
|
596
|
-
|
|
597
|
-
for p in [
|
|
598
|
-
p.add_argument(
|
|
599
|
-
|
|
681
|
+
# Common options for (legacy) copyleft and undeclared component inspection
|
|
682
|
+
for p in [p_inspect_raw_copyleft, p_inspect_raw_undeclared, p_inspect_legacy_copyleft, p_inspect_legacy_undeclared]:
|
|
683
|
+
p.add_argument(
|
|
684
|
+
'-i', '--input',
|
|
685
|
+
nargs='?',
|
|
686
|
+
help='Path to scan results file to analyse'
|
|
687
|
+
)
|
|
688
|
+
p.add_argument(
|
|
689
|
+
'-f', '--format',
|
|
690
|
+
required=False,
|
|
691
|
+
choices=['json', 'md', 'jira_md'],
|
|
692
|
+
default='json',
|
|
693
|
+
help='Output format: json (default), md (Markdown), or jira_md (JIRA Markdown)'
|
|
694
|
+
)
|
|
695
|
+
p.add_argument(
|
|
696
|
+
'-o', '--output',
|
|
697
|
+
type=str,
|
|
698
|
+
help='Save detailed results to specified file'
|
|
699
|
+
)
|
|
700
|
+
p.add_argument(
|
|
701
|
+
'-s', '--status',
|
|
702
|
+
type=str,
|
|
703
|
+
help='Save summary status report to Markdown file'
|
|
704
|
+
)
|
|
600
705
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
706
|
+
# Common options for (legacy) license and component summary commands
|
|
707
|
+
for p in [p_inspect_raw_license_summary, p_inspect_raw_component_summary,
|
|
708
|
+
p_inspect_legacy_license_summary, p_inspect_legacy_component_summary]:
|
|
709
|
+
p.add_argument(
|
|
710
|
+
'-i', '--input',
|
|
711
|
+
nargs='?',
|
|
712
|
+
help='Path to scan results file to analyse'
|
|
713
|
+
)
|
|
714
|
+
p.add_argument(
|
|
715
|
+
'-o', '--output',
|
|
716
|
+
type=str,
|
|
717
|
+
help='Save summary report to specified file'
|
|
718
|
+
)
|
|
605
719
|
|
|
606
|
-
|
|
720
|
+
# -------------------------------------------------------------------------
|
|
721
|
+
# DEPENDENCY TRACK INSPECTION - Analyse Dependency Track project data
|
|
722
|
+
# -------------------------------------------------------------------------
|
|
723
|
+
|
|
724
|
+
# Dependency Track parser - handles inspection of DT project status and violations
|
|
725
|
+
p_dep_track_sub = p_inspect_sub.add_parser(
|
|
726
|
+
'dependency-track',
|
|
727
|
+
aliases=['dt'],
|
|
728
|
+
description='Inspect and analyse Dependency Track project status and policy violations',
|
|
729
|
+
help='Analyse Dependency Track projects'
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
# Dependency Track sub-commands parser
|
|
733
|
+
p_inspect_dep_track_sub = p_dep_track_sub.add_subparsers(
|
|
734
|
+
title='Dependency Track Inspection Commands',
|
|
735
|
+
dest='subparser_subcmd',
|
|
736
|
+
description='Tools for analysing Dependency Track project data',
|
|
737
|
+
help='Choose a Dependency Track analysis type'
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
# Project violations inspection - analyses policy violations in DT projects
|
|
741
|
+
p_inspect_dt_project_violation = p_inspect_dep_track_sub.add_parser(
|
|
742
|
+
'project-violations',
|
|
743
|
+
aliases=['pv'],
|
|
744
|
+
description='Analyse policy violations and compliance issues in Dependency Track projects',
|
|
745
|
+
help='Inspect project policy violations'
|
|
746
|
+
)
|
|
747
|
+
# Dependency Track connection and authentication options
|
|
748
|
+
p_inspect_dt_project_violation.add_argument(
|
|
749
|
+
'--url',
|
|
750
|
+
required=True,
|
|
751
|
+
type=str,
|
|
752
|
+
help='Dependency Track server base URL (e.g., https://dtrack.example.com)'
|
|
753
|
+
)
|
|
754
|
+
p_inspect_dt_project_violation.add_argument(
|
|
755
|
+
'--upload-token', '-ut',
|
|
756
|
+
required=False,
|
|
757
|
+
type=str,
|
|
758
|
+
help='Project-specific upload token for accessing DT project data'
|
|
759
|
+
)
|
|
760
|
+
p_inspect_dt_project_violation.add_argument(
|
|
761
|
+
'--project-id', '-pid',
|
|
762
|
+
required=False,
|
|
763
|
+
type=str,
|
|
764
|
+
help='Dependency Track project UUID to inspect'
|
|
765
|
+
)
|
|
766
|
+
p_inspect_dt_project_violation.add_argument(
|
|
767
|
+
'--apikey', '-k',
|
|
768
|
+
required=True,
|
|
769
|
+
type=str,
|
|
770
|
+
help='Dependency Track API key for authentication'
|
|
771
|
+
)
|
|
772
|
+
p_inspect_dt_project_violation.add_argument(
|
|
773
|
+
'--project-name', '-pn',
|
|
774
|
+
required=False,
|
|
775
|
+
type=str,
|
|
776
|
+
help='Dependency Track project name'
|
|
777
|
+
)
|
|
778
|
+
p_inspect_dt_project_violation.add_argument(
|
|
779
|
+
'--project-version', '-pv',
|
|
780
|
+
required=False,
|
|
781
|
+
type=str,
|
|
782
|
+
help='Dependency Track project version'
|
|
783
|
+
)
|
|
784
|
+
p_inspect_dt_project_violation.add_argument(
|
|
785
|
+
'--output', '-o',
|
|
786
|
+
required=False,
|
|
787
|
+
type=str,
|
|
788
|
+
help='Save inspection results to specified file'
|
|
789
|
+
)
|
|
790
|
+
p_inspect_dt_project_violation.add_argument(
|
|
791
|
+
'--status',
|
|
792
|
+
required=False,
|
|
793
|
+
type=str,
|
|
794
|
+
help='Save summary status report to specified file'
|
|
795
|
+
)
|
|
796
|
+
p_inspect_dt_project_violation.add_argument(
|
|
797
|
+
'--format', '-f',
|
|
798
|
+
required=False,
|
|
799
|
+
choices=['json', 'md'],
|
|
800
|
+
default='json',
|
|
801
|
+
help='Output format: json (default) or md (Markdown)'
|
|
802
|
+
)
|
|
803
|
+
p_inspect_dt_project_violation.add_argument(
|
|
804
|
+
'--timeout', '-M',
|
|
805
|
+
required=False,
|
|
806
|
+
default='300',
|
|
807
|
+
help='Timeout (in seconds) for API communication (optional - default 300 sec)'
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
# TODO Move to the command call def location
|
|
811
|
+
# RAW results
|
|
812
|
+
p_inspect_raw_undeclared.set_defaults(func=inspect_undeclared)
|
|
813
|
+
p_inspect_raw_copyleft.set_defaults(func=inspect_copyleft)
|
|
814
|
+
p_inspect_raw_license_summary.set_defaults(func=inspect_license_summary)
|
|
815
|
+
p_inspect_raw_component_summary.set_defaults(func=inspect_component_summary)
|
|
816
|
+
# Legacy backward compatibility commands
|
|
817
|
+
p_inspect_legacy_copyleft.set_defaults(func=inspect_copyleft)
|
|
818
|
+
p_inspect_legacy_undeclared.set_defaults(func=inspect_undeclared)
|
|
819
|
+
p_inspect_legacy_license_summary.set_defaults(func=inspect_license_summary)
|
|
820
|
+
p_inspect_legacy_component_summary.set_defaults(func=inspect_component_summary)
|
|
821
|
+
# Dependency Track
|
|
822
|
+
p_inspect_dt_project_violation.set_defaults(func=inspect_dep_track_project_violations)
|
|
823
|
+
|
|
824
|
+
# =========================================================================
|
|
825
|
+
# END INSPECT SUBCOMMAND CONFIGURATION
|
|
826
|
+
# =========================================================================
|
|
827
|
+
|
|
828
|
+
# Sub-command: export
|
|
829
|
+
p_export = subparsers.add_parser(
|
|
830
|
+
'export',
|
|
831
|
+
aliases=['exp'],
|
|
832
|
+
description=f'Export SBOM files to external platforms: {__version__}',
|
|
833
|
+
help='Export SBOM files to external platforms',
|
|
834
|
+
)
|
|
835
|
+
|
|
836
|
+
export_sub = p_export.add_subparsers(
|
|
837
|
+
title='Export Commands',
|
|
838
|
+
dest='subparsercmd',
|
|
839
|
+
description='export sub-commands',
|
|
840
|
+
help='export sub-commands',
|
|
841
|
+
)
|
|
842
|
+
|
|
843
|
+
# Export Sub-command: export dt (Dependency Track)
|
|
844
|
+
e_dt = export_sub.add_parser(
|
|
845
|
+
'dt',
|
|
846
|
+
aliases=['dependency-track'],
|
|
847
|
+
description='Export SBOM to Dependency Track',
|
|
848
|
+
help='Upload SBOM files to Dependency Track',
|
|
849
|
+
)
|
|
850
|
+
e_dt.add_argument('-i', '--input', type=str, required=True, help='Input SBOM file (CycloneDX JSON format)')
|
|
851
|
+
e_dt.add_argument('--url', type=str, required=True, help='Dependency Track base URL')
|
|
852
|
+
e_dt.add_argument('--apikey', '-k', type=str, required=True, help='Dependency Track API key')
|
|
853
|
+
e_dt.add_argument('--output', '-o', type=str, help='File to save export token and uuid into')
|
|
854
|
+
e_dt.add_argument('--project-id', '-pid', type=str, help='Dependency Track project UUID')
|
|
855
|
+
e_dt.add_argument('--project-name', '-pn', type=str, help='Dependency Track project name')
|
|
856
|
+
e_dt.add_argument('--project-version', '-pv', type=str, help='Dependency Track project version')
|
|
857
|
+
e_dt.set_defaults(func=export_dt)
|
|
607
858
|
|
|
608
859
|
# Sub-command: folder-scan
|
|
609
860
|
p_folder_scan = subparsers.add_parser(
|
|
@@ -707,19 +958,6 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
707
958
|
help='Skip default settings file (scanoss.json) if it exists',
|
|
708
959
|
)
|
|
709
960
|
|
|
710
|
-
for p in [p_copyleft, p_undeclared]:
|
|
711
|
-
p.add_argument('-i', '--input', nargs='?', help='Path to results file')
|
|
712
|
-
p.add_argument(
|
|
713
|
-
'-f',
|
|
714
|
-
'--format',
|
|
715
|
-
required=False,
|
|
716
|
-
choices=['json', 'md', 'jira_md'],
|
|
717
|
-
default='json',
|
|
718
|
-
help='Output format (default: json)',
|
|
719
|
-
)
|
|
720
|
-
p.add_argument('-o', '--output', type=str, help='Save details into a file')
|
|
721
|
-
p.add_argument('-s', '--status', type=str, help='Save summary data into Markdown file')
|
|
722
|
-
|
|
723
961
|
# Global Scan command options
|
|
724
962
|
for p in [p_scan, p_cs]:
|
|
725
963
|
p.add_argument(
|
|
@@ -847,10 +1085,15 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
847
1085
|
c_versions,
|
|
848
1086
|
c_semgrep,
|
|
849
1087
|
p_results,
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
1088
|
+
p_inspect_raw_undeclared,
|
|
1089
|
+
p_inspect_raw_copyleft,
|
|
1090
|
+
p_inspect_raw_license_summary,
|
|
1091
|
+
p_inspect_raw_component_summary,
|
|
1092
|
+
p_inspect_legacy_copyleft,
|
|
1093
|
+
p_inspect_legacy_undeclared,
|
|
1094
|
+
p_inspect_legacy_license_summary,
|
|
1095
|
+
p_inspect_legacy_component_summary,
|
|
1096
|
+
p_inspect_dt_project_violation,
|
|
854
1097
|
c_provenance,
|
|
855
1098
|
p_folder_scan,
|
|
856
1099
|
p_folder_hash,
|
|
@@ -858,6 +1101,7 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
858
1101
|
p_crypto_algorithms,
|
|
859
1102
|
p_crypto_hints,
|
|
860
1103
|
p_crypto_versions_in_range,
|
|
1104
|
+
e_dt,
|
|
861
1105
|
]:
|
|
862
1106
|
p.add_argument('--debug', '-d', action='store_true', help='Enable debug messages')
|
|
863
1107
|
p.add_argument('--trace', '-t', action='store_true', help='Enable trace messages, including API posts')
|
|
@@ -871,10 +1115,14 @@ def setup_args() -> None: # noqa: PLR0912, PLR0915
|
|
|
871
1115
|
parser.print_help() # No sub command subcommand, print general help
|
|
872
1116
|
sys.exit(1)
|
|
873
1117
|
elif (
|
|
874
|
-
args.subparser
|
|
1118
|
+
args.subparser
|
|
1119
|
+
in ('utils', 'ut', 'component', 'comp', 'inspect', 'insp', 'ins', 'crypto', 'cr', 'export', 'exp')
|
|
875
1120
|
) and not args.subparsercmd:
|
|
876
1121
|
parser.parse_args([args.subparser, '--help']) # Force utils helps to be displayed
|
|
877
1122
|
sys.exit(1)
|
|
1123
|
+
elif (args.subparser in 'inspect') and (args.subparsercmd in ('raw', 'dt')) and (args.subparser_subcmd is None):
|
|
1124
|
+
parser.parse_args([args.subparser, args.subparsercmd, '--help']) # Force utils helps to be displayed
|
|
1125
|
+
sys.exit(1)
|
|
878
1126
|
args.func(parser, args) # Execute the function associated with the sub-command
|
|
879
1127
|
|
|
880
1128
|
|
|
@@ -908,16 +1156,14 @@ def file_count(parser, args):
|
|
|
908
1156
|
print_stderr('Please specify a folder')
|
|
909
1157
|
parser.parse_args([args.subparser, '-h'])
|
|
910
1158
|
sys.exit(1)
|
|
911
|
-
scan_output: str = None
|
|
912
1159
|
if args.output:
|
|
913
|
-
|
|
914
|
-
open(scan_output, 'w').close()
|
|
1160
|
+
initialise_empty_file(args.output)
|
|
915
1161
|
|
|
916
1162
|
counter = FileCount(
|
|
917
1163
|
debug=args.debug,
|
|
918
1164
|
quiet=args.quiet,
|
|
919
1165
|
trace=args.trace,
|
|
920
|
-
scan_output=
|
|
1166
|
+
scan_output=args.output,
|
|
921
1167
|
hidden_files_folders=args.all_hidden,
|
|
922
1168
|
)
|
|
923
1169
|
if not os.path.exists(args.scan_dir):
|
|
@@ -946,10 +1192,8 @@ def wfp(parser, args):
|
|
|
946
1192
|
sys.exit(1)
|
|
947
1193
|
if args.strip_hpsm and not args.hpsm and not args.quiet:
|
|
948
1194
|
print_stderr('Warning: --strip-hpsm option supplied without enabling HPSM (--hpsm). Ignoring.')
|
|
949
|
-
scan_output: str = None
|
|
950
1195
|
if args.output:
|
|
951
|
-
|
|
952
|
-
open(scan_output, 'w').close()
|
|
1196
|
+
initialise_empty_file(args.output)
|
|
953
1197
|
|
|
954
1198
|
# Load scan settings
|
|
955
1199
|
scan_settings = None
|
|
@@ -982,15 +1226,15 @@ def wfp(parser, args):
|
|
|
982
1226
|
)
|
|
983
1227
|
if args.stdin:
|
|
984
1228
|
contents = sys.stdin.buffer.read()
|
|
985
|
-
scanner.wfp_contents(args.stdin, contents,
|
|
1229
|
+
scanner.wfp_contents(args.stdin, contents, args.output)
|
|
986
1230
|
elif args.scan_dir:
|
|
987
1231
|
if not os.path.exists(args.scan_dir):
|
|
988
1232
|
print_stderr(f'Error: File or folder specified does not exist: {args.scan_dir}.')
|
|
989
1233
|
sys.exit(1)
|
|
990
1234
|
if os.path.isdir(args.scan_dir):
|
|
991
|
-
scanner.wfp_folder(args.scan_dir,
|
|
1235
|
+
scanner.wfp_folder(args.scan_dir, args.output)
|
|
992
1236
|
elif os.path.isfile(args.scan_dir):
|
|
993
|
-
scanner.wfp_file(args.scan_dir,
|
|
1237
|
+
scanner.wfp_file(args.scan_dir, args.output)
|
|
994
1238
|
else:
|
|
995
1239
|
print_stderr(f'Error: Path specified is neither a file or a folder: {args.scan_dir}.')
|
|
996
1240
|
sys.exit(1)
|
|
@@ -1087,10 +1331,8 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
|
1087
1331
|
if args.strip_hpsm and not args.hpsm and not args.quiet:
|
|
1088
1332
|
print_stderr('Warning: --strip-hpsm option supplied without enabling HPSM (--hpsm). Ignoring.')
|
|
1089
1333
|
|
|
1090
|
-
scan_output: str = None
|
|
1091
1334
|
if args.output:
|
|
1092
|
-
|
|
1093
|
-
open(scan_output, 'w').close()
|
|
1335
|
+
initialise_empty_file(args.output)
|
|
1094
1336
|
output_format = args.format if args.format else 'plain'
|
|
1095
1337
|
flags = args.flags if args.flags else None
|
|
1096
1338
|
if args.debug and not args.quiet:
|
|
@@ -1145,7 +1387,7 @@ def scan(parser, args): # noqa: PLR0912, PLR0915
|
|
|
1145
1387
|
quiet=args.quiet,
|
|
1146
1388
|
api_key=args.key,
|
|
1147
1389
|
url=args.apiurl,
|
|
1148
|
-
scan_output=
|
|
1390
|
+
scan_output=args.output,
|
|
1149
1391
|
output_format=output_format,
|
|
1150
1392
|
flags=flags,
|
|
1151
1393
|
nb_threads=args.threads,
|
|
@@ -1257,16 +1499,15 @@ def dependency(parser, args):
|
|
|
1257
1499
|
if not os.path.exists(args.scan_loc):
|
|
1258
1500
|
print_stderr(f'Error: File or folder specified does not exist: {args.scan_loc}.')
|
|
1259
1501
|
sys.exit(1)
|
|
1260
|
-
scan_output: str = None
|
|
1261
1502
|
if args.output:
|
|
1262
|
-
|
|
1263
|
-
open(scan_output, 'w').close()
|
|
1503
|
+
initialise_empty_file(args.output)
|
|
1264
1504
|
|
|
1265
1505
|
sc_deps = ScancodeDeps(
|
|
1266
1506
|
debug=args.debug, quiet=args.quiet, trace=args.trace, sc_command=args.sc_command, timeout=args.sc_timeout
|
|
1267
1507
|
)
|
|
1268
|
-
if not sc_deps.get_dependencies(what_to_scan=args.scan_loc, result_output=
|
|
1508
|
+
if not sc_deps.get_dependencies(what_to_scan=args.scan_loc, result_output=args.output):
|
|
1269
1509
|
sys.exit(1)
|
|
1510
|
+
return None
|
|
1270
1511
|
|
|
1271
1512
|
|
|
1272
1513
|
def convert(parser, args):
|
|
@@ -1304,143 +1545,341 @@ def convert(parser, args):
|
|
|
1304
1545
|
if not success:
|
|
1305
1546
|
sys.exit(1)
|
|
1306
1547
|
|
|
1307
|
-
|
|
1548
|
+
|
|
1549
|
+
# =============================================================================
|
|
1550
|
+
# INSPECT COMMAND HANDLERS - Functions that execute inspection operations
|
|
1551
|
+
# =============================================================================
|
|
1552
|
+
|
|
1308
1553
|
def inspect_copyleft(parser, args):
|
|
1309
1554
|
"""
|
|
1310
|
-
|
|
1555
|
+
Handle copyleft license inspection command.
|
|
1556
|
+
|
|
1557
|
+
Analyses scan results to identify components using copyleft licenses
|
|
1558
|
+
that may require compliance actions such as source code disclosure.
|
|
1559
|
+
|
|
1311
1560
|
Parameters
|
|
1312
1561
|
----------
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1562
|
+
parser : ArgumentParser
|
|
1563
|
+
Command line parser object for help display
|
|
1564
|
+
args : Namespace
|
|
1565
|
+
Parsed command line arguments containing:
|
|
1566
|
+
- input: Path to scan results file
|
|
1567
|
+
- output: Optional output file path
|
|
1568
|
+
- status: Optional status summary file path
|
|
1569
|
+
- format: Output format (json, md, jira_md)
|
|
1570
|
+
- include/exclude/explicit: License filter options
|
|
1317
1571
|
"""
|
|
1572
|
+
# Validate required input file parameter
|
|
1318
1573
|
if args.input is None:
|
|
1319
|
-
print_stderr('
|
|
1320
|
-
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1574
|
+
print_stderr('ERROR: Input file is required for copyleft inspection')
|
|
1575
|
+
parser.parse_args([args.subparser, args.subparsercmd, args.subparser_subcmd, '-h'])
|
|
1321
1576
|
sys.exit(1)
|
|
1322
|
-
output
|
|
1577
|
+
# Initialise output file if specified
|
|
1323
1578
|
if args.output:
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
status_output: str = None
|
|
1579
|
+
initialise_empty_file(args.output)
|
|
1580
|
+
# Initialise status summary file if specified
|
|
1328
1581
|
if args.status:
|
|
1329
|
-
|
|
1330
|
-
|
|
1582
|
+
initialise_empty_file(args.status)
|
|
1583
|
+
try:
|
|
1584
|
+
# Create and configure copyleft inspector
|
|
1585
|
+
i_copyleft = Copyleft(
|
|
1586
|
+
debug=args.debug,
|
|
1587
|
+
trace=args.trace,
|
|
1588
|
+
quiet=args.quiet,
|
|
1589
|
+
filepath=args.input,
|
|
1590
|
+
format_type=args.format,
|
|
1591
|
+
status=args.status,
|
|
1592
|
+
output=args.output,
|
|
1593
|
+
include=args.include, # Additional licenses to check
|
|
1594
|
+
exclude=args.exclude, # Licenses to ignore
|
|
1595
|
+
explicit=args.explicit, # Explicit license list
|
|
1596
|
+
)
|
|
1331
1597
|
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
include=args.include,
|
|
1341
|
-
exclude=args.exclude,
|
|
1342
|
-
explicit=args.explicit,
|
|
1343
|
-
)
|
|
1344
|
-
status, _ = i_copyleft.run()
|
|
1345
|
-
sys.exit(status)
|
|
1598
|
+
# Execute inspection and exit with appropriate status code
|
|
1599
|
+
status, _ = i_copyleft.run()
|
|
1600
|
+
sys.exit(status)
|
|
1601
|
+
except Exception as e:
|
|
1602
|
+
print_stderr(e)
|
|
1603
|
+
if args.debug:
|
|
1604
|
+
traceback.print_exc()
|
|
1605
|
+
sys.exit(1)
|
|
1346
1606
|
|
|
1347
1607
|
|
|
1348
1608
|
def inspect_undeclared(parser, args):
|
|
1349
1609
|
"""
|
|
1350
|
-
|
|
1610
|
+
Handle undeclared components inspection command.
|
|
1611
|
+
|
|
1612
|
+
Analyses scan results to identify components that are present in the
|
|
1613
|
+
codebase but not declared in SBOM or manifest files, which may indicate
|
|
1614
|
+
security or compliance risks.
|
|
1615
|
+
|
|
1351
1616
|
Parameters
|
|
1352
1617
|
----------
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1618
|
+
parser : ArgumentParser
|
|
1619
|
+
Command line parser object for help display
|
|
1620
|
+
args : Namespace
|
|
1621
|
+
Parsed command line arguments containing:
|
|
1622
|
+
- input: Path to scan results file
|
|
1623
|
+
- output: Optional output file path
|
|
1624
|
+
- status: Optional status summary file path
|
|
1625
|
+
- format: Output format (json, md, jira_md)
|
|
1626
|
+
- sbom_format: SBOM format type (legacy, settings)
|
|
1357
1627
|
"""
|
|
1628
|
+
# Validate required input file parameter
|
|
1358
1629
|
if args.input is None:
|
|
1359
|
-
print_stderr('
|
|
1360
|
-
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1630
|
+
print_stderr('ERROR: Input file is required for undeclared component inspection')
|
|
1631
|
+
parser.parse_args([args.subparser, args.subparsercmd, args.subparser_subcmd, '-h'])
|
|
1361
1632
|
sys.exit(1)
|
|
1362
|
-
|
|
1633
|
+
|
|
1634
|
+
# Initialise output file if specified
|
|
1363
1635
|
if args.output:
|
|
1364
|
-
|
|
1365
|
-
open(output, 'w').close()
|
|
1636
|
+
initialise_empty_file(args.output)
|
|
1366
1637
|
|
|
1367
|
-
|
|
1638
|
+
# Initialise status summary file if specified
|
|
1368
1639
|
if args.status:
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1640
|
+
initialise_empty_file(args.status)
|
|
1641
|
+
|
|
1642
|
+
try:
|
|
1643
|
+
# Create and configure undeclared component inspector
|
|
1644
|
+
i_undeclared = UndeclaredComponent(
|
|
1645
|
+
debug=args.debug,
|
|
1646
|
+
trace=args.trace,
|
|
1647
|
+
quiet=args.quiet,
|
|
1648
|
+
filepath=args.input,
|
|
1649
|
+
format_type=args.format,
|
|
1650
|
+
status=args.status,
|
|
1651
|
+
output=args.output,
|
|
1652
|
+
sbom_format=args.sbom_format, # Format for SBOM comparison
|
|
1653
|
+
)
|
|
1654
|
+
|
|
1655
|
+
# Execute inspection and exit with appropriate status code
|
|
1656
|
+
status, _ = i_undeclared.run()
|
|
1657
|
+
sys.exit(status)
|
|
1658
|
+
except Exception as e:
|
|
1659
|
+
print_stderr(e)
|
|
1660
|
+
if args.debug:
|
|
1661
|
+
traceback.print_exc()
|
|
1662
|
+
sys.exit(1)
|
|
1663
|
+
|
|
1383
1664
|
|
|
1384
1665
|
def inspect_license_summary(parser, args):
|
|
1385
1666
|
"""
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1667
|
+
Handle license summary inspection command.
|
|
1668
|
+
|
|
1669
|
+
Generates comprehensive summary of all licenses detected in scan results,
|
|
1670
|
+
including license counts, risk levels, and compliance recommendations.
|
|
1671
|
+
|
|
1672
|
+
Parameters
|
|
1673
|
+
----------
|
|
1674
|
+
parser : ArgumentParser
|
|
1675
|
+
Command line parser object for help display
|
|
1676
|
+
args : Namespace
|
|
1677
|
+
Parsed command line arguments containing:
|
|
1678
|
+
- input: Path to scan results file
|
|
1679
|
+
- output: Optional output file path
|
|
1680
|
+
- include/exclude/explicit: License filter options
|
|
1681
|
+
"""
|
|
1682
|
+
# Validate required input file parameter
|
|
1394
1683
|
if args.input is None:
|
|
1395
|
-
print_stderr('
|
|
1396
|
-
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1684
|
+
print_stderr('ERROR: Input file is required for license summary')
|
|
1685
|
+
parser.parse_args([args.subparser, args.subparsercmd, args.subparser_subcmd, '-h'])
|
|
1397
1686
|
sys.exit(1)
|
|
1398
|
-
|
|
1687
|
+
|
|
1688
|
+
# Initialise output file if specified
|
|
1399
1689
|
if args.output:
|
|
1400
|
-
|
|
1401
|
-
open(output, 'w').close()
|
|
1690
|
+
initialise_empty_file(args.output)
|
|
1402
1691
|
|
|
1692
|
+
# Create and configure license summary generator
|
|
1403
1693
|
i_license_summary = LicenseSummary(
|
|
1404
1694
|
debug=args.debug,
|
|
1405
1695
|
trace=args.trace,
|
|
1406
1696
|
quiet=args.quiet,
|
|
1407
1697
|
filepath=args.input,
|
|
1408
|
-
output=output,
|
|
1409
|
-
include=args.include,
|
|
1410
|
-
exclude=args.exclude,
|
|
1411
|
-
explicit=args.explicit,
|
|
1698
|
+
output=args.output,
|
|
1699
|
+
include=args.include, # Additional licenses to include
|
|
1700
|
+
exclude=args.exclude, # Licenses to exclude from summary
|
|
1701
|
+
explicit=args.explicit, # Explicit license list to summarize
|
|
1412
1702
|
)
|
|
1413
|
-
|
|
1703
|
+
try:
|
|
1704
|
+
# Execute summary generation
|
|
1705
|
+
i_license_summary.run()
|
|
1706
|
+
except Exception as e:
|
|
1707
|
+
print_stderr(e)
|
|
1708
|
+
if args.debug:
|
|
1709
|
+
traceback.print_exc()
|
|
1710
|
+
sys.exit(1)
|
|
1414
1711
|
|
|
1415
1712
|
def inspect_component_summary(parser, args):
|
|
1416
1713
|
"""
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1714
|
+
Handle component summary inspection command.
|
|
1715
|
+
|
|
1716
|
+
Generates a comprehensive summary of all components detected in scan results,
|
|
1717
|
+
including component counts, versions, match types, and security information.
|
|
1718
|
+
|
|
1719
|
+
Parameters
|
|
1720
|
+
----------
|
|
1721
|
+
parser : ArgumentParser
|
|
1722
|
+
Command line parser object for help display
|
|
1723
|
+
args : Namespace
|
|
1724
|
+
Parsed command line arguments containing:
|
|
1725
|
+
- input: Path to scan results file
|
|
1726
|
+
- output: Optional output file path
|
|
1727
|
+
"""
|
|
1728
|
+
# Validate required input file parameter
|
|
1425
1729
|
if args.input is None:
|
|
1426
|
-
print_stderr('
|
|
1427
|
-
parser.parse_args([args.subparser, args.subparsercmd, '-h'])
|
|
1730
|
+
print_stderr('ERROR: Input file is required for component summary')
|
|
1731
|
+
parser.parse_args([args.subparser, args.subparsercmd, args.subparser_subcmd, '-h'])
|
|
1428
1732
|
sys.exit(1)
|
|
1429
|
-
|
|
1733
|
+
|
|
1734
|
+
# Initialise an output file if specified
|
|
1430
1735
|
if args.output:
|
|
1431
|
-
output
|
|
1432
|
-
open(output, 'w').close()
|
|
1736
|
+
initialise_empty_file(args.output) # Create/clear output file
|
|
1433
1737
|
|
|
1738
|
+
# Create and configure component summary generator
|
|
1434
1739
|
i_component_summary = ComponentSummary(
|
|
1435
1740
|
debug=args.debug,
|
|
1436
1741
|
trace=args.trace,
|
|
1437
1742
|
quiet=args.quiet,
|
|
1438
1743
|
filepath=args.input,
|
|
1439
|
-
output=output,
|
|
1744
|
+
output=args.output,
|
|
1440
1745
|
)
|
|
1441
|
-
i_component_summary.run()
|
|
1442
1746
|
|
|
1443
|
-
|
|
1747
|
+
try:
|
|
1748
|
+
# Execute summary generation
|
|
1749
|
+
i_component_summary.run()
|
|
1750
|
+
except Exception as e:
|
|
1751
|
+
print_stderr(e)
|
|
1752
|
+
if args.debug:
|
|
1753
|
+
traceback.print_exc()
|
|
1754
|
+
sys.exit(1)
|
|
1755
|
+
|
|
1756
|
+
def inspect_dep_track_project_violations(parser, args):
|
|
1757
|
+
"""
|
|
1758
|
+
Handle Dependency Track project inspection command.
|
|
1759
|
+
|
|
1760
|
+
Analyses Dependency Track projects for policy violations, security issues,
|
|
1761
|
+
and compliance status. Connects to DT API to retrieve project data and
|
|
1762
|
+
generate detailed violation reports.
|
|
1763
|
+
|
|
1764
|
+
Parameters
|
|
1765
|
+
----------
|
|
1766
|
+
parser : ArgumentParser
|
|
1767
|
+
Command line parser object for help display
|
|
1768
|
+
args : Namespace
|
|
1769
|
+
Parsed command line arguments containing:
|
|
1770
|
+
- url: Dependency Track base URL
|
|
1771
|
+
- apikey: API key for authentication
|
|
1772
|
+
- project_id: Project UUID to inspect
|
|
1773
|
+
- project_name: Project name to inspect
|
|
1774
|
+
- project_version: Project version to inspect
|
|
1775
|
+
- upload_token: Upload token for project access
|
|
1776
|
+
- output: Optional output file path
|
|
1777
|
+
- format: Output format (json, md)
|
|
1778
|
+
- timeout: Optional timeout for API requests
|
|
1779
|
+
|
|
1780
|
+
"""
|
|
1781
|
+
# Make sure we have project id/project name and version
|
|
1782
|
+
_dt_args_validator(parser, args)
|
|
1783
|
+
# Initialise the output file if specified
|
|
1784
|
+
if args.output:
|
|
1785
|
+
initialise_empty_file(args.output)
|
|
1786
|
+
# Create and configure Dependency Track inspector
|
|
1787
|
+
try:
|
|
1788
|
+
dt_proj_violations = DependencyTrackProjectViolationPolicyCheck(
|
|
1789
|
+
debug=args.debug,
|
|
1790
|
+
trace=args.trace,
|
|
1791
|
+
quiet=args.quiet,
|
|
1792
|
+
output=args.output,
|
|
1793
|
+
status= args.status,
|
|
1794
|
+
format_type=args.format,
|
|
1795
|
+
url=args.url, # DT server URL
|
|
1796
|
+
api_key=args.apikey, # Authentication key
|
|
1797
|
+
project_id=args.project_id, # Target project UUID
|
|
1798
|
+
upload_token=args.upload_token, # Upload access token
|
|
1799
|
+
project_name=args.project_name, # DT project name
|
|
1800
|
+
project_version=args.project_version, # DT project version
|
|
1801
|
+
timeout=args.timeout,
|
|
1802
|
+
)
|
|
1803
|
+
|
|
1804
|
+
# Execute inspection and exit with appropriate status code
|
|
1805
|
+
status, _ = dt_proj_violations.run() #TODO remove datastructure from return
|
|
1806
|
+
sys.exit(status)
|
|
1807
|
+
except Exception as e:
|
|
1808
|
+
print_stderr(e)
|
|
1809
|
+
if args.debug:
|
|
1810
|
+
traceback.print_exc()
|
|
1811
|
+
sys.exit(1)
|
|
1812
|
+
|
|
1813
|
+
|
|
1814
|
+
# =============================================================================
|
|
1815
|
+
# END INSPECT COMMAND HANDLERS
|
|
1816
|
+
# =============================================================================
|
|
1817
|
+
|
|
1818
|
+
def export_dt(parser, args):
|
|
1819
|
+
"""
|
|
1820
|
+
Validates and exports a Software Bill of Materials (SBOM) to a Dependency-Track server.
|
|
1821
|
+
|
|
1822
|
+
Parameters:
|
|
1823
|
+
parser (argparse.ArgumentParser): The argument parser to validate input arguments.
|
|
1824
|
+
args (argparse.Namespace): Parsed arguments passed to the command.
|
|
1825
|
+
|
|
1826
|
+
Raises:
|
|
1827
|
+
SystemExit: If argument validation fails or uploading the SBOM to the Dependency-Track server
|
|
1828
|
+
is unsuccessful.
|
|
1829
|
+
"""
|
|
1830
|
+
# Make sure we have project id/project name and version
|
|
1831
|
+
_dt_args_validator(parser, args)
|
|
1832
|
+
if args.output:
|
|
1833
|
+
initialise_empty_file(args.output)
|
|
1834
|
+
if not args.quiet:
|
|
1835
|
+
print_stderr(f'Outputting export data result to: {args.output}')
|
|
1836
|
+
try:
|
|
1837
|
+
dt_exporter = DependencyTrackExporter(
|
|
1838
|
+
url=args.url,
|
|
1839
|
+
apikey=args.apikey,
|
|
1840
|
+
output=args.output,
|
|
1841
|
+
debug=args.debug,
|
|
1842
|
+
trace=args.trace,
|
|
1843
|
+
quiet=args.quiet,
|
|
1844
|
+
)
|
|
1845
|
+
success = dt_exporter.upload_sbom_file(args.input, args.project_id, args.project_name,
|
|
1846
|
+
args.project_version, args.output)
|
|
1847
|
+
if not success:
|
|
1848
|
+
sys.exit(1)
|
|
1849
|
+
except Exception as e:
|
|
1850
|
+
print_stderr(f'ERROR: {e}')
|
|
1851
|
+
if args.debug:
|
|
1852
|
+
traceback.print_exc()
|
|
1853
|
+
sys.exit(1)
|
|
1854
|
+
|
|
1855
|
+
def _dt_args_validator(parser, args):
|
|
1856
|
+
"""
|
|
1857
|
+
Validates command-line arguments related to project identification.
|
|
1858
|
+
|
|
1859
|
+
Parameters
|
|
1860
|
+
----------
|
|
1861
|
+
parser : argparse.ArgumentParser
|
|
1862
|
+
An argument parser instance for handling command-line arguments.
|
|
1863
|
+
args : argparse.Namespace
|
|
1864
|
+
Parsed arguments from the command line containing project-related information.
|
|
1865
|
+
|
|
1866
|
+
Raises
|
|
1867
|
+
------
|
|
1868
|
+
SystemExit
|
|
1869
|
+
If neither a project ID nor the required combination of project name and
|
|
1870
|
+
project version is provided, or if any of the compulsory arguments
|
|
1871
|
+
are missing.
|
|
1872
|
+
"""
|
|
1873
|
+
if not args.project_id and not args.project_name and not args.project_version:
|
|
1874
|
+
print_stderr(
|
|
1875
|
+
'Please specify either a project ID (--project-id) or a project name (--project-name) and '
|
|
1876
|
+
'version (--project-version)'
|
|
1877
|
+
)
|
|
1878
|
+
parser.parse_args([args.subparser, '-h'])
|
|
1879
|
+
sys.exit(1)
|
|
1880
|
+
if not args.project_id and (not args.project_name or not args.project_version):
|
|
1881
|
+
print_stderr('Please supply a project name (--project-name) and version (--project-version)')
|
|
1882
|
+
sys.exit(1)
|
|
1444
1883
|
|
|
1445
1884
|
def utils_certloc(*_):
|
|
1446
1885
|
"""
|
|
@@ -2045,7 +2484,31 @@ def get_scanoss_settings_from_args(args):
|
|
|
2045
2484
|
except ScanossSettingsError as e:
|
|
2046
2485
|
print_stderr(f'Error: {e}')
|
|
2047
2486
|
sys.exit(1)
|
|
2048
|
-
|
|
2487
|
+
return scanoss_settings
|
|
2488
|
+
|
|
2489
|
+
|
|
2490
|
+
def initialise_empty_file(filename: str):
|
|
2491
|
+
"""
|
|
2492
|
+
Initialises an empty file with the specified name. If the file already exists,
|
|
2493
|
+
it truncates its content. Ensures proper error handling in case of failure.
|
|
2494
|
+
|
|
2495
|
+
Args:
|
|
2496
|
+
filename (str): The name of the file to be initialised.
|
|
2497
|
+
|
|
2498
|
+
Raises:
|
|
2499
|
+
SystemExit: If the file cannot be created or written due to an exception,
|
|
2500
|
+
the function prints an error message and exits the program.
|
|
2501
|
+
|
|
2502
|
+
Note:
|
|
2503
|
+
This function writes an empty file and handles exceptions to ensure the
|
|
2504
|
+
program does not continue execution in case of an error.
|
|
2505
|
+
"""
|
|
2506
|
+
if filename:
|
|
2507
|
+
try:
|
|
2508
|
+
open(filename, 'w').close()
|
|
2509
|
+
except Exception as e:
|
|
2510
|
+
print_stderr(f'Error: Unable to create output file {filename}: {e}')
|
|
2511
|
+
sys.exit(1)
|
|
2049
2512
|
|
|
2050
2513
|
|
|
2051
2514
|
def main():
|