package contract import ( "bytes" "errors" "fmt" "strings" "git.ipao.vip/rogee/go-sip/contracts" "github.com/santhosh-tekuri/jsonschema/v6" ) // ValidateCurrent checks only the current project-local HTTP/MQ contract. // An absent schema is an error; it never falls back to historical bundles. func ValidateCurrent(surface string, raw []byte) error { var name string switch surface { case "config-read", "task-discovery", "mq": name = surface + ".schema.json" default: return fmt.Errorf("invalid current contract surface %q", surface) } value, err := jsonschema.UnmarshalJSON(bytes.NewReader(raw)) if err != nil { return fmt.Errorf("decode %s body: %w", surface, err) } key := "current/" + name cached, ok := compiledSchemas.Load(key) var schema *jsonschema.Schema if ok { schema = cached.(*jsonschema.Schema) } else { data, err := contracts.ReadCurrent(name) if err != nil { return err } doc, err := jsonschema.UnmarshalJSON(bytes.NewReader(data)) if err != nil { return fmt.Errorf("decode current schema %s: %w", name, err) } compiler := jsonschema.NewCompiler() compiler.AssertFormat() resource := "https://go-sip.local/contracts/current/" + name if err := compiler.AddResource(resource, doc); err != nil { return fmt.Errorf("register %s: %w", name, err) } schema, err = compiler.Compile(resource) if err != nil { return fmt.Errorf("compile %s: %w", name, err) } actual, _ := compiledSchemas.LoadOrStore(key, schema) schema = actual.(*jsonschema.Schema) } if err := schema.Validate(value); err != nil { var validation *jsonschema.ValidationError if errors.As(err, &validation) { return fmt.Errorf("%s validation failed at /%s", surface, strings.Join(validation.InstanceLocation, "/")) } return fmt.Errorf("%s validation failed", surface) } return nil }