@mitre/hdf-schema 3.0.1 → 3.1.0

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,695 +0,0 @@
1
- from enum import Enum
2
- from dataclasses import dataclass
3
- from typing import Optional, Any, Dict, List, TypeVar, Type, cast, Callable
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 to_enum(c: Type[EnumT], x: Any) -> EnumT:
33
- assert isinstance(x, c)
34
- return x.value
35
-
36
-
37
- def from_datetime(x: Any) -> datetime:
38
- return dateutil.parser.parse(x)
39
-
40
-
41
- def from_float(x: Any) -> float:
42
- assert isinstance(x, (float, int)) and not isinstance(x, bool)
43
- return float(x)
44
-
45
-
46
- def to_class(c: Type[T], x: Any) -> dict:
47
- assert isinstance(x, c)
48
- return cast(Any, x).to_dict()
49
-
50
-
51
- def to_float(x: Any) -> float:
52
- assert isinstance(x, (int, float))
53
- return x
54
-
55
-
56
- def from_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]:
57
- assert isinstance(x, dict)
58
- return { k: f(v) for (k, v) in x.items() }
59
-
60
-
61
- def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
62
- assert isinstance(x, list)
63
- return [f(y) for y in x]
64
-
65
-
66
- class AppliedByType(Enum):
67
- """The type of identifier. Use 'email' for email addresses, 'username' for user accounts,
68
- 'system' for automated systems, 'simple' for basic string identifiers without additional
69
- classification, or 'other' for custom identity systems.
70
- """
71
- EMAIL = "email"
72
- OTHER = "other"
73
- SIMPLE = "simple"
74
- SYSTEM = "system"
75
- USERNAME = "username"
76
-
77
-
78
- @dataclass
79
- class Identity:
80
- """Default identity of who created this amendments document. Individual overrides may
81
- specify their own appliedBy.
82
-
83
- Represents an identity that performed an action, such as capturing evidence or applying
84
- an override.
85
-
86
- Identity of the authorizing official who approved these amendments.
87
-
88
- Identity of who applied this amendment.
89
-
90
- Identity of who or what captured this evidence.
91
-
92
- Identity of who completed this milestone.
93
-
94
- The identity that created this signature.
95
- """
96
- identifier: str
97
- """The identifier value. Example: 'user@example.com', 'jdoe', 'automated-scanner-01'."""
98
-
99
- type: AppliedByType
100
- """The type of identifier. Use 'email' for email addresses, 'username' for user accounts,
101
- 'system' for automated systems, 'simple' for basic string identifiers without additional
102
- classification, or 'other' for custom identity systems.
103
- """
104
- description: Optional[str] = None
105
- """Optional description of the identity or identity system, particularly useful when type is
106
- 'other'.
107
- """
108
-
109
- @staticmethod
110
- def from_dict(obj: Any) -> 'Identity':
111
- assert isinstance(obj, dict)
112
- identifier = from_str(obj.get("identifier"))
113
- type = AppliedByType(obj.get("type"))
114
- description = from_union([from_str, from_none], obj.get("description"))
115
- return Identity(identifier, type, description)
116
-
117
- def to_dict(self) -> dict:
118
- result: dict = {}
119
- result["identifier"] = from_str(self.identifier)
120
- result["type"] = to_enum(AppliedByType, self.type)
121
- if self.description is not None:
122
- result["description"] = from_union([from_str, from_none], self.description)
123
- return result
124
-
125
-
126
- @dataclass
127
- class Generator:
128
- """Information about the tool that generated this document.
129
-
130
- Information about the tool that generated this HDF file.
131
- """
132
- name: str
133
- """The name of the software that produced this HDF file. Example: 'gosec-to-hdf'."""
134
-
135
- version: str
136
- """The version of the tool. Example: '5.22.3'."""
137
-
138
- @staticmethod
139
- def from_dict(obj: Any) -> 'Generator':
140
- assert isinstance(obj, dict)
141
- name = from_str(obj.get("name"))
142
- version = from_str(obj.get("version"))
143
- return Generator(name, version)
144
-
145
- def to_dict(self) -> dict:
146
- result: dict = {}
147
- result["name"] = from_str(self.name)
148
- result["version"] = from_str(self.version)
149
- return result
150
-
151
-
152
- class HashAlgorithm(Enum):
153
- """The hash algorithm used for the checksum.
154
-
155
- Supported cryptographic hash algorithms for checksums and integrity verification.
156
- """
157
- SHA256 = "sha256"
158
- SHA384 = "sha384"
159
- SHA512 = "sha512"
160
-
161
-
162
- @dataclass
163
- class Integrity:
164
- """Cryptographic integrity information for verifying this amendments document has not been
165
- tampered with.
166
-
167
- Cryptographic integrity information for verifying the HDF file has not been tampered
168
- with. If algorithm is provided, checksum must also be provided, and vice versa.
169
- """
170
- algorithm: Optional[HashAlgorithm] = None
171
- """The hash algorithm used for the checksum."""
172
-
173
- checksum: Optional[str] = None
174
- """The checksum value."""
175
-
176
- signature: Optional[str] = None
177
- """Optional cryptographic signature."""
178
-
179
- signed_by: Optional[str] = None
180
- """Identifier of who signed this file."""
181
-
182
- @staticmethod
183
- def from_dict(obj: Any) -> 'Integrity':
184
- assert isinstance(obj, dict)
185
- algorithm = from_union([HashAlgorithm, from_none], obj.get("algorithm"))
186
- checksum = from_union([from_str, from_none], obj.get("checksum"))
187
- signature = from_union([from_str, from_none], obj.get("signature"))
188
- signed_by = from_union([from_str, from_none], obj.get("signedBy"))
189
- return Integrity(algorithm, checksum, signature, signed_by)
190
-
191
- def to_dict(self) -> dict:
192
- result: dict = {}
193
- if self.algorithm is not None:
194
- result["algorithm"] = from_union([lambda x: to_enum(HashAlgorithm, x), from_none], self.algorithm)
195
- if self.checksum is not None:
196
- result["checksum"] = from_union([from_str, from_none], self.checksum)
197
- if self.signature is not None:
198
- result["signature"] = from_union([from_str, from_none], self.signature)
199
- if self.signed_by is not None:
200
- result["signedBy"] = from_union([from_str, from_none], self.signed_by)
201
- return result
202
-
203
-
204
- class EvidenceType(Enum):
205
- """The type of evidence being provided."""
206
-
207
- CODE = "code"
208
- FILE = "file"
209
- LOG = "log"
210
- OTHER = "other"
211
- SCREENSHOT = "screenshot"
212
- URL = "url"
213
-
214
-
215
- @dataclass
216
- class Evidence:
217
- """Supporting evidence for a finding or override, such as screenshots, code samples, log
218
- excerpts, or URLs.
219
- """
220
- data: str
221
- """The evidence content. For screenshots/files: base64-encoded data or URL. For code/logs:
222
- the raw text. For URLs: the URL string.
223
- """
224
- type: EvidenceType
225
- """The type of evidence being provided."""
226
-
227
- captured_at: Optional[datetime] = None
228
- """Timestamp when this evidence was captured. ISO 8601 format."""
229
-
230
- captured_by: Optional[Identity] = None
231
- """Identity of who or what captured this evidence."""
232
-
233
- description: Optional[str] = None
234
- """Human-readable description of what this evidence shows."""
235
-
236
- encoding: Optional[str] = None
237
- """Encoding used for the data. Example: 'base64', 'utf-8'."""
238
-
239
- mime_type: Optional[str] = None
240
- """MIME type of the evidence. Example: 'image/png', 'text/plain', 'application/json'."""
241
-
242
- size: Optional[float] = None
243
- """Size of the evidence data in bytes."""
244
-
245
- @staticmethod
246
- def from_dict(obj: Any) -> 'Evidence':
247
- assert isinstance(obj, dict)
248
- data = from_str(obj.get("data"))
249
- type = EvidenceType(obj.get("type"))
250
- captured_at = from_union([from_datetime, from_none], obj.get("capturedAt"))
251
- captured_by = from_union([Identity.from_dict, from_none], obj.get("capturedBy"))
252
- description = from_union([from_str, from_none], obj.get("description"))
253
- encoding = from_union([from_str, from_none], obj.get("encoding"))
254
- mime_type = from_union([from_str, from_none], obj.get("mimeType"))
255
- size = from_union([from_float, from_none], obj.get("size"))
256
- return Evidence(data, type, captured_at, captured_by, description, encoding, mime_type, size)
257
-
258
- def to_dict(self) -> dict:
259
- result: dict = {}
260
- result["data"] = from_str(self.data)
261
- result["type"] = to_enum(EvidenceType, self.type)
262
- if self.captured_at is not None:
263
- result["capturedAt"] = from_union([lambda x: x.isoformat(), from_none], self.captured_at)
264
- if self.captured_by is not None:
265
- result["capturedBy"] = from_union([lambda x: to_class(Identity, x), from_none], self.captured_by)
266
- if self.description is not None:
267
- result["description"] = from_union([from_str, from_none], self.description)
268
- if self.encoding is not None:
269
- result["encoding"] = from_union([from_str, from_none], self.encoding)
270
- if self.mime_type is not None:
271
- result["mimeType"] = from_union([from_str, from_none], self.mime_type)
272
- if self.size is not None:
273
- result["size"] = from_union([to_float, from_none], self.size)
274
- return result
275
-
276
-
277
- class Status(Enum):
278
- """Current status of this milestone."""
279
-
280
- COMPLETED = "completed"
281
- IN_PROGRESS = "inProgress"
282
- PENDING = "pending"
283
-
284
-
285
- @dataclass
286
- class Milestone:
287
- """A milestone or task within a POA&M remediation plan."""
288
-
289
- description: str
290
- """Description of this milestone or task."""
291
-
292
- estimated_completion: datetime
293
- """Estimated completion date. ISO 8601 format."""
294
-
295
- status: Status
296
- """Current status of this milestone."""
297
-
298
- completed_at: Optional[datetime] = None
299
- """Actual completion timestamp. ISO 8601 format."""
300
-
301
- completed_by: Optional[Identity] = None
302
- """Identity of who completed this milestone."""
303
-
304
- @staticmethod
305
- def from_dict(obj: Any) -> 'Milestone':
306
- assert isinstance(obj, dict)
307
- description = from_str(obj.get("description"))
308
- estimated_completion = from_datetime(obj.get("estimatedCompletion"))
309
- status = Status(obj.get("status"))
310
- completed_at = from_union([from_datetime, from_none], obj.get("completedAt"))
311
- completed_by = from_union([Identity.from_dict, from_none], obj.get("completedBy"))
312
- return Milestone(description, estimated_completion, status, completed_at, completed_by)
313
-
314
- def to_dict(self) -> dict:
315
- result: dict = {}
316
- result["description"] = from_str(self.description)
317
- result["estimatedCompletion"] = self.estimated_completion.isoformat()
318
- result["status"] = to_enum(Status, self.status)
319
- if self.completed_at is not None:
320
- result["completedAt"] = from_union([lambda x: x.isoformat(), from_none], self.completed_at)
321
- if self.completed_by is not None:
322
- result["completedBy"] = from_union([lambda x: to_class(Identity, x), from_none], self.completed_by)
323
- return result
324
-
325
-
326
- @dataclass
327
- class Checksum:
328
- """Checksum of the prior amendment in the chain. Creates a tamper-evident linked list. Null
329
- for the first amendment.
330
-
331
- Cryptographic checksum for baseline integrity verification.
332
- """
333
- algorithm: HashAlgorithm
334
- """The hash algorithm used for the checksum."""
335
-
336
- value: str
337
- """The checksum value."""
338
-
339
- @staticmethod
340
- def from_dict(obj: Any) -> 'Checksum':
341
- assert isinstance(obj, dict)
342
- algorithm = HashAlgorithm(obj.get("algorithm"))
343
- value = from_str(obj.get("value"))
344
- return Checksum(algorithm, value)
345
-
346
- def to_dict(self) -> dict:
347
- result: dict = {}
348
- result["algorithm"] = to_enum(HashAlgorithm, self.algorithm)
349
- result["value"] = from_str(self.value)
350
- return result
351
-
352
-
353
- @dataclass
354
- class VerificationMethod:
355
- """The verification method containing the public key for signature verification.
356
-
357
- Verification method containing the public key needed to verify a digital signature.
358
- Supports multiple key formats including JWK (for RSA, EC), PEM, and Base58.
359
- """
360
- controller: str
361
- """The entity that controls this verification method. Can be a DID, URI, or other identifier."""
362
-
363
- type: str
364
- """The type of verification method. Example: 'JsonWebKey2020', 'RsaVerificationKey2018',
365
- 'Ed25519VerificationKey2020'.
366
- """
367
- public_key_base58: Optional[str] = None
368
- """Public key in Base58 format, commonly used with Ed25519 keys."""
369
-
370
- public_key_jwk: Optional[Dict[str, Any]] = None
371
- """Public key in JSON Web Key format."""
372
-
373
- public_key_pem: Optional[str] = None
374
- """Public key in PEM format. Example: '-----BEGIN PUBLIC KEY-----...-----END PUBLIC
375
- KEY-----'.
376
- """
377
-
378
- @staticmethod
379
- def from_dict(obj: Any) -> 'VerificationMethod':
380
- assert isinstance(obj, dict)
381
- controller = from_str(obj.get("controller"))
382
- type = from_str(obj.get("type"))
383
- public_key_base58 = from_union([from_str, from_none], obj.get("publicKeyBase58"))
384
- public_key_jwk = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("publicKeyJwk"))
385
- public_key_pem = from_union([from_str, from_none], obj.get("publicKeyPem"))
386
- return VerificationMethod(controller, type, public_key_base58, public_key_jwk, public_key_pem)
387
-
388
- def to_dict(self) -> dict:
389
- result: dict = {}
390
- result["controller"] = from_str(self.controller)
391
- result["type"] = from_str(self.type)
392
- if self.public_key_base58 is not None:
393
- result["publicKeyBase58"] = from_union([from_str, from_none], self.public_key_base58)
394
- if self.public_key_jwk is not None:
395
- result["publicKeyJwk"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.public_key_jwk)
396
- if self.public_key_pem is not None:
397
- result["publicKeyPem"] = from_union([from_str, from_none], self.public_key_pem)
398
- return result
399
-
400
-
401
- @dataclass
402
- class Signature:
403
- """Digital signature for non-repudiation.
404
-
405
- A digital signature following W3C Data Integrity Proofs pattern. Supports hardware
406
- security tokens (PKCS#11/PKCS#12), Yubikeys, GPG keys, passkeys, and other cryptographic
407
- signing methods via JWK, PEM, or Base58 key formats.
408
-
409
- Document-level digital signature covering all amendments.
410
- """
411
- created: datetime
412
- """When the signature was created. ISO 8601 format."""
413
-
414
- creator: Identity
415
- """The identity that created this signature."""
416
-
417
- proof_purpose: str
418
- """The purpose of this signature. Example: 'attestation', 'authentication',
419
- 'assertionMethod'.
420
- """
421
- signature_value: str
422
- """The base64-encoded or base58-encoded signature value."""
423
-
424
- type: str
425
- """The signature suite type. Example: 'JsonWebSignature2020', 'RsaSignature2018',
426
- 'Ed25519Signature2020'.
427
- """
428
- verification_method: VerificationMethod
429
- """The verification method containing the public key for signature verification."""
430
-
431
- challenge: Optional[str] = None
432
- """Challenge value from the verifier, used in challenge-response authentication."""
433
-
434
- domain: Optional[str] = None
435
- """Domain restriction for the signature, prevents cross-domain replay attacks."""
436
-
437
- nonce: Optional[str] = None
438
- """Random value to prevent replay attacks."""
439
-
440
- @staticmethod
441
- def from_dict(obj: Any) -> 'Signature':
442
- assert isinstance(obj, dict)
443
- created = from_datetime(obj.get("created"))
444
- creator = Identity.from_dict(obj.get("creator"))
445
- proof_purpose = from_str(obj.get("proofPurpose"))
446
- signature_value = from_str(obj.get("signatureValue"))
447
- type = from_str(obj.get("type"))
448
- verification_method = VerificationMethod.from_dict(obj.get("verificationMethod"))
449
- challenge = from_union([from_str, from_none], obj.get("challenge"))
450
- domain = from_union([from_str, from_none], obj.get("domain"))
451
- nonce = from_union([from_str, from_none], obj.get("nonce"))
452
- return Signature(created, creator, proof_purpose, signature_value, type, verification_method, challenge, domain, nonce)
453
-
454
- def to_dict(self) -> dict:
455
- result: dict = {}
456
- result["created"] = self.created.isoformat()
457
- result["creator"] = to_class(Identity, self.creator)
458
- result["proofPurpose"] = from_str(self.proof_purpose)
459
- result["signatureValue"] = from_str(self.signature_value)
460
- result["type"] = from_str(self.type)
461
- result["verificationMethod"] = to_class(VerificationMethod, self.verification_method)
462
- if self.challenge is not None:
463
- result["challenge"] = from_union([from_str, from_none], self.challenge)
464
- if self.domain is not None:
465
- result["domain"] = from_union([from_str, from_none], self.domain)
466
- if self.nonce is not None:
467
- result["nonce"] = from_union([from_str, from_none], self.nonce)
468
- return result
469
-
470
-
471
- class ResultStatus(Enum):
472
- """The new status this amendment sets. For POA&Ms, this is the current status (POA&Ms track
473
- work, they don't change status).
474
-
475
- The status of an individual test result. 'notApplicable' indicates the requirement does
476
- not apply to the target. 'notReviewed' indicates the requirement was not assessed (e.g.,
477
- requires manual verification).
478
- """
479
- ERROR = "error"
480
- FAILED = "failed"
481
- NOT_APPLICABLE = "notApplicable"
482
- NOT_REVIEWED = "notReviewed"
483
- PASSED = "passed"
484
-
485
-
486
- class OverrideType(Enum):
487
- """The type of amendment.
488
-
489
- The type of amendment. 'waiver': risk accepted (AO). 'attestation': manually verified
490
- (assessor). 'exception': not applicable (system owner + AO). 'poam': remediation tracked
491
- (no status change). 'inherited': control provided by another component or system
492
- (overrides to notApplicable/passed).
493
- """
494
- ATTESTATION = "attestation"
495
- EXCEPTION = "exception"
496
- INHERITED = "inherited"
497
- POAM = "poam"
498
- WAIVER = "waiver"
499
-
500
-
501
- @dataclass
502
- class StandaloneOverride:
503
- """A standalone amendment that modifies a requirement's compliance status. Extends the
504
- inline Status_Override concept with requirementId and baselineRef for use outside of
505
- results documents.
506
- """
507
- applied_at: datetime
508
- """When this amendment was applied. ISO 8601 format."""
509
-
510
- applied_by: Identity
511
- """Identity of who applied this amendment."""
512
-
513
- expires_at: datetime
514
- """When this amendment expires and must be reviewed. No permanent amendments. ISO 8601
515
- format.
516
- """
517
- reason: str
518
- """Justification for this amendment."""
519
-
520
- requirement_id: str
521
- """The ID of the requirement being amended. Must match a requirement ID in the referenced
522
- baseline.
523
- """
524
- status: ResultStatus
525
- """The new status this amendment sets. For POA&Ms, this is the current status (POA&Ms track
526
- work, they don't change status).
527
- """
528
- type: OverrideType
529
- """The type of amendment."""
530
-
531
- baseline_ref: Optional[str] = None
532
- """Name of the baseline containing the requirement. Required when the system has multiple
533
- baselines with potentially overlapping requirement IDs.
534
- """
535
- component_ref: Optional[UUID] = None
536
- """componentId of the component this amendment is scoped to. When set, the amendment only
537
- applies to the specified component. When omitted, the amendment applies system-wide.
538
- """
539
- evidence: Optional[List[Evidence]] = None
540
- """Supporting evidence (screenshots, logs, URLs, documents)."""
541
-
542
- inherited_from: Optional[UUID] = None
543
- """componentId of the local component that provides this control. Set when the provider is
544
- in the same system. Omit for external or cross-system providers; the reason field
545
- explains the source. Primarily used with type 'inherited'.
546
- """
547
- milestones: Optional[List[Milestone]] = None
548
- """Remediation milestones (primarily for POA&M type amendments)."""
549
-
550
- previous_checksum: Optional[Checksum] = None
551
- """Checksum of the prior amendment in the chain. Creates a tamper-evident linked list. Null
552
- for the first amendment.
553
- """
554
- signature: Optional[Signature] = None
555
- """Digital signature for non-repudiation."""
556
-
557
- @staticmethod
558
- def from_dict(obj: Any) -> 'StandaloneOverride':
559
- assert isinstance(obj, dict)
560
- applied_at = from_datetime(obj.get("appliedAt"))
561
- applied_by = Identity.from_dict(obj.get("appliedBy"))
562
- expires_at = from_datetime(obj.get("expiresAt"))
563
- reason = from_str(obj.get("reason"))
564
- requirement_id = from_str(obj.get("requirementId"))
565
- status = ResultStatus(obj.get("status"))
566
- type = OverrideType(obj.get("type"))
567
- baseline_ref = from_union([from_str, from_none], obj.get("baselineRef"))
568
- component_ref = from_union([lambda x: UUID(x), from_none], obj.get("componentRef"))
569
- evidence = from_union([lambda x: from_list(Evidence.from_dict, x), from_none], obj.get("evidence"))
570
- inherited_from = from_union([lambda x: UUID(x), from_none], obj.get("inheritedFrom"))
571
- milestones = from_union([lambda x: from_list(Milestone.from_dict, x), from_none], obj.get("milestones"))
572
- previous_checksum = from_union([Checksum.from_dict, from_none], obj.get("previousChecksum"))
573
- signature = from_union([Signature.from_dict, from_none], obj.get("signature"))
574
- return StandaloneOverride(applied_at, applied_by, expires_at, reason, requirement_id, status, type, baseline_ref, component_ref, evidence, inherited_from, milestones, previous_checksum, signature)
575
-
576
- def to_dict(self) -> dict:
577
- result: dict = {}
578
- result["appliedAt"] = self.applied_at.isoformat()
579
- result["appliedBy"] = to_class(Identity, self.applied_by)
580
- result["expiresAt"] = self.expires_at.isoformat()
581
- result["reason"] = from_str(self.reason)
582
- result["requirementId"] = from_str(self.requirement_id)
583
- result["status"] = to_enum(ResultStatus, self.status)
584
- result["type"] = to_enum(OverrideType, self.type)
585
- if self.baseline_ref is not None:
586
- result["baselineRef"] = from_union([from_str, from_none], self.baseline_ref)
587
- if self.component_ref is not None:
588
- result["componentRef"] = from_union([lambda x: str(x), from_none], self.component_ref)
589
- if self.evidence is not None:
590
- result["evidence"] = from_union([lambda x: from_list(lambda x: to_class(Evidence, x), x), from_none], self.evidence)
591
- if self.inherited_from is not None:
592
- result["inheritedFrom"] = from_union([lambda x: str(x), from_none], self.inherited_from)
593
- if self.milestones is not None:
594
- result["milestones"] = from_union([lambda x: from_list(lambda x: to_class(Milestone, x), x), from_none], self.milestones)
595
- if self.previous_checksum is not None:
596
- result["previousChecksum"] = from_union([lambda x: to_class(Checksum, x), from_none], self.previous_checksum)
597
- if self.signature is not None:
598
- result["signature"] = from_union([lambda x: to_class(Signature, x), from_none], self.signature)
599
- return result
600
-
601
-
602
- @dataclass
603
- class HdfAmendments:
604
- """Waivers, attestations, exceptions, and POA&Ms that modify requirement compliance status.
605
- Amendments are standalone documents that can be applied to results via merge operations.
606
- """
607
- name: str
608
- """Human-readable name for this amendments document. Example: 'Portal Q1 2026 Waivers'."""
609
-
610
- overrides: List[StandaloneOverride]
611
- """The set of amendments (waivers, attestations, exceptions, POA&Ms)."""
612
-
613
- amendment_id: Optional[UUID] = None
614
- """Unique identifier for this amendments document. Useful for cross-referencing when
615
- multiple amendment documents target the same results.
616
- """
617
- applied_by: Optional[Identity] = None
618
- """Default identity of who created this amendments document. Individual overrides may
619
- specify their own appliedBy.
620
- """
621
- approved_by: Optional[Identity] = None
622
- """Identity of the authorizing official who approved these amendments."""
623
-
624
- description: Optional[str] = None
625
- """Description of the amendments' purpose and scope."""
626
-
627
- generator: Optional[Generator] = None
628
- """Information about the tool that generated this document."""
629
-
630
- integrity: Optional[Integrity] = None
631
- """Cryptographic integrity information for verifying this amendments document has not been
632
- tampered with.
633
- """
634
- labels: Optional[Dict[str, str]] = None
635
- """Optional key-value labels for grouping and querying amendments."""
636
-
637
- signature: Optional[Signature] = None
638
- """Document-level digital signature covering all amendments."""
639
-
640
- system_ref: Optional[str] = None
641
- """URI to the hdf-system document these amendments apply to."""
642
-
643
- version: Optional[str] = None
644
- """Version of this amendments document."""
645
-
646
- @staticmethod
647
- def from_dict(obj: Any) -> 'HdfAmendments':
648
- assert isinstance(obj, dict)
649
- name = from_str(obj.get("name"))
650
- overrides = from_list(StandaloneOverride.from_dict, obj.get("overrides"))
651
- amendment_id = from_union([lambda x: UUID(x), from_none], obj.get("amendmentId"))
652
- applied_by = from_union([Identity.from_dict, from_none], obj.get("appliedBy"))
653
- approved_by = from_union([Identity.from_dict, from_none], obj.get("approvedBy"))
654
- description = from_union([from_str, from_none], obj.get("description"))
655
- generator = from_union([Generator.from_dict, from_none], obj.get("generator"))
656
- integrity = from_union([Integrity.from_dict, from_none], obj.get("integrity"))
657
- labels = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("labels"))
658
- signature = from_union([Signature.from_dict, from_none], obj.get("signature"))
659
- system_ref = from_union([from_str, from_none], obj.get("systemRef"))
660
- version = from_union([from_str, from_none], obj.get("version"))
661
- return HdfAmendments(name, overrides, amendment_id, applied_by, approved_by, description, generator, integrity, labels, signature, system_ref, version)
662
-
663
- def to_dict(self) -> dict:
664
- result: dict = {}
665
- result["name"] = from_str(self.name)
666
- result["overrides"] = from_list(lambda x: to_class(StandaloneOverride, x), self.overrides)
667
- if self.amendment_id is not None:
668
- result["amendmentId"] = from_union([lambda x: str(x), from_none], self.amendment_id)
669
- if self.applied_by is not None:
670
- result["appliedBy"] = from_union([lambda x: to_class(Identity, x), from_none], self.applied_by)
671
- if self.approved_by is not None:
672
- result["approvedBy"] = from_union([lambda x: to_class(Identity, x), from_none], self.approved_by)
673
- if self.description is not None:
674
- result["description"] = from_union([from_str, from_none], self.description)
675
- if self.generator is not None:
676
- result["generator"] = from_union([lambda x: to_class(Generator, x), from_none], self.generator)
677
- if self.integrity is not None:
678
- result["integrity"] = from_union([lambda x: to_class(Integrity, x), from_none], self.integrity)
679
- if self.labels is not None:
680
- result["labels"] = from_union([lambda x: from_dict(from_str, x), from_none], self.labels)
681
- if self.signature is not None:
682
- result["signature"] = from_union([lambda x: to_class(Signature, x), from_none], self.signature)
683
- if self.system_ref is not None:
684
- result["systemRef"] = from_union([from_str, from_none], self.system_ref)
685
- if self.version is not None:
686
- result["version"] = from_union([from_str, from_none], self.version)
687
- return result
688
-
689
-
690
- def hdf_amendments_from_dict(s: Any) -> HdfAmendments:
691
- return HdfAmendments.from_dict(s)
692
-
693
-
694
- def hdf_amendments_to_dict(x: HdfAmendments) -> Any:
695
- return to_class(HdfAmendments, x)