|
15 | 15 | from vulnerabilities.utils import get_advisory_url |
16 | 16 | from vulnerabilities.utils import get_cwe_id |
17 | 17 | from vulnerabilities.utils import get_reference_id |
| 18 | +from vulnerabilities.utils import ssvc_calculator |
18 | 19 |
|
19 | 20 | logger = logging.getLogger(__name__) |
20 | 21 |
|
@@ -184,117 +185,3 @@ def parse_cve_advisory(raw_data, advisory_url): |
184 | 185 | weaknesses=sorted(weaknesses), |
185 | 186 | url=advisory_url, |
186 | 187 | ) |
187 | | - |
188 | | - |
189 | | -def ssvc_calculator(ssvc_data): |
190 | | - """ |
191 | | - Return the ssvc vector and the decision value |
192 | | - """ |
193 | | - options = ssvc_data.get("options", []) |
194 | | - timestamp = ssvc_data.get("timestamp") |
195 | | - |
196 | | - # Extract the options into a dictionary |
197 | | - options_dict = {k: v.lower() for option in options for k, v in option.items()} |
198 | | - |
199 | | - # We copied the table value from this link. |
200 | | - # https://www.cisa.gov/sites/default/files/publications/cisa-ssvc-guide%20508c.pdf |
201 | | - |
202 | | - # Determining Mission and Well-Being Impact Value |
203 | | - mission_well_being_table = { |
204 | | - # (Mission Prevalence, Public Well-being Impact) : "Mission & Well-being" |
205 | | - ("minimal", "minimal"): "low", |
206 | | - ("minimal", "material"): "medium", |
207 | | - ("minimal", "irreversible"): "high", |
208 | | - ("support", "minimal"): "medium", |
209 | | - ("support", "material"): "medium", |
210 | | - ("support", "irreversible"): "high", |
211 | | - ("essential", "minimal"): "high", |
212 | | - ("essential", "material"): "high", |
213 | | - ("essential", "irreversible"): "high", |
214 | | - } |
215 | | - |
216 | | - if "Mission Prevalence" not in options_dict: |
217 | | - options_dict["Mission Prevalence"] = "minimal" |
218 | | - |
219 | | - if "Public Well-being Impact" not in options_dict: |
220 | | - options_dict["Public Well-being Impact"] = "material" |
221 | | - |
222 | | - options_dict["Mission & Well-being"] = mission_well_being_table[ |
223 | | - (options_dict["Mission Prevalence"], options_dict["Public Well-being Impact"]) |
224 | | - ] |
225 | | - |
226 | | - decision_key = ( |
227 | | - options_dict.get("Exploitation"), |
228 | | - options_dict.get("Automatable"), |
229 | | - options_dict.get("Technical Impact"), |
230 | | - options_dict.get("Mission & Well-being"), |
231 | | - ) |
232 | | - |
233 | | - decision_points = { |
234 | | - "Exploitation": {"E": {"none": "N", "poc": "P", "active": "A"}}, |
235 | | - "Automatable": {"A": {"no": "N", "yes": "Y"}}, |
236 | | - "Technical Impact": {"T": {"partial": "P", "total": "T"}}, |
237 | | - "Public Well-being Impact": {"B": {"minimal": "M", "material": "A", "irreversible": "I"}}, |
238 | | - "Mission Prevalence": {"P": {"minimal": "M", "support": "S", "essential": "E"}}, |
239 | | - "Mission & Well-being": {"M": {"low": "L", "medium": "M", "high": "H"}}, |
240 | | - } |
241 | | - |
242 | | - # Create the SSVC vector |
243 | | - ssvc_vector = "SSVCv2/" |
244 | | - for key, value_map in options_dict.items(): |
245 | | - options_key = decision_points.get(key) |
246 | | - for lhs, rhs_map in options_key.items(): |
247 | | - ssvc_vector += f"{lhs}:{rhs_map.get(value_map)}/" |
248 | | - |
249 | | - # "Decision": {"D": {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"}}, |
250 | | - decision_values = {"Track": "T", "Track*": "R", "Attend": "A", "Act": "C"} |
251 | | - |
252 | | - decision_lookup = { |
253 | | - ("none", "no", "partial", "low"): "Track", |
254 | | - ("none", "no", "partial", "medium"): "Track", |
255 | | - ("none", "no", "partial", "high"): "Track", |
256 | | - ("none", "no", "total", "low"): "Track", |
257 | | - ("none", "no", "total", "medium"): "Track", |
258 | | - ("none", "no", "total", "high"): "Track*", |
259 | | - ("none", "yes", "partial", "low"): "Track", |
260 | | - ("none", "yes", "partial", "medium"): "Track", |
261 | | - ("none", "yes", "partial", "high"): "Attend", |
262 | | - ("none", "yes", "total", "low"): "Track", |
263 | | - ("none", "yes", "total", "medium"): "Track", |
264 | | - ("none", "yes", "total", "high"): "Attend", |
265 | | - ("poc", "no", "partial", "low"): "Track", |
266 | | - ("poc", "no", "partial", "medium"): "Track", |
267 | | - ("poc", "no", "partial", "high"): "Track*", |
268 | | - ("poc", "no", "total", "low"): "Track", |
269 | | - ("poc", "no", "total", "medium"): "Track*", |
270 | | - ("poc", "no", "total", "high"): "Attend", |
271 | | - ("poc", "yes", "partial", "low"): "Track", |
272 | | - ("poc", "yes", "partial", "medium"): "Track", |
273 | | - ("poc", "yes", "partial", "high"): "Attend", |
274 | | - ("poc", "yes", "total", "low"): "Track", |
275 | | - ("poc", "yes", "total", "medium"): "Track*", |
276 | | - ("poc", "yes", "total", "high"): "Attend", |
277 | | - ("active", "no", "partial", "low"): "Track", |
278 | | - ("active", "no", "partial", "medium"): "Track", |
279 | | - ("active", "no", "partial", "high"): "Attend", |
280 | | - ("active", "no", "total", "low"): "Track", |
281 | | - ("active", "no", "total", "medium"): "Attend", |
282 | | - ("active", "no", "total", "high"): "Act", |
283 | | - ("active", "yes", "partial", "low"): "Attend", |
284 | | - ("active", "yes", "partial", "medium"): "Attend", |
285 | | - ("active", "yes", "partial", "high"): "Act", |
286 | | - ("active", "yes", "total", "low"): "Attend", |
287 | | - ("active", "yes", "total", "medium"): "Act", |
288 | | - ("active", "yes", "total", "high"): "Act", |
289 | | - } |
290 | | - |
291 | | - decision = decision_lookup.get(decision_key, "") |
292 | | - |
293 | | - if decision: |
294 | | - ssvc_vector += f"D:{decision_values.get(decision)}/" |
295 | | - |
296 | | - if timestamp: |
297 | | - timestamp_formatted = dateparser.parse(timestamp).strftime("%Y-%m-%dT%H:%M:%SZ") |
298 | | - |
299 | | - ssvc_vector += f"{timestamp_formatted}/" |
300 | | - return ssvc_vector, decision |
0 commit comments