forked from ChelseaKR/tods-validate
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheck_public_contract.py
More file actions
92 lines (77 loc) · 3.55 KB
/
Copy pathcheck_public_contract.py
File metadata and controls
92 lines (77 loc) · 3.55 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
"""Fail when the implementation drifts from the reviewed v1 candidate.
Every field compared here is recomputed from the implementation. Anything that
cannot be is not compared at all, because a field built out of the snapshot and
then compared to the snapshot reports a pass it did not earn: ``contractVersion``
used to be read straight out of the file it was checked against, so it could not
mismatch under any code change, and ``cliExitCodes`` was three literals retyped
inside this script rather than the numbers the CLI exits with.
"""
from __future__ import annotations
import json
from pathlib import Path
import tods_validate
import tods_validate.read
import tods_validate.testing
from tods_validate.policy import EXIT_CLEAN, EXIT_FINDINGS, EXIT_USAGE
from tods_validate.report import REPORT_SCHEMA_VERSION
from tods_validate.rules import all_rules
from tods_validate.schema import SUPPORTED_SPEC_VERSIONS
ROOT = Path(__file__).resolve().parents[1]
SNAPSHOT = ROOT / "docs" / "v1-contract-candidate.json"
REPORT_SCHEMA = ROOT / "docs" / "report.schema.json"
# In the snapshot but deliberately not recomputed: it names the snapshot rather
# than describing the implementation, so there is nothing to derive it from and
# nothing it could disagree with. main() checks it is present and non-empty.
UNCHECKED_FIELDS = ("contractVersion",)
def _actual_contract() -> dict[str, object]:
report_schema = json.loads(REPORT_SCHEMA.read_text(encoding="utf-8"))
finding_schema = report_schema["properties"]["findings"]["items"]
return {
# Read from tods_validate.policy, which is what cli.py exits with; the
# behavioral goldens for all three are in tests/test_policy.py.
"cliExitCodes": {
"clean": EXIT_CLEAN,
"findingsAtOrAboveThreshold": EXIT_FINDINGS,
"usageOrInputError": EXIT_USAGE,
},
"supportedSpecVersions": list(SUPPORTED_SPEC_VERSIONS),
"jsonReport": {
"reportVersion": REPORT_SCHEMA_VERSION,
"requiredTopLevel": report_schema["required"],
"requiredFindingFields": finding_schema["required"],
},
"pythonExports": {
"tods_validate": tods_validate.__all__,
"tods_validate.read": tods_validate.read.__all__,
"tods_validate.testing": tods_validate.testing.__all__,
},
"rules": [
[rule.id, rule.severity.name, rule.category]
for rule in sorted(all_rules(), key=lambda item: (int(item.id[-3:]), item.id))
],
}
def drift() -> tuple[dict[str, object], dict[str, object]]:
"""The snapshot's checkable fields and the implementation's, for comparison.
Both sides carry exactly the same keys, so a field that stops being
recomputed shows up as a mismatch instead of quietly dropping out of the
comparison.
"""
snapshot = json.loads(SNAPSHOT.read_text(encoding="utf-8"))
missing = [f for f in UNCHECKED_FIELDS if not snapshot.get(f)]
if missing:
raise SystemExit(f"snapshot is missing {', '.join(missing)}")
expected = {k: v for k, v in snapshot.items() if k not in UNCHECKED_FIELDS}
return expected, _actual_contract()
def main() -> int:
expected, actual = drift()
if actual == expected:
print("v1 public-contract candidate is current")
return 0
print("v1 public-contract candidate has drifted")
print("Expected snapshot:")
print(json.dumps(expected, indent=2))
print("Actual implementation:")
print(json.dumps(actual, indent=2))
return 1
if __name__ == "__main__":
raise SystemExit(main())