mirror of
https://github.com/yannh/kubeconform.git
synced 2026-02-17 08:57:02 +00:00
651 lines
12 KiB
Go
651 lines
12 KiB
Go
package kind
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"strings"
|
|
|
|
"golang.org/x/text/message"
|
|
)
|
|
|
|
// --
|
|
|
|
type InvalidJsonValue struct {
|
|
Value any
|
|
}
|
|
|
|
func (*InvalidJsonValue) KeywordPath() []string {
|
|
return nil
|
|
}
|
|
|
|
func (k *InvalidJsonValue) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("invalid jsonType %T", k.Value)
|
|
}
|
|
|
|
// --
|
|
|
|
type Schema struct {
|
|
Location string
|
|
}
|
|
|
|
func (*Schema) KeywordPath() []string {
|
|
return nil
|
|
}
|
|
|
|
func (k *Schema) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("jsonschema validation failed with %s", quote(k.Location))
|
|
}
|
|
|
|
// --
|
|
|
|
type Group struct{}
|
|
|
|
func (*Group) KeywordPath() []string {
|
|
return nil
|
|
}
|
|
|
|
func (*Group) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("validation failed")
|
|
}
|
|
|
|
// --
|
|
|
|
type Not struct{}
|
|
|
|
func (*Not) KeywordPath() []string {
|
|
return nil
|
|
}
|
|
|
|
func (*Not) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("not failed")
|
|
}
|
|
|
|
// --
|
|
|
|
type AllOf struct{}
|
|
|
|
func (*AllOf) KeywordPath() []string {
|
|
return []string{"allOf"}
|
|
}
|
|
|
|
func (*AllOf) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("allOf failed")
|
|
}
|
|
|
|
// --
|
|
|
|
type AnyOf struct{}
|
|
|
|
func (*AnyOf) KeywordPath() []string {
|
|
return []string{"anyOf"}
|
|
}
|
|
|
|
func (*AnyOf) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("anyOf failed")
|
|
}
|
|
|
|
// --
|
|
|
|
type OneOf struct {
|
|
// Subschemas gives indexes of Subschemas that have matched.
|
|
// Value nil, means none of the subschemas matched.
|
|
Subschemas []int
|
|
}
|
|
|
|
func (*OneOf) KeywordPath() []string {
|
|
return []string{"oneOf"}
|
|
}
|
|
|
|
func (k *OneOf) LocalizedString(p *message.Printer) string {
|
|
if len(k.Subschemas) == 0 {
|
|
return p.Sprintf("oneOf failed, none matched")
|
|
}
|
|
return p.Sprintf("oneOf failed, subschemas %d, %d matched", k.Subschemas[0], k.Subschemas[1])
|
|
}
|
|
|
|
//--
|
|
|
|
type FalseSchema struct{}
|
|
|
|
func (*FalseSchema) KeywordPath() []string {
|
|
return nil
|
|
}
|
|
|
|
func (*FalseSchema) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("false schema")
|
|
}
|
|
|
|
// --
|
|
|
|
type RefCycle struct {
|
|
URL string
|
|
KeywordLocation1 string
|
|
KeywordLocation2 string
|
|
}
|
|
|
|
func (*RefCycle) KeywordPath() []string {
|
|
return nil
|
|
}
|
|
|
|
func (k *RefCycle) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("both %s and %s resolve to %q causing reference cycle", k.KeywordLocation1, k.KeywordLocation2, k.URL)
|
|
}
|
|
|
|
// --
|
|
|
|
type Type struct {
|
|
Got string
|
|
Want []string
|
|
}
|
|
|
|
func (*Type) KeywordPath() []string {
|
|
return []string{"type"}
|
|
}
|
|
|
|
func (k *Type) LocalizedString(p *message.Printer) string {
|
|
want := strings.Join(k.Want, " or ")
|
|
return p.Sprintf("got %s, want %s", k.Got, want)
|
|
}
|
|
|
|
// --
|
|
|
|
type Enum struct {
|
|
Got any
|
|
Want []any
|
|
}
|
|
|
|
// KeywordPath implements jsonschema.ErrorKind.
|
|
func (*Enum) KeywordPath() []string {
|
|
return []string{"enum"}
|
|
}
|
|
|
|
func (k *Enum) LocalizedString(p *message.Printer) string {
|
|
allPrimitive := true
|
|
loop:
|
|
for _, item := range k.Want {
|
|
switch item.(type) {
|
|
case []any, map[string]any:
|
|
allPrimitive = false
|
|
break loop
|
|
}
|
|
}
|
|
if allPrimitive {
|
|
if len(k.Want) == 1 {
|
|
return p.Sprintf("value must be %s", display(k.Want[0]))
|
|
}
|
|
var want []string
|
|
for _, v := range k.Want {
|
|
want = append(want, display(v))
|
|
}
|
|
return p.Sprintf("value must be one of %s", strings.Join(want, ", "))
|
|
}
|
|
return p.Sprintf("enum failed")
|
|
}
|
|
|
|
// --
|
|
|
|
type Const struct {
|
|
Got any
|
|
Want any
|
|
}
|
|
|
|
func (*Const) KeywordPath() []string {
|
|
return []string{"const"}
|
|
}
|
|
|
|
func (k *Const) LocalizedString(p *message.Printer) string {
|
|
switch want := k.Want.(type) {
|
|
case []any, map[string]any:
|
|
return p.Sprintf("const failed")
|
|
default:
|
|
return p.Sprintf("value must be %s", display(want))
|
|
}
|
|
}
|
|
|
|
// --
|
|
|
|
type Format struct {
|
|
Got any
|
|
Want string
|
|
Err error
|
|
}
|
|
|
|
func (*Format) KeywordPath() []string {
|
|
return []string{"format"}
|
|
}
|
|
|
|
func (k *Format) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("%s is not valid %s: %v", display(k.Got), k.Want, localizedError(k.Err, p))
|
|
}
|
|
|
|
// --
|
|
|
|
type Reference struct {
|
|
Keyword string
|
|
URL string
|
|
}
|
|
|
|
func (k *Reference) KeywordPath() []string {
|
|
return []string{k.Keyword}
|
|
}
|
|
|
|
func (*Reference) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("validation failed")
|
|
}
|
|
|
|
// --
|
|
|
|
type MinProperties struct {
|
|
Got, Want int
|
|
}
|
|
|
|
func (*MinProperties) KeywordPath() []string {
|
|
return []string{"minProperties"}
|
|
}
|
|
|
|
func (k *MinProperties) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("minProperties: got %d, want %d", k.Got, k.Want)
|
|
}
|
|
|
|
// --
|
|
|
|
type MaxProperties struct {
|
|
Got, Want int
|
|
}
|
|
|
|
func (*MaxProperties) KeywordPath() []string {
|
|
return []string{"maxProperties"}
|
|
}
|
|
|
|
func (k *MaxProperties) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("maxProperties: got %d, want %d", k.Got, k.Want)
|
|
}
|
|
|
|
// --
|
|
|
|
type MinItems struct {
|
|
Got, Want int
|
|
}
|
|
|
|
func (*MinItems) KeywordPath() []string {
|
|
return []string{"minItems"}
|
|
}
|
|
|
|
func (k *MinItems) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("minItems: got %d, want %d", k.Got, k.Want)
|
|
}
|
|
|
|
// --
|
|
|
|
type MaxItems struct {
|
|
Got, Want int
|
|
}
|
|
|
|
func (*MaxItems) KeywordPath() []string {
|
|
return []string{"maxItems"}
|
|
}
|
|
|
|
func (k *MaxItems) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("maxItems: got %d, want %d", k.Got, k.Want)
|
|
}
|
|
|
|
// --
|
|
|
|
type AdditionalItems struct {
|
|
Count int
|
|
}
|
|
|
|
func (*AdditionalItems) KeywordPath() []string {
|
|
return []string{"additionalItems"}
|
|
}
|
|
|
|
func (k *AdditionalItems) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("last %d additionalItem(s) not allowed", k.Count)
|
|
}
|
|
|
|
// --
|
|
|
|
type Required struct {
|
|
Missing []string
|
|
}
|
|
|
|
func (*Required) KeywordPath() []string {
|
|
return []string{"required"}
|
|
}
|
|
|
|
func (k *Required) LocalizedString(p *message.Printer) string {
|
|
if len(k.Missing) == 1 {
|
|
return p.Sprintf("missing property %s", quote(k.Missing[0]))
|
|
}
|
|
return p.Sprintf("missing properties %s", joinQuoted(k.Missing, ", "))
|
|
}
|
|
|
|
// --
|
|
|
|
type Dependency struct {
|
|
Prop string // dependency of prop that failed
|
|
Missing []string // missing props
|
|
}
|
|
|
|
func (k *Dependency) KeywordPath() []string {
|
|
return []string{"dependency", k.Prop}
|
|
}
|
|
|
|
func (k *Dependency) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("properties %s required, if %s exists", joinQuoted(k.Missing, ", "), quote(k.Prop))
|
|
}
|
|
|
|
// --
|
|
|
|
type DependentRequired struct {
|
|
Prop string // dependency of prop that failed
|
|
Missing []string // missing props
|
|
}
|
|
|
|
func (k *DependentRequired) KeywordPath() []string {
|
|
return []string{"dependentRequired", k.Prop}
|
|
}
|
|
|
|
func (k *DependentRequired) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("properties %s required, if %s exists", joinQuoted(k.Missing, ", "), quote(k.Prop))
|
|
}
|
|
|
|
// --
|
|
|
|
type AdditionalProperties struct {
|
|
Properties []string
|
|
}
|
|
|
|
func (*AdditionalProperties) KeywordPath() []string {
|
|
return []string{"additionalProperties"}
|
|
}
|
|
|
|
func (k *AdditionalProperties) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("additional properties %s not allowed", joinQuoted(k.Properties, ", "))
|
|
}
|
|
|
|
// --
|
|
|
|
type PropertyNames struct {
|
|
Property string
|
|
}
|
|
|
|
func (*PropertyNames) KeywordPath() []string {
|
|
return []string{"propertyNames"}
|
|
}
|
|
|
|
func (k *PropertyNames) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("invalid propertyName %s", quote(k.Property))
|
|
}
|
|
|
|
// --
|
|
|
|
type UniqueItems struct {
|
|
Duplicates [2]int
|
|
}
|
|
|
|
func (*UniqueItems) KeywordPath() []string {
|
|
return []string{"uniqueItems"}
|
|
}
|
|
|
|
func (k *UniqueItems) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("items at %d and %d are equal", k.Duplicates[0], k.Duplicates[1])
|
|
}
|
|
|
|
// --
|
|
|
|
type Contains struct{}
|
|
|
|
func (*Contains) KeywordPath() []string {
|
|
return []string{"contains"}
|
|
}
|
|
|
|
func (*Contains) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("no items match contains schema")
|
|
}
|
|
|
|
// --
|
|
|
|
type MinContains struct {
|
|
Got []int
|
|
Want int
|
|
}
|
|
|
|
func (*MinContains) KeywordPath() []string {
|
|
return []string{"minContains"}
|
|
}
|
|
|
|
func (k *MinContains) LocalizedString(p *message.Printer) string {
|
|
if len(k.Got) == 0 {
|
|
return p.Sprintf("min %d items required to match contains schema, but none matched", k.Want)
|
|
} else {
|
|
got := fmt.Sprintf("%v", k.Got)
|
|
return p.Sprintf("min %d items required to match contains schema, but matched %d items at %v", k.Want, len(k.Got), got[1:len(got)-1])
|
|
}
|
|
}
|
|
|
|
// --
|
|
|
|
type MaxContains struct {
|
|
Got []int
|
|
Want int
|
|
}
|
|
|
|
func (*MaxContains) KeywordPath() []string {
|
|
return []string{"maxContains"}
|
|
}
|
|
|
|
func (k *MaxContains) LocalizedString(p *message.Printer) string {
|
|
got := fmt.Sprintf("%v", k.Got)
|
|
return p.Sprintf("max %d items required to match contains schema, but matched %d items at %v", k.Want, len(k.Got), got[1:len(got)-1])
|
|
}
|
|
|
|
// --
|
|
|
|
type MinLength struct {
|
|
Got, Want int
|
|
}
|
|
|
|
func (*MinLength) KeywordPath() []string {
|
|
return []string{"minLength"}
|
|
}
|
|
|
|
func (k *MinLength) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("minLength: got %d, want %d", k.Got, k.Want)
|
|
}
|
|
|
|
// --
|
|
|
|
type MaxLength struct {
|
|
Got, Want int
|
|
}
|
|
|
|
func (*MaxLength) KeywordPath() []string {
|
|
return []string{"maxLength"}
|
|
}
|
|
|
|
func (k *MaxLength) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("maxLength: got %d, want %d", k.Got, k.Want)
|
|
}
|
|
|
|
// --
|
|
|
|
type Pattern struct {
|
|
Got string
|
|
Want string
|
|
}
|
|
|
|
func (*Pattern) KeywordPath() []string {
|
|
return []string{"pattern"}
|
|
}
|
|
|
|
func (k *Pattern) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("%s does not match pattern %s", quote(k.Got), quote(k.Want))
|
|
}
|
|
|
|
// --
|
|
|
|
type ContentEncoding struct {
|
|
Want string
|
|
Err error
|
|
}
|
|
|
|
func (*ContentEncoding) KeywordPath() []string {
|
|
return []string{"contentEncoding"}
|
|
}
|
|
|
|
func (k *ContentEncoding) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("value is not %s encoded: %v", quote(k.Want), localizedError(k.Err, p))
|
|
}
|
|
|
|
// --
|
|
|
|
type ContentMediaType struct {
|
|
Got []byte
|
|
Want string
|
|
Err error
|
|
}
|
|
|
|
func (*ContentMediaType) KeywordPath() []string {
|
|
return []string{"contentMediaType"}
|
|
}
|
|
|
|
func (k *ContentMediaType) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("value if not of mediatype %s: %v", quote(k.Want), k.Err)
|
|
}
|
|
|
|
// --
|
|
|
|
type ContentSchema struct{}
|
|
|
|
func (*ContentSchema) KeywordPath() []string {
|
|
return []string{"contentSchema"}
|
|
}
|
|
|
|
func (*ContentSchema) LocalizedString(p *message.Printer) string {
|
|
return p.Sprintf("contentSchema failed")
|
|
}
|
|
|
|
// --
|
|
|
|
type Minimum struct {
|
|
Got *big.Rat
|
|
Want *big.Rat
|
|
}
|
|
|
|
func (*Minimum) KeywordPath() []string {
|
|
return []string{"minimum"}
|
|
}
|
|
|
|
func (k *Minimum) LocalizedString(p *message.Printer) string {
|
|
got, _ := k.Got.Float64()
|
|
want, _ := k.Want.Float64()
|
|
return p.Sprintf("minimum: got %v, want %v", got, want)
|
|
}
|
|
|
|
// --
|
|
|
|
type Maximum struct {
|
|
Got *big.Rat
|
|
Want *big.Rat
|
|
}
|
|
|
|
func (*Maximum) KeywordPath() []string {
|
|
return []string{"maximum"}
|
|
}
|
|
|
|
func (k *Maximum) LocalizedString(p *message.Printer) string {
|
|
got, _ := k.Got.Float64()
|
|
want, _ := k.Want.Float64()
|
|
return p.Sprintf("maximum: got %v, want %v", got, want)
|
|
}
|
|
|
|
// --
|
|
|
|
type ExclusiveMinimum struct {
|
|
Got *big.Rat
|
|
Want *big.Rat
|
|
}
|
|
|
|
func (*ExclusiveMinimum) KeywordPath() []string {
|
|
return []string{"exclusiveMinimum"}
|
|
}
|
|
|
|
func (k *ExclusiveMinimum) LocalizedString(p *message.Printer) string {
|
|
got, _ := k.Got.Float64()
|
|
want, _ := k.Want.Float64()
|
|
return p.Sprintf("exclusiveMinimum: got %v, want %v", got, want)
|
|
}
|
|
|
|
// --
|
|
|
|
type ExclusiveMaximum struct {
|
|
Got *big.Rat
|
|
Want *big.Rat
|
|
}
|
|
|
|
func (*ExclusiveMaximum) KeywordPath() []string {
|
|
return []string{"exclusiveMaximum"}
|
|
}
|
|
|
|
func (k *ExclusiveMaximum) LocalizedString(p *message.Printer) string {
|
|
got, _ := k.Got.Float64()
|
|
want, _ := k.Want.Float64()
|
|
return p.Sprintf("exclusiveMaximum: got %v, want %v", got, want)
|
|
}
|
|
|
|
// --
|
|
|
|
type MultipleOf struct {
|
|
Got *big.Rat
|
|
Want *big.Rat
|
|
}
|
|
|
|
func (*MultipleOf) KeywordPath() []string {
|
|
return []string{"multipleOf"}
|
|
}
|
|
|
|
func (k *MultipleOf) LocalizedString(p *message.Printer) string {
|
|
got, _ := k.Got.Float64()
|
|
want, _ := k.Want.Float64()
|
|
return p.Sprintf("multipleOf: got %v, want %v", got, want)
|
|
}
|
|
|
|
// --
|
|
|
|
func quote(s string) string {
|
|
s = fmt.Sprintf("%q", s)
|
|
s = strings.ReplaceAll(s, `\"`, `"`)
|
|
s = strings.ReplaceAll(s, `'`, `\'`)
|
|
return "'" + s[1:len(s)-1] + "'"
|
|
}
|
|
|
|
func joinQuoted(arr []string, sep string) string {
|
|
var sb strings.Builder
|
|
for _, s := range arr {
|
|
if sb.Len() > 0 {
|
|
sb.WriteString(sep)
|
|
}
|
|
sb.WriteString(quote(s))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// to be used only for primitive.
|
|
func display(v any) string {
|
|
switch v := v.(type) {
|
|
case string:
|
|
return quote(v)
|
|
case []any, map[string]any:
|
|
return "value"
|
|
default:
|
|
return fmt.Sprintf("%v", v)
|
|
}
|
|
}
|
|
|
|
func localizedError(err error, p *message.Printer) string {
|
|
if err, ok := err.(interface{ LocalizedError(*message.Printer) string }); ok {
|
|
return err.LocalizedError(p)
|
|
}
|
|
return err.Error()
|
|
}
|