@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
package/dist/python/hdf_plan.py
DELETED
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from typing import Optional, Any, Dict, List, TypeVar, Callable, Type, cast
|
|
3
|
-
from uuid import UUID
|
|
4
|
-
from enum import Enum
|
|
5
|
-
from datetime import datetime
|
|
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_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]:
|
|
33
|
-
assert isinstance(x, dict)
|
|
34
|
-
return { k: f(v) for (k, v) in x.items() }
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def to_class(c: Type[T], x: Any) -> dict:
|
|
38
|
-
assert isinstance(x, c)
|
|
39
|
-
return cast(Any, x).to_dict()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def to_enum(c: Type[EnumT], x: Any) -> EnumT:
|
|
43
|
-
assert isinstance(x, c)
|
|
44
|
-
return x.value
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def from_datetime(x: Any) -> datetime:
|
|
48
|
-
return dateutil.parser.parse(x)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
|
|
52
|
-
assert isinstance(x, list)
|
|
53
|
-
return [f(y) for y in x]
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@dataclass
|
|
57
|
-
class RunnerConfig:
|
|
58
|
-
"""Runner/scanner configuration for this assessment.
|
|
59
|
-
|
|
60
|
-
Configuration for the assessment runner/scanner.
|
|
61
|
-
"""
|
|
62
|
-
name: Optional[str] = None
|
|
63
|
-
"""Name of the assessment runner. Example: 'cinc-auditor', 'inspec', 'openscap'."""
|
|
64
|
-
|
|
65
|
-
version: Optional[str] = None
|
|
66
|
-
"""Version of the runner."""
|
|
67
|
-
|
|
68
|
-
@staticmethod
|
|
69
|
-
def from_dict(obj: Any) -> 'RunnerConfig':
|
|
70
|
-
assert isinstance(obj, dict)
|
|
71
|
-
name = from_union([from_str, from_none], obj.get("name"))
|
|
72
|
-
version = from_union([from_str, from_none], obj.get("version"))
|
|
73
|
-
return RunnerConfig(name, version)
|
|
74
|
-
|
|
75
|
-
def to_dict(self) -> dict:
|
|
76
|
-
result: dict = {}
|
|
77
|
-
if self.name is not None:
|
|
78
|
-
result["name"] = from_union([from_str, from_none], self.name)
|
|
79
|
-
if self.version is not None:
|
|
80
|
-
result["version"] = from_union([from_str, from_none], self.version)
|
|
81
|
-
return result
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@dataclass
|
|
85
|
-
class Assessment:
|
|
86
|
-
"""A single assessment within a plan — defines which baseline to run against which targets
|
|
87
|
-
with what configuration.
|
|
88
|
-
"""
|
|
89
|
-
baseline_ref: str
|
|
90
|
-
"""Reference to the baseline to evaluate. May be a baseline name (e.g. 'RHEL9-STIG'), a
|
|
91
|
-
relative path to an HDF Baseline document (e.g. 'rhel9-stig.hdf-baseline.json'), or an
|
|
92
|
-
absolute URI.
|
|
93
|
-
"""
|
|
94
|
-
component_ref: Optional[UUID] = None
|
|
95
|
-
"""componentId of the system component this assessment targets. Use for direct component
|
|
96
|
-
binding. Alternative to targetSelector.
|
|
97
|
-
"""
|
|
98
|
-
description: Optional[str] = None
|
|
99
|
-
"""Description of this assessment's purpose."""
|
|
100
|
-
|
|
101
|
-
inputs: Optional[Dict[str, Any]] = None
|
|
102
|
-
"""Resolved input values for this assessment. Keys are input names, values are the final
|
|
103
|
-
resolved values (after baseline defaults + system overrides).
|
|
104
|
-
"""
|
|
105
|
-
runner: Optional[RunnerConfig] = None
|
|
106
|
-
"""Runner/scanner configuration for this assessment."""
|
|
107
|
-
|
|
108
|
-
target_selector: Optional[Dict[str, str]] = None
|
|
109
|
-
"""Label selector to match targets for this assessment. Overrides the system component's
|
|
110
|
-
targetSelector if provided.
|
|
111
|
-
"""
|
|
112
|
-
|
|
113
|
-
@staticmethod
|
|
114
|
-
def from_dict(obj: Any) -> 'Assessment':
|
|
115
|
-
assert isinstance(obj, dict)
|
|
116
|
-
baseline_ref = from_str(obj.get("baselineRef"))
|
|
117
|
-
component_ref = from_union([lambda x: UUID(x), from_none], obj.get("componentRef"))
|
|
118
|
-
description = from_union([from_str, from_none], obj.get("description"))
|
|
119
|
-
inputs = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("inputs"))
|
|
120
|
-
runner = from_union([RunnerConfig.from_dict, from_none], obj.get("runner"))
|
|
121
|
-
target_selector = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("targetSelector"))
|
|
122
|
-
return Assessment(baseline_ref, component_ref, description, inputs, runner, target_selector)
|
|
123
|
-
|
|
124
|
-
def to_dict(self) -> dict:
|
|
125
|
-
result: dict = {}
|
|
126
|
-
result["baselineRef"] = from_str(self.baseline_ref)
|
|
127
|
-
if self.component_ref is not None:
|
|
128
|
-
result["componentRef"] = from_union([lambda x: str(x), from_none], self.component_ref)
|
|
129
|
-
if self.description is not None:
|
|
130
|
-
result["description"] = from_union([from_str, from_none], self.description)
|
|
131
|
-
if self.inputs is not None:
|
|
132
|
-
result["inputs"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.inputs)
|
|
133
|
-
if self.runner is not None:
|
|
134
|
-
result["runner"] = from_union([lambda x: to_class(RunnerConfig, x), from_none], self.runner)
|
|
135
|
-
if self.target_selector is not None:
|
|
136
|
-
result["targetSelector"] = from_union([lambda x: from_dict(from_str, x), from_none], self.target_selector)
|
|
137
|
-
return result
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@dataclass
|
|
141
|
-
class Generator:
|
|
142
|
-
"""Information about the tool that generated this plan.
|
|
143
|
-
|
|
144
|
-
Information about the tool that generated this HDF file.
|
|
145
|
-
"""
|
|
146
|
-
name: str
|
|
147
|
-
"""The name of the software that produced this HDF file. Example: 'gosec-to-hdf'."""
|
|
148
|
-
|
|
149
|
-
version: str
|
|
150
|
-
"""The version of the tool. Example: '5.22.3'."""
|
|
151
|
-
|
|
152
|
-
@staticmethod
|
|
153
|
-
def from_dict(obj: Any) -> 'Generator':
|
|
154
|
-
assert isinstance(obj, dict)
|
|
155
|
-
name = from_str(obj.get("name"))
|
|
156
|
-
version = from_str(obj.get("version"))
|
|
157
|
-
return Generator(name, version)
|
|
158
|
-
|
|
159
|
-
def to_dict(self) -> dict:
|
|
160
|
-
result: dict = {}
|
|
161
|
-
result["name"] = from_str(self.name)
|
|
162
|
-
result["version"] = from_str(self.version)
|
|
163
|
-
return result
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
class HashAlgorithm(Enum):
|
|
167
|
-
"""The hash algorithm used for the checksum.
|
|
168
|
-
|
|
169
|
-
Supported cryptographic hash algorithms for checksums and integrity verification.
|
|
170
|
-
"""
|
|
171
|
-
SHA256 = "sha256"
|
|
172
|
-
SHA384 = "sha384"
|
|
173
|
-
SHA512 = "sha512"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
@dataclass
|
|
177
|
-
class Integrity:
|
|
178
|
-
"""Cryptographic integrity information for verifying this plan document has not been
|
|
179
|
-
tampered with.
|
|
180
|
-
|
|
181
|
-
Cryptographic integrity information for verifying the HDF file has not been tampered
|
|
182
|
-
with. If algorithm is provided, checksum must also be provided, and vice versa.
|
|
183
|
-
"""
|
|
184
|
-
algorithm: Optional[HashAlgorithm] = None
|
|
185
|
-
"""The hash algorithm used for the checksum."""
|
|
186
|
-
|
|
187
|
-
checksum: Optional[str] = None
|
|
188
|
-
"""The checksum value."""
|
|
189
|
-
|
|
190
|
-
signature: Optional[str] = None
|
|
191
|
-
"""Optional cryptographic signature."""
|
|
192
|
-
|
|
193
|
-
signed_by: Optional[str] = None
|
|
194
|
-
"""Identifier of who signed this file."""
|
|
195
|
-
|
|
196
|
-
@staticmethod
|
|
197
|
-
def from_dict(obj: Any) -> 'Integrity':
|
|
198
|
-
assert isinstance(obj, dict)
|
|
199
|
-
algorithm = from_union([HashAlgorithm, from_none], obj.get("algorithm"))
|
|
200
|
-
checksum = from_union([from_str, from_none], obj.get("checksum"))
|
|
201
|
-
signature = from_union([from_str, from_none], obj.get("signature"))
|
|
202
|
-
signed_by = from_union([from_str, from_none], obj.get("signedBy"))
|
|
203
|
-
return Integrity(algorithm, checksum, signature, signed_by)
|
|
204
|
-
|
|
205
|
-
def to_dict(self) -> dict:
|
|
206
|
-
result: dict = {}
|
|
207
|
-
if self.algorithm is not None:
|
|
208
|
-
result["algorithm"] = from_union([lambda x: to_enum(HashAlgorithm, x), from_none], self.algorithm)
|
|
209
|
-
if self.checksum is not None:
|
|
210
|
-
result["checksum"] = from_union([from_str, from_none], self.checksum)
|
|
211
|
-
if self.signature is not None:
|
|
212
|
-
result["signature"] = from_union([from_str, from_none], self.signature)
|
|
213
|
-
if self.signed_by is not None:
|
|
214
|
-
result["signedBy"] = from_union([from_str, from_none], self.signed_by)
|
|
215
|
-
return result
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
@dataclass
|
|
219
|
-
class Schedule:
|
|
220
|
-
"""Optional scheduling configuration for recurring assessments.
|
|
221
|
-
|
|
222
|
-
Scheduling configuration for recurring assessments.
|
|
223
|
-
"""
|
|
224
|
-
cron: Optional[str] = None
|
|
225
|
-
"""Cron expression for recurring assessments. Example: '0 2 1 * *' (2 AM on the 1st of each
|
|
226
|
-
month).
|
|
227
|
-
"""
|
|
228
|
-
end_date: Optional[datetime] = None
|
|
229
|
-
"""Date after which assessments should no longer run. ISO 8601 format."""
|
|
230
|
-
|
|
231
|
-
notify_on_completion: Optional[List[str]] = None
|
|
232
|
-
"""Email addresses or notification endpoints to alert when assessments complete."""
|
|
233
|
-
|
|
234
|
-
notify_on_regression: Optional[List[str]] = None
|
|
235
|
-
"""Email addresses or notification endpoints to alert when regressions are detected."""
|
|
236
|
-
|
|
237
|
-
start_date: Optional[datetime] = None
|
|
238
|
-
"""Earliest date to begin assessments. ISO 8601 format."""
|
|
239
|
-
|
|
240
|
-
@staticmethod
|
|
241
|
-
def from_dict(obj: Any) -> 'Schedule':
|
|
242
|
-
assert isinstance(obj, dict)
|
|
243
|
-
cron = from_union([from_str, from_none], obj.get("cron"))
|
|
244
|
-
end_date = from_union([from_datetime, from_none], obj.get("endDate"))
|
|
245
|
-
notify_on_completion = from_union([lambda x: from_list(from_str, x), from_none], obj.get("notifyOnCompletion"))
|
|
246
|
-
notify_on_regression = from_union([lambda x: from_list(from_str, x), from_none], obj.get("notifyOnRegression"))
|
|
247
|
-
start_date = from_union([from_datetime, from_none], obj.get("startDate"))
|
|
248
|
-
return Schedule(cron, end_date, notify_on_completion, notify_on_regression, start_date)
|
|
249
|
-
|
|
250
|
-
def to_dict(self) -> dict:
|
|
251
|
-
result: dict = {}
|
|
252
|
-
if self.cron is not None:
|
|
253
|
-
result["cron"] = from_union([from_str, from_none], self.cron)
|
|
254
|
-
if self.end_date is not None:
|
|
255
|
-
result["endDate"] = from_union([lambda x: x.isoformat(), from_none], self.end_date)
|
|
256
|
-
if self.notify_on_completion is not None:
|
|
257
|
-
result["notifyOnCompletion"] = from_union([lambda x: from_list(from_str, x), from_none], self.notify_on_completion)
|
|
258
|
-
if self.notify_on_regression is not None:
|
|
259
|
-
result["notifyOnRegression"] = from_union([lambda x: from_list(from_str, x), from_none], self.notify_on_regression)
|
|
260
|
-
if self.start_date is not None:
|
|
261
|
-
result["startDate"] = from_union([lambda x: x.isoformat(), from_none], self.start_date)
|
|
262
|
-
return result
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
class PlanType(Enum):
|
|
266
|
-
"""The type of assessment plan.
|
|
267
|
-
|
|
268
|
-
The type of assessment. 'automated' for scanner-driven, 'manual' for human-performed,
|
|
269
|
-
'hybrid' for both.
|
|
270
|
-
"""
|
|
271
|
-
AUTOMATED = "automated"
|
|
272
|
-
HYBRID = "hybrid"
|
|
273
|
-
MANUAL = "manual"
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
@dataclass
|
|
277
|
-
class HdfPlan:
|
|
278
|
-
"""Defines an assessment plan — what baselines to run against which targets, with resolved
|
|
279
|
-
inputs and scheduling. Maps to OSCAL Assessment Plan.
|
|
280
|
-
"""
|
|
281
|
-
assessments: List[Assessment]
|
|
282
|
-
"""The assessments to perform. Each assessment pairs a baseline with targets and resolved
|
|
283
|
-
inputs.
|
|
284
|
-
"""
|
|
285
|
-
name: str
|
|
286
|
-
"""Human-readable plan name. Example: 'Portal Monthly Assessment'."""
|
|
287
|
-
|
|
288
|
-
description: Optional[str] = None
|
|
289
|
-
"""Description of the plan's purpose and scope."""
|
|
290
|
-
|
|
291
|
-
generator: Optional[Generator] = None
|
|
292
|
-
"""Information about the tool that generated this plan."""
|
|
293
|
-
|
|
294
|
-
integrity: Optional[Integrity] = None
|
|
295
|
-
"""Cryptographic integrity information for verifying this plan document has not been
|
|
296
|
-
tampered with.
|
|
297
|
-
"""
|
|
298
|
-
labels: Optional[Dict[str, str]] = None
|
|
299
|
-
"""Optional key-value labels for grouping and querying plans."""
|
|
300
|
-
|
|
301
|
-
plan_id: Optional[UUID] = None
|
|
302
|
-
"""Unique identifier for this plan. Optional in casual use, expected in production
|
|
303
|
-
documents. Auto-generated if omitted during creation.
|
|
304
|
-
"""
|
|
305
|
-
schedule: Optional[Schedule] = None
|
|
306
|
-
"""Optional scheduling configuration for recurring assessments."""
|
|
307
|
-
|
|
308
|
-
system_ref: Optional[str] = None
|
|
309
|
-
"""URI to the hdf-system document this plan targets. Example: 'portal-prod.hdf-system.json'."""
|
|
310
|
-
|
|
311
|
-
type: Optional[PlanType] = None
|
|
312
|
-
"""The type of assessment plan."""
|
|
313
|
-
|
|
314
|
-
version: Optional[str] = None
|
|
315
|
-
"""Version of this plan document."""
|
|
316
|
-
|
|
317
|
-
@staticmethod
|
|
318
|
-
def from_dict(obj: Any) -> 'HdfPlan':
|
|
319
|
-
assert isinstance(obj, dict)
|
|
320
|
-
assessments = from_list(Assessment.from_dict, obj.get("assessments"))
|
|
321
|
-
name = from_str(obj.get("name"))
|
|
322
|
-
description = from_union([from_str, from_none], obj.get("description"))
|
|
323
|
-
generator = from_union([Generator.from_dict, from_none], obj.get("generator"))
|
|
324
|
-
integrity = from_union([Integrity.from_dict, from_none], obj.get("integrity"))
|
|
325
|
-
labels = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("labels"))
|
|
326
|
-
plan_id = from_union([lambda x: UUID(x), from_none], obj.get("planId"))
|
|
327
|
-
schedule = from_union([Schedule.from_dict, from_none], obj.get("schedule"))
|
|
328
|
-
system_ref = from_union([from_str, from_none], obj.get("systemRef"))
|
|
329
|
-
type = from_union([PlanType, from_none], obj.get("type"))
|
|
330
|
-
version = from_union([from_str, from_none], obj.get("version"))
|
|
331
|
-
return HdfPlan(assessments, name, description, generator, integrity, labels, plan_id, schedule, system_ref, type, version)
|
|
332
|
-
|
|
333
|
-
def to_dict(self) -> dict:
|
|
334
|
-
result: dict = {}
|
|
335
|
-
result["assessments"] = from_list(lambda x: to_class(Assessment, x), self.assessments)
|
|
336
|
-
result["name"] = from_str(self.name)
|
|
337
|
-
if self.description is not None:
|
|
338
|
-
result["description"] = from_union([from_str, from_none], self.description)
|
|
339
|
-
if self.generator is not None:
|
|
340
|
-
result["generator"] = from_union([lambda x: to_class(Generator, x), from_none], self.generator)
|
|
341
|
-
if self.integrity is not None:
|
|
342
|
-
result["integrity"] = from_union([lambda x: to_class(Integrity, x), from_none], self.integrity)
|
|
343
|
-
if self.labels is not None:
|
|
344
|
-
result["labels"] = from_union([lambda x: from_dict(from_str, x), from_none], self.labels)
|
|
345
|
-
if self.plan_id is not None:
|
|
346
|
-
result["planId"] = from_union([lambda x: str(x), from_none], self.plan_id)
|
|
347
|
-
if self.schedule is not None:
|
|
348
|
-
result["schedule"] = from_union([lambda x: to_class(Schedule, x), from_none], self.schedule)
|
|
349
|
-
if self.system_ref is not None:
|
|
350
|
-
result["systemRef"] = from_union([from_str, from_none], self.system_ref)
|
|
351
|
-
if self.type is not None:
|
|
352
|
-
result["type"] = from_union([lambda x: to_enum(PlanType, x), from_none], self.type)
|
|
353
|
-
if self.version is not None:
|
|
354
|
-
result["version"] = from_union([from_str, from_none], self.version)
|
|
355
|
-
return result
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
def hdf_plan_from_dict(s: Any) -> HdfPlan:
|
|
359
|
-
return HdfPlan.from_dict(s)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
def hdf_plan_to_dict(x: HdfPlan) -> Any:
|
|
363
|
-
return to_class(HdfPlan, x)
|