Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ require (
github.com/hashicorp/raft-wal v0.4.2
github.com/jackc/pglogrepl v0.0.0-20260401131349-e37c41485510
github.com/jackc/pgx/v5 v5.10.0
github.com/kaptinlin/jsonschema v0.9.3
github.com/kaptinlin/jsonschema v0.9.6
github.com/klauspost/compress v1.19.1
github.com/lib/pq v1.12.3
github.com/mattn/go-sqlite3 v1.14.49
Expand Down Expand Up @@ -173,7 +173,7 @@ require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jsimonetti/rtnetlink v1.4.1 // indirect
github.com/kaptinlin/jsonpointer v0.4.27 // indirect
github.com/kaptinlin/jsonpointer v0.4.28 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lucasb-eyer/go-colorful v1.4.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,10 @@ github.com/jsimonetti/rtnetlink v1.4.1/go.mod h1:xJjT7t59UIZ62GLZbv6PLLo8VFrostJ
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kaptinlin/jsonpointer v0.4.27 h1:5FOnhlkqQ4/lvHudaAWS8HJCXjN4yAHSIGl7aPKHI0Q=
github.com/kaptinlin/jsonpointer v0.4.27/go.mod h1:dfub/n58cWS32Dyf3AZsnKblSAgrz9PyOU76GDPpx8Q=
github.com/kaptinlin/jsonschema v0.9.3 h1:uDVd3w4aXwO0tbycblKYvFofhl3hVuE31vOl5JkDXI0=
github.com/kaptinlin/jsonschema v0.9.3/go.mod h1:LvtQ/mO0E1e/3c3DiOWTj05LTeot8cTv7DyQq7eJMQg=
github.com/kaptinlin/jsonpointer v0.4.28 h1:PyxOfdml9PGpxQz+JnNLGsyzQ+Rnm+OVNTGcgbVLqgg=
github.com/kaptinlin/jsonpointer v0.4.28/go.mod h1:JzeIDw1+60bryzOFea9P3zjKg8pfJHd+UIA/zfZ70x8=
github.com/kaptinlin/jsonschema v0.9.6 h1:RNqurZUqduQm+mINsCFbRzBQR0uKbAcRPBj3BqRA/I8=
github.com/kaptinlin/jsonschema v0.9.6/go.mod h1:TP7RFmFBNExjBE0b3fsM6RpA/9PeOzfg2g4weXqOrDg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk=
Expand Down
20 changes: 19 additions & 1 deletion runtime/lua/modules/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"sort"
"strconv"
Expand Down Expand Up @@ -638,7 +639,7 @@ func compileSchema(schemaJSON []byte) (*jsonschema.Schema, error) {
return schema, nil
}

compiler := jsonschema.NewCompiler()
compiler := jsonschema.NewCompiler().WithDecoderJSON(decodeSchemaInstance)
schema, err := compiler.Compile(schemaJSON)
if err != nil {
return nil, err
Expand All @@ -648,6 +649,23 @@ func compileSchema(schemaJSON []byte) (*jsonschema.Schema, error) {
return schema, nil
}

func decodeSchemaInstance(data []byte, value any) error {
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber()
if err := decoder.Decode(value); err != nil {
return err
}

var trailing any
if err := decoder.Decode(&trailing); !errors.Is(err, io.EOF) {
if err == nil {
return errors.New("multiple JSON values")
}
return err
}
return nil
}

func hashSchemaJSON(data []byte) string {
hash := sha256.Sum256(data)
return hex.EncodeToString(hash[:])
Expand Down
35 changes: 35 additions & 0 deletions runtime/lua/modules/json/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,41 @@ func TestValidateStringSuccess(t *testing.T) {
}
}

func TestValidateStringPreservesExactNumbers(t *testing.T) {
l := lua.NewState()
defer l.Close()
bindJSON(l)

err := l.DoString(`
local schema = '{"type":"integer","const":9007199254740993}'
local valid, validation_err = json.validate_string(schema, '9007199254740993')
if not valid then error("expected exact integer to validate: " .. tostring(validation_err)) end

valid, validation_err = json.validate_string(schema, '9007199254740992')
if valid then error("adjacent integer must not match exact const") end
if validation_err == nil then error("expected validation error") end
`)
if err != nil {
t.Errorf("validate_string exact number test failed: %v", err)
}
}

func TestValidateStringRejectsTrailingJSONValue(t *testing.T) {
l := lua.NewState()
defer l.Close()
bindJSON(l)

err := l.DoString(`
local schema = {type = "object"}
local valid, validation_err = json.validate_string(schema, '{} {}')
if valid then error("expected trailing JSON value to be rejected") end
if validation_err == nil then error("expected validation error") end
`)
if err != nil {
t.Errorf("validate_string trailing value test failed: %v", err)
}
}

func TestValidateMissingSchema(t *testing.T) {
l := lua.NewState()
defer l.Close()
Expand Down
Loading