Coverage for turvallisuusneuvonta/csaf/definitions.py: 75.96%
94 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 Document general definitions."""
2from __future__ import annotations
4from collections.abc import Sequence
5from enum import Enum
6from typing import Annotated, List, Optional, no_type_check
8from pydantic import AnyUrl, BaseModel, Field, validator
11class Id(BaseModel):
12 """
13 Gives the document producer a place to publish a unique label or tracking ID for the vulnerability
14 (if such information exists).
15 """
17 system_name: Annotated[
18 str,
19 Field(
20 description='Indicates the name of the vulnerability tracking or numbering system.',
21 examples=['Cisco Bug ID', 'GitHub Issue'],
22 min_length=1,
23 title='System name',
24 ),
25 ]
26 text: Annotated[
27 str,
28 Field(
29 description='Is unique label or tracking ID for the vulnerability (if such information exists).',
30 examples=['CSCso66472', 'oasis-tcs/csaf#210'],
31 min_length=1,
32 title='Text',
33 ),
34 ]
37class Name(BaseModel):
38 __root__: Annotated[
39 str,
40 Field(
41 description='Contains the name of a single person.',
42 examples=['Albert Einstein', 'Johann Sebastian Bach'],
43 min_length=1,
44 title='Name of entity being recognized',
45 ),
46 ]
49class Acknowledgment(BaseModel):
50 """
51 Acknowledges contributions by describing those that contributed.
52 """
54 names: Annotated[
55 Optional[List[Name]],
56 Field(
57 description='Contains the names of entities being recognized.',
58 min_items=1,
59 title='List of acknowledged names',
60 ),
61 ]
62 organization: Annotated[
63 Optional[str],
64 Field(
65 description='Contains the name of a contributing organization being recognized.',
66 examples=['CISA', 'Google Project Zero', 'Talos'],
67 min_length=1,
68 title='Contributing organization',
69 ),
70 ]
71 summary: Annotated[
72 Optional[str],
73 Field(
74 description='SHOULD represent any contextual details the document producers wish to make known about the'
75 ' acknowledgment or acknowledged parties.',
76 examples=['First analysis of Coordinated Multi-Stream Attack (CMSA)'],
77 min_length=1,
78 title='Summary of the acknowledgment',
79 ),
80 ]
81 urls: Annotated[
82 Optional[List[AnyUrl]],
83 Field(
84 description='Specifies a list of URLs or location of the reference to be acknowledged.',
85 min_items=1,
86 title='List of URLs',
87 ),
88 ]
90 @no_type_check
91 @validator('names', 'organization', 'summary', 'urls')
92 @classmethod
93 def check_len(cls, v):
94 if not v:
95 raise ValueError('optional element present but empty')
96 return v
99class Acknowledgments(BaseModel):
100 """
101 Contains a list of acknowledgment elements.
102 """
104 __root__: Annotated[
105 List[Acknowledgment],
106 Field(
107 description='Contains a list of acknowledgment elements.',
108 min_items=1,
109 title='List of acknowledgments',
110 ),
111 ]
113 @no_type_check
114 @validator('__root__')
115 @classmethod
116 def check_len(cls, v):
117 if not v:
118 raise ValueError('optional element present but empty')
119 return v
122class ReferenceTokenForProductGroupInstance(BaseModel):
123 __root__: Annotated[
124 str,
125 Field(
126 description=(
127 'Token required to identify a group of products so that it can be referred to from'
128 ' other parts in the document.'
129 ' There is no predefined or required format for the product_group_id as long as it uniquely identifies'
130 ' a group in the context of the current document.'
131 ),
132 examples=['CSAFGID-0001', 'CSAFGID-0002', 'CSAFGID-0020'],
133 min_length=1,
134 title='Reference token for product group instance',
135 ),
136 ]
139class ProductGroupId(BaseModel):
140 __root__: Annotated[
141 str,
142 Field(
143 description='Token required to identify a group of products so that it can be referred to from other'
144 ' parts in the document. There is no predefined or required format for the product_group_id'
145 ' as long as it uniquely identifies a group in the context of the current document.',
146 examples=['CSAFGID-0001', 'CSAFGID-0002', 'CSAFGID-0020'],
147 min_length=1,
148 title='Reference token for product group instance',
149 ),
150 ]
153class ProductGroupIds(BaseModel):
154 """
155 Specifies a list of product_group_ids to give context to the parent item.
156 """
158 __root__: Annotated[
159 List[ProductGroupId],
160 Field(
161 description='Specifies a list of product_group_ids to give context to the parent item.',
162 min_items=1,
163 title='List of product_group_ids',
164 ),
165 ]
167 @no_type_check
168 @validator('__root__')
169 @classmethod
170 def check_len(cls, v):
171 if not v:
172 raise ValueError('mandatory element present but empty')
173 return v
176class ProductId(BaseModel):
177 __root__: Annotated[
178 str,
179 Field(
180 description='Token required to identify a full_product_name so that it can be referred to from other parts'
181 ' in the document. There is no predefined or required format for the product_id as long as it'
182 ' uniquely identifies a product in the context of the current document.',
183 examples=['CSAFPID-0004', 'CSAFPID-0008'],
184 min_length=1,
185 title='Reference token for product instance',
186 ),
187 ]
190class Products(BaseModel):
191 """
192 Specifies a list of product_ids to give context to the parent item.
193 """
195 __root__: Annotated[
196 List[ProductId],
197 Field(
198 description='Specifies a list of product_ids to give context to the parent item.',
199 min_items=1,
200 title='List of product_ids',
201 ),
202 ]
205class ReferenceTokenForProductInstance(BaseModel):
206 value: Annotated[
207 str,
208 Field(
209 description=(
210 'Token required to identify a full_product_name so that it can be referred to from other'
211 ' parts in the document.'
212 ' There is no predefined or required format for the product_id as long as it uniquely'
213 ' identifies a product in the context of the current document.'
214 ),
215 examples=['CSAFPID-0004', 'CSAFPID-0008'],
216 min_length=1,
217 title='Reference token for product instance',
218 ),
219 ]
222class ListOfProductIds(BaseModel):
223 """
224 Specifies a list of product_ids to give context to the parent item.
225 """
227 product_ids: Annotated[
228 Sequence[ReferenceTokenForProductInstance],
229 Field(
230 description='Specifies a list of product_ids to give context to the parent item.',
231 # min_items=1,
232 title='List of product_ids',
233 ),
234 ]
236 @no_type_check
237 @validator('product_ids')
238 @classmethod
239 def check_len(cls, v):
240 if not v:
241 raise ValueError('mandatory element present but empty')
242 return v
245class Lang(BaseModel):
246 __root__: Annotated[
247 str,
248 Field(
249 description='Identifies a language, corresponding to IETF BCP 47 / RFC 5646. See IETF language'
250 ' registry: https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry',
251 examples=['de', 'en', 'fr', 'frc', 'jp'],
252 regex='^(([A-Za-z]{2,3}(-[A-Za-z]{3}(-[A-Za-z]{3}){0,2})?|[A-Za-z]{4,8})(-[A-Za-z]{4})?(-([A-Za-z]{2}|'
253 '[0-9]{3}))?(-([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-[A-WY-Za-wy-z0-9](-[A-Za-z0-9]{2,8})+)*'
254 '(-[Xx](-[A-Za-z0-9]{1,8})+)?|[Xx](-[A-Za-z0-9]{1,8})+|[Ii]-[Dd][Ee][Ff][Aa][Uu][Ll][Tt]|'
255 '[Ii]-[Mm][Ii][Nn][Gg][Oo])$',
256 title='Language type',
257 ),
258 ]
261class NoteCategory(Enum):
262 """
263 Choice of what kind of note this is.
264 """
266 description = 'description'
267 details = 'details'
268 faq = 'faq'
269 general = 'general'
270 legal_disclaimer = 'legal_disclaimer'
271 other = 'other'
272 summary = 'summary'
275class Note(BaseModel):
276 """
277 Is a place to put all manner of text blobs related to the current context.
278 """
280 audience: Annotated[
281 Optional[str],
282 Field(
283 description='Indicate who is intended to read it.',
284 examples=[
285 'all',
286 'executives',
287 'operational management and system administrators',
288 'safety engineers',
289 ],
290 min_length=1,
291 title='Audience of note',
292 ),
293 ]
294 category: Annotated[
295 NoteCategory,
296 Field(description='Choice of what kind of note this is.', title='Note category'),
297 ]
298 text: Annotated[
299 str,
300 Field(
301 description='The contents of the note. Content varies depending on type.',
302 min_length=1,
303 title='Note contents',
304 ),
305 ]
306 title: Annotated[
307 Optional[str],
308 Field(
309 description='Provides a concise description of what is contained in the text of the note.',
310 examples=[
311 'Details',
312 'Executive summary',
313 'Technical summary',
314 'Impact on safety systems',
315 ],
316 min_length=1,
317 title='Title of note',
318 ),
319 ]
322class Notes(BaseModel):
323 """
324 Contains notes which are specific to the current context.
325 """
327 __root__: Annotated[
328 List[Note],
329 Field(
330 description='Contains notes which are specific to the current context.',
331 min_items=1,
332 title='List of notes',
333 ),
334 ]
336 @no_type_check
337 @validator('__root__')
338 @classmethod
339 def check_len(cls, v):
340 if not v:
341 raise ValueError('mandatory element present but empty')
342 return v
345class ReferenceCategory(Enum):
346 """
347 Indicates whether the reference points to the same document or vulnerability in focus (depending on scope) or
348 to an external resource.
349 """
351 external = 'external'
352 self = 'self'
355class Reference(BaseModel):
356 """
357 Holds any reference to conferences, papers, advisories, and other resources that are related and considered
358 related to either a surrounding part of or the entire document and to be of value to the document consumer.
359 """
361 category: Annotated[
362 Optional[ReferenceCategory],
363 Field(
364 description='Indicates whether the reference points to the same document or vulnerability in focus'
365 ' (depending on scope) or to an external resource.',
366 title='Category of reference',
367 ),
368 ] = ReferenceCategory.external
369 summary: Annotated[
370 str,
371 Field(
372 description='Indicates what this reference refers to.',
373 min_length=1,
374 title='Summary of the reference',
375 ),
376 ]
377 url: Annotated[
378 AnyUrl,
379 Field(description='Provides the URL for the reference.', title='URL of reference'),
380 ]
383class References(BaseModel):
384 """
385 Holds a list of references.
386 """
388 __root__: Annotated[
389 List[Reference],
390 Field(
391 description='Holds a list of references.',
392 min_items=1,
393 title='List of references',
394 ),
395 ]
398class Version(BaseModel):
399 __root__: Annotated[
400 str,
401 Field(
402 description=(
403 'Specifies a version string to denote clearly the evolution of the content of the document.'
404 ' Format must be either integer or semantic versioning.'
405 ),
406 examples=['1', '4', '0.9.0', '1.4.3', '2.40.0+21AF26D3'],
407 regex=(
408 '^(0|[1-9][0-9]*)$|^((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)'
409 '(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?'
410 '(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)$'
411 ),
412 title='Version',
413 ),
414 ]