@@ -57,6 +57,27 @@ const inputSchema = /** @type {const} */ ({
5757
5858const validateInput = ajv . compile ( inputSchema )
5959
60+ /**
61+ * @param {string | undefined } name
62+ * @param {string | undefined } namespace
63+ * @param {string | undefined } version
64+ */
65+ function decisionPointHash ( name , namespace , version ) {
66+ return JSON . stringify ( {
67+ name : name ?? '' ,
68+ namespace : namespace ?? '' ,
69+ version : version ?? '' ,
70+ } )
71+ }
72+
73+ /** @type {Map<string,{ name: string; namespace: string; version: string; key?: string; values: { key: string; name: string; description: string; }[]; }> } */
74+ const decisionPointMap = new Map (
75+ ssvcDecisionPoints . decisionPoints . map ( ( obj ) => [
76+ decisionPointHash ( obj . name , obj . namespace , obj . version ) ,
77+ obj ,
78+ ] )
79+ )
80+
6081/**
6182 * This implements the mandatory test 6.1.48 of the CSAF 2.1 standard.
6283 *
@@ -74,16 +95,6 @@ export function mandatoryTest_6_1_48(doc) {
7495 }
7596
7697 const registeredSsvcNamespaces = [ 'ssvc' , 'cvss' ]
77- // subset of all the valid decision points containing only the relevant properties
78- const relevantSsvcDecisionPointsSubset =
79- ssvcDecisionPoints . decisionPoints . map ( ( dp ) =>
80- JSON . stringify ( {
81- name : dp . name ?? '' ,
82- namespace : dp . namespace ?? '' ,
83- version : dp . version ?? '' ,
84- values : dp . values ?? '' ,
85- } )
86- )
8798
8899 doc . vulnerabilities . forEach ( ( vulnerability , vulnerabilityIndex ) => {
89100 vulnerability . metrics ?. forEach ( ( metric , metricIndex ) => {
@@ -93,46 +104,31 @@ export function mandatoryTest_6_1_48(doc) {
93104 s . namespace !== undefined &&
94105 registeredSsvcNamespaces . includes ( s . namespace )
95106 )
96- selectionsWithRegisteredNamespace ?. forEach (
97- ( selection , selectionIndex ) => {
98- // check if a decision point with these properties exists
99- const filteredDecisionPoints =
100- relevantSsvcDecisionPointsSubset . filter ( ( jsonDp ) => {
101- const dp = JSON . parse ( jsonDp )
102- return (
103- dp . name === selection . name &&
104- dp . namespace === selection . namespace &&
105- dp . version === selection . version
106- )
107- } )
108- if ( filteredDecisionPoints . length === 0 ) {
107+ selectionsWithRegisteredNamespace ?. forEach ( ( select , selectionIndex ) => {
108+ // check if a decision point with these properties exists
109+ const selectedDecisionPnt = decisionPointMap . get (
110+ decisionPointHash ( select . name , select . namespace , select . version )
111+ )
112+
113+ if ( ! selectedDecisionPnt ) {
114+ ctx . isValid = false
115+ ctx . errors . push ( {
116+ instancePath : `/vulnerabilities/${ vulnerabilityIndex } /metrics/${ metricIndex } /content/ssvc_v1/selections/${ selectionIndex } ` ,
117+ message : `there exists no decision point with name ${ select . name } and version ${ select . version } in the namespace ${ select . namespace } ` ,
118+ } )
119+ } else {
120+ if (
121+ select . values &&
122+ ! areValuesValidAndinOrder ( selectedDecisionPnt . values , select . values )
123+ ) {
109124 ctx . isValid = false
110125 ctx . errors . push ( {
111126 instancePath : `/vulnerabilities/${ vulnerabilityIndex } /metrics/${ metricIndex } /content/ssvc_v1/selections/${ selectionIndex } ` ,
112- message : `there exists no decision point with name ${ selection . name } and version ${ selection . version } in the namespace ${ selection . namespace } ` ,
127+ message : `this decision point contains invalid values or its values are not in order ` ,
113128 } )
114- } else {
115- // name, namespace and version define a unique decisionPoint, i.e. the array filteredDecisionPoints
116- // can only have zero (catched in the previous if-statement) or one entry.
117- // Therefore, it is sufficient to access the first and only entry in filteredDecisionPoints here
118- if (
119- selection . values &&
120- ! areValuesValidAndinOrder (
121- JSON . parse ( filteredDecisionPoints [ 0 ] ) . values . map (
122- ( /** @type {{ name: string; } } */ value ) => value . name
123- ) ,
124- selection . values
125- )
126- ) {
127- ctx . isValid = false
128- ctx . errors . push ( {
129- instancePath : `/vulnerabilities/${ vulnerabilityIndex } /metrics/${ metricIndex } /content/ssvc_v1/selections/${ selectionIndex } ` ,
130- message : `this decision point contains invalid values or its values are not in order` ,
131- } )
132- }
133129 }
134130 }
135- )
131+ } )
136132 } )
137133 } )
138134
@@ -144,11 +140,12 @@ export function mandatoryTest_6_1_48(doc) {
144140 * according to the specification.
145141 * If values are missing, this is not an issue.
146142 *
147- * @param {string[] } specifiedValues the valid elements of the values array of the respective decision point
143+ * @param {{ key: string; name: string; description: string; } [] } decisionPointValues the valid elements of the values array of the respective decision point
148144 * and their order according to the SSVC specification
149145 * @param {string[] } usedValues the actual used values of the decision point
150146 */
151- function areValuesValidAndinOrder ( specifiedValues , usedValues ) {
147+ function areValuesValidAndinOrder ( decisionPointValues , usedValues ) {
148+ const specifiedValues = decisionPointValues . map ( ( value ) => value . name )
152149 //check if there is an invalid value used
153150 for ( let i = 0 ; i < usedValues . length ; i ++ ) {
154151 const element = usedValues [ i ]
0 commit comments