11from collections import defaultdict
22from typing import TYPE_CHECKING , Dict , List
33
4- import click
4+ import typer
55
66from cycode .cli .cli_types import SeverityOption
77from cycode .cli .consts import LICENSE_COMPLIANCE_POLICY_ID , PACKAGE_VULNERABILITY_POLICY_ID
88from cycode .cli .models import Detection
99from cycode .cli .printers .tables .table import Table
10- from cycode .cli .printers .tables .table_models import ColumnInfoBuilder , ColumnWidths
10+ from cycode .cli .printers .tables .table_models import ColumnInfoBuilder
1111from cycode .cli .printers .tables .table_printer_base import TablePrinterBase
1212from cycode .cli .utils .string_utils import shortcut_dependency_paths
1313
1919# Building must have strict order. Represents the order of the columns in the table (from left to right)
2020SEVERITY_COLUMN = column_builder .build (name = 'Severity' )
2121REPOSITORY_COLUMN = column_builder .build (name = 'Repository' )
22- CODE_PROJECT_COLUMN = column_builder .build (name = 'Code Project' ) # File path to manifest file
23- ECOSYSTEM_COLUMN = column_builder .build (name = 'Ecosystem' )
24- PACKAGE_COLUMN = column_builder .build (name = 'Package' )
25- CVE_COLUMNS = column_builder .build (name = 'CVE' )
22+ CODE_PROJECT_COLUMN = column_builder .build (name = 'Code Project' , highlight = False ) # File path to the manifest file
23+ ECOSYSTEM_COLUMN = column_builder .build (name = 'Ecosystem' , highlight = False )
24+ PACKAGE_COLUMN = column_builder .build (name = 'Package' , highlight = False )
25+ CVE_COLUMNS = column_builder .build (name = 'CVE' , highlight = False )
2626DEPENDENCY_PATHS_COLUMN = column_builder .build (name = 'Dependency Paths' )
2727UPGRADE_COLUMN = column_builder .build (name = 'Upgrade' )
28- LICENSE_COLUMN = column_builder .build (name = 'License' )
28+ LICENSE_COLUMN = column_builder .build (name = 'License' , highlight = False )
2929DIRECT_DEPENDENCY_COLUMN = column_builder .build (name = 'Direct Dependency' )
3030DEVELOPMENT_DEPENDENCY_COLUMN = column_builder .build (name = 'Development Dependency' )
3131
32- COLUMN_WIDTHS_CONFIG : ColumnWidths = {
33- REPOSITORY_COLUMN : 2 ,
34- CODE_PROJECT_COLUMN : 2 ,
35- PACKAGE_COLUMN : 3 ,
36- CVE_COLUMNS : 5 ,
37- UPGRADE_COLUMN : 3 ,
38- LICENSE_COLUMN : 2 ,
39- }
40-
4132
4233class ScaTablePrinter (TablePrinterBase ):
4334 def _print_results (self , local_scan_results : List ['LocalScanResult' ]) -> None :
4435 aggregation_report_url = self .ctx .obj .get ('aggregation_report_url' )
4536 detections_per_policy_id = self ._extract_detections_per_policy_id (local_scan_results )
4637 for policy_id , detections in detections_per_policy_id .items ():
4738 table = self ._get_table (policy_id )
48- table .set_cols_width (COLUMN_WIDTHS_CONFIG )
4939
5040 for detection in self ._sort_and_group_detections (detections ):
51- self ._enrich_table_with_values (table , detection )
41+ self ._enrich_table_with_values (policy_id , table , detection )
5242
5343 self ._print_summary_issues (len (detections ), self ._get_title (policy_id ))
5444 self ._print_table (table )
@@ -90,7 +80,7 @@ def _sort_and_group_detections(self, detections: List[Detection]) -> List[Detect
9080 """Sort detections by severity and group by repository, code project and package name.
9181
9282 Note:
93- Code Project is path to manifest file.
83+ Code Project is path to the manifest file.
9484
9585 Grouping by code projects also groups by ecosystem.
9686 Because manifest files are unique per ecosystem.
@@ -114,55 +104,75 @@ def _get_table(self, policy_id: str) -> Table:
114104 table = Table ()
115105
116106 if policy_id == PACKAGE_VULNERABILITY_POLICY_ID :
117- table .add (SEVERITY_COLUMN )
118- table .add (CVE_COLUMNS )
119- table .add (UPGRADE_COLUMN )
107+ table .add_column (CVE_COLUMNS )
108+ table .add_column (UPGRADE_COLUMN )
120109 elif policy_id == LICENSE_COMPLIANCE_POLICY_ID :
121- table .add (LICENSE_COLUMN )
110+ table .add_column (LICENSE_COLUMN )
122111
123112 if self ._is_git_repository ():
124- table .add (REPOSITORY_COLUMN )
113+ table .add_column (REPOSITORY_COLUMN )
125114
126- table .add (CODE_PROJECT_COLUMN )
127- table .add (ECOSYSTEM_COLUMN )
128- table .add (PACKAGE_COLUMN )
129- table .add (DIRECT_DEPENDENCY_COLUMN )
130- table .add (DEVELOPMENT_DEPENDENCY_COLUMN )
131- table .add (DEPENDENCY_PATHS_COLUMN )
115+ table .add_column (SEVERITY_COLUMN )
116+ table .add_column (CODE_PROJECT_COLUMN )
117+ table .add_column (ECOSYSTEM_COLUMN )
118+ table .add_column (PACKAGE_COLUMN )
119+ table .add_column (DIRECT_DEPENDENCY_COLUMN )
120+ table .add_column (DEVELOPMENT_DEPENDENCY_COLUMN )
121+ table .add_column (DEPENDENCY_PATHS_COLUMN )
132122
133123 return table
134124
135125 @staticmethod
136- def _enrich_table_with_values (table : Table , detection : Detection ) -> None :
126+ def _enrich_table_with_values (policy_id : str , table : Table , detection : Detection ) -> None :
137127 detection_details = detection .detection_details
138128
139- table .set (SEVERITY_COLUMN , detection_details .get ('advisory_severity' ))
140- table .set (REPOSITORY_COLUMN , detection_details .get ('repository_name' ))
141-
142- table .set (CODE_PROJECT_COLUMN , detection_details .get ('file_name' ))
143- table .set (ECOSYSTEM_COLUMN , detection_details .get ('ecosystem' ))
144- table .set (PACKAGE_COLUMN , detection_details .get ('package_name' ))
145- table .set (DIRECT_DEPENDENCY_COLUMN , detection_details .get ('is_direct_dependency_str' ))
146- table .set (DEVELOPMENT_DEPENDENCY_COLUMN , detection_details .get ('is_dev_dependency_str' ))
129+ severity = None
130+ if policy_id == PACKAGE_VULNERABILITY_POLICY_ID :
131+ severity = detection_details .get ('advisory_severity' )
132+ elif policy_id == LICENSE_COMPLIANCE_POLICY_ID :
133+ severity = detection .severity
134+
135+ if not severity :
136+ severity = 'N/A'
137+
138+ table .add_cell (SEVERITY_COLUMN , severity , SeverityOption .get_member_color (severity ))
139+
140+ table .add_cell (REPOSITORY_COLUMN , detection_details .get ('repository_name' ))
141+ table .add_file_path_cell (CODE_PROJECT_COLUMN , detection_details .get ('file_name' ))
142+ table .add_cell (ECOSYSTEM_COLUMN , detection_details .get ('ecosystem' ))
143+ table .add_cell (PACKAGE_COLUMN , detection_details .get ('package_name' ))
144+
145+ direct_dependency_color = 'green' if detection_details .get ('is_direct_dependency' ) else 'red'
146+ table .add_cell (
147+ column = DIRECT_DEPENDENCY_COLUMN ,
148+ value = detection_details .get ('is_direct_dependency_str' ),
149+ color = direct_dependency_color ,
150+ )
151+ dev_dependency_color = 'green' if detection_details .get ('is_dev_dependency' ) else 'red'
152+ table .add_cell (
153+ column = DEVELOPMENT_DEPENDENCY_COLUMN ,
154+ value = detection_details .get ('is_dev_dependency_str' ),
155+ color = dev_dependency_color ,
156+ )
147157
148158 dependency_paths = 'N/A'
149159 dependency_paths_raw = detection_details .get ('dependency_paths' )
150160 if dependency_paths_raw :
151161 dependency_paths = shortcut_dependency_paths (dependency_paths_raw )
152- table .set (DEPENDENCY_PATHS_COLUMN , dependency_paths )
162+ table .add_cell (DEPENDENCY_PATHS_COLUMN , dependency_paths )
153163
154164 upgrade = ''
155165 alert = detection_details .get ('alert' )
156166 if alert and alert .get ('first_patched_version' ):
157167 upgrade = f'{ alert .get ("vulnerable_requirements" )} -> { alert .get ("first_patched_version" )} '
158- table .set (UPGRADE_COLUMN , upgrade )
168+ table .add_cell (UPGRADE_COLUMN , upgrade )
159169
160- table .set (CVE_COLUMNS , detection_details .get ('vulnerability_id' ))
161- table .set (LICENSE_COLUMN , detection_details .get ('license' ))
170+ table .add_cell (CVE_COLUMNS , detection_details .get ('vulnerability_id' ))
171+ table .add_cell (LICENSE_COLUMN , detection_details .get ('license' ))
162172
163173 @staticmethod
164174 def _print_summary_issues (detections_count : int , title : str ) -> None :
165- click .echo (f'⛔ Found { detections_count } issues of type: { click .style (title , bold = True )} ' )
175+ typer .echo (f'⛔ Found { detections_count } issues of type: { typer .style (title , bold = True )} ' )
166176
167177 @staticmethod
168178 def _extract_detections_per_policy_id (
0 commit comments