@@ -217,7 +217,7 @@ const ENTROPY_MAX_WORD_LEN: usize = 40;
217217#[ derive( Debug , Clone ) ]
218218pub struct SecretScanner {
219219 pub regex_map : BTreeMap < String , EntropyRegex > ,
220- pub allowlist_map : BTreeMap < String , Vec < Regex > > ,
220+ pub allowlist_map : BTreeMap < String , AllowList > ,
221221 pub pretty_print : bool ,
222222 pub output_path : Option < String > ,
223223 pub entropy_min_word_len : usize ,
@@ -255,6 +255,22 @@ pub enum PatternEntropy {
255255 } ,
256256}
257257
258+ #[ derive( Deserialize , Debug ) ]
259+ #[ serde( untagged) ]
260+ pub enum AllowListEnum {
261+ PatternList ( Vec < String > ) ,
262+ AllowListJson {
263+ patterns : Vec < String > ,
264+ paths : Option < Vec < String > >
265+ }
266+ }
267+
268+ #[ derive( Debug , Clone ) ]
269+ pub struct AllowList {
270+ pub pattern_list : Vec < Regex > ,
271+ pub path_list : Vec < Regex >
272+ }
273+
258274/// Used to instantiate the `SecretScanner` object with user-supplied options
259275///
260276/// Use the `new()` function to create a builder object, perform configurations as needed, then
@@ -630,32 +646,40 @@ impl SecretScannerBuilder {
630646 . collect ( )
631647 }
632648
633- fn build_allowlist_from_str ( input : & str ) -> Result < BTreeMap < String , Vec < Regex > > , SimpleError > {
649+ fn vec_string_to_vec_regex ( incoming_array : Vec < String > ) -> Vec < Regex > {
650+ incoming_array
651+ . into_iter ( )
652+ . filter_map ( |x| match Regex :: new ( & x) {
653+ Ok ( r) => Some ( r) ,
654+ Err ( e) => {
655+ error ! ( "Failed to parse regex: {}" , e) ;
656+ None
657+ }
658+ } )
659+ . collect ( )
660+ }
661+
662+ fn build_allowlist_from_str ( input : & str ) -> Result < BTreeMap < String , AllowList > , SimpleError > {
634663 info ! ( "Attempting to parse JSON allowlist string" ) ;
635- let allowlist: BTreeMap < String , Value > = match serde_json:: from_str ( input) {
664+ let allowlist: BTreeMap < String , AllowListEnum > = match serde_json:: from_str ( input) {
636665 Ok ( m) => Ok ( m) ,
637666 Err ( e) => Err ( SimpleError :: with ( "Failed to parse allowlist JSON" , e) ) ,
638667 } ?;
639668 allowlist
640669 . into_iter ( )
641- . map ( |( p, list) | match list {
642- Value :: Array ( v) => {
643- let l = v
644- . into_iter ( )
645- . filter_map ( |v| match v {
646- Value :: String ( s) => match Regex :: new ( & s) {
647- Ok ( r) => Some ( r) ,
648- Err ( e) => {
649- error ! ( "Failed to parse regex in allowlist JSON: {}" , e) ;
650- None
651- }
652- } ,
653- _ => None ,
654- } )
655- . collect ( ) ;
656- Ok ( ( p, l) )
670+ . map ( |( p, allowlistobj) | match allowlistobj {
671+ AllowListEnum :: PatternList ( v) => {
672+ let l = SecretScannerBuilder :: vec_string_to_vec_regex ( v) ;
673+ Ok ( ( p, AllowList { pattern_list : l, path_list : vec ! [ ] } ) )
674+ }
675+ AllowListEnum :: AllowListJson { patterns : pattern_list, paths : path_list } => {
676+ let l1 = SecretScannerBuilder :: vec_string_to_vec_regex ( pattern_list) ;
677+ let l2 = match path_list {
678+ Some ( v) => SecretScannerBuilder :: vec_string_to_vec_regex ( v) ,
679+ None => Vec :: new ( )
680+ } ;
681+ Ok ( ( p, AllowList { pattern_list : l1, path_list : l2 } ) )
657682 }
658- _ => Err ( SimpleError :: new ( "Invalid allowlist JSON format" ) ) ,
659683 } )
660684 . collect ( )
661685 }
@@ -696,7 +720,7 @@ impl SecretScanner {
696720 let matches = x. 1 . pattern . find_iter ( line) ;
697721 let matches_filtered: Vec < RustyHogMatch > = matches
698722 . filter ( |m| self . check_entropy ( x. 0 , & line[ m. start ( ) ..m. end ( ) ] ) )
699- . filter ( |m| !self . is_allowlisted ( x. 0 , & line[ m. start ( ) ..m. end ( ) ] ) )
723+ . filter ( |m| !self . is_allowlisted_pattern ( x. 0 , & line[ m. start ( ) ..m. end ( ) ] ) )
700724 . map ( RustyHogMatch :: from)
701725 . inspect ( |x| debug ! ( "RustyHogMatch: {:?}" , x) )
702726 . collect ( ) ;
@@ -947,21 +971,24 @@ impl SecretScanner {
947971 Ok ( ( ) )
948972 }
949973
950- /// Checks if any of the provided tokens is allowlisted
951- pub fn is_allowlisted ( & self , pattern : & str , token : & [ u8 ] ) -> bool {
974+ /// Checks if the provided path name is allowlisted
975+ pub fn is_allowlisted_path ( & self , pattern : & str , path : & [ u8 ] ) -> bool {
952976 if let Some ( allowlist) = self . allowlist_map . get ( pattern) {
953- for allow_regex in allowlist {
954- if allow_regex. find ( token) . is_some ( ) {
955- return true ;
956- }
957- }
977+ if allowlist. path_list . iter ( ) . any ( |x| x. find ( path) . is_some ( ) ) { return true }
958978 }
959979 if let Some ( allowlist) = self . allowlist_map . get ( "<GLOBAL>" ) {
960- for allow_regex in allowlist {
961- if allow_regex. find ( token) . is_some ( ) {
962- return true ;
963- }
964- }
980+ if allowlist. path_list . iter ( ) . any ( |x| x. find ( path) . is_some ( ) ) { return true }
981+ }
982+ false
983+ }
984+
985+ /// Checks if the provided token is allowlisted
986+ pub fn is_allowlisted_pattern ( & self , pattern : & str , token : & [ u8 ] ) -> bool {
987+ if let Some ( allowlist) = self . allowlist_map . get ( pattern) {
988+ if allowlist. pattern_list . iter ( ) . any ( |x| x. find ( token) . is_some ( ) ) { return true }
989+ }
990+ if let Some ( allowlist) = self . allowlist_map . get ( "<GLOBAL>" ) {
991+ if allowlist. pattern_list . iter ( ) . any ( |x| x. find ( token) . is_some ( ) ) { return true }
965992 }
966993 false
967994 }
0 commit comments