30
30
from typing import Generator
31
31
from typing import Optional
32
32
from typing import Set
33
+ from typing import Tuple
33
34
34
35
from ..core .potential_secret import PotentialSecret
35
36
from ..util .code_snippet import CodeSnippet
@@ -67,6 +68,7 @@ class PrivateKeyDetector(RegexBasedDetector):
67
68
68
69
def __init__ (self ) -> None :
69
70
self ._analyzed_files : Set [str ] = set ()
71
+ self ._commit_hashes : Set [Tuple [str , str ]] = set ()
70
72
71
73
def analyze_line (
72
74
self ,
@@ -75,7 +77,7 @@ def analyze_line(
75
77
line_number : int = 0 ,
76
78
context : Optional [CodeSnippet ] = None ,
77
79
raw_context : Optional [CodeSnippet ] = None ,
78
- is_scan_diff : Optional [bool ] = False ,
80
+ commit_hash : Optional [str ] = '' ,
79
81
** kwargs : Any ,
80
82
) -> Set [PotentialSecret ]:
81
83
output : Set [PotentialSecret ] = set ()
@@ -87,36 +89,66 @@ def analyze_line(
87
89
),
88
90
)
89
91
90
- to_analyze_line = filename not in self ._analyzed_files
91
- if is_scan_diff :
92
- to_analyze_line = True
92
+ if output :
93
+ return output
93
94
94
- if not output and to_analyze_line \
95
+ # for git history
96
+ if commit_hash :
97
+ if (filename , commit_hash ) not in self ._commit_hashes :
98
+ file_content = ''
99
+ for file_line in context .lines : # type: ignore
100
+ file_content += file_line
101
+ found_secrets = super ().analyze_line (
102
+ filename = filename , line = file_content , line_number = 1 ,
103
+ context = context , raw_context = raw_context , ** kwargs ,
104
+ )
105
+ updated_secrets = self ._get_updated_secrets (
106
+ found_secrets = found_secrets ,
107
+ file_content = file_content ,
108
+ split_by_newline = True ,
109
+ )
110
+ output .update (updated_secrets )
111
+ self ._commit_hashes .add ((filename , commit_hash ))
112
+ return output
113
+
114
+ if filename not in self ._analyzed_files \
95
115
and 0 < self .get_file_size (filename ) < PrivateKeyDetector .MAX_FILE_SIZE :
96
- if not is_scan_diff :
97
- self ._analyzed_files .add (filename )
116
+ self ._analyzed_files .add (filename )
98
117
file_content = self .read_file (filename )
99
118
if file_content :
100
119
found_secrets = super ().analyze_line (
101
120
filename = filename , line = file_content , line_number = 1 ,
102
121
context = context , raw_context = raw_context , ** kwargs ,
103
122
)
104
- updated_secrets = set ()
105
- for sec in found_secrets :
106
- secret_val = sec .secret_value or ''
107
- line_number = self .find_line_number (file_content , secret_val )
108
- updated_secrets .add (
109
- PotentialSecret (
110
- type = self .secret_type ,
111
- filename = sec .filename ,
112
- secret = secret_val ,
113
- line_number = line_number ,
114
- is_verified = sec .is_verified ,
115
- ),
116
- )
123
+ updated_secrets = self ._get_updated_secrets (
124
+ found_secrets = found_secrets ,
125
+ file_content = file_content ,
126
+ )
117
127
output .update (updated_secrets )
118
128
return output
119
129
130
+ def _get_updated_secrets (
131
+ self , found_secrets : Set [PotentialSecret ],
132
+ file_content : str ,
133
+ split_by_newline : Optional [bool ] = False ,
134
+ ) -> Set [PotentialSecret ]:
135
+ updated_secrets : Set [PotentialSecret ] = set ()
136
+ for sec in found_secrets :
137
+ secret_val = sec .secret_value .strip () or '' # type: ignore
138
+ if split_by_newline and '\n ' in secret_val :
139
+ secret_val = secret_val .split ('\n ' )[0 ]
140
+ line_number = self .find_line_number (file_content , secret_val )
141
+ updated_secrets .add (
142
+ PotentialSecret (
143
+ type = self .secret_type ,
144
+ filename = sec .filename ,
145
+ secret = secret_val ,
146
+ line_number = line_number ,
147
+ is_verified = sec .is_verified ,
148
+ ),
149
+ )
150
+ return updated_secrets
151
+
120
152
def analyze_string (self , string : str ) -> Generator [str , None , None ]:
121
153
for regex in self .denylist :
122
154
for match in regex .findall (string ):
0 commit comments