@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.
- package/LICENSE.md +55 -0
- package/README.md +83 -40
- package/dist/go/hdf.go +148 -104
- package/dist/index.d.ts +26 -1
- package/dist/index.js +26 -1
- package/dist/schemas/hdf-amendments.schema.json +178 -53
- package/dist/schemas/hdf-baseline.schema.json +181 -56
- package/dist/schemas/hdf-comparison.schema.json +523 -108
- package/dist/schemas/hdf-evidence-package.schema.json +175 -50
- package/dist/schemas/hdf-plan.schema.json +181 -56
- package/dist/schemas/hdf-results.schema.json +502 -87
- package/dist/schemas/hdf-system.schema.json +190 -65
- package/dist/ts/hdf-amendments.d.ts +43 -15
- package/dist/ts/hdf-amendments.js +18 -7
- package/dist/ts/hdf-amendments.ts +44 -15
- package/dist/ts/hdf-results.d.ts +91 -37
- package/dist/ts/hdf-results.js +40 -20
- package/dist/ts/hdf-results.ts +91 -36
- package/package.json +44 -45
- package/dist/python/hdf_amendments.py +0 -695
- package/dist/python/hdf_baseline.py +0 -782
- package/dist/python/hdf_comparison.py +0 -1771
- package/dist/python/hdf_evidence_package.py +0 -593
- package/dist/python/hdf_plan.py +0 -363
- package/dist/python/hdf_results.py +0 -2163
- package/dist/python/hdf_system.py +0 -904
- package/src/schemas/hdf-amendments.schema.json +0 -97
- package/src/schemas/hdf-baseline.schema.json +0 -190
- package/src/schemas/hdf-comparison.schema.json +0 -107
- package/src/schemas/hdf-evidence-package.schema.json +0 -227
- package/src/schemas/hdf-plan.schema.json +0 -92
- package/src/schemas/hdf-results.schema.json +0 -304
- package/src/schemas/hdf-system.schema.json +0 -136
- package/src/schemas/primitives/amendments.schema.json +0 -155
- package/src/schemas/primitives/common.schema.json +0 -814
- package/src/schemas/primitives/comparison.schema.json +0 -809
- package/src/schemas/primitives/component.schema.json +0 -518
- package/src/schemas/primitives/data-flow.schema.json +0 -158
- package/src/schemas/primitives/extensions.schema.json +0 -342
- package/src/schemas/primitives/parameter.schema.json +0 -128
- package/src/schemas/primitives/plan.schema.json +0 -128
- package/src/schemas/primitives/platform.schema.json +0 -32
- package/src/schemas/primitives/result.schema.json +0 -133
- package/src/schemas/primitives/runner.schema.json +0 -83
- package/src/schemas/primitives/statistics.schema.json +0 -71
- package/src/schemas/primitives/system.schema.json +0 -132
- 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)
|