16
16
import macaron
17
17
from macaron .config .defaults import create_defaults , load_defaults
18
18
from macaron .config .global_config import global_config
19
+ from macaron .console import access_handler
19
20
from macaron .errors import ConfigurationError
20
21
from macaron .output_reporter .reporter import HTMLReporter , JSONReporter , PolicyReporter
21
22
from macaron .policy_engine .policy_engine import run_policy_engine , show_prelude
@@ -59,7 +60,8 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
59
60
if analyzer_single_args .provenance_expectation is not None :
60
61
if not os .path .exists (analyzer_single_args .provenance_expectation ):
61
62
logger .critical (
62
- 'The provenance expectation file "%s" does not exist.' , analyzer_single_args .provenance_expectation
63
+ 'The provenance expectation file "%s" does not exist.' ,
64
+ analyzer_single_args .provenance_expectation ,
63
65
)
64
66
sys .exit (os .EX_OSFILE )
65
67
global_config .load_expectation_files (analyzer_single_args .provenance_expectation )
@@ -68,7 +70,8 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
68
70
if analyzer_single_args .python_venv is not None :
69
71
if not os .path .exists (analyzer_single_args .python_venv ):
70
72
logger .critical (
71
- 'The Python virtual environment path "%s" does not exist.' , analyzer_single_args .python_venv
73
+ 'The Python virtual environment path "%s" does not exist.' ,
74
+ analyzer_single_args .python_venv ,
72
75
)
73
76
sys .exit (os .EX_OSFILE )
74
77
global_config .load_python_venv (analyzer_single_args .python_venv )
@@ -91,7 +94,10 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
91
94
else :
92
95
user_provided_local_maven_repo = analyzer_single_args .local_maven_repo
93
96
if not os .path .isdir (user_provided_local_maven_repo ):
94
- logger .error ("The user provided local Maven repo at %s is not valid." , user_provided_local_maven_repo )
97
+ logger .error (
98
+ "The user provided local Maven repo at %s is not valid." ,
99
+ user_provided_local_maven_repo ,
100
+ )
95
101
sys .exit (os .EX_USAGE )
96
102
97
103
global_config .local_maven_repo = user_provided_local_maven_repo
@@ -107,7 +113,8 @@ def analyze_slsa_levels_single(analyzer_single_args: argparse.Namespace) -> None
107
113
lstrip_blocks = True ,
108
114
)
109
115
html_reporter = HTMLReporter (
110
- env = custom_jinja_env , target_template = os .path .basename (analyzer_single_args .template_path )
116
+ env = custom_jinja_env ,
117
+ target_template = os .path .basename (analyzer_single_args .template_path ),
111
118
)
112
119
if not html_reporter .template :
113
120
logger .error ("Exiting because the custom template cannot be found." )
@@ -203,8 +210,10 @@ def verify_policy(verify_policy_args: argparse.Namespace) -> int:
203
210
204
211
result = run_policy_engine (verify_policy_args .database , policy_content )
205
212
vsa = generate_vsa (policy_content = policy_content , policy_result = result )
213
+ rich_handler = access_handler .get_handler ()
206
214
if vsa is not None :
207
215
vsa_filepath = os .path .join (global_config .output_path , "vsa.intoto.jsonl" )
216
+ rich_handler .update_vsa (vsa_filepath )
208
217
logger .info (
209
218
"Generating the Verification Summary Attestation (VSA) to %s." ,
210
219
os .path .relpath (vsa_filepath , os .getcwd ()),
@@ -218,8 +227,12 @@ def verify_policy(verify_policy_args: argparse.Namespace) -> int:
218
227
file .write (json .dumps (vsa ))
219
228
except OSError as err :
220
229
logger .error (
221
- "Could not generate the VSA to %s. Error: %s" , os .path .relpath (vsa_filepath , os .getcwd ()), err
230
+ "Could not generate the VSA to %s. Error: %s" ,
231
+ os .path .relpath (vsa_filepath , os .getcwd ()),
232
+ err ,
222
233
)
234
+ else :
235
+ rich_handler .update_vsa ("No VSA generated." )
223
236
224
237
policy_reporter = PolicyReporter ()
225
238
policy_reporter .generate (global_config .output_path , result )
@@ -245,16 +258,23 @@ def find_source(find_args: argparse.Namespace) -> int:
245
258
246
259
def perform_action (action_args : argparse .Namespace ) -> None :
247
260
"""Perform the indicated action of Macaron."""
261
+ rich_handler = access_handler .get_handler ()
248
262
match action_args .action :
249
263
case "dump-defaults" :
264
+ if not action_args .disable_rich_output :
265
+ rich_handler .start ("dump-defaults" )
250
266
# Create the defaults.ini file in the output dir and exit.
251
267
create_defaults (action_args .output_dir , os .getcwd ())
252
268
sys .exit (os .EX_OK )
253
269
254
270
case "verify-policy" :
271
+ if not action_args .disable_rich_output :
272
+ rich_handler .start ("verify-policy" )
255
273
sys .exit (verify_policy (action_args ))
256
274
257
275
case "analyze" :
276
+ if not action_args .disable_rich_output :
277
+ rich_handler .start ("analyze" )
258
278
if not global_config .gh_token :
259
279
logger .error ("GitHub access token not set." )
260
280
sys .exit (os .EX_USAGE )
@@ -272,6 +292,8 @@ def perform_action(action_args: argparse.Namespace) -> None:
272
292
analyze_slsa_levels_single (action_args )
273
293
274
294
case "find-source" :
295
+ if not action_args .disable_rich_output :
296
+ rich_handler .start ("find-source" )
275
297
try :
276
298
for git_service in GIT_SERVICES :
277
299
git_service .load_defaults ()
@@ -345,6 +367,14 @@ def main(argv: list[str] | None = None) -> None:
345
367
action = "store_true" ,
346
368
)
347
369
370
+ main_parser .add_argument (
371
+ "-dro" ,
372
+ "--disable-rich-output" ,
373
+ default = False ,
374
+ help = "Disable Rich UI output" ,
375
+ action = "store_true" ,
376
+ )
377
+
348
378
main_parser .add_argument (
349
379
"-o" ,
350
380
"--output-dir" ,
@@ -483,7 +513,10 @@ def main(argv: list[str] | None = None) -> None:
483
513
)
484
514
485
515
# Dump the default values.
486
- sub_parser .add_parser (name = "dump-defaults" , description = "Dumps the defaults.ini file to the output directory." )
516
+ sub_parser .add_parser (
517
+ name = "dump-defaults" ,
518
+ description = "Dumps the defaults.ini file to the output directory." ,
519
+ )
487
520
488
521
# Verify the Datalog policy.
489
522
vp_parser = sub_parser .add_parser (name = "verify-policy" )
@@ -521,65 +554,94 @@ def main(argv: list[str] | None = None) -> None:
521
554
main_parser .print_help ()
522
555
sys .exit (os .EX_USAGE )
523
556
524
- if args .verbose :
525
- log_level = logging .DEBUG
526
- log_format = "%(asctime)s [%(name)s:%(funcName)s:%(lineno)d] [%(levelname)s] %(message)s"
527
- else :
528
- log_level = logging .INFO
529
- log_format = "%(asctime)s [%(levelname)s] %(message)s"
530
-
531
557
# Set global logging config. We need the stream handler for the initial
532
558
# output directory checking log messages.
533
- st_handler = logging .StreamHandler (sys .stdout )
534
- logging .basicConfig (format = log_format , handlers = [st_handler ], force = True , level = log_level )
535
-
536
- # Set the output directory.
537
- if not args .output_dir :
538
- logger .error ("The output path cannot be empty. Exiting ..." )
539
- sys .exit (os .EX_USAGE )
559
+ st_handler : logging .StreamHandler = logging .StreamHandler (sys .stdout )
560
+ rich_handler : logging .Handler = logging .Handler ()
561
+ if args .disable_rich_output :
562
+ if args .verbose :
563
+ log_level = logging .DEBUG
564
+ log_format = "%(asctime)s [%(name)s:%(funcName)s:%(lineno)d] [%(levelname)s] %(message)s"
565
+ else :
566
+ log_level = logging .INFO
567
+ log_format = "%(asctime)s [%(levelname)s] %(message)s"
568
+ st_handler = logging .StreamHandler (sys .stdout )
569
+ logging .basicConfig (format = log_format , handlers = [st_handler ], force = True , level = log_level )
570
+ else :
571
+ if args .verbose :
572
+ log_level = logging .DEBUG
573
+ log_format = "%(asctime)s [%(name)s:%(funcName)s:%(lineno)d] %(message)s"
574
+ else :
575
+ log_level = logging .INFO
576
+ log_format = "%(asctime)s %(message)s"
577
+ rich_handler = access_handler .set_handler (args .verbose )
578
+ logging .basicConfig (format = log_format , handlers = [rich_handler ], force = True , level = log_level )
579
+
580
+ try :
581
+ # Set the output directory.
582
+ if not args .output_dir :
583
+ logger .error ("The output path cannot be empty. Exiting ..." )
584
+ sys .exit (os .EX_USAGE )
540
585
541
- if os .path .isfile (args .output_dir ):
542
- logger .error ("The output directory already exists. Exiting ..." )
543
- sys .exit (os .EX_USAGE )
586
+ if os .path .isfile (args .output_dir ):
587
+ logger .error ("The output directory already exists. Exiting ..." )
588
+ sys .exit (os .EX_USAGE )
544
589
545
- if os .path .isdir (args .output_dir ):
546
- logger .info ("Setting the output directory to %s" , os .path .relpath (args .output_dir , os .getcwd ()))
547
- else :
548
- logger .info ("No directory at %s. Creating one ..." , os .path .relpath (args .output_dir , os .getcwd ()))
549
- os .makedirs (args .output_dir )
550
-
551
- # Add file handler to the root logger. Remove stream handler from the
552
- # root logger to prevent dependencies printing logs to stdout.
553
- debug_log_path = os .path .join (args .output_dir , "debug.log" )
554
- log_file_handler = logging .FileHandler (debug_log_path , "w" )
555
- log_file_handler .setFormatter (logging .Formatter (log_format ))
556
- logging .getLogger ().removeHandler (st_handler )
557
- logging .getLogger ().addHandler (log_file_handler )
558
-
559
- # Add StreamHandler to the Macaron logger only.
560
- mcn_logger = logging .getLogger ("macaron" )
561
- mcn_logger .addHandler (st_handler )
562
-
563
- logger .info ("The logs will be stored in debug.log" )
564
-
565
- # Set Macaron's global configuration.
566
- # The path to provenance expectation files will be updated if
567
- # set through analyze sub-command.
568
- global_config .load (
569
- macaron_path = macaron .MACARON_PATH ,
570
- output_path = args .output_dir ,
571
- build_log_path = os .path .join (args .output_dir , "build_log" ),
572
- debug_level = log_level ,
573
- local_repos_path = args .local_repos_path ,
574
- resources_path = os .path .join (macaron .MACARON_PATH , "resources" ),
575
- )
590
+ if os .path .isdir (args .output_dir ):
591
+ logger .info (
592
+ "Setting the output directory to %s" ,
593
+ os .path .relpath (args .output_dir , os .getcwd ()),
594
+ )
595
+ else :
596
+ logger .info (
597
+ "No directory at %s. Creating one ..." ,
598
+ os .path .relpath (args .output_dir , os .getcwd ()),
599
+ )
600
+ os .makedirs (args .output_dir )
601
+
602
+ # Add file handler to the root logger. Remove stream handler from the
603
+ # root logger to prevent dependencies printing logs to stdout.
604
+ debug_log_path = os .path .join (args .output_dir , "debug.log" )
605
+ log_file_handler = logging .FileHandler (debug_log_path , "w" )
606
+ log_file_handler .setFormatter (logging .Formatter (log_format ))
607
+ if args .disable_rich_output :
608
+ logging .getLogger ().removeHandler (st_handler )
609
+ else :
610
+ logging .getLogger ().removeHandler (rich_handler )
611
+ logging .getLogger ().addHandler (log_file_handler )
612
+
613
+ # Add StreamHandler to the Macaron logger only.
614
+ mcn_logger = logging .getLogger ("macaron" )
615
+ if args .disable_rich_output :
616
+ mcn_logger .addHandler (st_handler )
617
+ else :
618
+ mcn_logger .addHandler (rich_handler )
619
+
620
+ logger .info ("The logs will be stored in debug.log" )
621
+
622
+ # Set Macaron's global configuration.
623
+ # The path to provenance expectation files will be updated if
624
+ # set through analyze sub-command.
625
+ global_config .load (
626
+ macaron_path = macaron .MACARON_PATH ,
627
+ output_path = args .output_dir ,
628
+ build_log_path = os .path .join (args .output_dir , "build_log" ),
629
+ debug_level = log_level ,
630
+ local_repos_path = args .local_repos_path ,
631
+ resources_path = os .path .join (macaron .MACARON_PATH , "resources" ),
632
+ )
576
633
577
- # Load the default values from defaults.ini files.
578
- if not load_defaults (args .defaults_path ):
579
- logger .error ("Exiting because the defaults configuration could not be loaded." )
580
- sys .exit (os .EX_NOINPUT )
634
+ # Load the default values from defaults.ini files.
635
+ if not load_defaults (args .defaults_path ):
636
+ logger .error ("Exiting because the defaults configuration could not be loaded." )
637
+ sys .exit (os .EX_NOINPUT )
581
638
582
- perform_action (args )
639
+ perform_action (args )
640
+ finally :
641
+ if args .disable_rich_output :
642
+ st_handler .close ()
643
+ else :
644
+ rich_handler .close ()
583
645
584
646
585
647
def _get_token_from_dict_or_env (token : str , token_dict : dict [str , str ]) -> str :
0 commit comments