feat: implement validation test 6.2.32 use of Same Product Identifica…#698
feat: implement validation test 6.2.32 use of Same Product Identifica…#698georgbramm wants to merge 10 commits into
Conversation
…tion Helper for Different Products
There was a problem hiding this comment.
Two more general comments: I think (and please correct me if I'm overlooking something) that some of the to_string() allocs are not necessary here. Is there a reason we are for example re-allocating the serial number as sn_str before using it as a hashmap key, and can this also be done without the to_string() call?
Also, the test coverage only seems to concern serial_numbers and model_numbers right now. I would argue this should be extended to als PIH's, if you have some thoughs here from your work on this task, feel free to open a ticket :)
| // Check PURLs | ||
| if let Some(purls) = helper.get_purls() { | ||
| for purl in purls { | ||
| let purl_str = format!("{purl:?}"); |
There was a problem hiding this comment.
This will use the debug output of CsafPurl enum returned by get_purls. This can be a) Valid or Invalid, depending on if the string could be parsed as a purl. The Valid struct provides a normalized_purl field, which might be helpful for the purpose of this test.
I think it would be interesting to discuss here if this test should consider purl normalization and how invalid purls (that break 6.1.13) should be handled, or if a simple comparison of the original strings is sufficient.
There was a problem hiding this comment.
@georgbramm
In the ValidPurl case, this would look like
Valid(ValidPurl { original_purl: "pkg:generic/Example-Company-Product-A@1.0?type=product", normalized_purl: "pkg:generic/Example-Company-Product-A@1.0?type=product", base_without_qualifiers: "pkg:generic/Example-Company-Product-A@1.0" })
which is not fitting for a hashmap key. You could use the normalized_purl in the valid case, and original_purl in the invalid case, or original_purl in both cases. Either way, we shouldn't use the Debug output for hash keys.
|
thanks again for your valuable feedback, i will try to incorporate the requested changes by next week, as i am currently on a business trip |
…or; inlined test cases; Wiring test case & updated README.md
|
Hopefully fixes Issue #318 |
…nimal lifetime allocations where possible
|
Case 03 Messaging & Cardinality:: |
| "/product_tree/branches/0/branches/0/branches/1/product", | ||
| ), | ||
| ]; | ||
| case_01_errors.sort_by_key(|e| e.instance_path.clone()); |
There was a problem hiding this comment.
Why is sorting necessary here?
There was a problem hiding this comment.
Since we collect product occurrences using a HashMap, the internal iteration order of the errors is non-deterministic across test runs. Because the .expect() test harness macro validates strict index-by-index positional array equality, sorting the expected vectors in the test blocks by instance_path guarantees deterministic passes without testing bugs.
There was a problem hiding this comment.
Sorry this is not correct. For the expect macro the cases itself must be in the correct order, but the expected errors within each don't have to be, see
|
i pushed a fix that hopefully resolves your requested changes |
| // Instead of one combined string, track each inner hash independently: | ||
| for fh in hash_obj.get_file_hashes() { | ||
| let specific_hash_key = | ||
| format!("file:{filename};alg:{:?};value:{}", fh.get_algorithm(), fh.get_hash()); |
There was a problem hiding this comment.
We shouldn't use the :? debug variant here too. Either use specific data or implement Display.
There was a problem hiding this comment.
Additionally, for algorithm and hash value, we should use lowercase here. The schema will prohibit uppercase letters in these parts, but this test shouldn't rely on the schema test to run.
| errors.sort_by(|a, b| a.instance_path.cmp(&b.instance_path).then(a.message.cmp(&b.message))); | ||
| errors.dedup_by(|a, b| a.instance_path == b.instance_path && a.message == b.message); |
There was a problem hiding this comment.
ValidationError is a struct with PartialEq so comparing the fields on its own should not be necessary. Maybe a simple dedup or other way to ensure uniqueness is simpler.
Also the sort_by should not be necessary, as the test comparison ignores ordering.
… Cleaned up the error deduplication by using simple .dedup() backed by ValidationError's native PartialEq
|
Excellent callouts.
|
|
Please also add some supplementary test cases for every edge case discussed here. |
|
I added three test cases for CSAF validation rule 6.2.32. The added tests verify that product identification helper metadata remains pairwise disjoint across all distinct entries within the product tree structure. These edge cases were implemented in a dedicated, isolated test function (test_test_6_2_32_edge_cases) to cleanly isolate manually structured validation payloads from the automatic schema formatting expectations of the pre-generated test matrix runner. The test suite evaluates three specific conditions: Case 01: Duplicate Cryptographic Hash Detection (Failure) Case 02: Duplicate Package URL (PURL) Detection (Failure) Case 03: Pairwise Disjoint Identifiers (Success) |
Perhaps my request was not clear enough: we try to create csaf test files to improve the overall test coverage of the oasis csaf repository. These are called supplementary test cases and are located within the Additionally, because I have only seen that now, your code doesn't cover all |
|
I have updated the test suite to address the comments and ensure full coverage of rule 6.2.32. Key changes: Comprehensive Test Asset: Added csaf-rs_csaf-csaf_2_1-6-2-32-s01.json to include intentional collisions for all ProductIdentificationHelper categories: hashes, purls, serial_numbers, model_numbers, and skus. Refactored Test Code: Updated the test expectation vector to match the new comprehensive collision set, ensuring deterministic validation. |
|
please wait with the review... im gonna fix the json & tests according to 6.2.31 comments |
…, refine test comments
|
now its ready for a review.. hopefully =) |
Please address or answer the open discussions in this PR. |
To fulfill the CSAF 2.0/2.1 specification for Test 6.2.32 (Use of Same Product Identification Helper for Different Products), I implemented a complete validation rule in src/validations/test_6_2_32.rs that ensures identifying product metadata is pairwise disjoint across all distinct products.
What Was Done
Comprehensive Path Traversal: Integrated the framework's native visit_all_products_generic visitor engine. This automatically sweeps all valid paths defined in the spec, including recursive nested branches[], flat full_product_names[], and product_paths[] structures without requiring manual pointer-chasing.
Pairwise Disjoint Set Validation: Implemented tracking maps (HashMap<String, String>) for every distinct helper property category: purls (Package URLs), skus (Stock Keeping Units), serial_numbers, model_numbers, hashes (Cryptographic file hashes)
Object Deep-Equality with Order Independence: Built a robust serialization strategy for complex array properties whose items are JSON objects (such as hashes). The implementation extracts the filename and maps nested hashes into a deterministic format (Algorithm:HashValue), then explicitly sorts the array signatures before structural comparison. This guarantees that deep-equality checks pass successfully even if keys or items appear out of order.
Error Reporting Alignment: Configured the rule to emit a detailed ValidationError whenever an identical identifier is found bound to multiple distinct product_id values, pinpointing the precise helper property path layout.
Test Suite Stabilization: Aligned the unit tests with the automated test fixtures (case_01, case_02, case_03), verifying that both intentional failures (like the nested branch serial/model number collisions in Examples 1 & 2) and valid layouts pass cleanly against the standard framework mock runner.