Coverage for turvallisuusneuvonta/csaf/vulnerability.py: 95.54%
220 statements
« prev ^ index » next coverage.py v7.0.3, created at 2023-01-07 19:14 +0100
« prev ^ index » next coverage.py v7.0.3, created at 2023-01-07 19:14 +0100
1"""CSAF Vulnerability model."""
2from __future__ import annotations
4from datetime import datetime
5from enum import Enum
6from typing import Annotated, List, Optional, Union, no_type_check
8from pydantic import AnyUrl, BaseModel, Field, validator
10from turvallisuusneuvonta.csaf.cvss.cvss import CVSS2, CVSS30, CVSS31
11from turvallisuusneuvonta.csaf.definitions import Acknowledgments, Id, Notes, ProductGroupIds, Products, References
12from turvallisuusneuvonta.csaf.product import ProductStatus
15class Cwe(BaseModel):
16 """
17 Holds the MITRE standard Common Weakness Enumeration (CWE) for the weakness associated.
18 """
20 id: Annotated[
21 str,
22 Field(
23 description='Holds the ID for the weakness associated.',
24 examples=['CWE-22', 'CWE-352', 'CWE-79'],
25 regex='^CWE-[1-9]\\d{0,5}$',
26 title='Weakness ID',
27 ),
28 ]
29 name: Annotated[
30 str,
31 Field(
32 description='Holds the full name of the weakness as given in the CWE specification.',
33 examples=[
34 'Cross-Site Request Forgery (CSRF)',
35 "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')",
36 "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')",
37 ],
38 min_length=1,
39 title='Weakness name',
40 ),
41 ]
44class PartyCategory(Enum):
45 """
46 Defines the category of the involved party.
47 """
49 coordinator = 'coordinator'
50 discoverer = 'discoverer'
51 other = 'other'
52 user = 'user'
53 vendor = 'vendor'
56class PartyStatus(Enum):
57 """
58 Defines contact status of the involved party.
59 """
61 completed = 'completed'
62 contact_attempted = 'contact_attempted'
63 disputed = 'disputed'
64 in_progress = 'in_progress'
65 not_contacted = 'not_contacted'
66 open = 'open'
69class Involvement(BaseModel):
70 """
71 Is a container, that allows the document producers to comment on the level of involvement (or engagement)
72 of themselves or third parties in the vulnerability identification, scoping, and remediation process.
73 """
75 date: Annotated[
76 Optional[datetime],
77 Field(
78 description='Holds the date and time of the involvement entry.',
79 title='Date of involvement',
80 ),
81 ] = None
82 party: Annotated[
83 PartyCategory,
84 Field(
85 description='Defines the category of the involved party.',
86 title='Party category',
87 ),
88 ]
89 status: Annotated[
90 PartyStatus,
91 Field(
92 description='Defines contact status of the involved party.',
93 title='Party status',
94 ),
95 ]
96 summary: Annotated[
97 Optional[str],
98 Field(
99 description='Contains additional context regarding what is going on.',
100 min_length=1,
101 title='Summary of the involvement',
102 ),
103 ] = None
106class RemediationCategory(Enum):
107 """
108 Specifies the category which this remediation belongs to.
109 """
111 mitigation = 'mitigation'
112 no_fix_planned = 'no_fix_planned'
113 none_available = 'none_available'
114 vendor_fix = 'vendor_fix'
115 workaround = 'workaround'
118class Entitlement(BaseModel):
119 __root__: Annotated[
120 str,
121 Field(
122 description='Contains any possible vendor-defined constraints for obtaining fixed software or hardware'
123 'that fully resolves the vulnerability.',
124 min_length=1,
125 title='Entitlement of the remediation',
126 ),
127 ]
130class RestartRequiredCategory(Enum):
131 """
132 Specifies what category of restart is required by this remediation to become effective.
133 """
135 connected = 'connected'
136 dependencies = 'dependencies'
137 machine = 'machine'
138 none = 'none'
139 parent = 'parent'
140 service = 'service'
141 system = 'system'
142 vulnerable_component = 'vulnerable_component'
143 zone = 'zone'
146class RestartRequired(BaseModel):
147 """
148 Provides information on category of restart is required by this remediation to become effective.
149 """
151 category: Annotated[
152 RestartRequiredCategory,
153 Field(
154 description='Specifies what category of restart is required by this remediation to become effective.',
155 title='Category of restart',
156 ),
157 ]
158 details: Annotated[
159 Optional[str],
160 Field(
161 description='Provides additional information for the restart. This can include details on procedures,'
162 'scope or impact.',
163 min_length=1,
164 title='Additional restart information',
165 ),
166 ]
169class ThreatCategory(Enum):
170 """
171 Categorizes the threat according to the rules of the specification.
172 """
174 exploit_status = 'exploit_status'
175 impact = 'impact'
176 target_set = 'target_set'
179class AccessVectorType(Enum):
180 network = 'NETWORK'
181 adjacent_network = 'ADJACENT_NETWORK'
182 local = 'LOCAL'
185class AccessComplexityType(Enum):
186 high = 'HIGH'
187 medium = 'MEDIUM'
188 low = 'LOW'
191class AuthenticationType(Enum):
192 multiple = 'MULTIPLE'
193 single = 'SINGLE'
194 none = 'NONE'
197class CiaType(Enum):
198 none = 'NONE'
199 partial = 'PARTIAL'
200 complete = 'COMPLETE'
203class ExploitabilityType(Enum):
204 unproven = 'UNPROVEN'
205 proof_of_concept = 'PROOF_OF_CONCEPT'
206 functional = 'FUNCTIONAL'
207 high = 'HIGH'
208 not_defined = 'NOT_DEFINED'
211class RemediationLevelType(Enum):
212 official_fix = 'OFFICIAL_FIX'
213 temporary_fix = 'TEMPORARY_FIX'
214 workaround = 'WORKAROUND'
215 unavailable = 'UNAVAILABLE'
216 not_defined = 'NOT_DEFINED'
219class ReportConfidenceType(Enum):
220 unconfirmed = 'UNCONFIRMED'
221 uncorroborated = 'UNCORROBORATED'
222 confirmed = 'CONFIRMED'
223 not_defined = 'NOT_DEFINED'
226class CollateralDamagePotentialType(Enum):
227 none = 'NONE'
228 low = 'LOW'
229 low_medium = 'LOW_MEDIUM'
230 medium_high = 'MEDIUM_HIGH'
231 high = 'HIGH'
232 not_defined = 'NOT_DEFINED'
235class TargetDistributionType(Enum):
236 none = 'NONE'
237 low = 'LOW'
238 medium = 'MEDIUM'
239 high = 'HIGH'
240 not_defined = 'NOT_DEFINED'
243class CiaRequirementType(Enum):
244 low = 'LOW'
245 medium = 'MEDIUM'
246 high = 'HIGH'
247 not_defined = 'NOT_DEFINED'
250class ScoreType(BaseModel):
251 value: Annotated[float, Field(ge=0.0, le=10.0)]
254class AttackVectorType(Enum):
255 network = 'NETWORK'
256 adjacent_network = 'ADJACENT_NETWORK'
257 local = 'LOCAL'
258 physical = 'PHYSICAL'
261class ModifiedAttackVectorType(Enum):
262 network = 'NETWORK'
263 adjacent_network = 'ADJACENT_NETWORK'
264 local = 'LOCAL'
265 physical = 'PHYSICAL'
266 not_defined = 'NOT_DEFINED'
269class AttackComplexityType(Enum):
270 high = 'HIGH'
271 low = 'LOW'
274class ModifiedAttackComplexityType(Enum):
275 high = 'HIGH'
276 low = 'LOW'
277 not_defined = 'NOT_DEFINED'
280class PrivilegesRequiredType(Enum):
281 high = 'HIGH'
282 low = 'LOW'
283 none = 'NONE'
286class ModifiedPrivilegesRequiredType(Enum):
287 high = 'HIGH'
288 low = 'LOW'
289 none = 'NONE'
290 not_defined = 'NOT_DEFINED'
293class UserInteractionType(Enum):
294 none = 'NONE'
295 required = 'REQUIRED'
298class ModifiedUserInteractionType(Enum):
299 none = 'NONE'
300 required = 'REQUIRED'
301 not_defined = 'NOT_DEFINED'
304class ScopeType(Enum):
305 unchanged = 'UNCHANGED'
306 changed = 'CHANGED'
309class ModifiedScopeType(Enum):
310 unchanged = 'UNCHANGED'
311 changed = 'CHANGED'
312 not_defined = 'NOT_DEFINED'
315class CiaTypeModel(Enum):
316 none = 'NONE'
317 low = 'LOW'
318 high = 'HIGH'
321class ModifiedCiaType(Enum):
322 none = 'NONE'
323 low = 'LOW'
324 high = 'HIGH'
325 not_defined = 'NOT_DEFINED'
328class ConfidenceType(Enum):
329 unknown = 'UNKNOWN'
330 reasonable = 'REASONABLE'
331 confirmed = 'CONFIRMED'
332 not_defined = 'NOT_DEFINED'
335class ScoreTypeModel(ScoreType):
336 pass
339class SeverityType(Enum):
340 none = 'NONE'
341 low = 'LOW'
342 medium = 'MEDIUM'
343 high = 'HIGH'
344 critical = 'CRITICAL'
347class ScoreTypeModel1(ScoreType):
348 pass
351class Remediation(BaseModel):
352 """
353 Specifies details on how to handle (and presumably, fix) a vulnerability.
354 """
356 category: Annotated[
357 RemediationCategory,
358 Field(
359 description='Specifies the category which this remediation belongs to.',
360 title='Category of the remediation',
361 ),
362 ]
363 date: Annotated[
364 Optional[datetime],
365 Field(
366 description='Contains the date from which the remediation is available.',
367 title='Date of the remediation',
368 ),
369 ]
370 details: Annotated[
371 str,
372 Field(
373 description='Contains a thorough human-readable discussion of the remediation.',
374 min_length=1,
375 title='Details of the remediation',
376 ),
377 ]
378 entitlements: Annotated[
379 Optional[List[Entitlement]],
380 Field(
381 description='Contains a list of entitlements.',
382 min_items=1,
383 title='List of entitlements',
384 ),
385 ]
386 group_ids: Optional[ProductGroupIds]
387 product_ids: Optional[Products]
388 restart_required: Annotated[
389 Optional[RestartRequired],
390 Field(
391 description='Provides information on category of restart is required by this remediation to'
392 ' become effective.',
393 title='Restart required by remediation',
394 ),
395 ]
396 url: Annotated[
397 Optional[AnyUrl],
398 Field(
399 description='Contains the URL where to obtain the remediation.',
400 title='URL to the remediation',
401 ),
402 ]
404 @no_type_check
405 @validator('entitlements')
406 @classmethod
407 def check_len(cls, v):
408 if not v:
409 raise ValueError('optional element present but empty')
410 return v
413class Threat(BaseModel):
414 """
415 Contains the vulnerability kinetic information. This information can change as the vulnerability ages and new
416 information becomes available.
417 """
419 category: Annotated[
420 ThreatCategory,
421 Field(
422 description='Categorizes the threat according to the rules of the specification.',
423 title='Category of the threat',
424 ),
425 ]
426 date: Annotated[
427 Optional[datetime],
428 Field(
429 description='Contains the date when the assessment was done or the threat appeared.',
430 title='Date of the threat',
431 ),
432 ]
433 details: Annotated[
434 str,
435 Field(
436 description='Represents a thorough human-readable discussion of the threat.',
437 min_length=1,
438 title='Details of the threat',
439 ),
440 ]
441 group_ids: Optional[ProductGroupIds]
442 product_ids: Optional[Products]
445class Score(BaseModel):
446 """
447 specifies information about (at least one) score of the vulnerability and for
448 which products the given value applies.
449 """
451 cvss_v2: Optional[CVSS2] = None
452 cvss_v3: Optional[Union[CVSS30, CVSS31]] = None
453 products: Products
456class Vulnerability(BaseModel):
457 """
458 Is a container for the aggregation of all fields that are related to a single vulnerability in the document.
459 """
461 acknowledgments: Annotated[
462 Optional[Acknowledgments],
463 Field(
464 description='Contains a list of acknowledgment elements associated with this vulnerability item.',
465 title='Vulnerability acknowledgments',
466 ),
467 ]
468 cve: Annotated[
469 Optional[str],
470 Field(
471 description='Holds the MITRE standard Common Vulnerabilities and Exposures (CVE) tracking number for'
472 ' the vulnerability.',
473 regex='^CVE-[0-9]{4}-[0-9]{4,}$',
474 title='CVE',
475 ),
476 ]
477 cwe: Annotated[
478 Optional[Cwe],
479 Field(
480 description='Holds the MITRE standard Common Weakness Enumeration (CWE) for the weakness associated.',
481 title='CWE',
482 ),
483 ]
484 discovery_date: Annotated[
485 Optional[datetime],
486 Field(
487 description='Holds the date and time the vulnerability was originally discovered.',
488 title='Discovery date',
489 ),
490 ]
491 id: Annotated[
492 Optional[Id],
493 Field(
494 description='Gives the document producer a place to publish a unique label or tracking ID for the'
495 ' vulnerability (if such information exists).',
496 title='ID',
497 ),
498 ]
499 involvements: Annotated[
500 Optional[List[Involvement]],
501 Field(
502 description='Contains a list of involvements.',
503 min_items=1,
504 title='List of involvements',
505 ),
506 ]
507 notes: Annotated[
508 Optional[Notes],
509 Field(
510 description='Holds notes associated with this vulnerability item.',
511 title='Vulnerability notes',
512 ),
513 ]
514 product_status: Annotated[
515 Optional[ProductStatus],
516 Field(
517 description='Contains different lists of product_ids which provide details on the status of the'
518 ' referenced product related to the current vulnerability. ',
519 title='Product status',
520 ),
521 ]
522 references: Annotated[
523 Optional[References],
524 Field(
525 description='Holds a list of references associated with this vulnerability item.',
526 title='Vulnerability references',
527 ),
528 ]
529 release_date: Annotated[
530 Optional[datetime],
531 Field(
532 description='Holds the date and time the vulnerability was originally released into the wild.',
533 title='Release date',
534 ),
535 ]
536 remediations: Annotated[
537 Optional[List[Remediation]],
538 Field(
539 description='Contains a list of remediations.',
540 min_items=1,
541 title='List of remediations',
542 ),
543 ]
544 scores: Annotated[
545 Optional[List[Score]],
546 Field(
547 description='contains score objects for the current vulnerability.',
548 min_items=1,
549 title='List of scores',
550 ),
551 ]
552 threats: Annotated[
553 Optional[List[Threat]],
554 Field(
555 description='Contains information about a vulnerability that can change with time.',
556 min_items=1,
557 title='List of threats',
558 ),
559 ]
560 title: Annotated[
561 Optional[str],
562 Field(
563 description='Gives the document producer the ability to apply a canonical name or title to'
564 ' the vulnerability.',
565 min_length=1,
566 title='Title',
567 ),
568 ]
570 @no_type_check
571 @validator('involvements', 'remediations', 'scores', 'threats')
572 @classmethod
573 def check_len(cls, v):
574 if not v:
575 raise ValueError('optional element present but empty')
576 return v