@mitre/hdf-schema 3.0.1 → 3.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +55 -0
- package/README.md +83 -40
- package/dist/go/hdf.go +148 -104
- package/dist/index.d.ts +26 -1
- package/dist/index.js +26 -1
- package/dist/schemas/hdf-amendments.schema.json +178 -53
- package/dist/schemas/hdf-baseline.schema.json +181 -56
- package/dist/schemas/hdf-comparison.schema.json +523 -108
- package/dist/schemas/hdf-evidence-package.schema.json +175 -50
- package/dist/schemas/hdf-plan.schema.json +181 -56
- package/dist/schemas/hdf-results.schema.json +502 -87
- package/dist/schemas/hdf-system.schema.json +190 -65
- package/dist/ts/hdf-amendments.d.ts +43 -15
- package/dist/ts/hdf-amendments.js +18 -7
- package/dist/ts/hdf-amendments.ts +44 -15
- package/dist/ts/hdf-results.d.ts +91 -37
- package/dist/ts/hdf-results.js +40 -20
- package/dist/ts/hdf-results.ts +91 -36
- package/package.json +44 -45
- package/dist/python/hdf_amendments.py +0 -695
- package/dist/python/hdf_baseline.py +0 -782
- package/dist/python/hdf_comparison.py +0 -1771
- package/dist/python/hdf_evidence_package.py +0 -593
- package/dist/python/hdf_plan.py +0 -363
- package/dist/python/hdf_results.py +0 -2163
- package/dist/python/hdf_system.py +0 -904
- package/src/schemas/hdf-amendments.schema.json +0 -97
- package/src/schemas/hdf-baseline.schema.json +0 -190
- package/src/schemas/hdf-comparison.schema.json +0 -107
- package/src/schemas/hdf-evidence-package.schema.json +0 -227
- package/src/schemas/hdf-plan.schema.json +0 -92
- package/src/schemas/hdf-results.schema.json +0 -304
- package/src/schemas/hdf-system.schema.json +0 -136
- package/src/schemas/primitives/amendments.schema.json +0 -155
- package/src/schemas/primitives/common.schema.json +0 -814
- package/src/schemas/primitives/comparison.schema.json +0 -809
- package/src/schemas/primitives/component.schema.json +0 -518
- package/src/schemas/primitives/data-flow.schema.json +0 -158
- package/src/schemas/primitives/extensions.schema.json +0 -342
- package/src/schemas/primitives/parameter.schema.json +0 -128
- package/src/schemas/primitives/plan.schema.json +0 -128
- package/src/schemas/primitives/platform.schema.json +0 -32
- package/src/schemas/primitives/result.schema.json +0 -133
- package/src/schemas/primitives/runner.schema.json +0 -83
- package/src/schemas/primitives/statistics.schema.json +0 -71
- package/src/schemas/primitives/system.schema.json +0 -132
- package/src/schemas/primitives/target.schema.json +0 -523
|
@@ -1,782 +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
|
-
|
|
5
|
-
|
|
6
|
-
T = TypeVar("T")
|
|
7
|
-
EnumT = TypeVar("EnumT", bound=Enum)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def from_str(x: Any) -> str:
|
|
11
|
-
assert isinstance(x, str)
|
|
12
|
-
return x
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def from_none(x: Any) -> Any:
|
|
16
|
-
assert x is None
|
|
17
|
-
return x
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def from_union(fs, x):
|
|
21
|
-
for f in fs:
|
|
22
|
-
try:
|
|
23
|
-
return f(x)
|
|
24
|
-
except:
|
|
25
|
-
pass
|
|
26
|
-
assert False
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
|
|
30
|
-
assert isinstance(x, list)
|
|
31
|
-
return [f(y) for y in x]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def from_float(x: Any) -> float:
|
|
35
|
-
assert isinstance(x, (float, int)) and not isinstance(x, bool)
|
|
36
|
-
return float(x)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def to_float(x: Any) -> float:
|
|
40
|
-
assert isinstance(x, (int, float))
|
|
41
|
-
return x
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def from_bool(x: Any) -> bool:
|
|
45
|
-
assert isinstance(x, bool)
|
|
46
|
-
return x
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def to_class(c: Type[T], x: Any) -> dict:
|
|
50
|
-
assert isinstance(x, c)
|
|
51
|
-
return cast(Any, x).to_dict()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def to_enum(c: Type[EnumT], x: Any) -> EnumT:
|
|
55
|
-
assert isinstance(x, c)
|
|
56
|
-
return x.value
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def from_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]:
|
|
60
|
-
assert isinstance(x, dict)
|
|
61
|
-
return { k: f(v) for (k, v) in x.items() }
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
@dataclass
|
|
65
|
-
class Dependency:
|
|
66
|
-
"""A dependency for a baseline. Can include relative paths or URLs for where to find the
|
|
67
|
-
dependency.
|
|
68
|
-
"""
|
|
69
|
-
branch: Optional[str] = None
|
|
70
|
-
"""The branch name for a git repo."""
|
|
71
|
-
|
|
72
|
-
compliance: Optional[str] = None
|
|
73
|
-
"""The 'user/profilename' attribute for an Automate server."""
|
|
74
|
-
|
|
75
|
-
git: Optional[str] = None
|
|
76
|
-
"""The location of the git repo. Example:
|
|
77
|
-
'https://github.com/my-org/ubuntu-22.04-stig-baseline.git'.
|
|
78
|
-
"""
|
|
79
|
-
name: Optional[str] = None
|
|
80
|
-
"""The name or assigned alias."""
|
|
81
|
-
|
|
82
|
-
path: Optional[str] = None
|
|
83
|
-
"""The relative path if the dependency is locally available."""
|
|
84
|
-
|
|
85
|
-
status: Optional[str] = None
|
|
86
|
-
"""The status. Should be: 'loaded', 'failed', or 'skipped'."""
|
|
87
|
-
|
|
88
|
-
status_message: Optional[str] = None
|
|
89
|
-
"""The reason for the status if it is 'failed' or 'skipped'."""
|
|
90
|
-
|
|
91
|
-
supermarket: Optional[str] = None
|
|
92
|
-
"""The 'user/profilename' attribute for a Supermarket server."""
|
|
93
|
-
|
|
94
|
-
url: Optional[str] = None
|
|
95
|
-
"""The address of the dependency."""
|
|
96
|
-
|
|
97
|
-
@staticmethod
|
|
98
|
-
def from_dict(obj: Any) -> 'Dependency':
|
|
99
|
-
assert isinstance(obj, dict)
|
|
100
|
-
branch = from_union([from_str, from_none], obj.get("branch"))
|
|
101
|
-
compliance = from_union([from_str, from_none], obj.get("compliance"))
|
|
102
|
-
git = from_union([from_str, from_none], obj.get("git"))
|
|
103
|
-
name = from_union([from_str, from_none], obj.get("name"))
|
|
104
|
-
path = from_union([from_str, from_none], obj.get("path"))
|
|
105
|
-
status = from_union([from_str, from_none], obj.get("status"))
|
|
106
|
-
status_message = from_union([from_str, from_none], obj.get("statusMessage"))
|
|
107
|
-
supermarket = from_union([from_str, from_none], obj.get("supermarket"))
|
|
108
|
-
url = from_union([from_str, from_none], obj.get("url"))
|
|
109
|
-
return Dependency(branch, compliance, git, name, path, status, status_message, supermarket, url)
|
|
110
|
-
|
|
111
|
-
def to_dict(self) -> dict:
|
|
112
|
-
result: dict = {}
|
|
113
|
-
if self.branch is not None:
|
|
114
|
-
result["branch"] = from_union([from_str, from_none], self.branch)
|
|
115
|
-
if self.compliance is not None:
|
|
116
|
-
result["compliance"] = from_union([from_str, from_none], self.compliance)
|
|
117
|
-
if self.git is not None:
|
|
118
|
-
result["git"] = from_union([from_str, from_none], self.git)
|
|
119
|
-
if self.name is not None:
|
|
120
|
-
result["name"] = from_union([from_str, from_none], self.name)
|
|
121
|
-
if self.path is not None:
|
|
122
|
-
result["path"] = from_union([from_str, from_none], self.path)
|
|
123
|
-
if self.status is not None:
|
|
124
|
-
result["status"] = from_union([from_str, from_none], self.status)
|
|
125
|
-
if self.status_message is not None:
|
|
126
|
-
result["statusMessage"] = from_union([from_str, from_none], self.status_message)
|
|
127
|
-
if self.supermarket is not None:
|
|
128
|
-
result["supermarket"] = from_union([from_str, from_none], self.supermarket)
|
|
129
|
-
if self.url is not None:
|
|
130
|
-
result["url"] = from_union([from_str, from_none], self.url)
|
|
131
|
-
return result
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
@dataclass
|
|
135
|
-
class Generator:
|
|
136
|
-
"""The tool that generated this file.
|
|
137
|
-
|
|
138
|
-
Information about the tool that generated this HDF file.
|
|
139
|
-
"""
|
|
140
|
-
name: str
|
|
141
|
-
"""The name of the software that produced this HDF file. Example: 'gosec-to-hdf'."""
|
|
142
|
-
|
|
143
|
-
version: str
|
|
144
|
-
"""The version of the tool. Example: '5.22.3'."""
|
|
145
|
-
|
|
146
|
-
@staticmethod
|
|
147
|
-
def from_dict(obj: Any) -> 'Generator':
|
|
148
|
-
assert isinstance(obj, dict)
|
|
149
|
-
name = from_str(obj.get("name"))
|
|
150
|
-
version = from_str(obj.get("version"))
|
|
151
|
-
return Generator(name, version)
|
|
152
|
-
|
|
153
|
-
def to_dict(self) -> dict:
|
|
154
|
-
result: dict = {}
|
|
155
|
-
result["name"] = from_str(self.name)
|
|
156
|
-
result["version"] = from_str(self.version)
|
|
157
|
-
return result
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
@dataclass
|
|
161
|
-
class RequirementGroup:
|
|
162
|
-
"""Describes a group of requirements, such as those defined in a single file."""
|
|
163
|
-
|
|
164
|
-
id: str
|
|
165
|
-
"""The unique identifier for the group. Example: the relative path to the file specifying
|
|
166
|
-
the requirements.
|
|
167
|
-
"""
|
|
168
|
-
requirements: List[str]
|
|
169
|
-
"""The set of requirements as specified by their ids in this group. Example: 'SV-238196'."""
|
|
170
|
-
|
|
171
|
-
title: Optional[str] = None
|
|
172
|
-
"""The title of the group - should be human readable."""
|
|
173
|
-
|
|
174
|
-
@staticmethod
|
|
175
|
-
def from_dict(obj: Any) -> 'RequirementGroup':
|
|
176
|
-
assert isinstance(obj, dict)
|
|
177
|
-
id = from_str(obj.get("id"))
|
|
178
|
-
requirements = from_list(from_str, obj.get("requirements"))
|
|
179
|
-
title = from_union([from_str, from_none], obj.get("title"))
|
|
180
|
-
return RequirementGroup(id, requirements, title)
|
|
181
|
-
|
|
182
|
-
def to_dict(self) -> dict:
|
|
183
|
-
result: dict = {}
|
|
184
|
-
result["id"] = from_str(self.id)
|
|
185
|
-
result["requirements"] = from_list(from_str, self.requirements)
|
|
186
|
-
if self.title is not None:
|
|
187
|
-
result["title"] = from_union([from_str, from_none], self.title)
|
|
188
|
-
return result
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
@dataclass
|
|
192
|
-
class InputConstraints:
|
|
193
|
-
"""Validation constraints for the input value.
|
|
194
|
-
|
|
195
|
-
Validation constraints for an input value.
|
|
196
|
-
"""
|
|
197
|
-
allowed_values: Optional[List[Any]] = None
|
|
198
|
-
"""Enumeration of permitted values."""
|
|
199
|
-
|
|
200
|
-
max: Optional[float] = None
|
|
201
|
-
"""Maximum allowed value (for Numeric inputs)."""
|
|
202
|
-
|
|
203
|
-
min: Optional[float] = None
|
|
204
|
-
"""Minimum allowed value (for Numeric inputs)."""
|
|
205
|
-
|
|
206
|
-
pattern: Optional[str] = None
|
|
207
|
-
"""Regular expression pattern the value must match (for String inputs)."""
|
|
208
|
-
|
|
209
|
-
@staticmethod
|
|
210
|
-
def from_dict(obj: Any) -> 'InputConstraints':
|
|
211
|
-
assert isinstance(obj, dict)
|
|
212
|
-
allowed_values = from_union([lambda x: from_list(lambda x: x, x), from_none], obj.get("allowedValues"))
|
|
213
|
-
max = from_union([from_float, from_none], obj.get("max"))
|
|
214
|
-
min = from_union([from_float, from_none], obj.get("min"))
|
|
215
|
-
pattern = from_union([from_str, from_none], obj.get("pattern"))
|
|
216
|
-
return InputConstraints(allowed_values, max, min, pattern)
|
|
217
|
-
|
|
218
|
-
def to_dict(self) -> dict:
|
|
219
|
-
result: dict = {}
|
|
220
|
-
if self.allowed_values is not None:
|
|
221
|
-
result["allowedValues"] = from_union([lambda x: from_list(lambda x: x, x), from_none], self.allowed_values)
|
|
222
|
-
if self.max is not None:
|
|
223
|
-
result["max"] = from_union([to_float, from_none], self.max)
|
|
224
|
-
if self.min is not None:
|
|
225
|
-
result["min"] = from_union([to_float, from_none], self.min)
|
|
226
|
-
if self.pattern is not None:
|
|
227
|
-
result["pattern"] = from_union([from_str, from_none], self.pattern)
|
|
228
|
-
return result
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
class ComparisonOperator(Enum):
|
|
232
|
-
"""The comparison operator used when evaluating this input against observed values.
|
|
233
|
-
|
|
234
|
-
Comparison operator for evaluating the input value against observed values. Numeric:
|
|
235
|
-
eq/ne/lt/le/gt/ge. String: eq/ne/contains/matches. Collection: in/notIn.
|
|
236
|
-
"""
|
|
237
|
-
CONTAINS = "contains"
|
|
238
|
-
EQ = "eq"
|
|
239
|
-
GE = "ge"
|
|
240
|
-
GT = "gt"
|
|
241
|
-
IN = "in"
|
|
242
|
-
LE = "le"
|
|
243
|
-
LT = "lt"
|
|
244
|
-
MATCHES = "matches"
|
|
245
|
-
NE = "ne"
|
|
246
|
-
NOT_IN = "notIn"
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
class InputType(Enum):
|
|
250
|
-
"""The data type of this input.
|
|
251
|
-
|
|
252
|
-
The data type of the input value. Aligns with InSpec input types.
|
|
253
|
-
"""
|
|
254
|
-
ARRAY = "Array"
|
|
255
|
-
BOOLEAN = "Boolean"
|
|
256
|
-
HASH = "Hash"
|
|
257
|
-
NUMERIC = "Numeric"
|
|
258
|
-
REGEXP = "Regexp"
|
|
259
|
-
STRING = "String"
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
@dataclass
|
|
263
|
-
class Input:
|
|
264
|
-
"""A typed input parameter that bridges governance requirements and scanner automation.
|
|
265
|
-
Inputs carry expected configuration values with type information, comparison operators,
|
|
266
|
-
and validation constraints, enabling traceability from policy through to scan results.
|
|
267
|
-
"""
|
|
268
|
-
name: str
|
|
269
|
-
"""The input name. Must be unique within a baseline or results document. Example:
|
|
270
|
-
'max_concurrent_sessions'.
|
|
271
|
-
"""
|
|
272
|
-
constraints: Optional[InputConstraints] = None
|
|
273
|
-
"""Validation constraints for the input value."""
|
|
274
|
-
|
|
275
|
-
description: Optional[str] = None
|
|
276
|
-
"""Human-readable description of what this input controls."""
|
|
277
|
-
|
|
278
|
-
operator: Optional[ComparisonOperator] = None
|
|
279
|
-
"""The comparison operator used when evaluating this input against observed values."""
|
|
280
|
-
|
|
281
|
-
required: Optional[bool] = None
|
|
282
|
-
"""Whether this input must be provided. Defaults to false if omitted."""
|
|
283
|
-
|
|
284
|
-
sensitive: Optional[bool] = None
|
|
285
|
-
"""Whether this input contains sensitive data (passwords, keys). Sensitive values should be
|
|
286
|
-
redacted in output. Defaults to false if omitted.
|
|
287
|
-
"""
|
|
288
|
-
type: Optional[InputType] = None
|
|
289
|
-
"""The data type of this input."""
|
|
290
|
-
|
|
291
|
-
value: Any
|
|
292
|
-
"""The input value. Type should match the declared type field. Accepts any JSON value."""
|
|
293
|
-
|
|
294
|
-
@staticmethod
|
|
295
|
-
def from_dict(obj: Any) -> 'Input':
|
|
296
|
-
assert isinstance(obj, dict)
|
|
297
|
-
name = from_str(obj.get("name"))
|
|
298
|
-
constraints = from_union([InputConstraints.from_dict, from_none], obj.get("constraints"))
|
|
299
|
-
description = from_union([from_str, from_none], obj.get("description"))
|
|
300
|
-
operator = from_union([ComparisonOperator, from_none], obj.get("operator"))
|
|
301
|
-
required = from_union([from_bool, from_none], obj.get("required"))
|
|
302
|
-
sensitive = from_union([from_bool, from_none], obj.get("sensitive"))
|
|
303
|
-
type = from_union([InputType, from_none], obj.get("type"))
|
|
304
|
-
value = obj.get("value")
|
|
305
|
-
return Input(name, constraints, description, operator, required, sensitive, type, value)
|
|
306
|
-
|
|
307
|
-
def to_dict(self) -> dict:
|
|
308
|
-
result: dict = {}
|
|
309
|
-
result["name"] = from_str(self.name)
|
|
310
|
-
if self.constraints is not None:
|
|
311
|
-
result["constraints"] = from_union([lambda x: to_class(InputConstraints, x), from_none], self.constraints)
|
|
312
|
-
if self.description is not None:
|
|
313
|
-
result["description"] = from_union([from_str, from_none], self.description)
|
|
314
|
-
if self.operator is not None:
|
|
315
|
-
result["operator"] = from_union([lambda x: to_enum(ComparisonOperator, x), from_none], self.operator)
|
|
316
|
-
if self.required is not None:
|
|
317
|
-
result["required"] = from_union([from_bool, from_none], self.required)
|
|
318
|
-
if self.sensitive is not None:
|
|
319
|
-
result["sensitive"] = from_union([from_bool, from_none], self.sensitive)
|
|
320
|
-
if self.type is not None:
|
|
321
|
-
result["type"] = from_union([lambda x: to_enum(InputType, x), from_none], self.type)
|
|
322
|
-
if self.value is not None:
|
|
323
|
-
result["value"] = self.value
|
|
324
|
-
return result
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
class HashAlgorithm(Enum):
|
|
328
|
-
"""The hash algorithm used for the checksum.
|
|
329
|
-
|
|
330
|
-
Supported cryptographic hash algorithms for checksums and integrity verification.
|
|
331
|
-
"""
|
|
332
|
-
SHA256 = "sha256"
|
|
333
|
-
SHA384 = "sha384"
|
|
334
|
-
SHA512 = "sha512"
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
@dataclass
|
|
338
|
-
class Integrity:
|
|
339
|
-
"""Cryptographic integrity information for verifying this baseline has not been tampered
|
|
340
|
-
with.
|
|
341
|
-
|
|
342
|
-
Cryptographic integrity information for verifying the HDF file has not been tampered
|
|
343
|
-
with. If algorithm is provided, checksum must also be provided, and vice versa.
|
|
344
|
-
"""
|
|
345
|
-
algorithm: Optional[HashAlgorithm] = None
|
|
346
|
-
"""The hash algorithm used for the checksum."""
|
|
347
|
-
|
|
348
|
-
checksum: Optional[str] = None
|
|
349
|
-
"""The checksum value."""
|
|
350
|
-
|
|
351
|
-
signature: Optional[str] = None
|
|
352
|
-
"""Optional cryptographic signature."""
|
|
353
|
-
|
|
354
|
-
signed_by: Optional[str] = None
|
|
355
|
-
"""Identifier of who signed this file."""
|
|
356
|
-
|
|
357
|
-
@staticmethod
|
|
358
|
-
def from_dict(obj: Any) -> 'Integrity':
|
|
359
|
-
assert isinstance(obj, dict)
|
|
360
|
-
algorithm = from_union([HashAlgorithm, from_none], obj.get("algorithm"))
|
|
361
|
-
checksum = from_union([from_str, from_none], obj.get("checksum"))
|
|
362
|
-
signature = from_union([from_str, from_none], obj.get("signature"))
|
|
363
|
-
signed_by = from_union([from_str, from_none], obj.get("signedBy"))
|
|
364
|
-
return Integrity(algorithm, checksum, signature, signed_by)
|
|
365
|
-
|
|
366
|
-
def to_dict(self) -> dict:
|
|
367
|
-
result: dict = {}
|
|
368
|
-
if self.algorithm is not None:
|
|
369
|
-
result["algorithm"] = from_union([lambda x: to_enum(HashAlgorithm, x), from_none], self.algorithm)
|
|
370
|
-
if self.checksum is not None:
|
|
371
|
-
result["checksum"] = from_union([from_str, from_none], self.checksum)
|
|
372
|
-
if self.signature is not None:
|
|
373
|
-
result["signature"] = from_union([from_str, from_none], self.signature)
|
|
374
|
-
if self.signed_by is not None:
|
|
375
|
-
result["signedBy"] = from_union([from_str, from_none], self.signed_by)
|
|
376
|
-
return result
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
@dataclass
|
|
380
|
-
class Checksum:
|
|
381
|
-
"""Optional cryptographic checksum for verifying the integrity of remediation resources
|
|
382
|
-
fetched from the URI. Recommended for security when referencing external automation
|
|
383
|
-
scripts.
|
|
384
|
-
|
|
385
|
-
Cryptographic checksum for baseline integrity verification.
|
|
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 Remediation:
|
|
409
|
-
"""Optional reference to automated remediation resources (Ansible playbooks, Terraform
|
|
410
|
-
scripts, etc.) for implementing the security controls defined in this baseline.
|
|
411
|
-
|
|
412
|
-
Reference to automated remediation resources for implementing security controls. Points
|
|
413
|
-
to external automation content like Ansible playbooks, Terraform scripts, or
|
|
414
|
-
vendor-provided remediation tools.
|
|
415
|
-
"""
|
|
416
|
-
uri: str
|
|
417
|
-
"""URI pointing to automated remediation resources (Ansible playbooks, Terraform scripts,
|
|
418
|
-
etc.). Examples: GitHub repository, DISA STIG Supplemental Automation Content,
|
|
419
|
-
vendor-provided scripts.
|
|
420
|
-
"""
|
|
421
|
-
checksum: Optional[Checksum] = None
|
|
422
|
-
"""Optional cryptographic checksum for verifying the integrity of remediation resources
|
|
423
|
-
fetched from the URI. Recommended for security when referencing external automation
|
|
424
|
-
scripts.
|
|
425
|
-
"""
|
|
426
|
-
|
|
427
|
-
@staticmethod
|
|
428
|
-
def from_dict(obj: Any) -> 'Remediation':
|
|
429
|
-
assert isinstance(obj, dict)
|
|
430
|
-
uri = from_str(obj.get("uri"))
|
|
431
|
-
checksum = from_union([Checksum.from_dict, from_none], obj.get("checksum"))
|
|
432
|
-
return Remediation(uri, checksum)
|
|
433
|
-
|
|
434
|
-
def to_dict(self) -> dict:
|
|
435
|
-
result: dict = {}
|
|
436
|
-
result["uri"] = from_str(self.uri)
|
|
437
|
-
if self.checksum is not None:
|
|
438
|
-
result["checksum"] = from_union([lambda x: to_class(Checksum, x), from_none], self.checksum)
|
|
439
|
-
return result
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
@dataclass
|
|
443
|
-
class Description:
|
|
444
|
-
data: str
|
|
445
|
-
"""The description text content."""
|
|
446
|
-
|
|
447
|
-
label: str
|
|
448
|
-
"""Description category. The 'default' label is required for the primary description. Common
|
|
449
|
-
labels: 'default', 'check', 'fix', 'rationale'. Tools may use custom labels.
|
|
450
|
-
"""
|
|
451
|
-
|
|
452
|
-
@staticmethod
|
|
453
|
-
def from_dict(obj: Any) -> 'Description':
|
|
454
|
-
assert isinstance(obj, dict)
|
|
455
|
-
data = from_str(obj.get("data"))
|
|
456
|
-
label = from_str(obj.get("label"))
|
|
457
|
-
return Description(data, label)
|
|
458
|
-
|
|
459
|
-
def to_dict(self) -> dict:
|
|
460
|
-
result: dict = {}
|
|
461
|
-
result["data"] = from_str(self.data)
|
|
462
|
-
result["label"] = from_str(self.label)
|
|
463
|
-
return result
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
@dataclass
|
|
467
|
-
class Reference:
|
|
468
|
-
"""A reference to an external document.
|
|
469
|
-
|
|
470
|
-
A reference using the 'ref' field.
|
|
471
|
-
|
|
472
|
-
A URL pointing at the reference.
|
|
473
|
-
|
|
474
|
-
A URI pointing at the reference.
|
|
475
|
-
"""
|
|
476
|
-
ref: Optional[Union[List[Dict[str, Any]], str]] = None
|
|
477
|
-
url: Optional[str] = None
|
|
478
|
-
uri: Optional[str] = None
|
|
479
|
-
|
|
480
|
-
@staticmethod
|
|
481
|
-
def from_dict(obj: Any) -> 'Reference':
|
|
482
|
-
assert isinstance(obj, dict)
|
|
483
|
-
ref = from_union([lambda x: from_list(lambda x: from_dict(lambda x: x, x), x), from_str, from_none], obj.get("ref"))
|
|
484
|
-
url = from_union([from_str, from_none], obj.get("url"))
|
|
485
|
-
uri = from_union([from_str, from_none], obj.get("uri"))
|
|
486
|
-
return Reference(ref, url, uri)
|
|
487
|
-
|
|
488
|
-
def to_dict(self) -> dict:
|
|
489
|
-
result: dict = {}
|
|
490
|
-
if self.ref is not None:
|
|
491
|
-
result["ref"] = from_union([lambda x: from_list(lambda x: from_dict(lambda x: x, x), x), from_str, from_none], self.ref)
|
|
492
|
-
if self.url is not None:
|
|
493
|
-
result["url"] = from_union([from_str, from_none], self.url)
|
|
494
|
-
if self.uri is not None:
|
|
495
|
-
result["uri"] = from_union([from_str, from_none], self.uri)
|
|
496
|
-
return result
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
class Severity(Enum):
|
|
500
|
-
"""Explicit severity rating. Typically derived from impact score but provided explicitly for
|
|
501
|
-
clarity.
|
|
502
|
-
|
|
503
|
-
Severity rating for a requirement. Typically derived from the numeric impact score.
|
|
504
|
-
"""
|
|
505
|
-
CRITICAL = "critical"
|
|
506
|
-
HIGH = "high"
|
|
507
|
-
INFORMATIONAL = "informational"
|
|
508
|
-
LOW = "low"
|
|
509
|
-
MEDIUM = "medium"
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
@dataclass
|
|
513
|
-
class SourceLocation:
|
|
514
|
-
"""The explicit location of the requirement within the source code.
|
|
515
|
-
|
|
516
|
-
The explicit location of a requirement within source code.
|
|
517
|
-
"""
|
|
518
|
-
line: Optional[float] = None
|
|
519
|
-
"""The line on which this requirement is located."""
|
|
520
|
-
|
|
521
|
-
ref: Optional[str] = None
|
|
522
|
-
"""Path to the file that this requirement originates from."""
|
|
523
|
-
|
|
524
|
-
@staticmethod
|
|
525
|
-
def from_dict(obj: Any) -> 'SourceLocation':
|
|
526
|
-
assert isinstance(obj, dict)
|
|
527
|
-
line = from_union([from_float, from_none], obj.get("line"))
|
|
528
|
-
ref = from_union([from_str, from_none], obj.get("ref"))
|
|
529
|
-
return SourceLocation(line, ref)
|
|
530
|
-
|
|
531
|
-
def to_dict(self) -> dict:
|
|
532
|
-
result: dict = {}
|
|
533
|
-
if self.line is not None:
|
|
534
|
-
result["line"] = from_union([to_float, from_none], self.line)
|
|
535
|
-
if self.ref is not None:
|
|
536
|
-
result["ref"] = from_union([from_str, from_none], self.ref)
|
|
537
|
-
return result
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
@dataclass
|
|
541
|
-
class BaselineRequirement:
|
|
542
|
-
"""A requirement definition without assessment results.
|
|
543
|
-
|
|
544
|
-
Core requirement fields shared between baseline requirements and evaluated requirements.
|
|
545
|
-
Contains the fundamental requirement definition without assessment results.
|
|
546
|
-
"""
|
|
547
|
-
descriptions: List[Description]
|
|
548
|
-
"""Array of labeled descriptions. At least one description with label 'default' must be
|
|
549
|
-
present. Convention: place default description first. Common labels: 'default', 'check',
|
|
550
|
-
'fix', 'rationale'.
|
|
551
|
-
"""
|
|
552
|
-
id: str
|
|
553
|
-
"""The requirement identifier. Example: 'SV-238196'."""
|
|
554
|
-
|
|
555
|
-
impact: float
|
|
556
|
-
"""The impactfulness or severity (0.0 to 1.0)."""
|
|
557
|
-
|
|
558
|
-
tags: Dict[str, Any]
|
|
559
|
-
"""A set of tags - usually metadata like CCI, STIG ID, severity."""
|
|
560
|
-
|
|
561
|
-
severity: Optional[Severity] = None
|
|
562
|
-
"""Explicit severity rating. Typically derived from impact score but provided explicitly for
|
|
563
|
-
clarity.
|
|
564
|
-
"""
|
|
565
|
-
code: Optional[str] = None
|
|
566
|
-
"""The raw source code of the requirement. Set to null for manual-only requirements or
|
|
567
|
-
requirements not yet implemented. Note that if this is an overlay, it does not include
|
|
568
|
-
the underlying source code.
|
|
569
|
-
"""
|
|
570
|
-
refs: Optional[List[Reference]] = None
|
|
571
|
-
"""The set of references to external documents."""
|
|
572
|
-
|
|
573
|
-
source_location: Optional[SourceLocation] = None
|
|
574
|
-
"""The explicit location of the requirement within the source code."""
|
|
575
|
-
|
|
576
|
-
title: Optional[str] = None
|
|
577
|
-
"""The title - is nullable."""
|
|
578
|
-
|
|
579
|
-
@staticmethod
|
|
580
|
-
def from_dict(obj: Any) -> 'BaselineRequirement':
|
|
581
|
-
assert isinstance(obj, dict)
|
|
582
|
-
descriptions = from_list(Description.from_dict, obj.get("descriptions"))
|
|
583
|
-
id = from_str(obj.get("id"))
|
|
584
|
-
impact = from_float(obj.get("impact"))
|
|
585
|
-
tags = from_dict(lambda x: x, obj.get("tags"))
|
|
586
|
-
severity = from_union([Severity, from_none], obj.get("severity"))
|
|
587
|
-
code = from_union([from_str, from_none], obj.get("code"))
|
|
588
|
-
refs = from_union([lambda x: from_list(Reference.from_dict, x), from_none], obj.get("refs"))
|
|
589
|
-
source_location = from_union([SourceLocation.from_dict, from_none], obj.get("sourceLocation"))
|
|
590
|
-
title = from_union([from_str, from_none], obj.get("title"))
|
|
591
|
-
return BaselineRequirement(descriptions, id, impact, tags, severity, code, refs, source_location, title)
|
|
592
|
-
|
|
593
|
-
def to_dict(self) -> dict:
|
|
594
|
-
result: dict = {}
|
|
595
|
-
result["descriptions"] = from_list(lambda x: to_class(Description, x), self.descriptions)
|
|
596
|
-
result["id"] = from_str(self.id)
|
|
597
|
-
result["impact"] = to_float(self.impact)
|
|
598
|
-
result["tags"] = from_dict(lambda x: x, self.tags)
|
|
599
|
-
if self.severity is not None:
|
|
600
|
-
result["severity"] = from_union([lambda x: to_enum(Severity, x), from_none], self.severity)
|
|
601
|
-
if self.code is not None:
|
|
602
|
-
result["code"] = from_union([from_str, from_none], self.code)
|
|
603
|
-
if self.refs is not None:
|
|
604
|
-
result["refs"] = from_union([lambda x: from_list(lambda x: to_class(Reference, x), x), from_none], self.refs)
|
|
605
|
-
if self.source_location is not None:
|
|
606
|
-
result["sourceLocation"] = from_union([lambda x: to_class(SourceLocation, x), from_none], self.source_location)
|
|
607
|
-
if self.title is not None:
|
|
608
|
-
result["title"] = from_union([from_str, from_none], self.title)
|
|
609
|
-
return result
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
@dataclass
|
|
613
|
-
class SupportedPlatform:
|
|
614
|
-
"""A supported platform target. Example: the platform name being 'ubuntu'."""
|
|
615
|
-
|
|
616
|
-
platform: Optional[str] = None
|
|
617
|
-
"""The location of the platform. Can be: 'os', 'aws', 'azure', or 'gcp'."""
|
|
618
|
-
|
|
619
|
-
platform_family: Optional[str] = None
|
|
620
|
-
"""The platform family. Example: 'redhat'."""
|
|
621
|
-
|
|
622
|
-
platform_name: Optional[str] = None
|
|
623
|
-
"""The platform name - can include wildcards. Example: 'debian'."""
|
|
624
|
-
|
|
625
|
-
release: Optional[str] = None
|
|
626
|
-
"""The release of the platform. Example: '20.04' for 'ubuntu'."""
|
|
627
|
-
|
|
628
|
-
@staticmethod
|
|
629
|
-
def from_dict(obj: Any) -> 'SupportedPlatform':
|
|
630
|
-
assert isinstance(obj, dict)
|
|
631
|
-
platform = from_union([from_str, from_none], obj.get("platform"))
|
|
632
|
-
platform_family = from_union([from_str, from_none], obj.get("platformFamily"))
|
|
633
|
-
platform_name = from_union([from_str, from_none], obj.get("platformName"))
|
|
634
|
-
release = from_union([from_str, from_none], obj.get("release"))
|
|
635
|
-
return SupportedPlatform(platform, platform_family, platform_name, release)
|
|
636
|
-
|
|
637
|
-
def to_dict(self) -> dict:
|
|
638
|
-
result: dict = {}
|
|
639
|
-
if self.platform is not None:
|
|
640
|
-
result["platform"] = from_union([from_str, from_none], self.platform)
|
|
641
|
-
if self.platform_family is not None:
|
|
642
|
-
result["platformFamily"] = from_union([from_str, from_none], self.platform_family)
|
|
643
|
-
if self.platform_name is not None:
|
|
644
|
-
result["platformName"] = from_union([from_str, from_none], self.platform_name)
|
|
645
|
-
if self.release is not None:
|
|
646
|
-
result["release"] = from_union([from_str, from_none], self.release)
|
|
647
|
-
return result
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
@dataclass
|
|
651
|
-
class HdfBaseline:
|
|
652
|
-
"""Information on the set of requirements that can be assessed, including baseline metadata
|
|
653
|
-
and requirement definitions.
|
|
654
|
-
|
|
655
|
-
Shared metadata fields for baselines. Used in both standalone baseline documents and
|
|
656
|
-
evaluated baseline results.
|
|
657
|
-
"""
|
|
658
|
-
requirements: List[BaselineRequirement]
|
|
659
|
-
"""The set of requirements - contains no findings as the assessment has not yet occurred."""
|
|
660
|
-
|
|
661
|
-
name: str
|
|
662
|
-
"""The name - must be unique."""
|
|
663
|
-
|
|
664
|
-
depends: Optional[List[Dependency]] = None
|
|
665
|
-
"""The set of dependencies this baseline depends on."""
|
|
666
|
-
|
|
667
|
-
generator: Optional[Generator] = None
|
|
668
|
-
"""The tool that generated this file."""
|
|
669
|
-
|
|
670
|
-
groups: Optional[List[RequirementGroup]] = None
|
|
671
|
-
"""A set of descriptions for the requirement groups."""
|
|
672
|
-
|
|
673
|
-
inputs: Optional[List[Input]] = None
|
|
674
|
-
"""The input(s) or attribute(s) to be used in the run."""
|
|
675
|
-
|
|
676
|
-
integrity: Optional[Integrity] = None
|
|
677
|
-
"""Cryptographic integrity information for verifying this baseline has not been tampered
|
|
678
|
-
with.
|
|
679
|
-
"""
|
|
680
|
-
remediation: Optional[Remediation] = None
|
|
681
|
-
"""Optional reference to automated remediation resources (Ansible playbooks, Terraform
|
|
682
|
-
scripts, etc.) for implementing the security controls defined in this baseline.
|
|
683
|
-
"""
|
|
684
|
-
copyright: Optional[str] = None
|
|
685
|
-
"""The copyright holder(s)."""
|
|
686
|
-
|
|
687
|
-
copyright_email: Optional[str] = None
|
|
688
|
-
"""The email address or other contact information of the copyright holder(s)."""
|
|
689
|
-
|
|
690
|
-
labels: Optional[Dict[str, str]] = None
|
|
691
|
-
"""Optional key-value labels for flexible grouping. Well-known keys: system, component,
|
|
692
|
-
environment, region, team. Values must be strings.
|
|
693
|
-
"""
|
|
694
|
-
license: Optional[str] = None
|
|
695
|
-
"""The copyright license. Example: 'Apache-2.0'."""
|
|
696
|
-
|
|
697
|
-
maintainer: Optional[str] = None
|
|
698
|
-
"""The maintainer(s)."""
|
|
699
|
-
|
|
700
|
-
status: Optional[str] = None
|
|
701
|
-
"""The status. Example: 'loaded'."""
|
|
702
|
-
|
|
703
|
-
summary: Optional[str] = None
|
|
704
|
-
"""The summary. Example: the Security Technical Implementation Guide (STIG) header."""
|
|
705
|
-
|
|
706
|
-
supports: Optional[List[SupportedPlatform]] = None
|
|
707
|
-
"""The set of supported platform targets."""
|
|
708
|
-
|
|
709
|
-
title: Optional[str] = None
|
|
710
|
-
"""The title - should be human readable."""
|
|
711
|
-
|
|
712
|
-
version: Optional[str] = None
|
|
713
|
-
"""The version of the baseline."""
|
|
714
|
-
|
|
715
|
-
@staticmethod
|
|
716
|
-
def from_dict(obj: Any) -> 'HdfBaseline':
|
|
717
|
-
assert isinstance(obj, dict)
|
|
718
|
-
requirements = from_list(BaselineRequirement.from_dict, obj.get("requirements"))
|
|
719
|
-
name = from_str(obj.get("name"))
|
|
720
|
-
depends = from_union([lambda x: from_list(Dependency.from_dict, x), from_none], obj.get("depends"))
|
|
721
|
-
generator = from_union([Generator.from_dict, from_none], obj.get("generator"))
|
|
722
|
-
groups = from_union([lambda x: from_list(RequirementGroup.from_dict, x), from_none], obj.get("groups"))
|
|
723
|
-
inputs = from_union([lambda x: from_list(Input.from_dict, x), from_none], obj.get("inputs"))
|
|
724
|
-
integrity = from_union([Integrity.from_dict, from_none], obj.get("integrity"))
|
|
725
|
-
remediation = from_union([Remediation.from_dict, from_none], obj.get("remediation"))
|
|
726
|
-
copyright = from_union([from_str, from_none], obj.get("copyright"))
|
|
727
|
-
copyright_email = from_union([from_str, from_none], obj.get("copyrightEmail"))
|
|
728
|
-
labels = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("labels"))
|
|
729
|
-
license = from_union([from_str, from_none], obj.get("license"))
|
|
730
|
-
maintainer = from_union([from_str, from_none], obj.get("maintainer"))
|
|
731
|
-
status = from_union([from_str, from_none], obj.get("status"))
|
|
732
|
-
summary = from_union([from_str, from_none], obj.get("summary"))
|
|
733
|
-
supports = from_union([lambda x: from_list(SupportedPlatform.from_dict, x), from_none], obj.get("supports"))
|
|
734
|
-
title = from_union([from_str, from_none], obj.get("title"))
|
|
735
|
-
version = from_union([from_str, from_none], obj.get("version"))
|
|
736
|
-
return HdfBaseline(requirements, name, depends, generator, groups, inputs, integrity, remediation, copyright, copyright_email, labels, license, maintainer, status, summary, supports, title, version)
|
|
737
|
-
|
|
738
|
-
def to_dict(self) -> dict:
|
|
739
|
-
result: dict = {}
|
|
740
|
-
result["requirements"] = from_list(lambda x: to_class(BaselineRequirement, x), self.requirements)
|
|
741
|
-
result["name"] = from_str(self.name)
|
|
742
|
-
if self.depends is not None:
|
|
743
|
-
result["depends"] = from_union([lambda x: from_list(lambda x: to_class(Dependency, x), x), from_none], self.depends)
|
|
744
|
-
if self.generator is not None:
|
|
745
|
-
result["generator"] = from_union([lambda x: to_class(Generator, x), from_none], self.generator)
|
|
746
|
-
if self.groups is not None:
|
|
747
|
-
result["groups"] = from_union([lambda x: from_list(lambda x: to_class(RequirementGroup, x), x), from_none], self.groups)
|
|
748
|
-
if self.inputs is not None:
|
|
749
|
-
result["inputs"] = from_union([lambda x: from_list(lambda x: to_class(Input, x), x), from_none], self.inputs)
|
|
750
|
-
if self.integrity is not None:
|
|
751
|
-
result["integrity"] = from_union([lambda x: to_class(Integrity, x), from_none], self.integrity)
|
|
752
|
-
if self.remediation is not None:
|
|
753
|
-
result["remediation"] = from_union([lambda x: to_class(Remediation, x), from_none], self.remediation)
|
|
754
|
-
if self.copyright is not None:
|
|
755
|
-
result["copyright"] = from_union([from_str, from_none], self.copyright)
|
|
756
|
-
if self.copyright_email is not None:
|
|
757
|
-
result["copyrightEmail"] = from_union([from_str, from_none], self.copyright_email)
|
|
758
|
-
if self.labels is not None:
|
|
759
|
-
result["labels"] = from_union([lambda x: from_dict(from_str, x), from_none], self.labels)
|
|
760
|
-
if self.license is not None:
|
|
761
|
-
result["license"] = from_union([from_str, from_none], self.license)
|
|
762
|
-
if self.maintainer is not None:
|
|
763
|
-
result["maintainer"] = from_union([from_str, from_none], self.maintainer)
|
|
764
|
-
if self.status is not None:
|
|
765
|
-
result["status"] = from_union([from_str, from_none], self.status)
|
|
766
|
-
if self.summary is not None:
|
|
767
|
-
result["summary"] = from_union([from_str, from_none], self.summary)
|
|
768
|
-
if self.supports is not None:
|
|
769
|
-
result["supports"] = from_union([lambda x: from_list(lambda x: to_class(SupportedPlatform, x), x), from_none], self.supports)
|
|
770
|
-
if self.title is not None:
|
|
771
|
-
result["title"] = from_union([from_str, from_none], self.title)
|
|
772
|
-
if self.version is not None:
|
|
773
|
-
result["version"] = from_union([from_str, from_none], self.version)
|
|
774
|
-
return result
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
def hdf_baseline_from_dict(s: Any) -> HdfBaseline:
|
|
778
|
-
return HdfBaseline.from_dict(s)
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
def hdf_baseline_to_dict(x: HdfBaseline) -> Any:
|
|
782
|
-
return to_class(HdfBaseline, x)
|