Files
go-sip/internal/contract/failure.go
T

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, "; ")}
}