Skip to content

Commit c75f7e8

Browse files
committed
jsonschema: validate object keywords
Add validation for JSON objects (Go maps). The map keys are called "properties." As with arrays, annotations are needed to support the unevaluatedProperties keyword. Change-Id: Ia01f74300f4bcdbce94065572d83c46dfaa53ae7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/668256 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Alan Donovan <[email protected]>
1 parent efd15d8 commit c75f7e8

15 files changed

+3310
-3
lines changed

internal/mcp/internal/jsonschema/annotations.go

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type annotations struct {
1414
allItems bool // all items were evaluated
1515
endIndex int // 1+largest index evaluated by prefixItems
1616
evaluatedIndexes map[int]bool // set of indexes evaluated by contains
17+
allProperties bool // all properties were evaluated
1718
evaluatedProperties map[string]bool // set of properties evaluated by various keywords
1819
}
1920

@@ -58,6 +59,9 @@ func (a *annotations) merge(b *annotations) {
5859
a.endIndex = b.endIndex
5960
}
6061
a.evaluatedIndexes = merge(a.evaluatedIndexes, b.evaluatedIndexes)
62+
if b.allProperties {
63+
a.allProperties = true
64+
}
6165
a.evaluatedProperties = merge(a.evaluatedProperties, b.evaluatedProperties)
6266
}
6367

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
[
2+
{
3+
"description":
4+
"additionalProperties being false does not allow other properties",
5+
"specification": [ { "core":"10.3.2.3", "quote": "The value of \"additionalProperties\" MUST be a valid JSON Schema. Boolean \"false\" forbids everything." } ],
6+
"schema": {
7+
"$schema": "https://json-schema.org/draft/2020-12/schema",
8+
"properties": {"foo": {}, "bar": {}},
9+
"patternProperties": { "^v": {} },
10+
"additionalProperties": false
11+
},
12+
"tests": [
13+
{
14+
"description": "no additional properties is valid",
15+
"data": {"foo": 1},
16+
"valid": true
17+
},
18+
{
19+
"description": "an additional property is invalid",
20+
"data": {"foo" : 1, "bar" : 2, "quux" : "boom"},
21+
"valid": false
22+
},
23+
{
24+
"description": "ignores arrays",
25+
"data": [1, 2, 3],
26+
"valid": true
27+
},
28+
{
29+
"description": "ignores strings",
30+
"data": "foobarbaz",
31+
"valid": true
32+
},
33+
{
34+
"description": "ignores other non-objects",
35+
"data": 12,
36+
"valid": true
37+
},
38+
{
39+
"description": "patternProperties are not additional properties",
40+
"data": {"foo":1, "vroom": 2},
41+
"valid": true
42+
}
43+
]
44+
},
45+
{
46+
"description": "non-ASCII pattern with additionalProperties",
47+
"specification": [ { "core":"10.3.2.3"} ],
48+
"schema": {
49+
"$schema": "https://json-schema.org/draft/2020-12/schema",
50+
"patternProperties": {"^á": {}},
51+
"additionalProperties": false
52+
},
53+
"tests": [
54+
{
55+
"description": "matching the pattern is valid",
56+
"data": {"ármányos": 2},
57+
"valid": true
58+
},
59+
{
60+
"description": "not matching the pattern is invalid",
61+
"data": {"élmény": 2},
62+
"valid": false
63+
}
64+
]
65+
},
66+
{
67+
"description": "additionalProperties with schema",
68+
"specification": [ { "core":"10.3.2.3", "quote": "The value of \"additionalProperties\" MUST be a valid JSON Schema." } ],
69+
"schema": {
70+
"$schema": "https://json-schema.org/draft/2020-12/schema",
71+
"properties": {"foo": {}, "bar": {}},
72+
"additionalProperties": {"type": "boolean"}
73+
},
74+
"tests": [
75+
{
76+
"description": "no additional properties is valid",
77+
"data": {"foo": 1},
78+
"valid": true
79+
},
80+
{
81+
"description": "an additional valid property is valid",
82+
"data": {"foo" : 1, "bar" : 2, "quux" : true},
83+
"valid": true
84+
},
85+
{
86+
"description": "an additional invalid property is invalid",
87+
"data": {"foo" : 1, "bar" : 2, "quux" : 12},
88+
"valid": false
89+
}
90+
]
91+
},
92+
{
93+
"description": "additionalProperties can exist by itself",
94+
"specification": [ { "core":"10.3.2.3", "quote": "With no other applicator applying to object instances. This validates all the instance values irrespective of their property names" } ],
95+
"schema": {
96+
"$schema": "https://json-schema.org/draft/2020-12/schema",
97+
"additionalProperties": {"type": "boolean"}
98+
},
99+
"tests": [
100+
{
101+
"description": "an additional valid property is valid",
102+
"data": {"foo" : true},
103+
"valid": true
104+
},
105+
{
106+
"description": "an additional invalid property is invalid",
107+
"data": {"foo" : 1},
108+
"valid": false
109+
}
110+
]
111+
},
112+
{
113+
"description": "additionalProperties are allowed by default",
114+
"specification": [ { "core":"10.3.2.3", "quote": "Omitting this keyword has the same assertion behavior as an empty schema." } ],
115+
"schema": {
116+
"$schema": "https://json-schema.org/draft/2020-12/schema",
117+
"properties": {"foo": {}, "bar": {}}
118+
},
119+
"tests": [
120+
{
121+
"description": "additional properties are allowed",
122+
"data": {"foo": 1, "bar": 2, "quux": true},
123+
"valid": true
124+
}
125+
]
126+
},
127+
{
128+
"description": "additionalProperties does not look in applicators",
129+
"specification":[ { "core": "10.2", "quote": "Subschemas of applicator keywords evaluate the instance completely independently such that the results of one such subschema MUST NOT impact the results of sibling subschemas." } ],
130+
"schema": {
131+
"$schema": "https://json-schema.org/draft/2020-12/schema",
132+
"allOf": [
133+
{"properties": {"foo": {}}}
134+
],
135+
"additionalProperties": {"type": "boolean"}
136+
},
137+
"tests": [
138+
{
139+
"description": "properties defined in allOf are not examined",
140+
"data": {"foo": 1, "bar": true},
141+
"valid": false
142+
}
143+
]
144+
},
145+
{
146+
"description": "additionalProperties with null valued instance properties",
147+
"specification": [ { "core":"10.3.2.3" } ],
148+
"schema": {
149+
"$schema": "https://json-schema.org/draft/2020-12/schema",
150+
"additionalProperties": {
151+
"type": "null"
152+
}
153+
},
154+
"tests": [
155+
{
156+
"description": "allows null values",
157+
"data": {"foo": null},
158+
"valid": true
159+
}
160+
]
161+
},
162+
{
163+
"description": "additionalProperties with propertyNames",
164+
"schema": {
165+
"$schema": "https://json-schema.org/draft/2020-12/schema",
166+
"propertyNames": {
167+
"maxLength": 5
168+
},
169+
"additionalProperties": {
170+
"type": "number"
171+
}
172+
},
173+
"tests": [
174+
{
175+
"description": "Valid against both keywords",
176+
"data": { "apple": 4 },
177+
"valid": true
178+
},
179+
{
180+
"description": "Valid against propertyNames, but not additionalProperties",
181+
"data": { "fig": 2, "pear": "available" },
182+
"valid": false
183+
}
184+
]
185+
},
186+
{
187+
"description": "dependentSchemas with additionalProperties",
188+
"schema": {
189+
"$schema": "https://json-schema.org/draft/2020-12/schema",
190+
"properties": {"foo2": {}},
191+
"dependentSchemas": {
192+
"foo" : {},
193+
"foo2": {
194+
"properties": {
195+
"bar": {}
196+
}
197+
}
198+
},
199+
"additionalProperties": false
200+
},
201+
"tests": [
202+
{
203+
"description": "additionalProperties doesn't consider dependentSchemas",
204+
"data": {"foo": ""},
205+
"valid": false
206+
},
207+
{
208+
"description": "additionalProperties can't see bar",
209+
"data": {"bar": ""},
210+
"valid": false
211+
},
212+
{
213+
"description": "additionalProperties can't see bar even when foo2 is present",
214+
"data": {"foo2": "", "bar": ""},
215+
"valid": false
216+
}
217+
]
218+
}
219+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
[
2+
{
3+
"description": "boolean schema 'true'",
4+
"schema": true,
5+
"tests": [
6+
{
7+
"description": "number is valid",
8+
"data": 1,
9+
"valid": true
10+
},
11+
{
12+
"description": "string is valid",
13+
"data": "foo",
14+
"valid": true
15+
},
16+
{
17+
"description": "boolean true is valid",
18+
"data": true,
19+
"valid": true
20+
},
21+
{
22+
"description": "boolean false is valid",
23+
"data": false,
24+
"valid": true
25+
},
26+
{
27+
"description": "null is valid",
28+
"data": null,
29+
"valid": true
30+
},
31+
{
32+
"description": "object is valid",
33+
"data": {"foo": "bar"},
34+
"valid": true
35+
},
36+
{
37+
"description": "empty object is valid",
38+
"data": {},
39+
"valid": true
40+
},
41+
{
42+
"description": "array is valid",
43+
"data": ["foo"],
44+
"valid": true
45+
},
46+
{
47+
"description": "empty array is valid",
48+
"data": [],
49+
"valid": true
50+
}
51+
]
52+
},
53+
{
54+
"description": "boolean schema 'false'",
55+
"schema": false,
56+
"tests": [
57+
{
58+
"description": "number is invalid",
59+
"data": 1,
60+
"valid": false
61+
},
62+
{
63+
"description": "string is invalid",
64+
"data": "foo",
65+
"valid": false
66+
},
67+
{
68+
"description": "boolean true is invalid",
69+
"data": true,
70+
"valid": false
71+
},
72+
{
73+
"description": "boolean false is invalid",
74+
"data": false,
75+
"valid": false
76+
},
77+
{
78+
"description": "null is invalid",
79+
"data": null,
80+
"valid": false
81+
},
82+
{
83+
"description": "object is invalid",
84+
"data": {"foo": "bar"},
85+
"valid": false
86+
},
87+
{
88+
"description": "empty object is invalid",
89+
"data": {},
90+
"valid": false
91+
},
92+
{
93+
"description": "array is invalid",
94+
"data": ["foo"],
95+
"valid": false
96+
},
97+
{
98+
"description": "empty array is invalid",
99+
"data": [],
100+
"valid": false
101+
}
102+
]
103+
}
104+
]

0 commit comments

Comments
 (0)