@@ -4,7 +4,7 @@ use kernel::model::rule_test::RuleTest;
44use kernel:: model:: ruleset:: RuleSet ;
55use secrets:: model:: secret_rule:: {
66 SecretRule , SecretRuleMatchValidation , SecretRuleMatchValidationHttp ,
7- SecretRuleMatchValidationHttpCode , SecretRuleMatchValidationHttpMethod ,
7+ SecretRuleMatchValidationHttpCode , SecretRuleMatchValidationHttpMethod , SecretRuleValidator ,
88} ;
99use serde:: { Deserialize , Serialize } ;
1010use std:: collections:: BTreeMap ;
@@ -346,6 +346,22 @@ impl TryFrom<SecretRuleApiMatchValidation> for SecretRuleMatchValidation {
346346 }
347347}
348348
349+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
350+ pub struct SecretRuleApiValidator {
351+ #[ serde( rename = "type" ) ]
352+ pub r#type : String ,
353+ pub config : Option < serde_json:: Value > ,
354+ }
355+
356+ impl From < SecretRuleApiValidator > for SecretRuleValidator {
357+ fn from ( val : SecretRuleApiValidator ) -> Self {
358+ SecretRuleValidator {
359+ type_ : val. r#type ,
360+ config : val. config ,
361+ }
362+ }
363+ }
364+
349365#[ derive( Serialize , Deserialize , Debug , Clone ) ]
350366pub struct SecretRuleApiAttributes {
351367 pub name : String ,
@@ -357,7 +373,9 @@ pub struct SecretRuleApiAttributes {
357373 pub default_excluded_keywords : Option < Vec < String > > ,
358374 pub look_ahead_character_count : Option < usize > ,
359375 pub validators : Option < Vec < String > > ,
376+ pub validators_v2 : Option < Vec < SecretRuleApiValidator > > ,
360377 pub match_validation : Option < SecretRuleApiMatchValidation > ,
378+ pub pattern_capture_groups : Option < Vec < String > > ,
361379}
362380
363381#[ derive( Serialize , Deserialize , Debug , Clone ) ]
@@ -392,8 +410,16 @@ impl TryFrom<SecretRuleApiType> for SecretRule {
392410 look_ahead_character_count : val. attributes . look_ahead_character_count ,
393411 priority : val. attributes . priority . as_str ( ) . try_into ( ) ?,
394412 validators : val. attributes . validators ,
413+ validators_v2 : val
414+ . attributes
415+ . validators_v2
416+ . map ( |v| v. into_iter ( ) . map ( |validator| validator. into ( ) ) . collect ( ) ) ,
395417 match_validation : Some ( validation) ,
396418 sds_id : val. attributes . sds_id ,
419+ pattern_capture_groups : val
420+ . attributes
421+ . pattern_capture_groups
422+ . unwrap_or_default ( ) ,
397423 } ) ,
398424 Err ( s) => Err ( s) ,
399425 }
@@ -415,7 +441,12 @@ impl TryFrom<SecretRuleApiType> for SecretRule {
415441 . unwrap_or_default ( ) ,
416442 look_ahead_character_count : val. attributes . look_ahead_character_count ,
417443 validators : val. attributes . validators ,
444+ validators_v2 : val
445+ . attributes
446+ . validators_v2
447+ . map ( |v| v. into_iter ( ) . map ( |validator| validator. into ( ) ) . collect ( ) ) ,
418448 match_validation : None ,
449+ pattern_capture_groups : val. attributes . pattern_capture_groups . unwrap_or_default ( ) ,
419450 } )
420451 }
421452 }
@@ -558,6 +589,7 @@ mod tests {
558589 default_excluded_keywords : None ,
559590 look_ahead_character_count : None ,
560591 validators : None ,
592+ validators_v2 : None ,
561593 match_validation : Some ( SecretRuleApiMatchValidation {
562594 r#type : "foo" . to_string ( ) ,
563595 endpoint : None ,
@@ -568,6 +600,7 @@ mod tests {
568600 valid_http_status_code : None ,
569601 invalid_http_status_code : None ,
570602 } ) ,
603+ pattern_capture_groups : None ,
571604 } ,
572605 } ;
573606 let converted = <SecretRuleApiType as TryInto < SecretRule > >:: try_into (
@@ -591,6 +624,7 @@ mod tests {
591624 look_ahead_character_count : None ,
592625 sds_id : "71A7A0ED-DD03-45C5-9C2E-56B30CB566E0" . to_string ( ) ,
593626 validators : None ,
627+ validators_v2 : None ,
594628 match_validation : Some ( SecretRuleApiMatchValidation {
595629 r#type : SecretRuleApiMatchValidation :: CUSTOM_HTTP_STRING . to_string ( ) ,
596630 endpoint : Some ( "endpoint" . to_string ( ) ) ,
@@ -601,6 +635,7 @@ mod tests {
601635 valid_http_status_code : None ,
602636 invalid_http_status_code : None ,
603637 } ) ,
638+ pattern_capture_groups : None ,
604639 } ,
605640 } ;
606641 let converted = <SecretRuleApiType as TryInto < SecretRule > >:: try_into (
@@ -623,6 +658,7 @@ mod tests {
623658 look_ahead_character_count : None ,
624659 sds_id : "71A7A0ED-DD03-45C5-9C2E-56B30CB566E0" . to_string ( ) ,
625660 validators : None ,
661+ validators_v2 : None ,
626662 match_validation : Some ( SecretRuleApiMatchValidation {
627663 r#type : SecretRuleApiMatchValidation :: AWS_SECRET_STRING . to_string ( ) ,
628664 endpoint : None ,
@@ -633,6 +669,7 @@ mod tests {
633669 valid_http_status_code : None ,
634670 invalid_http_status_code : None ,
635671 } ) ,
672+ pattern_capture_groups : None ,
636673 } ,
637674 } ;
638675 let converted = <SecretRuleApiType as TryInto < SecretRule > >:: try_into (
@@ -661,6 +698,7 @@ mod tests {
661698 default_excluded_keywords : None ,
662699 look_ahead_character_count : None ,
663700 validators : None ,
701+ validators_v2 : None ,
664702 match_validation : Some ( SecretRuleApiMatchValidation {
665703 r#type : SecretRuleApiMatchValidation :: AWS_ID_STRING . to_string ( ) ,
666704 endpoint : None ,
@@ -671,6 +709,7 @@ mod tests {
671709 valid_http_status_code : None ,
672710 invalid_http_status_code : None ,
673711 } ) ,
712+ pattern_capture_groups : None ,
674713 } ,
675714 } ;
676715 let converted = <SecretRuleApiType as TryInto < SecretRule > >:: try_into (
@@ -699,6 +738,7 @@ mod tests {
699738 default_excluded_keywords : None ,
700739 look_ahead_character_count : None ,
701740 validators : None ,
741+ validators_v2 : None ,
702742 match_validation : Some ( SecretRuleApiMatchValidation {
703743 r#type : SecretRuleApiMatchValidation :: AWS_SESSION_STRING . to_string ( ) ,
704744 endpoint : None ,
@@ -709,6 +749,7 @@ mod tests {
709749 valid_http_status_code : None ,
710750 invalid_http_status_code : None ,
711751 } ) ,
752+ pattern_capture_groups : None ,
712753 } ,
713754 } ;
714755 let converted = <SecretRuleApiType as TryInto < SecretRule > >:: try_into (
@@ -722,4 +763,104 @@ mod tests {
722763 SecretRuleMatchValidation :: AwsSession
723764 ) ;
724765 }
766+
767+ #[ test]
768+ fn convert_secrets_rules_with_validators_v2 ( ) {
769+ let json_data = json ! ( {
770+ "data" : [
771+ {
772+ "id" : "secrets/adobe-access-token" ,
773+ "type" : "secret_rule" ,
774+ "attributes" : {
775+ "default_included_keywords" : [ ] ,
776+ "description" : "test description" ,
777+ "license" : "legal notice" ,
778+ "name" : "Adobe Access Token Scanner" ,
779+ "pattern" : "\\ b(?<sds_match>abc)" ,
780+ "pattern_capture_groups" : [ "sds_match" ] ,
781+ "priority" : "medium" ,
782+ "sds_id" : "qORGfxt5PrpmZ3uvQA937v" ,
783+ "validators" : null,
784+ "validators_v2" : [
785+ {
786+ "type" : "JwtClaimsValidator" ,
787+ "config" : {
788+ "required_claims" : {
789+ "as" : { "type" : "Present" } ,
790+ "client_id" : { "type" : "Present" }
791+ } ,
792+ "required_headers" : {
793+ "itt" : { "type" : "ExactValue" , "config" : "at" } ,
794+ "x5u" : { "type" : "Present" }
795+ }
796+ }
797+ }
798+ ]
799+ }
800+ } ,
801+ {
802+ "id" : "secrets/github-access-token" ,
803+ "type" : "secret_rule" ,
804+ "attributes" : {
805+ "default_included_keywords" : [ "access" , "github" , "token" ] ,
806+ "description" : "test description" ,
807+ "license" : "legal notice" ,
808+ "name" : "Github Access Token Scanner" ,
809+ "pattern" : "\\ bgh[opsu]_[0-9a-zA-Z]{36}\\ b" ,
810+ "priority" : "high" ,
811+ "sds_id" : "5rjXkBMvQ3GbbYrpVP_HdQ" ,
812+ "validators" : [ "GithubTokenChecksum" ] ,
813+ "validators_v2" : [
814+ {
815+ "type" : "GithubTokenChecksum"
816+ }
817+ ]
818+ }
819+ }
820+ ]
821+ } ) ;
822+
823+ let api_response: StaticAnalysisSecretsAPIResponse =
824+ serde_json:: from_value ( json_data) . expect ( "Failed to deserialize JSON" ) ;
825+
826+ // Test Adobe Access Token with JwtClaimsValidator config
827+ let adobe_rule: SecretRule = api_response. data [ 0 ]
828+ . clone ( )
829+ . try_into ( )
830+ . expect ( "Failed to convert Adobe rule" ) ;
831+
832+ assert_eq ! ( adobe_rule. id, "secrets/adobe-access-token" ) ;
833+ assert ! ( adobe_rule. validators_v2. is_some( ) ) ;
834+ let adobe_validators = adobe_rule. validators_v2 . as_ref ( ) . unwrap ( ) ;
835+ assert_eq ! ( adobe_validators. len( ) , 1 ) ;
836+ assert_eq ! ( adobe_validators[ 0 ] . type_, "JwtClaimsValidator" ) ;
837+ assert ! ( adobe_validators[ 0 ] . config. is_some( ) ) ;
838+
839+ // Verify the validator can be successfully converted to dd_sds::SecondaryValidator
840+ let secondary_validator = adobe_validators[ 0 ] . try_to_secondary_validator ( false ) ;
841+ assert ! (
842+ secondary_validator. is_some( ) ,
843+ "Should successfully convert to SecondaryValidator::JwtClaimsValidator"
844+ ) ;
845+
846+ // Check pattern capture groups
847+ assert_eq ! ( adobe_rule. pattern_capture_groups. len( ) , 1 ) ;
848+ assert_eq ! ( adobe_rule. pattern_capture_groups[ 0 ] , "sds_match" ) ;
849+
850+ // Test Github Access Token with simple validator (no config)
851+ let github_rule: SecretRule = api_response. data [ 1 ]
852+ . clone ( )
853+ . try_into ( )
854+ . expect ( "Failed to convert Github rule" ) ;
855+
856+ assert_eq ! ( github_rule. id, "secrets/github-access-token" ) ;
857+ assert ! ( github_rule. validators_v2. is_some( ) ) ;
858+ let github_validators = github_rule. validators_v2 . as_ref ( ) . unwrap ( ) ;
859+ assert_eq ! ( github_validators. len( ) , 1 ) ;
860+ assert_eq ! ( github_validators[ 0 ] . type_, "GithubTokenChecksum" ) ;
861+ assert ! ( github_validators[ 0 ] . config. is_none( ) ) ;
862+
863+ // Check pattern capture group is empty
864+ assert ! ( github_rule. pattern_capture_groups. is_empty( ) ) ;
865+ }
725866}
0 commit comments