Coverage for csaf/document.py: 94.44%
88 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-18 20:12:48 +00:00
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-18 20:12:48 +00:00
1"""CSAF Document meta information model."""
3from __future__ import annotations
5from datetime import datetime
6from enum import Enum
7from typing import Annotated, List, Optional, no_type_check
9from pydantic import AnyUrl, BaseModel, Field, RootModel, field_validator
11from csaf.definitions import Acknowledgments, Lang, Notes, References, Version
14class Revision(BaseModel):
15 """
16 Contains all the information elements required to track the evolution of a CSAF document.
17 """
19 date: Annotated[
20 datetime,
21 Field(description='The date of the revision entry', title='Date of the revision'),
22 ]
23 legacy_version: Annotated[
24 Optional[str],
25 Field(
26 description='Contains the version string used in an existing document with the same content.',
27 min_length=1,
28 title='Legacy version of the revision',
29 ),
30 ] = None
31 number: Version
32 summary: Annotated[
33 str,
34 Field(
35 description='Holds a single non-empty string representing a short description of the changes.',
36 examples=['Initial version.'],
37 min_length=1,
38 title='Summary of the revision',
39 ),
40 ]
43class Tracking(BaseModel):
44 """
45 Is a container designated to hold all management attributes necessary to track a CSAF document as a whole.
46 """
48 aliases: Annotated[
49 Optional[List[Alias]],
50 Field(
51 description='Contains a list of alternate names for the same document.',
52 title='Aliases',
53 ),
54 ] = None
55 current_release_date: Annotated[
56 datetime,
57 Field(
58 description='The date when the current revision of this document was released',
59 title='Current release date',
60 ),
61 ]
62 generator: Annotated[
63 Optional[Generator],
64 Field(
65 description='Is a container to hold all elements related to the generation of the document.'
66 ' These items will reference when the document was actually created,'
67 ' including the date it was generated and the entity that generated it.',
68 title='Document generator',
69 ),
70 ] = None
71 id: Annotated[
72 str,
73 Field(
74 description='The ID is a simple label that provides for a wide range of numbering values, types,'
75 ' and schemes. Its value SHOULD be assigned and maintained by the original document'
76 ' issuing authority.',
77 examples=[
78 'Example Company - 2019-YH3234',
79 'RHBA-2019:0024',
80 'cisco-sa-20190513-secureboot',
81 ],
82 min_length=1,
83 pattern='^[\\S](.*[\\S])?$',
84 title='Unique identifier for the document',
85 ),
86 ]
87 initial_release_date: Annotated[
88 datetime,
89 Field(
90 description='The date when this document was first published.',
91 title='Initial release date',
92 ),
93 ]
94 revision_history: Annotated[
95 List[Revision],
96 Field(
97 description='Holds one revision item for each version of the CSAF document, including the initial one.',
98 min_length=1,
99 title='Revision history',
100 ),
101 ]
102 status: Annotated[
103 DocumentStatus,
104 Field(
105 description='Defines the draft status of the document.',
106 title='Document status',
107 ),
108 ]
109 version: Version
111 @classmethod
112 @no_type_check
113 @field_validator('aliases', 'revision_history')
114 def check_len(cls, v):
115 if not v:
116 raise ValueError('mandatory element present but empty')
117 return v
120class AggregateSeverity(BaseModel):
121 """
122 Is a vehicle that is provided by the document producer to convey the urgency and criticality with which the one or
123 more vulnerabilities reported should be addressed. It is a document-level metric and applied to the document as a
124 whole — not any specific vulnerability. The range of values in this field is defined according to the document
125 producer's policies and procedures.
126 """
128 namespace: Annotated[
129 Optional[AnyUrl],
130 Field(
131 description='Points to the namespace so referenced.',
132 title='Namespace of aggregate severity',
133 ),
134 ] = None
135 text: Annotated[
136 str,
137 Field(
138 description='Provides a severity which is independent of - and in addition to - any other standard metric'
139 ' for determining the impact or severity of a given vulnerability (such as CVSS).',
140 examples=['Critical', 'Important', 'Moderate'],
141 min_length=1,
142 title='Text of aggregate severity',
143 ),
144 ]
147class CsafVersion(Enum):
148 """
149 Gives the version of the CSAF specification which the document was generated for.
150 """
152 version_2_0 = '2.0'
155class Label(Enum):
156 """
157 Provides the TLP label of the document.
158 """
160 AMBER = 'AMBER'
161 GREEN = 'GREEN'
162 RED = 'RED'
163 WHITE = 'WHITE'
166class TrafficLightProtocol(BaseModel):
167 """
168 Provides details about the TLP classification of the document.
169 """
171 label: Annotated[
172 Label,
173 Field(description='Provides the TLP label of the document.', title='Label of TLP'),
174 ]
175 url: Annotated[
176 Optional[AnyUrl],
177 Field(
178 description='Provides a URL where to find the textual description of the TLP version which is used in this'
179 ' document. Default is the URL to the definition by FIRST.',
180 examples=[
181 'https://www.us-cert.gov/tlp',
182 'https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Kritis/Merkblatt_TLP.pdf',
183 ],
184 title='URL of TLP version',
185 ),
186 ] = AnyUrl(url='https://www.first.org/tlp/')
189class Distribution(BaseModel):
190 """
191 Describe any constraints on how this document might be shared.
192 """
194 text: Annotated[
195 Optional[str],
196 Field(
197 description='Provides a textual description of additional constraints.',
198 examples=[
199 'Copyright 2021, Example Company, All Rights Reserved.',
200 'Distribute freely.',
201 'Share only on a need-to-know-basis only.',
202 ],
203 min_length=1,
204 title='Textual description',
205 ),
206 ] = None
207 tlp: Annotated[
208 Optional[TrafficLightProtocol],
209 Field(
210 description='Provides details about the TLP classification of the document.',
211 title='Traffic Light Protocol (TLP)',
212 ),
213 ] = None
216class PublisherCategory(Enum):
217 """
218 Provides information about the category of publisher releasing the document.
219 """
221 coordinator = 'coordinator'
222 discoverer = 'discoverer'
223 other = 'other'
224 translator = 'translator'
225 user = 'user'
226 vendor = 'vendor'
229class Publisher(BaseModel):
230 """
231 Provides information about the publisher of the document.
232 """
234 category: Annotated[
235 PublisherCategory,
236 Field(
237 description='Provides information about the category of publisher releasing the document.',
238 title='Category of publisher',
239 ),
240 ]
241 contact_details: Annotated[
242 Optional[str],
243 Field(
244 description='Information on how to contact the publisher, possibly including details such as web sites,'
245 ' email addresses, phone numbers, and postal mail addresses.',
246 examples=[
247 'Example Company can be reached at [email protected], or via our website'
248 ' at https://www.example.com/contact.'
249 ],
250 min_length=1,
251 title='Contact details',
252 ),
253 ] = None
254 issuing_authority: Annotated[
255 Optional[str],
256 Field(
257 description='Provides information about the authority of the issuing party to release the document,'
258 " in particular, the party's constituency and responsibilities or other obligations.",
259 min_length=1,
260 title='Issuing authority',
261 ),
262 ] = None
263 name: Annotated[
264 str,
265 Field(
266 description='Contains the name of the issuing party.',
267 examples=['BSI', 'Cisco PSIRT', 'Siemens ProductCERT'],
268 min_length=1,
269 title='Name of publisher',
270 ),
271 ]
272 namespace: Annotated[
273 AnyUrl,
274 Field(
275 description='Contains a URL which is under control of the issuing party and can be used as a globally'
276 ' unique identifier for that issuing party.',
277 examples=['https://csaf.io', 'https://www.example.com'],
278 title='Namespace of publisher',
279 ),
280 ]
283class Alias(
284 RootModel[
285 Annotated[
286 str,
287 Field(
288 description='Specifies a non-empty string that represents a distinct optional alternative ID used to'
289 ' refer to the document.',
290 examples=['CVE-2019-12345'],
291 min_length=1,
292 title='Alternate name',
293 ),
294 ]
295 ]
296):
297 pass
300class Engine(BaseModel):
301 """
302 Contains information about the engine that generated the CSAF document.
303 """
305 name: Annotated[
306 str,
307 Field(
308 description='Represents the name of the engine that generated the CSAF document.',
309 examples=['Red Hat rhsa-to-cvrf', 'Secvisogram', 'TVCE'],
310 min_length=1,
311 title='Engine name',
312 ),
313 ]
314 version: Annotated[
315 Optional[str],
316 Field(
317 description='Contains the version of the engine that generated the CSAF document.',
318 examples=['0.6.0', '1.0.0-beta+exp.sha.a1c44f85', '2'],
319 min_length=1,
320 title='Engine version',
321 ),
322 ] = None
325class Generator(BaseModel):
326 """
327 Is a container to hold all elements related to the generation of the document. These items will reference when
328 the document was actually created, including the date it was generated and the entity that generated it.
329 """
331 date: Annotated[
332 Optional[datetime],
333 Field(
334 description='This SHOULD be the current date that the document was generated. Because documents are'
335 ' often generated internally by a document producer and exist for a nonzero amount of time'
336 ' before being released, this field MAY be different from the Initial Release Date and'
337 ' Current Release Date.',
338 title='Date of document generation',
339 ),
340 ] = None
341 engine: Annotated[
342 Engine,
343 Field(
344 description='Contains information about the engine that generated the CSAF document.',
345 title='Engine of document generation',
346 ),
347 ]
350class DocumentStatus(Enum):
351 """
352 Defines the draft status of the document.
353 """
355 draft = 'draft'
356 final = 'final'
357 interim = 'interim'
360class RelationshipCategory(Enum):
361 """
362 Defines the category of relationship for the referenced component.
363 """
365 default_component_of = 'default_component_of'
366 external_component_of = 'external_component_of'
367 installed_on = 'installed_on'
368 installed_with = 'installed_with'
369 optional_component_of = 'optional_component_of'
372class Document(BaseModel):
373 """
374 Captures the meta-data about this document describing a particular set of security advisories.
375 """
377 acknowledgments: Annotated[
378 Optional[Acknowledgments],
379 Field(
380 description='Contains a list of acknowledgment elements associated with the whole document.',
381 title='Document acknowledgments',
382 ),
383 ] = None
384 aggregate_severity: Annotated[
385 Optional[AggregateSeverity],
386 Field(
387 description='Is a vehicle that is provided by the document producer to convey the urgency and'
388 ' criticality with which the one or more vulnerabilities reported should be addressed.'
389 ' It is a document-level metric and applied to the document as a whole'
390 ' — not any specific vulnerability. The range of values in this field is defined according'
391 " to the document producer's policies and procedures.",
392 title='Aggregate severity',
393 ),
394 ] = None
395 category: Annotated[
396 str,
397 Field(
398 description='Defines a short canonical name, chosen by the document producer, which will inform the end'
399 ' user as to the category of document.',
400 examples=[
401 'csaf_base',
402 'csaf_security_advisory',
403 'csaf_vex',
404 'Example Company Security Notice',
405 ],
406 min_length=1,
407 pattern='^[^\\s\\-_\\.](.*[^\\s\\-_\\.])?$',
408 title='Document category',
409 ),
410 ]
411 csaf_version: Annotated[
412 CsafVersion,
413 Field(
414 description='Gives the version of the CSAF specification which the document was generated for.',
415 title='CSAF version',
416 ),
417 ]
418 distribution: Annotated[
419 Optional[Distribution],
420 Field(
421 description='Describe any constraints on how this document might be shared.',
422 title='Rules for sharing document',
423 ),
424 ] = None
425 lang: Annotated[
426 Optional[Lang],
427 Field(
428 description='Identifies the language used by this document, corresponding to IETF BCP 47 / RFC 5646.',
429 title='Document language',
430 ),
431 ] = None
432 notes: Annotated[
433 Optional[Notes],
434 Field(
435 description='Holds notes associated with the whole document.',
436 title='Document notes',
437 ),
438 ] = None
439 publisher: Annotated[
440 Publisher,
441 Field(
442 description='Provides information about the publisher of the document.',
443 title='Publisher',
444 ),
445 ]
446 references: Annotated[
447 Optional[References],
448 Field(
449 description='Holds a list of references associated with the whole document.',
450 title='Document references',
451 ),
452 ] = None
453 source_lang: Annotated[
454 Optional[Lang],
455 Field(
456 description='If this copy of the document is a translation then the value of this property describes'
457 ' from which language this document was translated.',
458 title='Source language',
459 ),
460 ] = None
461 title: Annotated[
462 str,
463 Field(
464 description='This SHOULD be a canonical name for the document, and sufficiently unique to distinguish'
465 ' it from similar documents.',
466 examples=[
467 'Cisco IPv6 Crafted Packet Denial of Service Vulnerability',
468 'Example Company Cross-Site-Scripting Vulnerability in Example Generator',
469 ],
470 min_length=1,
471 title='Title of this document',
472 ),
473 ]
474 tracking: Annotated[
475 Tracking,
476 Field(
477 description='Is a container designated to hold all management attributes necessary to track a'
478 ' CSAF document as a whole.',
479 title='Tracking',
480 ),
481 ]
484Tracking.model_rebuild()