33from typing import Dict , List , Optional , Tuple
44
55from pygitguardian .client import VERSIONS
6- from pygitguardian .models import PolicyBreak
6+ from pygitguardian .models import DiffKind , PolicyBreak
77
88from ggshield .core .filter import group_policy_breaks_by_ignore_sha
99from ggshield .core .lines import Line , get_offset , get_padding
3131class SecretTextOutputHandler (SecretOutputHandler ):
3232 def _process_scan_impl (self , scan : SecretScanCollection ) -> str :
3333 """Output Secret Scan Collection in text format"""
34- processed_scan_results = self .process_scan_results (scan )
34+ diff_kinds = [DiffKind .ADDITION ]
35+ if self .verbose :
36+ diff_kinds += [DiffKind .DELETION , DiffKind .CONTEXT ]
3537
38+ processed_scan_results = self .process_scan_results (scan , diff_kinds = diff_kinds )
3639 scan_buf = StringIO ()
3740 if self .verbose :
3841 scan_buf .write (secrets_engine_version ())
3942 scan_buf .write (processed_scan_results )
4043 if not processed_scan_results :
44+ if self .ignore_known_secrets and scan .known_secrets_count :
45+ scan_buf .write (no_new_leak_message ())
46+ elif scan .deletion_or_context_secrets_count :
47+ scan_buf .write (no_introduced_leak_message ())
48+ else :
49+ scan_buf .write (no_leak_message ())
50+
51+ if not self .verbose and scan .deletion_or_context_secrets_count :
4152 scan_buf .write (
42- no_new_leak_message ()
43- if (self .ignore_known_secrets and scan .known_secrets_count )
44- else no_leak_message ()
53+ f"\n Warning: { scan .deletion_or_context_secrets_count } "
54+ f"{ pluralize ('secret' , scan .deletion_or_context_secrets_count )} ignored "
55+ f"because { pluralize ('it is' , scan .deletion_or_context_secrets_count , 'they are' )} removed or in the "
56+ f"context of a commit.\n Use `--verbose` for more details.\n "
4557 )
4658
4759 if self .ignore_known_secrets and scan .known_secrets_count > 0 :
@@ -52,22 +64,29 @@ def _process_scan_impl(self, scan: SecretScanCollection) -> str:
5264 )
5365
5466 if self .verbose :
55- scan_buf .write (self .process_scan_results (scan , True ))
67+ scan_buf .write (
68+ self .process_scan_results (
69+ scan , diff_kinds = diff_kinds , show_only_known_secrets = True
70+ )
71+ )
5672 else :
5773 scan_buf .write ("Use `--verbose` for more details.\n " )
5874
5975 return scan_buf .getvalue ()
6076
6177 def process_scan_results (
62- self , scan : SecretScanCollection , show_only_known_secrets : bool = False
78+ self ,
79+ scan : SecretScanCollection ,
80+ diff_kinds : List [DiffKind ],
81+ show_only_known_secrets : bool = False ,
6382 ) -> str :
6483 """Iterate through the scans and sub-scan results to prepare the display."""
6584 results_buf = StringIO ()
6685 if scan .results :
6786 current_result_buf = StringIO ()
6887 for result in scan .results .results :
6988 current_result_buf .write (
70- self .process_result (result , show_only_known_secrets )
89+ self .process_result (result , diff_kinds , show_only_known_secrets )
7190 )
7291 current_result_string = current_result_buf .getvalue ()
7392
@@ -80,14 +99,17 @@ def process_scan_results(
8099 if scan .scans :
81100 for sub_scan in scan .scans :
82101 inner_scan_str = self .process_scan_results (
83- sub_scan , show_only_known_secrets
102+ sub_scan , diff_kinds , show_only_known_secrets
84103 )
85104 results_buf .write (inner_scan_str )
86105
87106 return results_buf .getvalue ()
88107
89108 def process_result (
90- self , result : Result , show_only_known_secrets : bool = False
109+ self ,
110+ result : Result ,
111+ diff_kinds : List [DiffKind ],
112+ show_only_known_secrets : bool = False ,
91113 ) -> str :
92114 """
93115 Build readable message on the found incidents.
@@ -99,7 +121,9 @@ def process_result(
99121 """
100122 result_buf = StringIO ()
101123
102- sha_dict = group_policy_breaks_by_ignore_sha (result .scan .policy_breaks )
124+ sha_dict = group_policy_breaks_by_ignore_sha (
125+ result .policy_breaks (diff_kinds = diff_kinds )
126+ )
103127
104128 if not self .show_secrets :
105129 result .censor ()
@@ -306,6 +330,13 @@ def no_new_leak_message() -> str:
306330 return format_text ("\n No new secrets have been found\n " , STYLE ["no_secret" ])
307331
308332
333+ def no_introduced_leak_message () -> str :
334+ """
335+ Build a message if no secrets are introduced.
336+ """
337+ return format_text ("\n No introduced secrets have been found\n " , STYLE ["no_secret" ])
338+
339+
309340def format_line_with_secret (
310341 line_content : str ,
311342 secret_index_start : int ,
0 commit comments