69 lines
2.1 KiB
Go
69 lines
2.1 KiB
Go
package contract
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.ipao.vip/rogee/go-sip/contracts"
|
|
"github.com/santhosh-tekuri/jsonschema/v6"
|
|
"github.com/santhosh-tekuri/jsonschema/v6/kind"
|
|
)
|
|
|
|
// ValidationFailure retains original bytes for private evidence, never Error/log output.
|
|
type ValidationFailure struct {
|
|
Surface string
|
|
Resource string
|
|
Raw []byte
|
|
Reason string
|
|
}
|
|
|
|
func (e *ValidationFailure) Error() string { return e.Surface + " validation failed: " + e.Reason }
|
|
|
|
func newValidationFailure(surface string, raw []byte, value any, cause error) error {
|
|
// Discriminate the MQ branch only to explain an already proven validation failure.
|
|
// This does not broaden acceptance or replace validation of the complete union.
|
|
if surface == "mq" {
|
|
if m, ok := value.(map[string]any); ok {
|
|
p, _ := m["payload"].(map[string]any)
|
|
if _, receipt := p["status"]; !receipt {
|
|
names := map[string]string{"task.control": "mq-task-control-request.schema.json", "call.execute": "mq-call-execute-request.schema.json", "sip.config": "mq-sip-config.schema.json"}
|
|
if name := names[fmt.Sprint(m["event_type"])]; name != "" {
|
|
if s, err := contracts.CompileCurrent(name); err == nil {
|
|
if detail := s.Validate(value); detail != nil {
|
|
cause = detail
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var details []string
|
|
var walk func(*jsonschema.ValidationError)
|
|
walk = func(e *jsonschema.ValidationError) {
|
|
if len(details) >= 32 {
|
|
return
|
|
}
|
|
if len(e.Causes) > 0 {
|
|
for _, c := range e.Causes {
|
|
walk(c)
|
|
}
|
|
return
|
|
}
|
|
path := "/" + strings.Join(e.InstanceLocation, "/")
|
|
if r, ok := e.ErrorKind.(*kind.Required); ok {
|
|
for _, k := range r.Missing {
|
|
details = append(details, strings.TrimSuffix(path, "/")+"/"+k+": required field missing")
|
|
}
|
|
return
|
|
}
|
|
details = append(details, path+": "+strings.Join(e.ErrorKind.KeywordPath(), "/"))
|
|
}
|
|
if e, ok := cause.(*jsonschema.ValidationError); ok {
|
|
walk(e)
|
|
}
|
|
if len(details) == 0 {
|
|
details = append(details, "structure does not match current Schema")
|
|
}
|
|
return &ValidationFailure{Surface: surface, Raw: append([]byte(nil), raw...), Reason: strings.Join(details, "; ")}
|
|
}
|