Skip to content

Commit

Permalink
validate ObjectMeta
Browse files Browse the repository at this point in the history
  • Loading branch information
chonton committed Sep 25, 2024
1 parent 1bd4498 commit 4fea5e0
Show file tree
Hide file tree
Showing 19 changed files with 453 additions and 39 deletions.
50 changes: 50 additions & 0 deletions acceptance.bats
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,56 @@ resetCacheFolder() {
[ "$status" -eq 1 ]
}

@test "Fail when annotation key is invalid" {
run bin/kubeconform fixtures/annotation_key_invalid.yaml
[ "$status" -eq 1 ]
}

@test "Fail when annotation value is missing" {
run bin/kubeconform fixtures/annotation_missing_value.yaml
[ "$status" -eq 1 ]
}

@test "Fail when annotation value is null" {
run bin/kubeconform fixtures/annotation_null_value.yaml
[ "$status" -eq 1 ]
}

@test "Fail when label name is too long" {
run bin/kubeconform fixtures/label_name_length.yaml
[ "$status" -eq 1 ]
}

@test "Fail when label namespace is invalid domain" {
run bin/kubeconform fixtures/label_namespace.yaml
[ "$status" -eq 1 ]
}

@test "Fail when label value is too long" {
run bin/kubeconform fixtures/label_value_length.yaml
[ "$status" -eq 1 ]
}

@test "Fail when metadata name is missing" {
run bin/kubeconform fixtures/metadata_name_missing.yaml
[ "$status" -eq 1 ]
}

@test "Pass if skip-metadata added" {
run bin/kubeconform -skip-metadata fixtures/metadata_name_missing.yaml
[ "$status" -eq 0 ]
}

@test "Pass with extra metadata fields" {
run bin/kubeconform fixtures/metadata_extra.yaml
[ "$status" -eq 0 ]
}

@test "Fail extra metadata fields when strict" {
run bin/kubeconform -strict fixtures/metadata_extra.yaml
[ "$status" -eq 1 ]
}

@test "Return relevant error for non-existent file" {
run bin/kubeconform fixtures/not-here
[ "$status" -eq 1 ]
Expand Down
1 change: 1 addition & 0 deletions cmd/kubeconform/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func kubeconform(cfg config.Config) int {
SkipKinds: cfg.SkipKinds,
RejectKinds: cfg.RejectKinds,
KubernetesVersion: cfg.KubernetesVersion.String(),
SkipMetadata: cfg.SkipMetadata,
Strict: cfg.Strict,
IgnoreMissingSchemas: cfg.IgnoreMissingSchemas,
})
Expand Down
8 changes: 8 additions & 0 deletions fixtures/annotation_key_invalid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: some-values
annotations:
cert(manager.io/cluster-issuer": issue #275
data:
file.name: "a value"
8 changes: 8 additions & 0 deletions fixtures/annotation_missing_value.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: some-values
annotations:
some.domain/some-key:
data:
file.name: "a value"
8 changes: 8 additions & 0 deletions fixtures/annotation_null_value.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: some-values
annotations:
some.domain/some-key: null
data:
file.name: "a value"
8 changes: 8 additions & 0 deletions fixtures/label_name_length.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: some-values
labels:
abcdefghijklmnopqrstuvwxyz-01234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ: "123456789_123456789_123456789_123456789_123456789_123456789_123"
data:
file.name: "a value"
8 changes: 8 additions & 0 deletions fixtures/label_namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: some-values
labels:
abcdefghijklmnopqrstuvwxyz-01234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ.example.com/ABCDEFGHIJKLMNOPQRSTUVWXYZ: "123456789_123456789_123456789_123456789_123456789_123456789_123"
data:
file.name: "a value"
8 changes: 8 additions & 0 deletions fixtures/label_value_length.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: some-values
labels:
some.domain/some-key: "123456789_123456789_123456789_123456789_123456789_123456789_1234"
data:
file.name: "a value"
9 changes: 9 additions & 0 deletions fixtures/metadata_extra.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: some-values
namespace: my-namespace
annotation:
flub: annotation should be annotations
data:
file.name: "a value"
4 changes: 4 additions & 0 deletions fixtures/metadata_missing.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: ConfigMap
data:
file.name: "a value"
6 changes: 6 additions & 0 deletions fixtures/metadata_name_missing.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:

data:
file.name: "a value"
6 changes: 6 additions & 0 deletions fixtures/object_name-max_length.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: abcdefghijklmnopqrstuvwxyz-01234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ
data:
file.name: "a value"
2 changes: 2 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Config struct {
RejectKinds map[string]struct{} `yaml:"reject" json:"reject"`
SchemaLocations []string `yaml:"schemaLocations" json:"schemaLocations"`
SkipKinds map[string]struct{} `yaml:"skip" json:"skip"`
SkipMetadata bool `yaml:"skipMetadata" json:"skipMetadata"`
SkipTLS bool `yaml:"insecureSkipTLSVerify" json:"insecureSkipTLSVerify"`
Strict bool `yaml:"strict" json:"strict"`
Summary bool `yaml:"summary" json:"summary"`
Expand Down Expand Up @@ -97,6 +98,7 @@ func FromFlags(progName string, args []string) (Config, string, error) {
flags.StringVar(&c.OutputFormat, "output", "text", "output format - json, junit, pretty, tap, text")
flags.BoolVar(&c.Verbose, "verbose", false, "print results for all resources (ignored for tap and junit output)")
flags.BoolVar(&c.SkipTLS, "insecure-skip-tls-verify", false, "disable verification of the server's SSL certificate. This will make your HTTPS connections insecure")
flags.BoolVar(&c.SkipMetadata, "skip-metadata", false, "skip extra validations of metadata section")
flags.StringVar(&c.Cache, "cache", "", "cache schemas downloaded via HTTP to this folder")
flags.BoolVar(&c.Help, "h", false, "show help information")
flags.BoolVar(&c.Version, "v", false, "show version information")
Expand Down
35 changes: 35 additions & 0 deletions pkg/registry/embeded.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package registry

import (
"embed"
)

//go:embed *.json
var content embed.FS

type EmbeddedRegistry struct {
debug bool
strict bool
}

// NewEmbeddedRegistry creates a new "registry", that will serve schemas from embedded resource
func NewEmbeddedRegistry(debug bool, strict bool) *EmbeddedRegistry {
return &EmbeddedRegistry{
debug, strict,
}
}

// DownloadSchema retrieves the schema from a file for the resource
func (r EmbeddedRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, []byte, error) {
var fileName string
if r.strict {
fileName = resourceKind + "-strict.json"
} else {
fileName = resourceKind + ".json"
}
bytes, err := content.ReadFile(fileName)
if err != nil {
return resourceKind, nil, nil
}
return "embedded:" + resourceKind, bytes, nil
}
110 changes: 110 additions & 0 deletions pkg/registry/metadata-strict.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"apiVersion": {
"$ref": "#/$defs/PREFIXED"
},
"kind": {
"$ref": "#/$defs/NAME"
},
"metadata": {
"type": "object",
"additionalProperties": false,
"properties": {
"annotations": {
"type": "object",
"propertyNames": {
"$ref": "#/$defs/PREFIXED"
},
"patternProperties": {
"^.+$": {
"type": "string",
"minLength": 1
}
}
},
"finalizers": {
"type": "array",
"items": {
"type": "string"
}
},
"generateName": {
"$ref": "#/$defs/RFC-1123-prefix"
},
"labels": {
"type": "object",
"propertyNames": {
"$ref": "#/$defs/PREFIXED"
},
"patternProperties": {
"^.+$": {
"$ref": "#/$defs/NAME"
}
}
},
"managedFields": {
"type": "array",
"items": {
"type": "object"
}
},
"name": {
"$ref": "#/$defs/RFC-1123"
},
"namespace": {
"$ref": "#/$defs/RFC-1123"
}
},
"oneOf": [
{
"required": [
"name"
]
},
{
"required": [
"generateName"
]
}
]
}
},
"required": [
"apiVersion",
"kind",
"metadata"
],
"$defs": {
"PREFIXED": {
"allOf": [
{
"pattern": "^(.{0,253}/)?.{1,63}$",
"type": "string"
},
{
"pattern": "^([a-z0-9-]{1,63}(\\.[a-z0-9-]{1,63})*/)?[a-z0-9A-Z]+([_.-][a-z0-9A-Z]+)*$"
}
]
},
"NAME": {
"type": "string",
"minLength": 1,
"maxLength": 63,
"pattern": "^[a-z0-9A-Z]+([_.-][a-z0-9A-Z]+)*$"
},
"RFC-1123": {
"type": "string",
"minLength": 1,
"maxLength": 63,
"pattern": "^[a-z0-9]+(-+[a-z0-9]+)*$"
},
"RFC-1123-prefix": {
"type": "string",
"minLength": 1,
"maxLength": 58,
"pattern": "^[a-z0-9]+[a-z0-9-]*$"
}
}
}
Loading

0 comments on commit 4fea5e0

Please sign in to comment.