@mitre/hdf-schema 3.0.0 → 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 +96 -41
- package/dist/go/hdf.go +148 -104
- package/dist/helpers.js +4 -44
- 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 -44
- 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,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)
|