forked from ChelseaKR/oscal-validate
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_ai_verify.py
More file actions
129 lines (110 loc) · 4.59 KB
/
Copy pathtest_ai_verify.py
File metadata and controls
129 lines (110 loc) · 4.59 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
121
122
123
124
125
126
127
128
129
"""The verifier: quotes checked against the corpus, prose screened, replies parsed strictly."""
from __future__ import annotations
import json
import pytest
from oscal_validate.ai.guard import WITHHELD
from oscal_validate.ai.verify import (
INLINE_WITHHELD,
ReplyError,
parse_reply,
render_quotes,
render_withheld,
verify,
)
#: A sentence that is really on the identifier-use page.
REAL = (
"OSCAL's machine-oriented UUID identifiers are always globally-unique. Human-oriented "
"identifiers must be defined and managed organizationally"
)
def test_parse_reply_accepts_bare_and_fenced_json_and_rejects_the_rest() -> None:
assert parse_reply('{"a": 1}') == {"a": 1}
assert parse_reply('```json\n{"a": 1}\n```') == {"a": 1}
assert parse_reply('Sure:\n{"a": 1}\nthanks') == {"a": 1}
with pytest.raises(ReplyError, match="no JSON object"):
parse_reply("no json here")
with pytest.raises(ReplyError, match="not valid JSON"):
parse_reply('{"a": }')
def test_a_verified_quote_is_kept_with_its_url_and_date() -> None:
verified = verify(
{
"explanation": "UUIDs are global [Q1].",
"quotes": [{"id": "Q1", "source": "identifier-use", "text": REAL}],
},
"explanation",
)
assert verified.clean
assert verified.prose == "UUIDs are global [Q1]."
assert [q.identifier for q in verified.quotes] == ["Q1"]
assert verified.quotes[0].url.startswith("https://pages.nist.gov/")
assert "retrieved" in render_quotes(verified.quotes)
assert render_withheld(verified) == ""
def test_an_invented_quote_is_withheld_and_its_marker_struck() -> None:
verified = verify(
{
"explanation": "NIST says so [Q1] and also [Q2] and [Q9].",
"quotes": [
{
"id": "Q1",
"source": "identifier-use",
"text": "NIST requires every UUID to be v7.",
},
{"id": "Q2", "source": "no-such-source", "text": REAL},
],
},
"explanation",
)
assert verified.prose == (
"NIST says so [quote Q1 withheld] and also [quote Q2 withheld] and [quote Q9 withheld]."
)
reasons = {w.identifier: w.reason for w in verified.withheld_quotes}
assert reasons["Q1"] == "not found verbatim in that source"
assert reasons["Q2"] == "names a source that does not exist"
assert reasons["Q9"] == "cited but never supplied"
assert not verified.quotes
assert "quote Q1 withheld from identifier-use" in render_withheld(verified)
def test_a_short_quote_is_withheld_as_unverifiable() -> None:
verified = verify(
{"explanation": "x [Q1]", "quotes": [{"id": "Q1", "source": "uri-use", "text": "OSCAL"}]},
"explanation",
)
assert verified.withheld_quotes[0].reason == "too short to verify"
def test_an_inline_quotation_is_held_to_the_same_standard() -> None:
invented = (
"The validator shall consider every control implemented once its id is unique "
"across the catalog."
)
literal = '"id": "ex-1" and the second control carries "id": "ex-1" as well'
verified = verify(
{
"explanation": f'NIST writes "{REAL}" and also "{invented}" Here {literal}.',
"quotes": [],
},
"explanation",
)
assert f'"{REAL}"' in verified.prose
assert INLINE_WITHHELD in verified.prose
assert invented not in verified.prose
# JSON literals written into the prose are not quotations and are left alone.
assert literal in verified.prose
assert any("inline quotation" in w.reason for w in verified.withheld_quotes)
def test_a_judgment_in_the_prose_or_the_refusal_is_withheld_by_the_guard() -> None:
verified = verify(
{
"refused": True,
"refusal": "I cannot judge that. The system is secure though.",
"explanation": "The id is duplicated. This control is fully implemented.",
"quotes": [],
},
"explanation",
)
assert verified.refused
assert verified.prose == f"The id is duplicated. {WITHHELD}"
assert verified.refusal == f"I cannot judge that. {WITHHELD}"
assert len(verified.withheld_sentences) == 2
assert "2 sentence(s) withheld by the boundary guard" in render_withheld(verified)
def test_extra_fields_survive_and_missing_fields_default() -> None:
verified = verify({"next_step": "add it", "patch": [1]}, "explanation")
assert verified.prose == ""
assert verified.extra == {"next_step": "add it", "patch": [1]}
assert not verified.refused
assert json.dumps(verified.extra)