forked from ChelseaKR/oscal-validate
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstructure.py
More file actions
120 lines (107 loc) · 4.19 KB
/
Copy pathstructure.py
File metadata and controls
120 lines (107 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""Check 1: the document's shape against the vendored JSON Schema.
The schema is the least interesting layer of OSCAL and the one every tool
already checks, so this exists mainly because the walk that produces it is what
tells every other check what a value *is*. Required properties, properties the
schema forbids, JSON type mismatches, and objects no declared alternative
accepts fall out of that walk for free.
The last finding here is the important one: where the walk could not descend,
it says so. An unread subtree is reported UNVERIFIABLE rather than counted as
clean.
"""
from __future__ import annotations
from .. import rules
from ..findings import Finding, Severity
from ..session import Session
def check(session: Session) -> list[Finding]:
walked = session.corpus.primary.walked
findings: list[Finding] = []
for note in walked.missing:
findings.append(
Finding(
code="REQUIRED_PROPERTY_MISSING",
severity=Severity.ERROR,
location=note.pointer,
prop=note.name,
value="(absent)",
message=(
f"{note.detail} requires a {note.name!r} property and this one does "
"not have it."
),
rule=rules.required_property_rule(note.detail, note.name),
)
)
for note in walked.undeclared:
findings.append(
Finding(
code="PROPERTY_UNDECLARED",
severity=Severity.ERROR,
location=note.pointer,
prop=note.name,
value="(present)",
message=(
f"{note.detail} does not declare a property named {note.name!r}, and "
"the schema forbids any property it does not declare. Either the name "
"is a typo or the document was authored against a different OSCAL "
"release than the one vendored here."
),
rule=rules.undeclared_property_rule(note.detail, note.name),
)
)
for note in walked.no_branch:
findings.append(
Finding(
code="NO_SCHEMA_ALTERNATIVE",
severity=Severity.ERROR,
location=note.pointer,
prop=note.name,
value="(object)",
message=note.detail,
rule=rules.no_alternative_rule(note.name),
)
)
for short in walked.short:
findings.append(
Finding(
code="ARRAY_TOO_SHORT",
severity=Severity.ERROR,
location=short.pointer,
prop=short.name,
value=f"{short.found} item(s)",
message=(
f"The schema requires at least {short.minimum} item(s) in "
f"{short.name!r}, and this array has {short.found}. An array present "
"but empty is not the same as the property being absent, and the "
"schema permits only the second."
),
rule=rules.min_items_rule(short.name, short.minimum),
)
)
for note in walked.mistyped:
findings.append(
Finding(
code="TYPE_MISMATCH",
severity=Severity.ERROR,
location=note.pointer,
prop=note.name,
value="(wrong JSON type)",
message=note.detail,
rule=rules.type_rule(note.name, note.detail.split("'")[1]),
)
)
for note in walked.unwalked:
findings.append(
Finding(
code="SUBTREE_NOT_READ",
severity=Severity.UNVERIFIABLE,
location=note.pointer,
prop=note.name,
value="(not read)",
message=(
f"This subtree was not read: {note.detail}. Nothing below it has been "
"checked by any rule in this tool, and it is reported rather than "
"passed over."
),
rule=rules.NOT_WALKED_POLICY,
)
)
return findings