@@ -155,6 +155,8 @@ pub struct Rule {
155155 pub tests : Vec < RuleTest > ,
156156 #[ serde( default ) ]
157157 pub is_testing : bool ,
158+ #[ serde( default ) ]
159+ pub documentation_url : Option < String > ,
158160}
159161
160162#[ derive( Clone , Deserialize , Debug , Serialize , Builder , Eq , PartialEq ) ]
@@ -208,10 +210,14 @@ impl DiffAware for Rule {
208210
209211impl Rule {
210212 pub fn get_url ( & self ) -> String {
211- format ! (
212- "https://docs.datadoghq.com/static_analysis/rules/{}" ,
213- self . name
214- )
213+ if let Some ( url) = & self . documentation_url {
214+ url. clone ( )
215+ } else {
216+ format ! (
217+ "https://docs.datadoghq.com/static_analysis/rules/{}" ,
218+ self . name
219+ )
220+ }
215221 }
216222
217223 // Sometimes, the API returns an empty CWE as an empty string. If we have an empty
@@ -341,6 +347,54 @@ mod tests {
341347 use super :: * ;
342348 use crate :: utils:: encode_base64_string;
343349
350+ #[ test]
351+ fn test_get_url ( ) {
352+ let rule_without_url = Rule {
353+ name : "myrule" . to_string ( ) ,
354+ short_description_base64 : Some ( "bla" . to_string ( ) ) ,
355+ description_base64 : Some ( "bli" . to_string ( ) ) ,
356+ category : RuleCategory :: BestPractices ,
357+ severity : RuleSeverity :: Warning ,
358+ language : Language :: Python ,
359+ rule_type : RuleType :: TreeSitterQuery ,
360+ entity_checked : None ,
361+ code_base64 : "mycode" . to_string ( ) ,
362+ checksum : "foobar" . to_string ( ) ,
363+ pattern : None ,
364+ cwe : None ,
365+ tree_sitter_query_base64 : None ,
366+ arguments : vec ! [ ] ,
367+ tests : vec ! [ ] ,
368+ is_testing : false ,
369+ documentation_url : None ,
370+ } ;
371+ assert_eq ! (
372+ rule_without_url. get_url( ) ,
373+ "https://docs.datadoghq.com/static_analysis/rules/myrule"
374+ ) ;
375+
376+ let rule_with_url = Rule {
377+ name : "myrule" . to_string ( ) ,
378+ short_description_base64 : Some ( "bla" . to_string ( ) ) ,
379+ description_base64 : Some ( "bli" . to_string ( ) ) ,
380+ category : RuleCategory :: BestPractices ,
381+ severity : RuleSeverity :: Warning ,
382+ language : Language :: Python ,
383+ rule_type : RuleType :: TreeSitterQuery ,
384+ entity_checked : None ,
385+ code_base64 : "mycode" . to_string ( ) ,
386+ checksum : "foobar" . to_string ( ) ,
387+ pattern : None ,
388+ cwe : None ,
389+ tree_sitter_query_base64 : None ,
390+ arguments : vec ! [ ] ,
391+ tests : vec ! [ ] ,
392+ is_testing : false ,
393+ documentation_url : Some ( "https://my-rule-url" . to_string ( ) ) ,
394+ } ;
395+ assert_eq ! ( rule_with_url. get_url( ) , "https://my-rule-url" ) ;
396+ }
397+
344398 #[ test]
345399 fn test_checksum_valid ( ) {
346400 let rule_invalid_checksum = Rule {
@@ -360,6 +414,7 @@ mod tests {
360414 arguments : vec ! [ ] ,
361415 tests : vec ! [ ] ,
362416 is_testing : false ,
417+ documentation_url : None ,
363418 } ;
364419 let rule_valid_checksum = Rule {
365420 name : "myrule" . to_string ( ) ,
@@ -379,6 +434,7 @@ mod tests {
379434 arguments : vec ! [ ] ,
380435 tests : vec ! [ ] ,
381436 is_testing : false ,
437+ documentation_url : None ,
382438 } ;
383439 assert ! ( !rule_invalid_checksum. verify_checksum( ) ) ;
384440 assert ! ( rule_valid_checksum. verify_checksum( ) ) ;
@@ -403,6 +459,7 @@ mod tests {
403459 arguments : vec ! [ ] ,
404460 tests : vec ! [ ] ,
405461 is_testing : false ,
462+ documentation_url : None ,
406463 } ;
407464 let fixed_ruled = rule. fix_cwe ( ) ;
408465 assert ! ( fixed_ruled. cwe. is_none( ) ) ;
@@ -427,6 +484,7 @@ mod tests {
427484 arguments : vec ! [ ] ,
428485 tests : vec ! [ ] ,
429486 is_testing : false ,
487+ documentation_url : None ,
430488 } ;
431489 let fixed_ruled = rule. fix_cwe ( ) ;
432490 assert ! ( fixed_ruled. cwe. is_none( ) ) ;
@@ -451,6 +509,7 @@ mod tests {
451509 arguments : vec ! [ ] ,
452510 tests : vec ! [ ] ,
453511 is_testing : false ,
512+ documentation_url : None ,
454513 } ;
455514 let fixed_ruled = rule. fix_cwe ( ) ;
456515 assert ! ( fixed_ruled. cwe. is_some( ) ) ;
0 commit comments