20
20
)
21
21
from macaron .config .defaults import create_defaults , load_defaults
22
22
from macaron .config .global_config import global_config
23
+ from macaron .console import access_handler
23
24
from macaron .errors import ConfigurationError
24
25
from macaron .output_reporter .reporter import HTMLReporter , JSONReporter , PolicyReporter
25
26
from macaron .policy_engine .policy_engine import run_policy_engine , show_prelude
@@ -63,7 +64,8 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
63
64
if analyzer_single_args .provenance_expectation is not None :
64
65
if not os .path .exists (analyzer_single_args .provenance_expectation ):
65
66
logger .critical (
66
- 'The provenance expectation file "%s" does not exist.' , analyzer_single_args .provenance_expectation
67
+ 'The provenance expectation file "%s" does not exist.' ,
68
+ analyzer_single_args .provenance_expectation ,
67
69
)
68
70
sys .exit (os .EX_OSFILE )
69
71
global_config .load_expectation_files (analyzer_single_args .provenance_expectation )
@@ -72,7 +74,8 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
72
74
if analyzer_single_args .python_venv is not None :
73
75
if not os .path .exists (analyzer_single_args .python_venv ):
74
76
logger .critical (
75
- 'The Python virtual environment path "%s" does not exist.' , analyzer_single_args .python_venv
77
+ 'The Python virtual environment path "%s" does not exist.' ,
78
+ analyzer_single_args .python_venv ,
76
79
)
77
80
sys .exit (os .EX_OSFILE )
78
81
global_config .load_python_venv (analyzer_single_args .python_venv )
@@ -95,7 +98,10 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
95
98
else :
96
99
user_provided_local_maven_repo = analyzer_single_args .local_maven_repo
97
100
if not os .path .isdir (user_provided_local_maven_repo ):
98
- logger .error ("The user provided local Maven repo at %s is not valid." , user_provided_local_maven_repo )
101
+ logger .error (
102
+ "The user provided local Maven repo at %s is not valid." ,
103
+ user_provided_local_maven_repo ,
104
+ )
99
105
sys .exit (os .EX_USAGE )
100
106
101
107
global_config .local_maven_repo = user_provided_local_maven_repo
@@ -111,7 +117,8 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
111
117
lstrip_blocks = True ,
112
118
)
113
119
html_reporter = HTMLReporter (
114
- env = custom_jinja_env , target_template = os .path .basename (analyzer_single_args .template_path )
120
+ env = custom_jinja_env ,
121
+ target_template = os .path .basename (analyzer_single_args .template_path ),
115
122
)
116
123
if not html_reporter .template :
117
124
logger .error ("Exiting because the custom template cannot be found." )
@@ -207,8 +214,10 @@ def verify_policy(verify_policy_args: argparse.Namespace) -> int:
207
214
208
215
result = run_policy_engine (verify_policy_args .database , policy_content )
209
216
vsa = generate_vsa (policy_content = policy_content , policy_result = result )
217
+ rich_handler = access_handler .get_handler ()
210
218
if vsa is not None :
211
219
vsa_filepath = os .path .join (global_config .output_path , "vsa.intoto.jsonl" )
220
+ rich_handler .update_vsa (vsa_filepath )
212
221
logger .info (
213
222
"Generating the Verification Summary Attestation (VSA) to %s." ,
214
223
os .path .relpath (vsa_filepath , os .getcwd ()),
@@ -222,8 +231,12 @@ def verify_policy(verify_policy_args: argparse.Namespace) -> int:
222
231
file .write (json .dumps (vsa ))
223
232
except OSError as err :
224
233
logger .error (
225
- "Could not generate the VSA to %s. Error: %s" , os .path .relpath (vsa_filepath , os .getcwd ()), err
234
+ "Could not generate the VSA to %s. Error: %s" ,
235
+ os .path .relpath (vsa_filepath , os .getcwd ()),
236
+ err ,
226
237
)
238
+ else :
239
+ rich_handler .update_vsa ("No VSA generated." )
227
240
228
241
policy_reporter = PolicyReporter ()
229
242
policy_reporter .generate (global_config .output_path , result )
@@ -290,16 +303,23 @@ def find_source(find_args: argparse.Namespace) -> int:
290
303
291
304
def perform_action (action_args : argparse .Namespace ) -> None :
292
305
"""Perform the indicated action of Macaron."""
306
+ rich_handler = access_handler .get_handler ()
293
307
match action_args .action :
294
308
case "dump-defaults" :
309
+ if not action_args .disable_rich_output :
310
+ rich_handler .start ("dump-defaults" )
295
311
# Create the defaults.ini file in the output dir and exit.
296
312
create_defaults (action_args .output_dir , os .getcwd ())
297
313
sys .exit (os .EX_OK )
298
314
299
315
case "verify-policy" :
316
+ if not action_args .disable_rich_output :
317
+ rich_handler .start ("verify-policy" )
300
318
sys .exit (verify_policy (action_args ))
301
319
302
320
case "analyze" :
321
+ if not action_args .disable_rich_output :
322
+ rich_handler .start ("analyze" )
303
323
if not global_config .gh_token :
304
324
logger .error ("GitHub access token not set." )
305
325
sys .exit (os .EX_USAGE )
@@ -317,6 +337,8 @@ def perform_action(action_args: argparse.Namespace) -> None:
317
337
analyze_slsa_levels_single (action_args )
318
338
319
339
case "find-source" :
340
+ if not action_args .disable_rich_output :
341
+ rich_handler .start ("find-source" )
320
342
try :
321
343
for git_service in GIT_SERVICES :
322
344
git_service .load_defaults ()
@@ -393,6 +415,14 @@ def main(argv: list[str] | None = None) -> None:
393
415
action = "store_true" ,
394
416
)
395
417
418
+ main_parser .add_argument (
419
+ "-dro" ,
420
+ "--disable-rich-output" ,
421
+ default = False ,
422
+ help = "Disable Rich UI output" ,
423
+ action = "store_true" ,
424
+ )
425
+
396
426
main_parser .add_argument (
397
427
"-o" ,
398
428
"--output-dir" ,
@@ -531,7 +561,10 @@ def main(argv: list[str] | None = None) -> None:
531
561
)
532
562
533
563
# Dump the default values.
534
- sub_parser .add_parser (name = "dump-defaults" , description = "Dumps the defaults.ini file to the output directory." )
564
+ sub_parser .add_parser (
565
+ name = "dump-defaults" ,
566
+ description = "Dumps the defaults.ini file to the output directory." ,
567
+ )
535
568
536
569
# Verify the Datalog policy.
537
570
vp_parser = sub_parser .add_parser (name = "verify-policy" )
@@ -593,65 +626,94 @@ def main(argv: list[str] | None = None) -> None:
593
626
main_parser .print_help ()
594
627
sys .exit (os .EX_USAGE )
595
628
596
- if args .verbose :
597
- log_level = logging .DEBUG
598
- log_format = "%(asctime)s [%(name)s:%(funcName)s:%(lineno)d] [%(levelname)s] %(message)s"
599
- else :
600
- log_level = logging .INFO
601
- log_format = "%(asctime)s [%(levelname)s] %(message)s"
602
-
603
629
# Set global logging config. We need the stream handler for the initial
604
630
# output directory checking log messages.
605
- st_handler = logging .StreamHandler (sys .stdout )
606
- logging .basicConfig (format = log_format , handlers = [st_handler ], force = True , level = log_level )
631
+ st_handler : logging .StreamHandler = logging .StreamHandler (sys .stdout )
632
+ rich_handler : logging .Handler = logging .Handler ()
633
+ if args .disable_rich_output :
634
+ if args .verbose :
635
+ log_level = logging .DEBUG
636
+ log_format = "%(asctime)s [%(name)s:%(funcName)s:%(lineno)d] [%(levelname)s] %(message)s"
637
+ else :
638
+ log_level = logging .INFO
639
+ log_format = "%(asctime)s [%(levelname)s] %(message)s"
640
+ st_handler = logging .StreamHandler (sys .stdout )
641
+ logging .basicConfig (format = log_format , handlers = [st_handler ], force = True , level = log_level )
642
+ else :
643
+ if args .verbose :
644
+ log_level = logging .DEBUG
645
+ log_format = "%(asctime)s [%(name)s:%(funcName)s:%(lineno)d] %(message)s"
646
+ else :
647
+ log_level = logging .INFO
648
+ log_format = "%(asctime)s %(message)s"
649
+ rich_handler = access_handler .set_handler (args .verbose )
650
+ logging .basicConfig (format = log_format , handlers = [rich_handler ], force = True , level = log_level )
607
651
608
- # Set the output directory.
609
- if not args .output_dir :
610
- logger .error ("The output path cannot be empty. Exiting ..." )
611
- sys .exit (os .EX_USAGE )
652
+ try :
653
+ # Set the output directory.
654
+ if not args .output_dir :
655
+ logger .error ("The output path cannot be empty. Exiting ..." )
656
+ sys .exit (os .EX_USAGE )
612
657
613
- if os .path .isfile (args .output_dir ):
614
- logger .error ("The output directory already exists. Exiting ..." )
615
- sys .exit (os .EX_USAGE )
658
+ if os .path .isfile (args .output_dir ):
659
+ logger .error ("The output directory already exists. Exiting ..." )
660
+ sys .exit (os .EX_USAGE )
616
661
617
- if os .path .isdir (args .output_dir ):
618
- logger .info ("Setting the output directory to %s" , os .path .relpath (args .output_dir , os .getcwd ()))
619
- else :
620
- logger .info ("No directory at %s. Creating one ..." , os .path .relpath (args .output_dir , os .getcwd ()))
621
- os .makedirs (args .output_dir )
622
-
623
- # Add file handler to the root logger. Remove stream handler from the
624
- # root logger to prevent dependencies printing logs to stdout.
625
- debug_log_path = os .path .join (args .output_dir , "debug.log" )
626
- log_file_handler = logging .FileHandler (debug_log_path , "w" )
627
- log_file_handler .setFormatter (logging .Formatter (log_format ))
628
- logging .getLogger ().removeHandler (st_handler )
629
- logging .getLogger ().addHandler (log_file_handler )
630
-
631
- # Add StreamHandler to the Macaron logger only.
632
- mcn_logger = logging .getLogger ("macaron" )
633
- mcn_logger .addHandler (st_handler )
634
-
635
- logger .info ("The logs will be stored in debug.log" )
636
-
637
- # Set Macaron's global configuration.
638
- # The path to provenance expectation files will be updated if
639
- # set through analyze sub-command.
640
- global_config .load (
641
- macaron_path = macaron .MACARON_PATH ,
642
- output_path = args .output_dir ,
643
- build_log_path = os .path .join (args .output_dir , "build_log" ),
644
- debug_level = log_level ,
645
- local_repos_path = args .local_repos_path ,
646
- resources_path = os .path .join (macaron .MACARON_PATH , "resources" ),
647
- )
662
+ if os .path .isdir (args .output_dir ):
663
+ logger .info (
664
+ "Setting the output directory to %s" ,
665
+ os .path .relpath (args .output_dir , os .getcwd ()),
666
+ )
667
+ else :
668
+ logger .info (
669
+ "No directory at %s. Creating one ..." ,
670
+ os .path .relpath (args .output_dir , os .getcwd ()),
671
+ )
672
+ os .makedirs (args .output_dir )
673
+
674
+ # Add file handler to the root logger. Remove stream handler from the
675
+ # root logger to prevent dependencies printing logs to stdout.
676
+ debug_log_path = os .path .join (args .output_dir , "debug.log" )
677
+ log_file_handler = logging .FileHandler (debug_log_path , "w" )
678
+ log_file_handler .setFormatter (logging .Formatter (log_format ))
679
+ if args .disable_rich_output :
680
+ logging .getLogger ().removeHandler (st_handler )
681
+ else :
682
+ logging .getLogger ().removeHandler (rich_handler )
683
+ logging .getLogger ().addHandler (log_file_handler )
684
+
685
+ # Add StreamHandler to the Macaron logger only.
686
+ mcn_logger = logging .getLogger ("macaron" )
687
+ if args .disable_rich_output :
688
+ mcn_logger .addHandler (st_handler )
689
+ else :
690
+ mcn_logger .addHandler (rich_handler )
691
+
692
+ logger .info ("The logs will be stored in debug.log" )
693
+
694
+ # Set Macaron's global configuration.
695
+ # The path to provenance expectation files will be updated if
696
+ # set through analyze sub-command.
697
+ global_config .load (
698
+ macaron_path = macaron .MACARON_PATH ,
699
+ output_path = args .output_dir ,
700
+ build_log_path = os .path .join (args .output_dir , "build_log" ),
701
+ debug_level = log_level ,
702
+ local_repos_path = args .local_repos_path ,
703
+ resources_path = os .path .join (macaron .MACARON_PATH , "resources" ),
704
+ )
648
705
649
- # Load the default values from defaults.ini files.
650
- if not load_defaults (args .defaults_path ):
651
- logger .error ("Exiting because the defaults configuration could not be loaded." )
652
- sys .exit (os .EX_NOINPUT )
706
+ # Load the default values from defaults.ini files.
707
+ if not load_defaults (args .defaults_path ):
708
+ logger .error ("Exiting because the defaults configuration could not be loaded." )
709
+ sys .exit (os .EX_NOINPUT )
653
710
654
- perform_action (args )
711
+ perform_action (args )
712
+ finally :
713
+ if args .disable_rich_output :
714
+ st_handler .close ()
715
+ else :
716
+ rich_handler .close ()
655
717
656
718
657
719
def _get_token_from_dict_or_env (token : str , token_dict : dict [str , str ]) -> str :
0 commit comments