1- use crate :: csaf_traits:: { CsafTrait , ProductIdentificationHelperTrait , ProductTrait , ProductTreeTrait } ;
1+ use crate :: csaf_traits:: {
2+ CsafTrait , CsafVersion , DocumentTrait , ProductIdentificationHelperTrait , ProductTrait , ProductTreeTrait ,
3+ } ;
24use crate :: validation:: ValidationError ;
35use packageurl:: PackageUrl ;
46use regex:: Regex ;
@@ -7,24 +9,51 @@ use std::sync::LazyLock;
79
810static PURL_REGEX : LazyLock < Regex > = LazyLock :: new ( || Regex :: new ( r"^pkg:[A-Za-z.\-+][A-Za-z0-9.\-+]*/.+" ) . unwrap ( ) ) ;
911
10- fn generate_purl_regex_error ( purl_str : & str , path : & str , index : usize ) -> ValidationError {
12+ fn get_purl_instance_path_substring ( csaf_version : & CsafVersion ) -> & ' static str {
13+ match csaf_version {
14+ CsafVersion :: X20 => "purl" ,
15+ CsafVersion :: X21 => "purls" ,
16+ }
17+ }
18+
19+ fn generate_purl_regex_error ( csaf_version : & CsafVersion , purl_str : & str , path : & str , index : usize ) -> ValidationError {
1120 ValidationError {
1221 message : format ! ( "PURL doesn't comply with CSAF PURL regex: {}" , purl_str) ,
13- instance_path : format ! ( "{}/product_identification_helper/purls/{}" , path, index) ,
22+ instance_path : format ! (
23+ "{}/product_identification_helper/{}/{}" ,
24+ path,
25+ get_purl_instance_path_substring( csaf_version) ,
26+ index
27+ ) ,
1428 }
1529}
1630
17- fn generate_purl_format_error ( purl_str : & str , error_msg : & str , path : & str , index : usize ) -> ValidationError {
31+ fn generate_purl_format_error (
32+ csaf_version : & CsafVersion ,
33+ purl_str : & str ,
34+ error_msg : & str ,
35+ path : & str ,
36+ index : usize ,
37+ ) -> ValidationError {
1838 ValidationError {
1939 message : format ! ( "Invalid PURL format: {}, Error: {}" , purl_str, error_msg) ,
20- instance_path : format ! ( "{}/product_identification_helper/purls/{}" , path, index) ,
40+ instance_path : format ! (
41+ "{}/product_identification_helper/{}/{}" ,
42+ path,
43+ get_purl_instance_path_substring( csaf_version) ,
44+ index
45+ ) ,
2146 }
2247}
2348
49+ /// 6.1.13 PURL
50+ /// Checks the validity of PURLs in the document. Validation is done via a Regex specified in the standard and
51+ /// via the packageurl::purl parser.
2452pub fn test_6_1_13_purl ( doc : & impl CsafTrait ) -> Result < ( ) , Vec < ValidationError > > {
2553 let mut errors: Option < Vec < ValidationError > > = None ;
2654
2755 if let Some ( product_tree) = doc. get_product_tree ( ) {
56+ let version = doc. get_document ( ) . get_csaf_version ( ) ;
2857 product_tree. visit_all_products ( & mut |product, path| {
2958 if let Some ( helper) = product. get_product_identification_helper ( ) {
3059 if let Some ( purls) = helper. get_purls ( ) {
@@ -33,12 +62,13 @@ pub fn test_6_1_13_purl(doc: &impl CsafTrait) -> Result<(), Vec<ValidationError>
3362 if !PURL_REGEX . is_match ( purl_str) {
3463 errors
3564 . get_or_insert_with ( Vec :: new)
36- . push ( generate_purl_regex_error ( purl_str, path, i) ) ;
65+ . push ( generate_purl_regex_error ( version , purl_str, path, i) ) ;
3766 continue ;
3867 }
3968 // Parse the PURL
4069 if let Err ( e) = PackageUrl :: from_str ( purl_str) {
4170 errors. get_or_insert_with ( Vec :: new) . push ( generate_purl_format_error (
71+ version,
4272 purl_str,
4373 & e. to_string ( ) ,
4474 path,
@@ -62,10 +92,33 @@ mod tests {
6292
6393 #[ test]
6494 fn test_test_6_1_13 ( ) {
65- let errors = HashMap :: from ( [
95+ let errors_x20 = HashMap :: from ( [
96+ (
97+ "01" ,
98+ vec ! [ generate_purl_format_error(
99+ & CsafVersion :: X20 ,
100+ "pkg:maven/@1.3.4" ,
101+ "missing name" ,
102+ "/product_tree/full_product_names/0" ,
103+ 0 ,
104+ ) ] ,
105+ ) ,
106+ (
107+ "02" ,
108+ vec ! [ generate_purl_format_error(
109+ & CsafVersion :: X20 ,
110+ "pkg:oci/com.example/product-A@sha256%3Add134261219b2" ,
111+ "no namespace allowed for type \" oci\" " ,
112+ "/product_tree/full_product_names/0" ,
113+ 0 ,
114+ ) ] ,
115+ ) ,
116+ ] ) ;
117+ let errors_x21 = HashMap :: from ( [
66118 (
67119 "01" ,
68120 vec ! [ generate_purl_format_error(
121+ & CsafVersion :: X21 ,
69122 "pkg:maven/@1.3.4" ,
70123 "missing name" ,
71124 "/product_tree/full_product_names/0" ,
@@ -75,14 +128,15 @@ mod tests {
75128 (
76129 "02" ,
77130 vec ! [ generate_purl_format_error(
131+ & CsafVersion :: X21 ,
78132 "pkg:oci/com.example/product-A@sha256%3Add134261219b2" ,
79133 "no namespace allowed for type \" oci\" " ,
80134 "/product_tree/full_product_names/0" ,
81135 0 ,
82136 ) ] ,
83137 ) ,
84138 ] ) ;
85- run_csaf20_tests ( "13" , test_6_1_13_purl, errors . clone ( ) ) ;
86- run_csaf21_tests ( "13" , test_6_1_13_purl, errors ) ;
139+ run_csaf20_tests ( "13" , test_6_1_13_purl, errors_x20 ) ;
140+ run_csaf21_tests ( "13" , test_6_1_13_purl, errors_x21 ) ;
87141 }
88142}
0 commit comments