@mitre/hdf-schema 3.0.1 → 3.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE.md +55 -0
  2. package/README.md +83 -40
  3. package/dist/go/hdf.go +148 -104
  4. package/dist/index.d.ts +26 -1
  5. package/dist/index.js +26 -1
  6. package/dist/schemas/hdf-amendments.schema.json +178 -53
  7. package/dist/schemas/hdf-baseline.schema.json +181 -56
  8. package/dist/schemas/hdf-comparison.schema.json +523 -108
  9. package/dist/schemas/hdf-evidence-package.schema.json +175 -50
  10. package/dist/schemas/hdf-plan.schema.json +181 -56
  11. package/dist/schemas/hdf-results.schema.json +502 -87
  12. package/dist/schemas/hdf-system.schema.json +190 -65
  13. package/dist/ts/hdf-amendments.d.ts +43 -15
  14. package/dist/ts/hdf-amendments.js +18 -7
  15. package/dist/ts/hdf-amendments.ts +44 -15
  16. package/dist/ts/hdf-results.d.ts +91 -37
  17. package/dist/ts/hdf-results.js +40 -20
  18. package/dist/ts/hdf-results.ts +91 -36
  19. package/package.json +44 -45
  20. package/dist/python/hdf_amendments.py +0 -695
  21. package/dist/python/hdf_baseline.py +0 -782
  22. package/dist/python/hdf_comparison.py +0 -1771
  23. package/dist/python/hdf_evidence_package.py +0 -593
  24. package/dist/python/hdf_plan.py +0 -363
  25. package/dist/python/hdf_results.py +0 -2163
  26. package/dist/python/hdf_system.py +0 -904
  27. package/src/schemas/hdf-amendments.schema.json +0 -97
  28. package/src/schemas/hdf-baseline.schema.json +0 -190
  29. package/src/schemas/hdf-comparison.schema.json +0 -107
  30. package/src/schemas/hdf-evidence-package.schema.json +0 -227
  31. package/src/schemas/hdf-plan.schema.json +0 -92
  32. package/src/schemas/hdf-results.schema.json +0 -304
  33. package/src/schemas/hdf-system.schema.json +0 -136
  34. package/src/schemas/primitives/amendments.schema.json +0 -155
  35. package/src/schemas/primitives/common.schema.json +0 -814
  36. package/src/schemas/primitives/comparison.schema.json +0 -809
  37. package/src/schemas/primitives/component.schema.json +0 -518
  38. package/src/schemas/primitives/data-flow.schema.json +0 -158
  39. package/src/schemas/primitives/extensions.schema.json +0 -342
  40. package/src/schemas/primitives/parameter.schema.json +0 -128
  41. package/src/schemas/primitives/plan.schema.json +0 -128
  42. package/src/schemas/primitives/platform.schema.json +0 -32
  43. package/src/schemas/primitives/result.schema.json +0 -133
  44. package/src/schemas/primitives/runner.schema.json +0 -83
  45. package/src/schemas/primitives/statistics.schema.json +0 -71
  46. package/src/schemas/primitives/system.schema.json +0 -132
  47. package/src/schemas/primitives/target.schema.json +0 -523
@@ -1,2163 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Optional, Any, List, Dict, Union, TypeVar, Callable, Type, cast
3
- from enum import Enum
4
- from datetime import datetime
5
- from uuid import UUID
6
- import dateutil.parser
7
-
8
-
9
- T = TypeVar("T")
10
- EnumT = TypeVar("EnumT", bound=Enum)
11
-
12
-
13
- def from_str(x: Any) -> str:
14
- assert isinstance(x, str)
15
- return x
16
-
17
-
18
- def from_none(x: Any) -> Any:
19
- assert x is None
20
- return x
21
-
22
-
23
- def from_union(fs, x):
24
- for f in fs:
25
- try:
26
- return f(x)
27
- except:
28
- pass
29
- assert False
30
-
31
-
32
- def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
33
- assert isinstance(x, list)
34
- return [f(y) for y in x]
35
-
36
-
37
- def from_float(x: Any) -> float:
38
- assert isinstance(x, (float, int)) and not isinstance(x, bool)
39
- return float(x)
40
-
41
-
42
- def to_float(x: Any) -> float:
43
- assert isinstance(x, (int, float))
44
- return x
45
-
46
-
47
- def from_bool(x: Any) -> bool:
48
- assert isinstance(x, bool)
49
- return x
50
-
51
-
52
- def to_class(c: Type[T], x: Any) -> dict:
53
- assert isinstance(x, c)
54
- return cast(Any, x).to_dict()
55
-
56
-
57
- def to_enum(c: Type[EnumT], x: Any) -> EnumT:
58
- assert isinstance(x, c)
59
- return x.value
60
-
61
-
62
- def from_datetime(x: Any) -> datetime:
63
- return dateutil.parser.parse(x)
64
-
65
-
66
- def from_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]:
67
- assert isinstance(x, dict)
68
- return { k: f(v) for (k, v) in x.items() }
69
-
70
-
71
- def from_int(x: Any) -> int:
72
- assert isinstance(x, int) and not isinstance(x, bool)
73
- return x
74
-
75
-
76
- @dataclass
77
- class Dependency:
78
- """A dependency for a baseline. Can include relative paths or URLs for where to find the
79
- dependency.
80
- """
81
- branch: Optional[str] = None
82
- """The branch name for a git repo."""
83
-
84
- compliance: Optional[str] = None
85
- """The 'user/profilename' attribute for an Automate server."""
86
-
87
- git: Optional[str] = None
88
- """The location of the git repo. Example:
89
- 'https://github.com/my-org/ubuntu-22.04-stig-baseline.git'.
90
- """
91
- name: Optional[str] = None
92
- """The name or assigned alias."""
93
-
94
- path: Optional[str] = None
95
- """The relative path if the dependency is locally available."""
96
-
97
- status: Optional[str] = None
98
- """The status. Should be: 'loaded', 'failed', or 'skipped'."""
99
-
100
- status_message: Optional[str] = None
101
- """The reason for the status if it is 'failed' or 'skipped'."""
102
-
103
- supermarket: Optional[str] = None
104
- """The 'user/profilename' attribute for a Supermarket server."""
105
-
106
- url: Optional[str] = None
107
- """The address of the dependency."""
108
-
109
- @staticmethod
110
- def from_dict(obj: Any) -> 'Dependency':
111
- assert isinstance(obj, dict)
112
- branch = from_union([from_str, from_none], obj.get("branch"))
113
- compliance = from_union([from_str, from_none], obj.get("compliance"))
114
- git = from_union([from_str, from_none], obj.get("git"))
115
- name = from_union([from_str, from_none], obj.get("name"))
116
- path = from_union([from_str, from_none], obj.get("path"))
117
- status = from_union([from_str, from_none], obj.get("status"))
118
- status_message = from_union([from_str, from_none], obj.get("statusMessage"))
119
- supermarket = from_union([from_str, from_none], obj.get("supermarket"))
120
- url = from_union([from_str, from_none], obj.get("url"))
121
- return Dependency(branch, compliance, git, name, path, status, status_message, supermarket, url)
122
-
123
- def to_dict(self) -> dict:
124
- result: dict = {}
125
- if self.branch is not None:
126
- result["branch"] = from_union([from_str, from_none], self.branch)
127
- if self.compliance is not None:
128
- result["compliance"] = from_union([from_str, from_none], self.compliance)
129
- if self.git is not None:
130
- result["git"] = from_union([from_str, from_none], self.git)
131
- if self.name is not None:
132
- result["name"] = from_union([from_str, from_none], self.name)
133
- if self.path is not None:
134
- result["path"] = from_union([from_str, from_none], self.path)
135
- if self.status is not None:
136
- result["status"] = from_union([from_str, from_none], self.status)
137
- if self.status_message is not None:
138
- result["statusMessage"] = from_union([from_str, from_none], self.status_message)
139
- if self.supermarket is not None:
140
- result["supermarket"] = from_union([from_str, from_none], self.supermarket)
141
- if self.url is not None:
142
- result["url"] = from_union([from_str, from_none], self.url)
143
- return result
144
-
145
-
146
- @dataclass
147
- class RequirementGroup:
148
- """Describes a group of requirements, such as those defined in a single file."""
149
-
150
- id: str
151
- """The unique identifier for the group. Example: the relative path to the file specifying
152
- the requirements.
153
- """
154
- requirements: List[str]
155
- """The set of requirements as specified by their ids in this group. Example: 'SV-238196'."""
156
-
157
- title: Optional[str] = None
158
- """The title of the group - should be human readable."""
159
-
160
- @staticmethod
161
- def from_dict(obj: Any) -> 'RequirementGroup':
162
- assert isinstance(obj, dict)
163
- id = from_str(obj.get("id"))
164
- requirements = from_list(from_str, obj.get("requirements"))
165
- title = from_union([from_str, from_none], obj.get("title"))
166
- return RequirementGroup(id, requirements, title)
167
-
168
- def to_dict(self) -> dict:
169
- result: dict = {}
170
- result["id"] = from_str(self.id)
171
- result["requirements"] = from_list(from_str, self.requirements)
172
- if self.title is not None:
173
- result["title"] = from_union([from_str, from_none], self.title)
174
- return result
175
-
176
-
177
- @dataclass
178
- class InputConstraints:
179
- """Validation constraints for the input value.
180
-
181
- Validation constraints for an input value.
182
- """
183
- allowed_values: Optional[List[Any]] = None
184
- """Enumeration of permitted values."""
185
-
186
- max: Optional[float] = None
187
- """Maximum allowed value (for Numeric inputs)."""
188
-
189
- min: Optional[float] = None
190
- """Minimum allowed value (for Numeric inputs)."""
191
-
192
- pattern: Optional[str] = None
193
- """Regular expression pattern the value must match (for String inputs)."""
194
-
195
- @staticmethod
196
- def from_dict(obj: Any) -> 'InputConstraints':
197
- assert isinstance(obj, dict)
198
- allowed_values = from_union([lambda x: from_list(lambda x: x, x), from_none], obj.get("allowedValues"))
199
- max = from_union([from_float, from_none], obj.get("max"))
200
- min = from_union([from_float, from_none], obj.get("min"))
201
- pattern = from_union([from_str, from_none], obj.get("pattern"))
202
- return InputConstraints(allowed_values, max, min, pattern)
203
-
204
- def to_dict(self) -> dict:
205
- result: dict = {}
206
- if self.allowed_values is not None:
207
- result["allowedValues"] = from_union([lambda x: from_list(lambda x: x, x), from_none], self.allowed_values)
208
- if self.max is not None:
209
- result["max"] = from_union([to_float, from_none], self.max)
210
- if self.min is not None:
211
- result["min"] = from_union([to_float, from_none], self.min)
212
- if self.pattern is not None:
213
- result["pattern"] = from_union([from_str, from_none], self.pattern)
214
- return result
215
-
216
-
217
- class ComparisonOperator(Enum):
218
- """The comparison operator used when evaluating this input against observed values.
219
-
220
- Comparison operator for evaluating the input value against observed values. Numeric:
221
- eq/ne/lt/le/gt/ge. String: eq/ne/contains/matches. Collection: in/notIn.
222
- """
223
- CONTAINS = "contains"
224
- EQ = "eq"
225
- GE = "ge"
226
- GT = "gt"
227
- IN = "in"
228
- LE = "le"
229
- LT = "lt"
230
- MATCHES = "matches"
231
- NE = "ne"
232
- NOT_IN = "notIn"
233
-
234
-
235
- class InputType(Enum):
236
- """The data type of this input.
237
-
238
- The data type of the input value. Aligns with InSpec input types.
239
- """
240
- ARRAY = "Array"
241
- BOOLEAN = "Boolean"
242
- HASH = "Hash"
243
- NUMERIC = "Numeric"
244
- REGEXP = "Regexp"
245
- STRING = "String"
246
-
247
-
248
- @dataclass
249
- class Input:
250
- """A typed input parameter that bridges governance requirements and scanner automation.
251
- Inputs carry expected configuration values with type information, comparison operators,
252
- and validation constraints, enabling traceability from policy through to scan results.
253
- """
254
- name: str
255
- """The input name. Must be unique within a baseline or results document. Example:
256
- 'max_concurrent_sessions'.
257
- """
258
- constraints: Optional[InputConstraints] = None
259
- """Validation constraints for the input value."""
260
-
261
- description: Optional[str] = None
262
- """Human-readable description of what this input controls."""
263
-
264
- operator: Optional[ComparisonOperator] = None
265
- """The comparison operator used when evaluating this input against observed values."""
266
-
267
- required: Optional[bool] = None
268
- """Whether this input must be provided. Defaults to false if omitted."""
269
-
270
- sensitive: Optional[bool] = None
271
- """Whether this input contains sensitive data (passwords, keys). Sensitive values should be
272
- redacted in output. Defaults to false if omitted.
273
- """
274
- type: Optional[InputType] = None
275
- """The data type of this input."""
276
-
277
- value: Any
278
- """The input value. Type should match the declared type field. Accepts any JSON value."""
279
-
280
- @staticmethod
281
- def from_dict(obj: Any) -> 'Input':
282
- assert isinstance(obj, dict)
283
- name = from_str(obj.get("name"))
284
- constraints = from_union([InputConstraints.from_dict, from_none], obj.get("constraints"))
285
- description = from_union([from_str, from_none], obj.get("description"))
286
- operator = from_union([ComparisonOperator, from_none], obj.get("operator"))
287
- required = from_union([from_bool, from_none], obj.get("required"))
288
- sensitive = from_union([from_bool, from_none], obj.get("sensitive"))
289
- type = from_union([InputType, from_none], obj.get("type"))
290
- value = obj.get("value")
291
- return Input(name, constraints, description, operator, required, sensitive, type, value)
292
-
293
- def to_dict(self) -> dict:
294
- result: dict = {}
295
- result["name"] = from_str(self.name)
296
- if self.constraints is not None:
297
- result["constraints"] = from_union([lambda x: to_class(InputConstraints, x), from_none], self.constraints)
298
- if self.description is not None:
299
- result["description"] = from_union([from_str, from_none], self.description)
300
- if self.operator is not None:
301
- result["operator"] = from_union([lambda x: to_enum(ComparisonOperator, x), from_none], self.operator)
302
- if self.required is not None:
303
- result["required"] = from_union([from_bool, from_none], self.required)
304
- if self.sensitive is not None:
305
- result["sensitive"] = from_union([from_bool, from_none], self.sensitive)
306
- if self.type is not None:
307
- result["type"] = from_union([lambda x: to_enum(InputType, x), from_none], self.type)
308
- if self.value is not None:
309
- result["value"] = self.value
310
- return result
311
-
312
-
313
- class HashAlgorithm(Enum):
314
- """The hash algorithm used for the checksum.
315
-
316
- Supported cryptographic hash algorithms for checksums and integrity verification.
317
- """
318
- SHA256 = "sha256"
319
- SHA384 = "sha384"
320
- SHA512 = "sha512"
321
-
322
-
323
- @dataclass
324
- class Integrity:
325
- """Cryptographic integrity information for verifying this baseline has not been tampered
326
- with.
327
-
328
- Cryptographic integrity information for verifying the HDF file has not been tampered
329
- with. If algorithm is provided, checksum must also be provided, and vice versa.
330
-
331
- Cryptographic integrity information for verifying this file.
332
- """
333
- algorithm: Optional[HashAlgorithm] = None
334
- """The hash algorithm used for the checksum."""
335
-
336
- checksum: Optional[str] = None
337
- """The checksum value."""
338
-
339
- signature: Optional[str] = None
340
- """Optional cryptographic signature."""
341
-
342
- signed_by: Optional[str] = None
343
- """Identifier of who signed this file."""
344
-
345
- @staticmethod
346
- def from_dict(obj: Any) -> 'Integrity':
347
- assert isinstance(obj, dict)
348
- algorithm = from_union([HashAlgorithm, from_none], obj.get("algorithm"))
349
- checksum = from_union([from_str, from_none], obj.get("checksum"))
350
- signature = from_union([from_str, from_none], obj.get("signature"))
351
- signed_by = from_union([from_str, from_none], obj.get("signedBy"))
352
- return Integrity(algorithm, checksum, signature, signed_by)
353
-
354
- def to_dict(self) -> dict:
355
- result: dict = {}
356
- if self.algorithm is not None:
357
- result["algorithm"] = from_union([lambda x: to_enum(HashAlgorithm, x), from_none], self.algorithm)
358
- if self.checksum is not None:
359
- result["checksum"] = from_union([from_str, from_none], self.checksum)
360
- if self.signature is not None:
361
- result["signature"] = from_union([from_str, from_none], self.signature)
362
- if self.signed_by is not None:
363
- result["signedBy"] = from_union([from_str, from_none], self.signed_by)
364
- return result
365
-
366
-
367
- @dataclass
368
- class Checksum:
369
- """SHA-256 checksum of the original baseline definition file (before execution). This is an
370
- immutable reference to the baseline as defined, used to detect tampering with baseline
371
- requirements or metadata.
372
-
373
- Cryptographic checksum for baseline integrity verification.
374
-
375
- SHA-256 checksum of the previous amendment in chronological order. Creates a
376
- tamper-evident chain of amendments (similar to blockchain). Null for the first amendment
377
- on a requirement.
378
-
379
- SHA-256 checksum of the raw results before any amendments (statusOverrides or POAMs).
380
- Used to detect tampering with test results. Compare with currentChecksum to verify
381
- amendment integrity.
382
-
383
- Optional cryptographic checksum for verifying the integrity of remediation resources
384
- fetched from the URI. Recommended for security when referencing external automation
385
- scripts.
386
- """
387
- algorithm: HashAlgorithm
388
- """The hash algorithm used for the checksum."""
389
-
390
- value: str
391
- """The checksum value."""
392
-
393
- @staticmethod
394
- def from_dict(obj: Any) -> 'Checksum':
395
- assert isinstance(obj, dict)
396
- algorithm = HashAlgorithm(obj.get("algorithm"))
397
- value = from_str(obj.get("value"))
398
- return Checksum(algorithm, value)
399
-
400
- def to_dict(self) -> dict:
401
- result: dict = {}
402
- result["algorithm"] = to_enum(HashAlgorithm, self.algorithm)
403
- result["value"] = from_str(self.value)
404
- return result
405
-
406
-
407
- @dataclass
408
- class Description:
409
- data: str
410
- """The description text content."""
411
-
412
- label: str
413
- """Description category. The 'default' label is required for the primary description. Common
414
- labels: 'default', 'check', 'fix', 'rationale'. Tools may use custom labels.
415
- """
416
-
417
- @staticmethod
418
- def from_dict(obj: Any) -> 'Description':
419
- assert isinstance(obj, dict)
420
- data = from_str(obj.get("data"))
421
- label = from_str(obj.get("label"))
422
- return Description(data, label)
423
-
424
- def to_dict(self) -> dict:
425
- result: dict = {}
426
- result["data"] = from_str(self.data)
427
- result["label"] = from_str(self.label)
428
- return result
429
-
430
-
431
- class ResultStatus(Enum):
432
- """The current effective status of this requirement after applying the most recent
433
- non-expired override, or computed from results if no overrides exist.
434
-
435
- The status of an individual test result. 'notApplicable' indicates the requirement does
436
- not apply to the target. 'notReviewed' indicates the requirement was not assessed (e.g.,
437
- requires manual verification).
438
-
439
- The status of this test within the requirement. Example: 'failed'.
440
-
441
- The new status this override sets for the requirement. This intentionally changes the
442
- compliance status.
443
- """
444
- ERROR = "error"
445
- FAILED = "failed"
446
- NOT_APPLICABLE = "notApplicable"
447
- NOT_REVIEWED = "notReviewed"
448
- PASSED = "passed"
449
-
450
-
451
- class OperatorType(Enum):
452
- """The type of identifier. Use 'email' for email addresses, 'username' for user accounts,
453
- 'system' for automated systems, 'simple' for basic string identifiers without additional
454
- classification, or 'other' for custom identity systems.
455
- """
456
- EMAIL = "email"
457
- OTHER = "other"
458
- SIMPLE = "simple"
459
- SYSTEM = "system"
460
- USERNAME = "username"
461
-
462
-
463
- @dataclass
464
- class Identity:
465
- """Identity of who or what captured this evidence.
466
-
467
- Represents an identity that performed an action, such as capturing evidence or applying
468
- an override.
469
-
470
- Identity of who created this POA&M. For simple cases, use type 'simple' with just an
471
- identifier.
472
-
473
- Identity of who completed this milestone.
474
-
475
- The identity that created this signature.
476
-
477
- Identity of who applied this status override. For simple cases, use type 'simple' with
478
- just an identifier.
479
-
480
- Identity of the person or system that approved this override.
481
-
482
- Team or individual responsible for this component. Enables per-component ownership when
483
- different teams manage different parts of a system.
484
-
485
- The identity of the person or system responsible for executing the test. This could be a
486
- human auditor manually completing a checklist, an automated CI/CD system, or a security
487
- tool. Optional field to support both automated and manual HDF generation.
488
- """
489
- identifier: str
490
- """The identifier value. Example: 'user@example.com', 'jdoe', 'automated-scanner-01'."""
491
-
492
- type: OperatorType
493
- """The type of identifier. Use 'email' for email addresses, 'username' for user accounts,
494
- 'system' for automated systems, 'simple' for basic string identifiers without additional
495
- classification, or 'other' for custom identity systems.
496
- """
497
- description: Optional[str] = None
498
- """Optional description of the identity or identity system, particularly useful when type is
499
- 'other'.
500
- """
501
-
502
- @staticmethod
503
- def from_dict(obj: Any) -> 'Identity':
504
- assert isinstance(obj, dict)
505
- identifier = from_str(obj.get("identifier"))
506
- type = OperatorType(obj.get("type"))
507
- description = from_union([from_str, from_none], obj.get("description"))
508
- return Identity(identifier, type, description)
509
-
510
- def to_dict(self) -> dict:
511
- result: dict = {}
512
- result["identifier"] = from_str(self.identifier)
513
- result["type"] = to_enum(OperatorType, self.type)
514
- if self.description is not None:
515
- result["description"] = from_union([from_str, from_none], self.description)
516
- return result
517
-
518
-
519
- class EvidenceType(Enum):
520
- """The type of evidence being provided."""
521
-
522
- CODE = "code"
523
- FILE = "file"
524
- LOG = "log"
525
- OTHER = "other"
526
- SCREENSHOT = "screenshot"
527
- URL = "url"
528
-
529
-
530
- @dataclass
531
- class Evidence:
532
- """Supporting evidence for a finding or override, such as screenshots, code samples, log
533
- excerpts, or URLs.
534
- """
535
- data: str
536
- """The evidence content. For screenshots/files: base64-encoded data or URL. For code/logs:
537
- the raw text. For URLs: the URL string.
538
- """
539
- type: EvidenceType
540
- """The type of evidence being provided."""
541
-
542
- captured_at: Optional[datetime] = None
543
- """Timestamp when this evidence was captured. ISO 8601 format."""
544
-
545
- captured_by: Optional[Identity] = None
546
- """Identity of who or what captured this evidence."""
547
-
548
- description: Optional[str] = None
549
- """Human-readable description of what this evidence shows."""
550
-
551
- encoding: Optional[str] = None
552
- """Encoding used for the data. Example: 'base64', 'utf-8'."""
553
-
554
- mime_type: Optional[str] = None
555
- """MIME type of the evidence. Example: 'image/png', 'text/plain', 'application/json'."""
556
-
557
- size: Optional[float] = None
558
- """Size of the evidence data in bytes."""
559
-
560
- @staticmethod
561
- def from_dict(obj: Any) -> 'Evidence':
562
- assert isinstance(obj, dict)
563
- data = from_str(obj.get("data"))
564
- type = EvidenceType(obj.get("type"))
565
- captured_at = from_union([from_datetime, from_none], obj.get("capturedAt"))
566
- captured_by = from_union([Identity.from_dict, from_none], obj.get("capturedBy"))
567
- description = from_union([from_str, from_none], obj.get("description"))
568
- encoding = from_union([from_str, from_none], obj.get("encoding"))
569
- mime_type = from_union([from_str, from_none], obj.get("mimeType"))
570
- size = from_union([from_float, from_none], obj.get("size"))
571
- return Evidence(data, type, captured_at, captured_by, description, encoding, mime_type, size)
572
-
573
- def to_dict(self) -> dict:
574
- result: dict = {}
575
- result["data"] = from_str(self.data)
576
- result["type"] = to_enum(EvidenceType, self.type)
577
- if self.captured_at is not None:
578
- result["capturedAt"] = from_union([lambda x: x.isoformat(), from_none], self.captured_at)
579
- if self.captured_by is not None:
580
- result["capturedBy"] = from_union([lambda x: to_class(Identity, x), from_none], self.captured_by)
581
- if self.description is not None:
582
- result["description"] = from_union([from_str, from_none], self.description)
583
- if self.encoding is not None:
584
- result["encoding"] = from_union([from_str, from_none], self.encoding)
585
- if self.mime_type is not None:
586
- result["mimeType"] = from_union([from_str, from_none], self.mime_type)
587
- if self.size is not None:
588
- result["size"] = from_union([to_float, from_none], self.size)
589
- return result
590
-
591
-
592
- class Status(Enum):
593
- """Current status of this milestone."""
594
-
595
- COMPLETED = "completed"
596
- IN_PROGRESS = "inProgress"
597
- PENDING = "pending"
598
-
599
-
600
- @dataclass
601
- class Milestone:
602
- """A milestone or task within a POA&M remediation plan."""
603
-
604
- description: str
605
- """Description of this milestone or task."""
606
-
607
- estimated_completion: datetime
608
- """Estimated completion date. ISO 8601 format."""
609
-
610
- status: Status
611
- """Current status of this milestone."""
612
-
613
- completed_at: Optional[datetime] = None
614
- """Actual completion timestamp. ISO 8601 format."""
615
-
616
- completed_by: Optional[Identity] = None
617
- """Identity of who completed this milestone."""
618
-
619
- @staticmethod
620
- def from_dict(obj: Any) -> 'Milestone':
621
- assert isinstance(obj, dict)
622
- description = from_str(obj.get("description"))
623
- estimated_completion = from_datetime(obj.get("estimatedCompletion"))
624
- status = Status(obj.get("status"))
625
- completed_at = from_union([from_datetime, from_none], obj.get("completedAt"))
626
- completed_by = from_union([Identity.from_dict, from_none], obj.get("completedBy"))
627
- return Milestone(description, estimated_completion, status, completed_at, completed_by)
628
-
629
- def to_dict(self) -> dict:
630
- result: dict = {}
631
- result["description"] = from_str(self.description)
632
- result["estimatedCompletion"] = self.estimated_completion.isoformat()
633
- result["status"] = to_enum(Status, self.status)
634
- if self.completed_at is not None:
635
- result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at)
636
- if self.completed_by is not None:
637
- result["completedBy"] = from_union([lambda x: to_class(Identity, x), from_none], self.completed_by)
638
- return result
639
-
640
-
641
- @dataclass
642
- class VerificationMethod:
643
- """The verification method containing the public key for signature verification.
644
-
645
- Verification method containing the public key needed to verify a digital signature.
646
- Supports multiple key formats including JWK (for RSA, EC), PEM, and Base58.
647
- """
648
- controller: str
649
- """The entity that controls this verification method. Can be a DID, URI, or other identifier."""
650
-
651
- type: str
652
- """The type of verification method. Example: 'JsonWebKey2020', 'RsaVerificationKey2018',
653
- 'Ed25519VerificationKey2020'.
654
- """
655
- public_key_base58: Optional[str] = None
656
- """Public key in Base58 format, commonly used with Ed25519 keys."""
657
-
658
- public_key_jwk: Optional[Dict[str, Any]] = None
659
- """Public key in JSON Web Key format."""
660
-
661
- public_key_pem: Optional[str] = None
662
- """Public key in PEM format. Example: '-----BEGIN PUBLIC KEY-----...-----END PUBLIC
663
- KEY-----'.
664
- """
665
-
666
- @staticmethod
667
- def from_dict(obj: Any) -> 'VerificationMethod':
668
- assert isinstance(obj, dict)
669
- controller = from_str(obj.get("controller"))
670
- type = from_str(obj.get("type"))
671
- public_key_base58 = from_union([from_str, from_none], obj.get("publicKeyBase58"))
672
- public_key_jwk = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("publicKeyJwk"))
673
- public_key_pem = from_union([from_str, from_none], obj.get("publicKeyPem"))
674
- return VerificationMethod(controller, type, public_key_base58, public_key_jwk, public_key_pem)
675
-
676
- def to_dict(self) -> dict:
677
- result: dict = {}
678
- result["controller"] = from_str(self.controller)
679
- result["type"] = from_str(self.type)
680
- if self.public_key_base58 is not None:
681
- result["publicKeyBase58"] = from_union([from_str, from_none], self.public_key_base58)
682
- if self.public_key_jwk is not None:
683
- result["publicKeyJwk"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.public_key_jwk)
684
- if self.public_key_pem is not None:
685
- result["publicKeyPem"] = from_union([from_str, from_none], self.public_key_pem)
686
- return result
687
-
688
-
689
- @dataclass
690
- class Signature:
691
- """Optional digital signature for enhanced trust and non-repudiation.
692
-
693
- A digital signature following W3C Data Integrity Proofs pattern. Supports hardware
694
- security tokens (PKCS#11/PKCS#12), Yubikeys, GPG keys, passkeys, and other cryptographic
695
- signing methods via JWK, PEM, or Base58 key formats.
696
-
697
- Optional digital signature for enhanced trust and non-repudiation. Supports hardware
698
- security tokens (PKCS#11/PKCS#12), Yubikeys, GPG keys, passkeys, and other signing
699
- methods.
700
- """
701
- created: datetime
702
- """When the signature was created. ISO 8601 format."""
703
-
704
- creator: Identity
705
- """The identity that created this signature."""
706
-
707
- proof_purpose: str
708
- """The purpose of this signature. Example: 'attestation', 'authentication',
709
- 'assertionMethod'.
710
- """
711
- signature_value: str
712
- """The base64-encoded or base58-encoded signature value."""
713
-
714
- type: str
715
- """The signature suite type. Example: 'JsonWebSignature2020', 'RsaSignature2018',
716
- 'Ed25519Signature2020'.
717
- """
718
- verification_method: VerificationMethod
719
- """The verification method containing the public key for signature verification."""
720
-
721
- challenge: Optional[str] = None
722
- """Challenge value from the verifier, used in challenge-response authentication."""
723
-
724
- domain: Optional[str] = None
725
- """Domain restriction for the signature, prevents cross-domain replay attacks."""
726
-
727
- nonce: Optional[str] = None
728
- """Random value to prevent replay attacks."""
729
-
730
- @staticmethod
731
- def from_dict(obj: Any) -> 'Signature':
732
- assert isinstance(obj, dict)
733
- created = from_datetime(obj.get("created"))
734
- creator = Identity.from_dict(obj.get("creator"))
735
- proof_purpose = from_str(obj.get("proofPurpose"))
736
- signature_value = from_str(obj.get("signatureValue"))
737
- type = from_str(obj.get("type"))
738
- verification_method = VerificationMethod.from_dict(obj.get("verificationMethod"))
739
- challenge = from_union([from_str, from_none], obj.get("challenge"))
740
- domain = from_union([from_str, from_none], obj.get("domain"))
741
- nonce = from_union([from_str, from_none], obj.get("nonce"))
742
- return Signature(created, creator, proof_purpose, signature_value, type, verification_method, challenge, domain, nonce)
743
-
744
- def to_dict(self) -> dict:
745
- result: dict = {}
746
- result["created"] = self.created.isoformat()
747
- result["creator"] = to_class(Identity, self.creator)
748
- result["proofPurpose"] = from_str(self.proof_purpose)
749
- result["signatureValue"] = from_str(self.signature_value)
750
- result["type"] = from_str(self.type)
751
- result["verificationMethod"] = to_class(VerificationMethod, self.verification_method)
752
- if self.challenge is not None:
753
- result["challenge"] = from_union([from_str, from_none], self.challenge)
754
- if self.domain is not None:
755
- result["domain"] = from_union([from_str, from_none], self.domain)
756
- if self.nonce is not None:
757
- result["nonce"] = from_union([from_str, from_none], self.nonce)
758
- return result
759
-
760
-
761
- class PoamType(Enum):
762
- """The type of POA&M. 'remediation' fixes root cause. 'mitigation' reduces risk via
763
- compensating controls. 'riskAcceptance' documents decision to accept risk.
764
- """
765
- MITIGATION = "mitigation"
766
- REMEDIATION = "remediation"
767
- RISK_ACCEPTANCE = "riskAcceptance"
768
-
769
-
770
- @dataclass
771
- class Poam:
772
- """Plan of Action and Milestones for tracking remediation, mitigation, or risk acceptance.
773
- POAMs do NOT change the effectiveStatus - the requirement remains in its current state
774
- while the POA&M tracks remediation efforts.
775
- """
776
- applied_at: datetime
777
- """Timestamp when this POA&M was created. ISO 8601 format."""
778
-
779
- applied_by: Identity
780
- """Identity of who created this POA&M. For simple cases, use type 'simple' with just an
781
- identifier.
782
- """
783
- explanation: str
784
- """Detailed explanation of the plan, including what actions will be taken."""
785
-
786
- type: PoamType
787
- """The type of POA&M. 'remediation' fixes root cause. 'mitigation' reduces risk via
788
- compensating controls. 'riskAcceptance' documents decision to accept risk.
789
- """
790
- evidence: Optional[List[Evidence]] = None
791
- """Supporting evidence for this POA&M, such as documentation of compensating controls or
792
- mitigation implementation.
793
- """
794
- expires_at: Optional[datetime] = None
795
- """Optional expiration date for this POA&M requiring review/renewal. ISO 8601 format."""
796
-
797
- milestones: Optional[List[Milestone]] = None
798
- """Optional array of milestones tracking progress toward completion."""
799
-
800
- previous_checksum: Optional[Checksum] = None
801
- """SHA-256 checksum of the previous amendment in chronological order. Creates a
802
- tamper-evident chain of amendments (similar to blockchain). Null for the first amendment
803
- on a requirement.
804
- """
805
- signature: Optional[Signature] = None
806
- """Optional digital signature for enhanced trust and non-repudiation."""
807
-
808
- @staticmethod
809
- def from_dict(obj: Any) -> 'Poam':
810
- assert isinstance(obj, dict)
811
- applied_at = from_datetime(obj.get("appliedAt"))
812
- applied_by = Identity.from_dict(obj.get("appliedBy"))
813
- explanation = from_str(obj.get("explanation"))
814
- type = PoamType(obj.get("type"))
815
- evidence = from_union([lambda x: from_list(Evidence.from_dict, x), from_none], obj.get("evidence"))
816
- expires_at = from_union([from_datetime, from_none], obj.get("expiresAt"))
817
- milestones = from_union([lambda x: from_list(Milestone.from_dict, x), from_none], obj.get("milestones"))
818
- previous_checksum = from_union([Checksum.from_dict, from_none], obj.get("previousChecksum"))
819
- signature = from_union([Signature.from_dict, from_none], obj.get("signature"))
820
- return Poam(applied_at, applied_by, explanation, type, evidence, expires_at, milestones, previous_checksum, signature)
821
-
822
- def to_dict(self) -> dict:
823
- result: dict = {}
824
- result["appliedAt"] = self.applied_at.isoformat()
825
- result["appliedBy"] = to_class(Identity, self.applied_by)
826
- result["explanation"] = from_str(self.explanation)
827
- result["type"] = to_enum(PoamType, self.type)
828
- if self.evidence is not None:
829
- result["evidence"] = from_union([lambda x: from_list(lambda x: to_class(Evidence, x), x), from_none], self.evidence)
830
- if self.expires_at is not None:
831
- result["expiresAt"] = from_union([lambda x: x.isoformat(), from_none], self.expires_at)
832
- if self.milestones is not None:
833
- result["milestones"] = from_union([lambda x: from_list(lambda x: to_class(Milestone, x), x), from_none], self.milestones)
834
- if self.previous_checksum is not None:
835
- result["previousChecksum"] = from_union([lambda x: to_class(Checksum, x), from_none], self.previous_checksum)
836
- if self.signature is not None:
837
- result["signature"] = from_union([lambda x: to_class(Signature, x), from_none], self.signature)
838
- return result
839
-
840
-
841
- @dataclass
842
- class Reference:
843
- """A reference to an external document.
844
-
845
- A reference using the 'ref' field.
846
-
847
- A URL pointing at the reference.
848
-
849
- A URI pointing at the reference.
850
- """
851
- ref: Optional[Union[List[Dict[str, Any]], str]] = None
852
- url: Optional[str] = None
853
- uri: Optional[str] = None
854
-
855
- @staticmethod
856
- def from_dict(obj: Any) -> 'Reference':
857
- assert isinstance(obj, dict)
858
- ref = from_union([lambda x: from_list(lambda x: from_dict(lambda x: x, x), x), from_str, from_none], obj.get("ref"))
859
- url = from_union([from_str, from_none], obj.get("url"))
860
- uri = from_union([from_str, from_none], obj.get("uri"))
861
- return Reference(ref, url, uri)
862
-
863
- def to_dict(self) -> dict:
864
- result: dict = {}
865
- if self.ref is not None:
866
- result["ref"] = from_union([lambda x: from_list(lambda x: from_dict(lambda x: x, x), x), from_str, from_none], self.ref)
867
- if self.url is not None:
868
- result["url"] = from_union([from_str, from_none], self.url)
869
- if self.uri is not None:
870
- result["uri"] = from_union([from_str, from_none], self.uri)
871
- return result
872
-
873
-
874
- @dataclass
875
- class RequirementResult:
876
- """A test within a requirement and its results and findings such as how long it took to run."""
877
-
878
- code_desc: str
879
- """A description of this test. Example: 'limits.conf * is expected to include ["hard",
880
- "maxlogins", "10"]'.
881
- """
882
- start_time: datetime
883
- """The time at which the test started."""
884
-
885
- status: ResultStatus
886
- """The status of this test within the requirement. Example: 'failed'."""
887
-
888
- backtrace: Optional[List[str]] = None
889
- """The stacktrace/backtrace of the exception if one occurred."""
890
-
891
- exception: Optional[str] = None
892
- """The type of exception if an exception was thrown."""
893
-
894
- message: Optional[str] = None
895
- """An explanation of the test result. Typically provided for failed tests, errors, or to
896
- explain why a test was not applicable or not reviewed.
897
- """
898
- resource: Optional[str] = None
899
- """The resource used in the test. Example: 'file', 'command', 'service'."""
900
-
901
- resource_id: Optional[str] = None
902
- """The unique identifier of the resource. Example: '/etc/passwd'."""
903
-
904
- run_time: Optional[float] = None
905
- """The execution time in seconds for the test."""
906
-
907
- @staticmethod
908
- def from_dict(obj: Any) -> 'RequirementResult':
909
- assert isinstance(obj, dict)
910
- code_desc = from_str(obj.get("codeDesc"))
911
- start_time = from_datetime(obj.get("startTime"))
912
- status = ResultStatus(obj.get("status"))
913
- backtrace = from_union([lambda x: from_list(from_str, x), from_none], obj.get("backtrace"))
914
- exception = from_union([from_str, from_none], obj.get("exception"))
915
- message = from_union([from_str, from_none], obj.get("message"))
916
- resource = from_union([from_str, from_none], obj.get("resource"))
917
- resource_id = from_union([from_str, from_none], obj.get("resourceId"))
918
- run_time = from_union([from_float, from_none], obj.get("runTime"))
919
- return RequirementResult(code_desc, start_time, status, backtrace, exception, message, resource, resource_id, run_time)
920
-
921
- def to_dict(self) -> dict:
922
- result: dict = {}
923
- result["codeDesc"] = from_str(self.code_desc)
924
- result["startTime"] = self.start_time.isoformat()
925
- result["status"] = to_enum(ResultStatus, self.status)
926
- if self.backtrace is not None:
927
- result["backtrace"] = from_union([lambda x: from_list(from_str, x), from_none], self.backtrace)
928
- if self.exception is not None:
929
- result["exception"] = from_union([from_str, from_none], self.exception)
930
- if self.message is not None:
931
- result["message"] = from_union([from_str, from_none], self.message)
932
- if self.resource is not None:
933
- result["resource"] = from_union([from_str, from_none], self.resource)
934
- if self.resource_id is not None:
935
- result["resourceId"] = from_union([from_str, from_none], self.resource_id)
936
- if self.run_time is not None:
937
- result["runTime"] = from_union([to_float, from_none], self.run_time)
938
- return result
939
-
940
-
941
- class Severity(Enum):
942
- """Explicit severity rating. Typically derived from impact score but provided explicitly for
943
- clarity.
944
-
945
- Severity rating for a requirement. Typically derived from the numeric impact score.
946
- """
947
- CRITICAL = "critical"
948
- HIGH = "high"
949
- INFORMATIONAL = "informational"
950
- LOW = "low"
951
- MEDIUM = "medium"
952
-
953
-
954
- @dataclass
955
- class SourceLocation:
956
- """The explicit location of the requirement within the source code.
957
-
958
- The explicit location of a requirement within source code.
959
- """
960
- line: Optional[float] = None
961
- """The line on which this requirement is located."""
962
-
963
- ref: Optional[str] = None
964
- """Path to the file that this requirement originates from."""
965
-
966
- @staticmethod
967
- def from_dict(obj: Any) -> 'SourceLocation':
968
- assert isinstance(obj, dict)
969
- line = from_union([from_float, from_none], obj.get("line"))
970
- ref = from_union([from_str, from_none], obj.get("ref"))
971
- return SourceLocation(line, ref)
972
-
973
- def to_dict(self) -> dict:
974
- result: dict = {}
975
- if self.line is not None:
976
- result["line"] = from_union([to_float, from_none], self.line)
977
- if self.ref is not None:
978
- result["ref"] = from_union([from_str, from_none], self.ref)
979
- return result
980
-
981
-
982
- class OverrideType(Enum):
983
- """The type of status override applied to this requirement.
984
-
985
- The type of amendment. 'waiver': risk accepted (AO). 'attestation': manually verified
986
- (assessor). 'exception': not applicable (system owner + AO). 'poam': remediation tracked
987
- (no status change). 'inherited': control provided by another component or system
988
- (overrides to notApplicable/passed).
989
- """
990
- ATTESTATION = "attestation"
991
- EXCEPTION = "exception"
992
- INHERITED = "inherited"
993
- POAM = "poam"
994
- WAIVER = "waiver"
995
-
996
-
997
- @dataclass
998
- class StatusOverride:
999
- """An intentional change to a requirement's compliance status (waiver or attestation).
1000
- Status overrides change the effectiveStatus of the requirement. All status overrides must
1001
- have an expiration date to enforce periodic review.
1002
- """
1003
- applied_at: datetime
1004
- """Timestamp when this status override was applied. ISO 8601 format."""
1005
-
1006
- applied_by: Identity
1007
- """Identity of who applied this status override. For simple cases, use type 'simple' with
1008
- just an identifier.
1009
- """
1010
- expires_at: datetime
1011
- """Timestamp when this status override expires and must be reviewed/renewed. REQUIRED - no
1012
- permanent status overrides allowed. ISO 8601 format.
1013
- """
1014
- reason: str
1015
- """Explanation for why this status override was applied."""
1016
-
1017
- status: ResultStatus
1018
- """The new status this override sets for the requirement. This intentionally changes the
1019
- compliance status.
1020
- """
1021
- type: OverrideType
1022
- """The type of status override applied to this requirement."""
1023
-
1024
- evidence: Optional[List[Evidence]] = None
1025
- """Supporting evidence for this status override, such as screenshots demonstrating manual
1026
- verification for attestations.
1027
- """
1028
- previous_checksum: Optional[Checksum] = None
1029
- """SHA-256 checksum of the previous amendment in chronological order. Creates a
1030
- tamper-evident chain of amendments (similar to blockchain). Null for the first amendment
1031
- on a requirement.
1032
- """
1033
- signature: Optional[Signature] = None
1034
- """Optional digital signature for enhanced trust and non-repudiation. Supports hardware
1035
- security tokens (PKCS#11/PKCS#12), Yubikeys, GPG keys, passkeys, and other signing
1036
- methods.
1037
- """
1038
-
1039
- @staticmethod
1040
- def from_dict(obj: Any) -> 'StatusOverride':
1041
- assert isinstance(obj, dict)
1042
- applied_at = from_datetime(obj.get("appliedAt"))
1043
- applied_by = Identity.from_dict(obj.get("appliedBy"))
1044
- expires_at = from_datetime(obj.get("expiresAt"))
1045
- reason = from_str(obj.get("reason"))
1046
- status = ResultStatus(obj.get("status"))
1047
- type = OverrideType(obj.get("type"))
1048
- evidence = from_union([lambda x: from_list(Evidence.from_dict, x), from_none], obj.get("evidence"))
1049
- previous_checksum = from_union([Checksum.from_dict, from_none], obj.get("previousChecksum"))
1050
- signature = from_union([Signature.from_dict, from_none], obj.get("signature"))
1051
- return StatusOverride(applied_at, applied_by, expires_at, reason, status, type, evidence, previous_checksum, signature)
1052
-
1053
- def to_dict(self) -> dict:
1054
- result: dict = {}
1055
- result["appliedAt"] = self.applied_at.isoformat()
1056
- result["appliedBy"] = to_class(Identity, self.applied_by)
1057
- result["expiresAt"] = self.expires_at.isoformat()
1058
- result["reason"] = from_str(self.reason)
1059
- result["status"] = to_enum(ResultStatus, self.status)
1060
- result["type"] = to_enum(OverrideType, self.type)
1061
- if self.evidence is not None:
1062
- result["evidence"] = from_union([lambda x: from_list(lambda x: to_class(Evidence, x), x), from_none], self.evidence)
1063
- if self.previous_checksum is not None:
1064
- result["previousChecksum"] = from_union([lambda x: to_class(Checksum, x), from_none], self.previous_checksum)
1065
- if self.signature is not None:
1066
- result["signature"] = from_union([lambda x: to_class(Signature, x), from_none], self.signature)
1067
- return result
1068
-
1069
-
1070
- @dataclass
1071
- class EvaluatedRequirement:
1072
- """A requirement that has been evaluated, including any findings.
1073
-
1074
- Core requirement fields shared between baseline requirements and evaluated requirements.
1075
- Contains the fundamental requirement definition without assessment results.
1076
- """
1077
- descriptions: List[Description]
1078
- """Array of labeled descriptions. At least one description with label 'default' must be
1079
- present. Convention: place default description first. Common labels: 'default', 'check',
1080
- 'fix', 'rationale'.
1081
- """
1082
- results: List[RequirementResult]
1083
- """The set of all tests within the requirement and their results."""
1084
-
1085
- id: str
1086
- """The requirement identifier. Example: 'SV-238196'."""
1087
-
1088
- impact: float
1089
- """The impactfulness or severity (0.0 to 1.0)."""
1090
-
1091
- tags: Dict[str, Any]
1092
- """A set of tags - usually metadata like CCI, STIG ID, severity."""
1093
-
1094
- effective_status: Optional[ResultStatus] = None
1095
- """The current effective status of this requirement after applying the most recent
1096
- non-expired override, or computed from results if no overrides exist.
1097
- """
1098
- evidence: Optional[List[Evidence]] = None
1099
- """Supporting evidence for this requirement's findings, such as screenshots, code samples,
1100
- or log excerpts.
1101
- """
1102
- poams: Optional[List[Poam]] = None
1103
- """Plan of Action and Milestones for tracking remediation, mitigation, or risk acceptance.
1104
- POAMs do NOT change effectiveStatus - they track the work being done to address a
1105
- failure. Separate from statusOverrides which DO change status.
1106
- """
1107
- severity: Optional[Severity] = None
1108
- """Explicit severity rating. Typically derived from impact score but provided explicitly for
1109
- clarity.
1110
- """
1111
- source_location: Optional[SourceLocation] = None
1112
- """The explicit location of the requirement within the source code."""
1113
-
1114
- status_overrides: Optional[List[StatusOverride]] = None
1115
- """Chronological history of all status overrides applied to this requirement. Status
1116
- overrides are intentional changes to the compliance status (waivers, attestations). Most
1117
- recent override should be first in array. Preserves full audit trail.
1118
- """
1119
- code: Optional[str] = None
1120
- """The raw source code of the requirement. Set to null for manual-only requirements or
1121
- requirements not yet implemented. Note that if this is an overlay, it does not include
1122
- the underlying source code.
1123
- """
1124
- refs: Optional[List[Reference]] = None
1125
- """The set of references to external documents."""
1126
-
1127
- title: Optional[str] = None
1128
- """The title - is nullable."""
1129
-
1130
- @staticmethod
1131
- def from_dict(obj: Any) -> 'EvaluatedRequirement':
1132
- assert isinstance(obj, dict)
1133
- descriptions = from_list(Description.from_dict, obj.get("descriptions"))
1134
- results = from_list(RequirementResult.from_dict, obj.get("results"))
1135
- id = from_str(obj.get("id"))
1136
- impact = from_float(obj.get("impact"))
1137
- tags = from_dict(lambda x: x, obj.get("tags"))
1138
- effective_status = from_union([ResultStatus, from_none], obj.get("effectiveStatus"))
1139
- evidence = from_union([lambda x: from_list(Evidence.from_dict, x), from_none], obj.get("evidence"))
1140
- poams = from_union([lambda x: from_list(Poam.from_dict, x), from_none], obj.get("poams"))
1141
- severity = from_union([Severity, from_none], obj.get("severity"))
1142
- source_location = from_union([SourceLocation.from_dict, from_none], obj.get("sourceLocation"))
1143
- status_overrides = from_union([lambda x: from_list(StatusOverride.from_dict, x), from_none], obj.get("statusOverrides"))
1144
- code = from_union([from_str, from_none], obj.get("code"))
1145
- refs = from_union([lambda x: from_list(Reference.from_dict, x), from_none], obj.get("refs"))
1146
- title = from_union([from_str, from_none], obj.get("title"))
1147
- return EvaluatedRequirement(descriptions, results, id, impact, tags, effective_status, evidence, poams, severity, source_location, status_overrides, code, refs, title)
1148
-
1149
- def to_dict(self) -> dict:
1150
- result: dict = {}
1151
- result["descriptions"] = from_list(lambda x: to_class(Description, x), self.descriptions)
1152
- result["results"] = from_list(lambda x: to_class(RequirementResult, x), self.results)
1153
- result["id"] = from_str(self.id)
1154
- result["impact"] = to_float(self.impact)
1155
- result["tags"] = from_dict(lambda x: x, self.tags)
1156
- if self.effective_status is not None:
1157
- result["effectiveStatus"] = from_union([lambda x: to_enum(ResultStatus, x), from_none], self.effective_status)
1158
- if self.evidence is not None:
1159
- result["evidence"] = from_union([lambda x: from_list(lambda x: to_class(Evidence, x), x), from_none], self.evidence)
1160
- if self.poams is not None:
1161
- result["poams"] = from_union([lambda x: from_list(lambda x: to_class(Poam, x), x), from_none], self.poams)
1162
- if self.severity is not None:
1163
- result["severity"] = from_union([lambda x: to_enum(Severity, x), from_none], self.severity)
1164
- if self.source_location is not None:
1165
- result["sourceLocation"] = from_union([lambda x: to_class(SourceLocation, x), from_none], self.source_location)
1166
- if self.status_overrides is not None:
1167
- result["statusOverrides"] = from_union([lambda x: from_list(lambda x: to_class(StatusOverride, x), x), from_none], self.status_overrides)
1168
- if self.code is not None:
1169
- result["code"] = from_union([from_str, from_none], self.code)
1170
- if self.refs is not None:
1171
- result["refs"] = from_union([lambda x: from_list(lambda x: to_class(Reference, x), x), from_none], self.refs)
1172
- if self.title is not None:
1173
- result["title"] = from_union([from_str, from_none], self.title)
1174
- return result
1175
-
1176
-
1177
- @dataclass
1178
- class SupportedPlatform:
1179
- """A supported platform target. Example: the platform name being 'ubuntu'."""
1180
-
1181
- platform: Optional[str] = None
1182
- """The location of the platform. Can be: 'os', 'aws', 'azure', or 'gcp'."""
1183
-
1184
- platform_family: Optional[str] = None
1185
- """The platform family. Example: 'redhat'."""
1186
-
1187
- platform_name: Optional[str] = None
1188
- """The platform name - can include wildcards. Example: 'debian'."""
1189
-
1190
- release: Optional[str] = None
1191
- """The release of the platform. Example: '20.04' for 'ubuntu'."""
1192
-
1193
- @staticmethod
1194
- def from_dict(obj: Any) -> 'SupportedPlatform':
1195
- assert isinstance(obj, dict)
1196
- platform = from_union([from_str, from_none], obj.get("platform"))
1197
- platform_family = from_union([from_str, from_none], obj.get("platformFamily"))
1198
- platform_name = from_union([from_str, from_none], obj.get("platformName"))
1199
- release = from_union([from_str, from_none], obj.get("release"))
1200
- return SupportedPlatform(platform, platform_family, platform_name, release)
1201
-
1202
- def to_dict(self) -> dict:
1203
- result: dict = {}
1204
- if self.platform is not None:
1205
- result["platform"] = from_union([from_str, from_none], self.platform)
1206
- if self.platform_family is not None:
1207
- result["platformFamily"] = from_union([from_str, from_none], self.platform_family)
1208
- if self.platform_name is not None:
1209
- result["platformName"] = from_union([from_str, from_none], self.platform_name)
1210
- if self.release is not None:
1211
- result["release"] = from_union([from_str, from_none], self.release)
1212
- return result
1213
-
1214
-
1215
- @dataclass
1216
- class EvaluatedBaseline:
1217
- """Information on a baseline that was evaluated, including any findings.
1218
-
1219
- Shared metadata fields for baselines. Used in both standalone baseline documents and
1220
- evaluated baseline results.
1221
- """
1222
- requirements: List[EvaluatedRequirement]
1223
- """The set of requirements including any findings. A baseline must have at least one
1224
- requirement.
1225
- """
1226
- name: str
1227
- """The name - must be unique."""
1228
-
1229
- depends: Optional[List[Dependency]] = None
1230
- """The set of dependencies this baseline depends on."""
1231
-
1232
- description: Optional[str] = None
1233
- """The description - should be more detailed than the summary."""
1234
-
1235
- extensions: Optional[Dict[str, Any]] = None
1236
- """Reserved for tool-specific baseline metadata not defined in the HDF standard."""
1237
-
1238
- groups: Optional[List[RequirementGroup]] = None
1239
- """A set of descriptions for the requirement groups."""
1240
-
1241
- inputs: Optional[List[Input]] = None
1242
- """Typed inputs used to parameterize this baseline at execution time. See the Input
1243
- primitive for the full schema.
1244
- """
1245
- integrity: Optional[Integrity] = None
1246
- """Cryptographic integrity information for verifying this baseline has not been tampered
1247
- with.
1248
- """
1249
- original_checksum: Optional[Checksum] = None
1250
- """SHA-256 checksum of the original baseline definition file (before execution). This is an
1251
- immutable reference to the baseline as defined, used to detect tampering with baseline
1252
- requirements or metadata.
1253
- """
1254
- parent_baseline: Optional[str] = None
1255
- """The name of the parent baseline if this is a dependency of another."""
1256
-
1257
- results_checksum: Optional[Checksum] = None
1258
- """SHA-256 checksum of the raw results before any amendments (statusOverrides or POAMs).
1259
- Used to detect tampering with test results. Compare with currentChecksum to verify
1260
- amendment integrity.
1261
- """
1262
- status_message: Optional[str] = None
1263
- """An explanation of the baseline status. Example: why it was skipped, failed to load, or
1264
- any other status details.
1265
- """
1266
- copyright: Optional[str] = None
1267
- """The copyright holder(s)."""
1268
-
1269
- copyright_email: Optional[str] = None
1270
- """The email address or other contact information of the copyright holder(s)."""
1271
-
1272
- labels: Optional[Dict[str, str]] = None
1273
- """Optional key-value labels for flexible grouping. Well-known keys: system, component,
1274
- environment, region, team. Values must be strings.
1275
- """
1276
- license: Optional[str] = None
1277
- """The copyright license. Example: 'Apache-2.0'."""
1278
-
1279
- maintainer: Optional[str] = None
1280
- """The maintainer(s)."""
1281
-
1282
- status: Optional[str] = None
1283
- """The status. Example: 'loaded'."""
1284
-
1285
- summary: Optional[str] = None
1286
- """The summary. Example: the Security Technical Implementation Guide (STIG) header."""
1287
-
1288
- supports: Optional[List[SupportedPlatform]] = None
1289
- """The set of supported platform targets."""
1290
-
1291
- title: Optional[str] = None
1292
- """The title - should be human readable."""
1293
-
1294
- version: Optional[str] = None
1295
- """The version of the baseline."""
1296
-
1297
- @staticmethod
1298
- def from_dict(obj: Any) -> 'EvaluatedBaseline':
1299
- assert isinstance(obj, dict)
1300
- requirements = from_list(EvaluatedRequirement.from_dict, obj.get("requirements"))
1301
- name = from_str(obj.get("name"))
1302
- depends = from_union([lambda x: from_list(Dependency.from_dict, x), from_none], obj.get("depends"))
1303
- description = from_union([from_str, from_none], obj.get("description"))
1304
- extensions = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("extensions"))
1305
- groups = from_union([lambda x: from_list(RequirementGroup.from_dict, x), from_none], obj.get("groups"))
1306
- inputs = from_union([lambda x: from_list(Input.from_dict, x), from_none], obj.get("inputs"))
1307
- integrity = from_union([Integrity.from_dict, from_none], obj.get("integrity"))
1308
- original_checksum = from_union([Checksum.from_dict, from_none], obj.get("originalChecksum"))
1309
- parent_baseline = from_union([from_str, from_none], obj.get("parentBaseline"))
1310
- results_checksum = from_union([Checksum.from_dict, from_none], obj.get("resultsChecksum"))
1311
- status_message = from_union([from_str, from_none], obj.get("statusMessage"))
1312
- copyright = from_union([from_str, from_none], obj.get("copyright"))
1313
- copyright_email = from_union([from_str, from_none], obj.get("copyrightEmail"))
1314
- labels = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("labels"))
1315
- license = from_union([from_str, from_none], obj.get("license"))
1316
- maintainer = from_union([from_str, from_none], obj.get("maintainer"))
1317
- status = from_union([from_str, from_none], obj.get("status"))
1318
- summary = from_union([from_str, from_none], obj.get("summary"))
1319
- supports = from_union([lambda x: from_list(SupportedPlatform.from_dict, x), from_none], obj.get("supports"))
1320
- title = from_union([from_str, from_none], obj.get("title"))
1321
- version = from_union([from_str, from_none], obj.get("version"))
1322
- return EvaluatedBaseline(requirements, name, depends, description, extensions, groups, inputs, integrity, original_checksum, parent_baseline, results_checksum, status_message, copyright, copyright_email, labels, license, maintainer, status, summary, supports, title, version)
1323
-
1324
- def to_dict(self) -> dict:
1325
- result: dict = {}
1326
- result["requirements"] = from_list(lambda x: to_class(EvaluatedRequirement, x), self.requirements)
1327
- result["name"] = from_str(self.name)
1328
- if self.depends is not None:
1329
- result["depends"] = from_union([lambda x: from_list(lambda x: to_class(Dependency, x), x), from_none], self.depends)
1330
- if self.description is not None:
1331
- result["description"] = from_union([from_str, from_none], self.description)
1332
- if self.extensions is not None:
1333
- result["extensions"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.extensions)
1334
- if self.groups is not None:
1335
- result["groups"] = from_union([lambda x: from_list(lambda x: to_class(RequirementGroup, x), x), from_none], self.groups)
1336
- if self.inputs is not None:
1337
- result["inputs"] = from_union([lambda x: from_list(lambda x: to_class(Input, x), x), from_none], self.inputs)
1338
- if self.integrity is not None:
1339
- result["integrity"] = from_union([lambda x: to_class(Integrity, x), from_none], self.integrity)
1340
- if self.original_checksum is not None:
1341
- result["originalChecksum"] = from_union([lambda x: to_class(Checksum, x), from_none], self.original_checksum)
1342
- if self.parent_baseline is not None:
1343
- result["parentBaseline"] = from_union([from_str, from_none], self.parent_baseline)
1344
- if self.results_checksum is not None:
1345
- result["resultsChecksum"] = from_union([lambda x: to_class(Checksum, x), from_none], self.results_checksum)
1346
- if self.status_message is not None:
1347
- result["statusMessage"] = from_union([from_str, from_none], self.status_message)
1348
- if self.copyright is not None:
1349
- result["copyright"] = from_union([from_str, from_none], self.copyright)
1350
- if self.copyright_email is not None:
1351
- result["copyrightEmail"] = from_union([from_str, from_none], self.copyright_email)
1352
- if self.labels is not None:
1353
- result["labels"] = from_union([lambda x: from_dict(from_str, x), from_none], self.labels)
1354
- if self.license is not None:
1355
- result["license"] = from_union([from_str, from_none], self.license)
1356
- if self.maintainer is not None:
1357
- result["maintainer"] = from_union([from_str, from_none], self.maintainer)
1358
- if self.status is not None:
1359
- result["status"] = from_union([from_str, from_none], self.status)
1360
- if self.summary is not None:
1361
- result["summary"] = from_union([from_str, from_none], self.summary)
1362
- if self.supports is not None:
1363
- result["supports"] = from_union([lambda x: from_list(lambda x: to_class(SupportedPlatform, x), x), from_none], self.supports)
1364
- if self.title is not None:
1365
- result["title"] = from_union([from_str, from_none], self.title)
1366
- if self.version is not None:
1367
- result["version"] = from_union([from_str, from_none], self.version)
1368
- return result
1369
-
1370
-
1371
- @dataclass
1372
- class InputOverride:
1373
- """An override of a baseline input value for a specific component. Enables system-specific
1374
- tailoring of baseline parameters.
1375
- """
1376
- input_name: str
1377
- """Name of the input being overridden. Must match an Input.name in the referenced baseline."""
1378
-
1379
- value: Any
1380
- """The overridden value. Should match the type of the original input."""
1381
-
1382
- approved_by: Optional[Identity] = None
1383
- """Identity of the person or system that approved this override."""
1384
-
1385
- baseline_ref: Optional[str] = None
1386
- """Name of the baseline this override applies to. If omitted, applies to all baselines that
1387
- define this input.
1388
- """
1389
- justification: Optional[str] = None
1390
- """Rationale for why this override is needed."""
1391
-
1392
- @staticmethod
1393
- def from_dict(obj: Any) -> 'InputOverride':
1394
- assert isinstance(obj, dict)
1395
- input_name = from_str(obj.get("inputName"))
1396
- value = obj.get("value")
1397
- approved_by = from_union([Identity.from_dict, from_none], obj.get("approvedBy"))
1398
- baseline_ref = from_union([from_str, from_none], obj.get("baselineRef"))
1399
- justification = from_union([from_str, from_none], obj.get("justification"))
1400
- return InputOverride(input_name, value, approved_by, baseline_ref, justification)
1401
-
1402
- def to_dict(self) -> dict:
1403
- result: dict = {}
1404
- result["inputName"] = from_str(self.input_name)
1405
- result["value"] = self.value
1406
- if self.approved_by is not None:
1407
- result["approvedBy"] = from_union([lambda x: to_class(Identity, x), from_none], self.approved_by)
1408
- if self.baseline_ref is not None:
1409
- result["baselineRef"] = from_union([from_str, from_none], self.baseline_ref)
1410
- if self.justification is not None:
1411
- result["justification"] = from_union([from_str, from_none], self.justification)
1412
- return result
1413
-
1414
-
1415
- class CloudProvider(Enum):
1416
- AWS = "aws"
1417
- AZURE = "azure"
1418
- GCP = "gcp"
1419
- OCI = "oci"
1420
- OTHER = "other"
1421
-
1422
-
1423
- class SbomFormat(Enum):
1424
- """Format of the SBOM (embedded or referenced). Required when sbom or sbomRef is present."""
1425
-
1426
- CYCLONEDX = "cyclonedx"
1427
- SPDX = "spdx"
1428
-
1429
-
1430
- class Copyright(Enum):
1431
- """A human readable/meaningful reference. Example: a book title.
1432
-
1433
- IP address of the host.
1434
- """
1435
- APPLICATION = "application"
1436
- ARTIFACT = "artifact"
1437
- CLOUD_ACCOUNT = "cloudAccount"
1438
- CLOUD_RESOURCE = "cloudResource"
1439
- CONTAINER_IMAGE = "containerImage"
1440
- CONTAINER_INSTANCE = "containerInstance"
1441
- CONTAINER_PLATFORM = "containerPlatform"
1442
- DATABASE = "database"
1443
- HOST = "host"
1444
- NETWORK = "network"
1445
- REPOSITORY = "repository"
1446
-
1447
-
1448
- @dataclass
1449
- class Component:
1450
- """A system component. Uses discriminated union pattern with 'type' field as discriminator.
1451
- Superset of Target with identity, external IDs, and SBOM support.
1452
-
1453
- A physical or virtual server, workstation, or network device.
1454
-
1455
- Base properties shared by all component types. Extends the Target concept with stable
1456
- identity, external references, and SBOM embedding.
1457
-
1458
- A static container image (not running).
1459
-
1460
- A running container instance.
1461
-
1462
- A container orchestration platform (Kubernetes, OpenShift, ECS, etc.).
1463
-
1464
- A cloud provider account (AWS account, Azure subscription, GCP project).
1465
-
1466
- A specific cloud resource (EC2 instance, S3 bucket, Azure VM, etc.).
1467
-
1468
- A code repository (for SAST tools).
1469
-
1470
- A running application or API (for DAST tools).
1471
-
1472
- A software artifact or dependency (for SCA tools).
1473
-
1474
- A network segment or network device.
1475
-
1476
- A database instance.
1477
- """
1478
- name: str
1479
- """Human-readable name for this component."""
1480
-
1481
- type: Copyright
1482
- """Component type discriminator. Same values as Target types."""
1483
-
1484
- baseline_refs: Optional[List[str]] = None
1485
- """Names of baselines that apply to this component."""
1486
-
1487
- component_id: Optional[UUID] = None
1488
- """Stable UUID (RFC 4122) for this component. Required in hdf-system documents, optional in
1489
- hdf-results. Enables cross-document correlation, diffing, and data flow references.
1490
- """
1491
- description: Optional[str] = None
1492
- """Description of this component's role or purpose."""
1493
-
1494
- external_ids: Optional[Dict[str, str]] = None
1495
- """Map of external identifier scheme to value. Well-known schemes: aws (instance ID), azure
1496
- (resource ID), cmdb (asset ID), emass (system ID), cve (CVE ID). Custom schemes are
1497
- allowed.
1498
- """
1499
- input_overrides: Optional[List[InputOverride]] = None
1500
- """System-specific overrides for baseline input values."""
1501
-
1502
- labels: Optional[Dict[str, str]] = None
1503
- """Optional key-value labels for flexible grouping. Well-known keys: system, component,
1504
- environment, region, team. Values must be strings.
1505
- """
1506
- owner: Optional[Identity] = None
1507
- """Team or individual responsible for this component. Enables per-component ownership when
1508
- different teams manage different parts of a system.
1509
- """
1510
- sbom: Any
1511
- """Embedded CycloneDX or SPDX SBOM document representing this component's software
1512
- inventory. The sbomFormat field determines which format constraints apply.
1513
- """
1514
- sbom_format: Optional[SbomFormat] = None
1515
- """Format of the SBOM (embedded or referenced). Required when sbom or sbomRef is present."""
1516
-
1517
- sbom_ref: Optional[str] = None
1518
- """URI reference to an external CycloneDX or SPDX SBOM document for this component. May be a
1519
- relative path, absolute URI, or fragment identifier.
1520
- """
1521
- target_selector: Optional[Dict[str, str]] = None
1522
- """Label selector to match targets belonging to this component during migration. Targets
1523
- with matching labels are automatically included.
1524
- """
1525
- fqdn: Optional[str] = None
1526
- """Fully qualified domain name."""
1527
-
1528
- ip_address: Optional[str] = None
1529
- """IP address of the host."""
1530
-
1531
- mac_address: Optional[str] = None
1532
- """MAC address in colon-separated hexadecimal format."""
1533
-
1534
- os_name: Optional[str] = None
1535
- """Operating system name."""
1536
-
1537
- os_version: Optional[str] = None
1538
- """Operating system version."""
1539
-
1540
- digest: Optional[str] = None
1541
- """Image digest for immutable reference."""
1542
-
1543
- image_id: Optional[str] = None
1544
- """Container image ID."""
1545
-
1546
- registry: Optional[str] = None
1547
- """Container registry. Example: 'docker.io'."""
1548
-
1549
- repository: Optional[str] = None
1550
- """Repository name. Example: 'library/nginx'."""
1551
-
1552
- tag: Optional[str] = None
1553
- """Image tag. Example: '1.25'."""
1554
-
1555
- container_id: Optional[str] = None
1556
- """Running container ID."""
1557
-
1558
- image: Optional[str] = None
1559
- """Image the container was started from."""
1560
-
1561
- runtime: Optional[str] = None
1562
- """Container runtime. Example: 'docker', 'containerd', 'cri-o'."""
1563
-
1564
- cluster_name: Optional[str] = None
1565
- """Cluster name."""
1566
-
1567
- namespace: Optional[str] = None
1568
- """Namespace within the cluster, if applicable."""
1569
-
1570
- platform_type: Optional[str] = None
1571
- """Platform type. Example: 'kubernetes', 'openshift', 'ecs', 'docker-swarm'."""
1572
-
1573
- version: Optional[str] = None
1574
- """Platform version.
1575
-
1576
- Application version.
1577
-
1578
- Package version.
1579
-
1580
- Database version.
1581
- """
1582
- account_id: Optional[str] = None
1583
- """Cloud account identifier."""
1584
-
1585
- provider: Optional[CloudProvider] = None
1586
- """Cloud provider."""
1587
-
1588
- region: Optional[str] = None
1589
- """Cloud region, if applicable.
1590
-
1591
- Cloud region where the resource resides.
1592
- """
1593
- arn: Optional[str] = None
1594
- """Amazon Resource Name (AWS only)."""
1595
-
1596
- resource_id: Optional[str] = None
1597
- """Provider-specific resource identifier."""
1598
-
1599
- resource_type: Optional[str] = None
1600
- """Type of cloud resource. Example: 'ec2:instance', 's3:bucket'."""
1601
-
1602
- branch: Optional[str] = None
1603
- """Branch that was scanned."""
1604
-
1605
- commit: Optional[str] = None
1606
- """Commit SHA that was scanned."""
1607
-
1608
- url: Optional[str] = None
1609
- """Repository URL.
1610
-
1611
- Application URL (for DAST tools).
1612
- """
1613
- environment: Optional[str] = None
1614
- """Environment. Example: 'production', 'staging', 'development'."""
1615
-
1616
- checksum: Optional[str] = None
1617
- """Package checksum for verification."""
1618
-
1619
- package_manager: Optional[str] = None
1620
- """Package manager. Example: 'npm', 'maven', 'pip', 'nuget'."""
1621
-
1622
- package_name: Optional[str] = None
1623
- """Package name."""
1624
-
1625
- cidr: Optional[str] = None
1626
- """Network CIDR block."""
1627
-
1628
- gateway: Optional[str] = None
1629
- """Network gateway address."""
1630
-
1631
- engine: Optional[str] = None
1632
- """Database engine. Example: 'postgresql', 'mysql', 'oracle', 'mssql'."""
1633
-
1634
- host: Optional[str] = None
1635
- """Database host."""
1636
-
1637
- port: Optional[int] = None
1638
- """Database port."""
1639
-
1640
- @staticmethod
1641
- def from_dict(obj: Any) -> 'Component':
1642
- assert isinstance(obj, dict)
1643
- name = from_str(obj.get("name"))
1644
- type = Copyright(obj.get("type"))
1645
- baseline_refs = from_union([lambda x: from_list(from_str, x), from_none], obj.get("baselineRefs"))
1646
- component_id = from_union([lambda x: UUID(x), from_none], obj.get("componentId"))
1647
- description = from_union([from_str, from_none], obj.get("description"))
1648
- external_ids = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("externalIds"))
1649
- input_overrides = from_union([lambda x: from_list(InputOverride.from_dict, x), from_none], obj.get("inputOverrides"))
1650
- labels = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("labels"))
1651
- owner = from_union([Identity.from_dict, from_none], obj.get("owner"))
1652
- sbom = obj.get("sbom")
1653
- sbom_format = from_union([SbomFormat, from_none], obj.get("sbomFormat"))
1654
- sbom_ref = from_union([from_str, from_none], obj.get("sbomRef"))
1655
- target_selector = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("targetSelector"))
1656
- fqdn = from_union([from_str, from_none], obj.get("fqdn"))
1657
- ip_address = from_union([from_str, from_none], obj.get("ipAddress"))
1658
- mac_address = from_union([from_str, from_none], obj.get("macAddress"))
1659
- os_name = from_union([from_str, from_none], obj.get("osName"))
1660
- os_version = from_union([from_str, from_none], obj.get("osVersion"))
1661
- digest = from_union([from_str, from_none], obj.get("digest"))
1662
- image_id = from_union([from_str, from_none], obj.get("imageId"))
1663
- registry = from_union([from_str, from_none], obj.get("registry"))
1664
- repository = from_union([from_str, from_none], obj.get("repository"))
1665
- tag = from_union([from_str, from_none], obj.get("tag"))
1666
- container_id = from_union([from_str, from_none], obj.get("containerId"))
1667
- image = from_union([from_str, from_none], obj.get("image"))
1668
- runtime = from_union([from_str, from_none], obj.get("runtime"))
1669
- cluster_name = from_union([from_str, from_none], obj.get("clusterName"))
1670
- namespace = from_union([from_str, from_none], obj.get("namespace"))
1671
- platform_type = from_union([from_str, from_none], obj.get("platformType"))
1672
- version = from_union([from_str, from_none], obj.get("version"))
1673
- account_id = from_union([from_str, from_none], obj.get("accountId"))
1674
- provider = from_union([from_none, CloudProvider], obj.get("provider"))
1675
- region = from_union([from_str, from_none], obj.get("region"))
1676
- arn = from_union([from_str, from_none], obj.get("arn"))
1677
- resource_id = from_union([from_str, from_none], obj.get("resourceId"))
1678
- resource_type = from_union([from_str, from_none], obj.get("resourceType"))
1679
- branch = from_union([from_str, from_none], obj.get("branch"))
1680
- commit = from_union([from_str, from_none], obj.get("commit"))
1681
- url = from_union([from_str, from_none], obj.get("url"))
1682
- environment = from_union([from_str, from_none], obj.get("environment"))
1683
- checksum = from_union([from_str, from_none], obj.get("checksum"))
1684
- package_manager = from_union([from_str, from_none], obj.get("packageManager"))
1685
- package_name = from_union([from_str, from_none], obj.get("packageName"))
1686
- cidr = from_union([from_str, from_none], obj.get("cidr"))
1687
- gateway = from_union([from_str, from_none], obj.get("gateway"))
1688
- engine = from_union([from_str, from_none], obj.get("engine"))
1689
- host = from_union([from_str, from_none], obj.get("host"))
1690
- port = from_union([from_int, from_none], obj.get("port"))
1691
- return Component(name, type, baseline_refs, component_id, description, external_ids, input_overrides, labels, owner, sbom, sbom_format, sbom_ref, target_selector, fqdn, ip_address, mac_address, os_name, os_version, digest, image_id, registry, repository, tag, container_id, image, runtime, cluster_name, namespace, platform_type, version, account_id, provider, region, arn, resource_id, resource_type, branch, commit, url, environment, checksum, package_manager, package_name, cidr, gateway, engine, host, port)
1692
-
1693
- def to_dict(self) -> dict:
1694
- result: dict = {}
1695
- result["name"] = from_str(self.name)
1696
- result["type"] = to_enum(Copyright, self.type)
1697
- if self.baseline_refs is not None:
1698
- result["baselineRefs"] = from_union([lambda x: from_list(from_str, x), from_none], self.baseline_refs)
1699
- if self.component_id is not None:
1700
- result["componentId"] = from_union([lambda x: str(x), from_none], self.component_id)
1701
- if self.description is not None:
1702
- result["description"] = from_union([from_str, from_none], self.description)
1703
- if self.external_ids is not None:
1704
- result["externalIds"] = from_union([lambda x: from_dict(from_str, x), from_none], self.external_ids)
1705
- if self.input_overrides is not None:
1706
- result["inputOverrides"] = from_union([lambda x: from_list(lambda x: to_class(InputOverride, x), x), from_none], self.input_overrides)
1707
- if self.labels is not None:
1708
- result["labels"] = from_union([lambda x: from_dict(from_str, x), from_none], self.labels)
1709
- if self.owner is not None:
1710
- result["owner"] = from_union([lambda x: to_class(Identity, x), from_none], self.owner)
1711
- if self.sbom is not None:
1712
- result["sbom"] = self.sbom
1713
- if self.sbom_format is not None:
1714
- result["sbomFormat"] = from_union([lambda x: to_enum(SbomFormat, x), from_none], self.sbom_format)
1715
- if self.sbom_ref is not None:
1716
- result["sbomRef"] = from_union([from_str, from_none], self.sbom_ref)
1717
- if self.target_selector is not None:
1718
- result["targetSelector"] = from_union([lambda x: from_dict(from_str, x), from_none], self.target_selector)
1719
- if self.fqdn is not None:
1720
- result["fqdn"] = from_union([from_str, from_none], self.fqdn)
1721
- if self.ip_address is not None:
1722
- result["ipAddress"] = from_union([from_str, from_none], self.ip_address)
1723
- if self.mac_address is not None:
1724
- result["macAddress"] = from_union([from_str, from_none], self.mac_address)
1725
- if self.os_name is not None:
1726
- result["osName"] = from_union([from_str, from_none], self.os_name)
1727
- if self.os_version is not None:
1728
- result["osVersion"] = from_union([from_str, from_none], self.os_version)
1729
- if self.digest is not None:
1730
- result["digest"] = from_union([from_str, from_none], self.digest)
1731
- if self.image_id is not None:
1732
- result["imageId"] = from_union([from_str, from_none], self.image_id)
1733
- if self.registry is not None:
1734
- result["registry"] = from_union([from_str, from_none], self.registry)
1735
- if self.repository is not None:
1736
- result["repository"] = from_union([from_str, from_none], self.repository)
1737
- if self.tag is not None:
1738
- result["tag"] = from_union([from_str, from_none], self.tag)
1739
- if self.container_id is not None:
1740
- result["containerId"] = from_union([from_str, from_none], self.container_id)
1741
- if self.image is not None:
1742
- result["image"] = from_union([from_str, from_none], self.image)
1743
- if self.runtime is not None:
1744
- result["runtime"] = from_union([from_str, from_none], self.runtime)
1745
- if self.cluster_name is not None:
1746
- result["clusterName"] = from_union([from_str, from_none], self.cluster_name)
1747
- if self.namespace is not None:
1748
- result["namespace"] = from_union([from_str, from_none], self.namespace)
1749
- if self.platform_type is not None:
1750
- result["platformType"] = from_union([from_str, from_none], self.platform_type)
1751
- if self.version is not None:
1752
- result["version"] = from_union([from_str, from_none], self.version)
1753
- if self.account_id is not None:
1754
- result["accountId"] = from_union([from_str, from_none], self.account_id)
1755
- if self.provider is not None:
1756
- result["provider"] = from_union([from_none, lambda x: to_enum(CloudProvider, x)], self.provider)
1757
- if self.region is not None:
1758
- result["region"] = from_union([from_str, from_none], self.region)
1759
- if self.arn is not None:
1760
- result["arn"] = from_union([from_str, from_none], self.arn)
1761
- if self.resource_id is not None:
1762
- result["resourceId"] = from_union([from_str, from_none], self.resource_id)
1763
- if self.resource_type is not None:
1764
- result["resourceType"] = from_union([from_str, from_none], self.resource_type)
1765
- if self.branch is not None:
1766
- result["branch"] = from_union([from_str, from_none], self.branch)
1767
- if self.commit is not None:
1768
- result["commit"] = from_union([from_str, from_none], self.commit)
1769
- if self.url is not None:
1770
- result["url"] = from_union([from_str, from_none], self.url)
1771
- if self.environment is not None:
1772
- result["environment"] = from_union([from_str, from_none], self.environment)
1773
- if self.checksum is not None:
1774
- result["checksum"] = from_union([from_str, from_none], self.checksum)
1775
- if self.package_manager is not None:
1776
- result["packageManager"] = from_union([from_str, from_none], self.package_manager)
1777
- if self.package_name is not None:
1778
- result["packageName"] = from_union([from_str, from_none], self.package_name)
1779
- if self.cidr is not None:
1780
- result["cidr"] = from_union([from_str, from_none], self.cidr)
1781
- if self.gateway is not None:
1782
- result["gateway"] = from_union([from_str, from_none], self.gateway)
1783
- if self.engine is not None:
1784
- result["engine"] = from_union([from_str, from_none], self.engine)
1785
- if self.host is not None:
1786
- result["host"] = from_union([from_str, from_none], self.host)
1787
- if self.port is not None:
1788
- result["port"] = from_union([from_int, from_none], self.port)
1789
- return result
1790
-
1791
-
1792
- @dataclass
1793
- class Generator:
1794
- """Information about the tool that generated this file.
1795
-
1796
- Information about the tool that generated this HDF file.
1797
- """
1798
- name: str
1799
- """The name of the software that produced this HDF file. Example: 'gosec-to-hdf'."""
1800
-
1801
- version: str
1802
- """The version of the tool. Example: '5.22.3'."""
1803
-
1804
- @staticmethod
1805
- def from_dict(obj: Any) -> 'Generator':
1806
- assert isinstance(obj, dict)
1807
- name = from_str(obj.get("name"))
1808
- version = from_str(obj.get("version"))
1809
- return Generator(name, version)
1810
-
1811
- def to_dict(self) -> dict:
1812
- result: dict = {}
1813
- result["name"] = from_str(self.name)
1814
- result["version"] = from_str(self.version)
1815
- return result
1816
-
1817
-
1818
- @dataclass
1819
- class Remediation:
1820
- """Optional reference to automated remediation resources (Ansible playbooks, Terraform
1821
- scripts, etc.) for fixing failing requirements found in this assessment.
1822
-
1823
- Reference to automated remediation resources for implementing security controls. Points
1824
- to external automation content like Ansible playbooks, Terraform scripts, or
1825
- vendor-provided remediation tools.
1826
- """
1827
- uri: str
1828
- """URI pointing to automated remediation resources (Ansible playbooks, Terraform scripts,
1829
- etc.). Examples: GitHub repository, DISA STIG Supplemental Automation Content,
1830
- vendor-provided scripts.
1831
- """
1832
- checksum: Optional[Checksum] = None
1833
- """Optional cryptographic checksum for verifying the integrity of remediation resources
1834
- fetched from the URI. Recommended for security when referencing external automation
1835
- scripts.
1836
- """
1837
-
1838
- @staticmethod
1839
- def from_dict(obj: Any) -> 'Remediation':
1840
- assert isinstance(obj, dict)
1841
- uri = from_str(obj.get("uri"))
1842
- checksum = from_union([Checksum.from_dict, from_none], obj.get("checksum"))
1843
- return Remediation(uri, checksum)
1844
-
1845
- def to_dict(self) -> dict:
1846
- result: dict = {}
1847
- result["uri"] = from_str(self.uri)
1848
- if self.checksum is not None:
1849
- result["checksum"] = from_union([lambda x: to_class(Checksum, x), from_none], self.checksum)
1850
- return result
1851
-
1852
-
1853
- @dataclass
1854
- class Runner:
1855
- """Information about the test execution environment where the security tool was run.
1856
- Distinct from targets (what is being tested).
1857
-
1858
- Information about the test execution environment. This is distinct from the target being
1859
- scanned - the runner is where the security tool executes, while targets are what is being
1860
- assessed.
1861
- """
1862
- name: str
1863
- """The name of the runner environment. Examples: 'ubuntu', 'macos', 'windows', 'docker',
1864
- 'kubernetes-pod', 'manual'.
1865
- """
1866
- architecture: Optional[str] = None
1867
- """The CPU architecture of the runner system. Example: 'x86_64', 'arm64', 'aarch64'."""
1868
-
1869
- container_id: Optional[str] = None
1870
- """The container instance identifier. Example: 'a1b2c3d4e5f6', 'security-scan-job-xyz123'.
1871
- Can be a Docker container ID, Kubernetes pod name, or other container runtime identifier.
1872
- """
1873
- container_image: Optional[str] = None
1874
- """The container image used for the test execution. Example: 'inspec/inspec:latest',
1875
- 'ghcr.io/my-org/scanner:v2.1.0'. Useful for CI/CD pipelines where tests run in containers.
1876
- """
1877
- hostname: Optional[str] = None
1878
- """The hostname of the runner system. Example: 'ci-runner-01', 'jenkins-agent-03',
1879
- 'k8s-node-worker-03'.
1880
- """
1881
- operator: Optional[Identity] = None
1882
- """The identity of the person or system responsible for executing the test. This could be a
1883
- human auditor manually completing a checklist, an automated CI/CD system, or a security
1884
- tool. Optional field to support both automated and manual HDF generation.
1885
- """
1886
- release: Optional[str] = None
1887
- """The version/release of the operating system or runtime. Example: '20.04', '13.2', '11'."""
1888
-
1889
- @staticmethod
1890
- def from_dict(obj: Any) -> 'Runner':
1891
- assert isinstance(obj, dict)
1892
- name = from_str(obj.get("name"))
1893
- architecture = from_union([from_str, from_none], obj.get("architecture"))
1894
- container_id = from_union([from_str, from_none], obj.get("containerId"))
1895
- container_image = from_union([from_str, from_none], obj.get("containerImage"))
1896
- hostname = from_union([from_str, from_none], obj.get("hostname"))
1897
- operator = from_union([Identity.from_dict, from_none], obj.get("operator"))
1898
- release = from_union([from_str, from_none], obj.get("release"))
1899
- return Runner(name, architecture, container_id, container_image, hostname, operator, release)
1900
-
1901
- def to_dict(self) -> dict:
1902
- result: dict = {}
1903
- result["name"] = from_str(self.name)
1904
- if self.architecture is not None:
1905
- result["architecture"] = from_union([from_str, from_none], self.architecture)
1906
- if self.container_id is not None:
1907
- result["containerId"] = from_union([from_str, from_none], self.container_id)
1908
- if self.container_image is not None:
1909
- result["containerImage"] = from_union([from_str, from_none], self.container_image)
1910
- if self.hostname is not None:
1911
- result["hostname"] = from_union([from_str, from_none], self.hostname)
1912
- if self.operator is not None:
1913
- result["operator"] = from_union([lambda x: to_class(Identity, x), from_none], self.operator)
1914
- if self.release is not None:
1915
- result["release"] = from_union([from_str, from_none], self.release)
1916
- return result
1917
-
1918
-
1919
- @dataclass
1920
- class StatisticBlock:
1921
- """Statistics for requirements that encountered an error during assessment.
1922
-
1923
- Statistics for a given item, such as the total count.
1924
-
1925
- Statistics for requirements that failed.
1926
-
1927
- Statistics for requirements that are not applicable to the target.
1928
-
1929
- Statistics for requirements that were not reviewed (manual check required).
1930
-
1931
- Statistics for requirements that passed.
1932
- """
1933
- total: int
1934
- """The total count. Example: the total number of requirements in a given category for a run."""
1935
-
1936
- @staticmethod
1937
- def from_dict(obj: Any) -> 'StatisticBlock':
1938
- assert isinstance(obj, dict)
1939
- total = from_int(obj.get("total"))
1940
- return StatisticBlock(total)
1941
-
1942
- def to_dict(self) -> dict:
1943
- result: dict = {}
1944
- result["total"] = from_int(self.total)
1945
- return result
1946
-
1947
-
1948
- @dataclass
1949
- class StatisticHash:
1950
- """Breakdowns of requirement statistics by result status.
1951
-
1952
- Statistics for requirement results, grouped by status.
1953
- """
1954
- error: Optional[StatisticBlock] = None
1955
- """Statistics for requirements that encountered an error during assessment."""
1956
-
1957
- failed: Optional[StatisticBlock] = None
1958
- """Statistics for requirements that failed."""
1959
-
1960
- not_applicable: Optional[StatisticBlock] = None
1961
- """Statistics for requirements that are not applicable to the target."""
1962
-
1963
- not_reviewed: Optional[StatisticBlock] = None
1964
- """Statistics for requirements that were not reviewed (manual check required)."""
1965
-
1966
- passed: Optional[StatisticBlock] = None
1967
- """Statistics for requirements that passed."""
1968
-
1969
- @staticmethod
1970
- def from_dict(obj: Any) -> 'StatisticHash':
1971
- assert isinstance(obj, dict)
1972
- error = from_union([StatisticBlock.from_dict, from_none], obj.get("error"))
1973
- failed = from_union([StatisticBlock.from_dict, from_none], obj.get("failed"))
1974
- not_applicable = from_union([StatisticBlock.from_dict, from_none], obj.get("notApplicable"))
1975
- not_reviewed = from_union([StatisticBlock.from_dict, from_none], obj.get("notReviewed"))
1976
- passed = from_union([StatisticBlock.from_dict, from_none], obj.get("passed"))
1977
- return StatisticHash(error, failed, not_applicable, not_reviewed, passed)
1978
-
1979
- def to_dict(self) -> dict:
1980
- result: dict = {}
1981
- if self.error is not None:
1982
- result["error"] = from_union([lambda x: to_class(StatisticBlock, x), from_none], self.error)
1983
- if self.failed is not None:
1984
- result["failed"] = from_union([lambda x: to_class(StatisticBlock, x), from_none], self.failed)
1985
- if self.not_applicable is not None:
1986
- result["notApplicable"] = from_union([lambda x: to_class(StatisticBlock, x), from_none], self.not_applicable)
1987
- if self.not_reviewed is not None:
1988
- result["notReviewed"] = from_union([lambda x: to_class(StatisticBlock, x), from_none], self.not_reviewed)
1989
- if self.passed is not None:
1990
- result["passed"] = from_union([lambda x: to_class(StatisticBlock, x), from_none], self.passed)
1991
- return result
1992
-
1993
-
1994
- @dataclass
1995
- class Statistics:
1996
- """Statistics for the assessment run, including duration and result counts.
1997
-
1998
- Statistics for the assessment run(s) such as duration and result counts.
1999
- """
2000
- duration: Optional[float] = None
2001
- """How long (in seconds) this assessment run took."""
2002
-
2003
- requirements: Optional[StatisticHash] = None
2004
- """Breakdowns of requirement statistics by result status."""
2005
-
2006
- @staticmethod
2007
- def from_dict(obj: Any) -> 'Statistics':
2008
- assert isinstance(obj, dict)
2009
- duration = from_union([from_float, from_none], obj.get("duration"))
2010
- requirements = from_union([StatisticHash.from_dict, from_none], obj.get("requirements"))
2011
- return Statistics(duration, requirements)
2012
-
2013
- def to_dict(self) -> dict:
2014
- result: dict = {}
2015
- if self.duration is not None:
2016
- result["duration"] = from_union([to_float, from_none], self.duration)
2017
- if self.requirements is not None:
2018
- result["requirements"] = from_union([lambda x: to_class(StatisticHash, x), from_none], self.requirements)
2019
- return result
2020
-
2021
-
2022
- @dataclass
2023
- class Tool:
2024
- """The security tool that produced the assessment data in this file.
2025
-
2026
- The security tool that produced the assessment data represented in this HDF file. Aligns
2027
- with SARIF, OSCAL, and CycloneDX terminology.
2028
- """
2029
- format: Optional[str] = None
2030
- """The file format, if it is a recognized named format shared by multiple tools. Examples:
2031
- 'SARIF', 'XCCDF'. Omit for tool-specific formats where the tool name already implies the
2032
- format (Nessus XML, gosec JSON).
2033
- """
2034
- name: Optional[str] = None
2035
- """The name of the security tool that produced the data. Examples: 'gosec', 'Semgrep',
2036
- 'OpenSCAP', 'AWS Config', 'Nessus'. Omit if the tool cannot be identified.
2037
- """
2038
- version: Optional[str] = None
2039
- """Version of the source tool, if available in the tool's output. Example: '5.22.3'."""
2040
-
2041
- @staticmethod
2042
- def from_dict(obj: Any) -> 'Tool':
2043
- assert isinstance(obj, dict)
2044
- format = from_union([from_str, from_none], obj.get("format"))
2045
- name = from_union([from_str, from_none], obj.get("name"))
2046
- version = from_union([from_str, from_none], obj.get("version"))
2047
- return Tool(format, name, version)
2048
-
2049
- def to_dict(self) -> dict:
2050
- result: dict = {}
2051
- if self.format is not None:
2052
- result["format"] = from_union([from_str, from_none], self.format)
2053
- if self.name is not None:
2054
- result["name"] = from_union([from_str, from_none], self.name)
2055
- if self.version is not None:
2056
- result["version"] = from_union([from_str, from_none], self.version)
2057
- return result
2058
-
2059
-
2060
- @dataclass
2061
- class HdfResults:
2062
- """The top level value containing all assessment results."""
2063
-
2064
- baselines: List[EvaluatedBaseline]
2065
- """Information on the baselines that were evaluated, including findings."""
2066
-
2067
- components: Optional[List[Component]] = None
2068
- """The components that were assessed. Each component describes a system element (host,
2069
- container, cloud resource, application, etc.) with optional identity, SBOM, and external
2070
- references.
2071
- """
2072
- extensions: Optional[Dict[str, Any]] = None
2073
- """Reserved for tool-specific data not defined in the HDF standard. Use this to preserve
2074
- original tool output, auxiliary data, or custom metadata.
2075
- """
2076
- generator: Optional[Generator] = None
2077
- """Information about the tool that generated this file."""
2078
-
2079
- id: Optional[UUID] = None
2080
- """Unique identifier for this assessment run."""
2081
-
2082
- integrity: Optional[Integrity] = None
2083
- """Cryptographic integrity information for verifying this file."""
2084
-
2085
- plan_ref: Optional[str] = None
2086
- """Reference to an hdf-plan document describing the assessment plan that produced these
2087
- results. May be a relative path, absolute URI, or fragment identifier.
2088
- """
2089
- remediation: Optional[Remediation] = None
2090
- """Optional reference to automated remediation resources (Ansible playbooks, Terraform
2091
- scripts, etc.) for fixing failing requirements found in this assessment.
2092
- """
2093
- runner: Optional[Runner] = None
2094
- """Information about the test execution environment where the security tool was run.
2095
- Distinct from targets (what is being tested).
2096
- """
2097
- statistics: Optional[Statistics] = None
2098
- """Statistics for the assessment run, including duration and result counts."""
2099
-
2100
- system_ref: Optional[str] = None
2101
- """Reference to an hdf-system document describing the system under assessment. May be a
2102
- relative path, absolute URI, or fragment identifier.
2103
- """
2104
- timestamp: Optional[datetime] = None
2105
- """When this assessment was executed."""
2106
-
2107
- tool: Optional[Tool] = None
2108
- """The security tool that produced the assessment data in this file."""
2109
-
2110
- @staticmethod
2111
- def from_dict(obj: Any) -> 'HdfResults':
2112
- assert isinstance(obj, dict)
2113
- baselines = from_list(EvaluatedBaseline.from_dict, obj.get("baselines"))
2114
- components = from_union([lambda x: from_list(Component.from_dict, x), from_none], obj.get("components"))
2115
- extensions = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("extensions"))
2116
- generator = from_union([Generator.from_dict, from_none], obj.get("generator"))
2117
- id = from_union([lambda x: UUID(x), from_none], obj.get("id"))
2118
- integrity = from_union([Integrity.from_dict, from_none], obj.get("integrity"))
2119
- plan_ref = from_union([from_str, from_none], obj.get("planRef"))
2120
- remediation = from_union([Remediation.from_dict, from_none], obj.get("remediation"))
2121
- runner = from_union([Runner.from_dict, from_none], obj.get("runner"))
2122
- statistics = from_union([Statistics.from_dict, from_none], obj.get("statistics"))
2123
- system_ref = from_union([from_str, from_none], obj.get("systemRef"))
2124
- timestamp = from_union([from_datetime, from_none], obj.get("timestamp"))
2125
- tool = from_union([Tool.from_dict, from_none], obj.get("tool"))
2126
- return HdfResults(baselines, components, extensions, generator, id, integrity, plan_ref, remediation, runner, statistics, system_ref, timestamp, tool)
2127
-
2128
- def to_dict(self) -> dict:
2129
- result: dict = {}
2130
- result["baselines"] = from_list(lambda x: to_class(EvaluatedBaseline, x), self.baselines)
2131
- if self.components is not None:
2132
- result["components"] = from_union([lambda x: from_list(lambda x: to_class(Component, x), x), from_none], self.components)
2133
- if self.extensions is not None:
2134
- result["extensions"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.extensions)
2135
- if self.generator is not None:
2136
- result["generator"] = from_union([lambda x: to_class(Generator, x), from_none], self.generator)
2137
- if self.id is not None:
2138
- result["id"] = from_union([lambda x: str(x), from_none], self.id)
2139
- if self.integrity is not None:
2140
- result["integrity"] = from_union([lambda x: to_class(Integrity, x), from_none], self.integrity)
2141
- if self.plan_ref is not None:
2142
- result["planRef"] = from_union([from_str, from_none], self.plan_ref)
2143
- if self.remediation is not None:
2144
- result["remediation"] = from_union([lambda x: to_class(Remediation, x), from_none], self.remediation)
2145
- if self.runner is not None:
2146
- result["runner"] = from_union([lambda x: to_class(Runner, x), from_none], self.runner)
2147
- if self.statistics is not None:
2148
- result["statistics"] = from_union([lambda x: to_class(Statistics, x), from_none], self.statistics)
2149
- if self.system_ref is not None:
2150
- result["systemRef"] = from_union([from_str, from_none], self.system_ref)
2151
- if self.timestamp is not None:
2152
- result["timestamp"] = from_union([lambda x: x.isoformat(), from_none], self.timestamp)
2153
- if self.tool is not None:
2154
- result["tool"] = from_union([lambda x: to_class(Tool, x), from_none], self.tool)
2155
- return result
2156
-
2157
-
2158
- def hdf_results_from_dict(s: Any) -> HdfResults:
2159
- return HdfResults.from_dict(s)
2160
-
2161
-
2162
- def hdf_results_to_dict(x: HdfResults) -> Any:
2163
- return to_class(HdfResults, x)