Skip to content

Commit

Permalink
encoding/jsonschema: disallow $schema at non-root for earlier versions
Browse files Browse the repository at this point in the history
Before 2019-09, the specification says [1]:

> The "$schema" keyword SHOULD be used in a root schema. It MUST NOT
> appear in subschemas.

This change makes us more spec-compliant in that respect.

Also change a test case where we were using `$schema` at non-root location.

[1]: https://json-schema.org/draft-07/draft-handrews-json-schema-01#rfc.section.7

Signed-off-by: Roger Peppe <[email protected]>
Change-Id: If74b25848cc3c334eaaefb46adfe4fe89d0cbb45
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1202562
Unity-Result: CUE porcuepine <[email protected]>
Reviewed-by: Daniel Martí <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
  • Loading branch information
rogpeppe committed Oct 15, 2024
1 parent 4543183 commit 2c6ed18
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 2 deletions.
6 changes: 6 additions & 0 deletions encoding/jsonschema/constraints_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ func constraintID(key string, n cue.Value, s *state) {
// constraintSchema implements $schema, which
// identifies this as a JSON schema and specifies its version.
func constraintSchema(key string, n cue.Value, s *state) {
if !s.isRoot && !vfrom(VersionDraft2019_09).contains(s.schemaVersion) {
// Before 2019-09, the $schema keyword was not allowed
// to appear anywhere but the root.
s.errf(n, "$schema can only appear at the root in JSON Schema version %v", s.schemaVersion)
return
}
str, ok := s.strValue(n)
if !ok {
// If there's no $schema value, use the default.
Expand Down
6 changes: 6 additions & 0 deletions encoding/jsonschema/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func (d *decoder) schema(ref []ast.Label, v cue.Value) (a []ast.Decl) {
root := state{
decoder: d,
schemaVersion: d.cfg.DefaultVersion,
isRoot: true,
}

var name ast.Label
Expand Down Expand Up @@ -415,6 +416,10 @@ type state struct {
// to $ref.
hasRefKeyword bool

// isRoot holds whether this state is at the root
// of the schema.
isRoot bool

minContains *uint64
maxContains *uint64

Expand Down Expand Up @@ -709,6 +714,7 @@ func (s0 *state) schemaState(n cue.Value, types cue.Kind, idRef []label) (ast.Ex
knownTypes: allTypes,
idRef: idRef,
pos: n,
isRoot: s0.isRoot && n == s0.pos,
}
if n.Kind() == cue.BoolKind {
if vfrom(VersionDraft6).contains(s.schemaVersion) {
Expand Down
2 changes: 0 additions & 2 deletions encoding/jsonschema/testdata/txtar/id_in_oneOf.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
"$id": "https://test.example/foo",
"oneOf": [
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://1.test.example/string",
"type": "string"
},
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://2.test.example/object",
"type": "object"
}
Expand Down
16 changes: 16 additions & 0 deletions encoding/jsonschema/testdata/txtar/schema_not_at_root.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- schema.json --
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://test.example/foo",
"oneOf": [
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "string"
}
]
}

-- out/decode/extract --
ERROR:
$schema can only appear at the root in JSON Schema version http://json-schema.org/draft-07/schema#:
schema.json:6:11

0 comments on commit 2c6ed18

Please sign in to comment.