Preserve exact JSON validation semantics
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
package validate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -175,18 +177,17 @@ func validateArtifact(ctx context.Context, artifact *domain.Artifact, contract d
|
||||
res.IsValid = true
|
||||
return res, nil
|
||||
case domain.ValidationJSON:
|
||||
_, jsonErr := parseJSON(artifact.Body)
|
||||
if jsonErr != nil {
|
||||
if !json.Valid(artifact.Body) {
|
||||
res.Status = domain.ValidationFailed
|
||||
res.IsValid = false
|
||||
res.Errors = []string{fmt.Sprintf("invalid JSON: %v", jsonErr)}
|
||||
res.Errors = []string{"invalid JSON"}
|
||||
return res, nil
|
||||
}
|
||||
res.Status = domain.ValidationPassed
|
||||
res.IsValid = true
|
||||
return res, nil
|
||||
case domain.ValidationJSONSchema:
|
||||
instance, jsonErr := parseJSON(artifact.Body)
|
||||
instance, jsonErr := decodeJSONValue(artifact.Body)
|
||||
if jsonErr != nil {
|
||||
res.Status = domain.ValidationFailed
|
||||
res.IsValid = false
|
||||
@@ -260,12 +261,22 @@ func (v *FSValidator) validateJSONSchema(instance any, schemaPath string) ([]str
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func parseJSON(body []byte) (any, error) {
|
||||
var v any
|
||||
if err := json.Unmarshal(body, &v); err != nil {
|
||||
func decodeJSONValue(body []byte) (any, error) {
|
||||
decoder := json.NewDecoder(bytes.NewReader(body))
|
||||
decoder.UseNumber()
|
||||
|
||||
var value any
|
||||
if err := decoder.Decode(&value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
|
||||
var trailing any
|
||||
if err := decoder.Decode(&trailing); errors.Is(err, io.EOF) {
|
||||
return value, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errors.New("multiple JSON values")
|
||||
}
|
||||
|
||||
func (v *StandardValidator) LoadSchemaDocument(ctx context.Context, schemaPath string) (any, error) {
|
||||
@@ -285,8 +296,8 @@ func (v *StandardValidator) LoadSchemaDocument(ctx context.Context, schemaPath s
|
||||
return nil, fmt.Errorf("failed to read schema file %q: %w", resolved, err)
|
||||
}
|
||||
|
||||
var doc any
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
doc, err := decodeJSONValue(raw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode JSON schema %q: %w", resolved, err)
|
||||
}
|
||||
if err := validateSchemaDialect(doc); err != nil {
|
||||
@@ -356,8 +367,8 @@ func (v *FSValidator) loadSchemaDocument(schemaPath string) (string, any, error)
|
||||
return "", nil, fmt.Errorf("failed to read schema file %q: %w", resolved, err)
|
||||
}
|
||||
|
||||
var doc any
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
doc, err := decodeJSONValue(raw)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to decode JSON schema %q: %w", resolved, err)
|
||||
}
|
||||
if err := validateSchemaDialect(doc); err != nil {
|
||||
@@ -490,8 +501,8 @@ func loadJSONSchemaFile(name string) (any, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var doc any
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
doc, err := decodeJSONValue(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateSchemaDialect(doc); err != nil {
|
||||
@@ -538,8 +549,8 @@ func (l fsSchemaLoader) Load(resourceURL string) (any, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var doc any
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
doc, err := decodeJSONValue(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateSchemaDialect(doc); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user