Skip to content

Commit 31e9679

Browse files
authored
Update jsonschema library to v6 (#324)
1 parent df26feb commit 31e9679

File tree

125 files changed

+35571
-5134
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+35571
-5134
lines changed

Dockerfile.bats

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
FROM bats/bats:1.11.0
22
RUN apk --no-cache add ca-certificates parallel libxml2-utils
3-
COPY dist/kubeconform_linux_amd64_v1/kubeconform /code/bin/
3+
COPY bin/kubeconform /code/bin/
44
COPY acceptance.bats acceptance-nonetwork.bats /code/
55
COPY fixtures /code/fixtures

acceptance.bats

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,14 @@ resetCacheFolder() {
299299
@test "Fail when parsing a List that contains an invalid resource" {
300300
run bin/kubeconform -summary fixtures/list_invalid.yaml
301301
[ "$status" -eq 1 ]
302-
[ "${lines[0]}" == 'fixtures/list_invalid.yaml - ReplicationController bob is invalid: problem validating schema. Check JSON formatting: jsonschema: '\''/spec/replicas'\'' does not validate with https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone/replicationcontroller-v1.json#/properties/spec/properties/replicas/type: expected integer or null, but got string' ]
302+
[ "${lines[0]}" == 'fixtures/list_invalid.yaml - ReplicationController bob is invalid: problem validating schema. Check JSON formatting: jsonschema validation failed with '\''https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone/replicationcontroller-v1.json#'\'' - at '\''/spec/replicas'\'': got string, want null or integer' ]
303303
[ "${lines[1]}" == 'Summary: 2 resources found in 1 file - Valid: 1, Invalid: 1, Errors: 0, Skipped: 0' ]
304304
}
305305

306306
@test "Fail when parsing a List that contains an invalid resource from stdin" {
307307
run bash -c "cat fixtures/list_invalid.yaml | bin/kubeconform -summary -"
308308
[ "$status" -eq 1 ]
309-
[ "${lines[0]}" == 'stdin - ReplicationController bob is invalid: problem validating schema. Check JSON formatting: jsonschema: '\''/spec/replicas'\'' does not validate with https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone/replicationcontroller-v1.json#/properties/spec/properties/replicas/type: expected integer or null, but got string' ]
309+
[ "${lines[0]}" == 'stdin - ReplicationController bob is invalid: problem validating schema. Check JSON formatting: jsonschema validation failed with '\''https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master-standalone/replicationcontroller-v1.json#'\'' - at '\''/spec/replicas'\'': got string, want null or integer' ]
310310
[ "${lines[1]}" == 'Summary: 2 resources found parsing stdin - Valid: 1, Invalid: 1, Errors: 0, Skipped: 0' ]
311311
}
312312

fixtures/cache/6dd0c06492c957fe2118a16dae1c5b9e76be072b527a9a45fd1044bd54237334

Lines changed: 10655 additions & 0 deletions
Large diffs are not rendered by default.

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ go 1.24
44

55
require (
66
github.com/hashicorp/go-retryablehttp v0.7.7
7-
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
7+
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
8+
golang.org/x/text v0.25.0
89
sigs.k8s.io/yaml v1.4.0
910
)
1011

go.sum

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
2+
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
13
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
24
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
35
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@@ -12,10 +14,12 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
1214
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
1315
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
1416
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
15-
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
16-
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
17+
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
18+
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
1719
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
1820
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
21+
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
22+
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
1923
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2024
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2125
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=

pkg/cache/cache.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package cache
22

33
type Cache interface {
4-
Get(resourceKind, resourceAPIVersion, k8sVersion string) (interface{}, error)
5-
Set(resourceKind, resourceAPIVersion, k8sVersion string, schema interface{}) error
4+
Get(key string) (any, error)
5+
Set(key string, schema any) error
66
}

pkg/cache/inmemory.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,21 @@ import (
1010
// - This cache caches the parsed Schemas
1111
type inMemory struct {
1212
sync.RWMutex
13-
schemas map[string]interface{}
13+
schemas map[string]any
1414
}
1515

1616
// New creates a new cache for downloaded schemas
1717
func NewInMemoryCache() Cache {
1818
return &inMemory{
19-
schemas: map[string]interface{}{},
19+
schemas: make(map[string]any),
2020
}
2121
}
2222

23-
func key(resourceKind, resourceAPIVersion, k8sVersion string) string {
24-
return fmt.Sprintf("%s-%s-%s", resourceKind, resourceAPIVersion, k8sVersion)
25-
}
26-
2723
// Get retrieves the JSON schema given a resource signature
28-
func (c *inMemory) Get(resourceKind, resourceAPIVersion, k8sVersion string) (interface{}, error) {
29-
k := key(resourceKind, resourceAPIVersion, k8sVersion)
24+
func (c *inMemory) Get(key string) (any, error) {
3025
c.RLock()
3126
defer c.RUnlock()
32-
schema, ok := c.schemas[k]
27+
schema, ok := c.schemas[key]
3328

3429
if !ok {
3530
return nil, fmt.Errorf("schema not found in in-memory cache")
@@ -39,11 +34,10 @@ func (c *inMemory) Get(resourceKind, resourceAPIVersion, k8sVersion string) (int
3934
}
4035

4136
// Set adds a JSON schema to the schema cache
42-
func (c *inMemory) Set(resourceKind, resourceAPIVersion, k8sVersion string, schema interface{}) error {
43-
k := key(resourceKind, resourceAPIVersion, k8sVersion)
37+
func (c *inMemory) Set(key string, schema any) error {
4438
c.Lock()
4539
defer c.Unlock()
46-
c.schemas[k] = schema
40+
c.schemas[key] = schema
4741

4842
return nil
4943
}

pkg/cache/ondisk.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package cache
33
import (
44
"crypto/sha256"
55
"encoding/hex"
6-
"fmt"
76
"io"
87
"os"
98
"path"
@@ -22,17 +21,17 @@ func NewOnDiskCache(cache string) Cache {
2221
}
2322
}
2423

25-
func cachePath(folder, resourceKind, resourceAPIVersion, k8sVersion string) string {
26-
hash := sha256.Sum256([]byte(fmt.Sprintf("%s-%s-%s", resourceKind, resourceAPIVersion, k8sVersion)))
24+
func cachePath(folder, key string) string {
25+
hash := sha256.Sum256([]byte(key))
2726
return path.Join(folder, hex.EncodeToString(hash[:]))
2827
}
2928

3029
// Get retrieves the JSON schema given a resource signature
31-
func (c *onDisk) Get(resourceKind, resourceAPIVersion, k8sVersion string) (interface{}, error) {
30+
func (c *onDisk) Get(key string) (any, error) {
3231
c.RLock()
3332
defer c.RUnlock()
3433

35-
f, err := os.Open(cachePath(c.folder, resourceKind, resourceAPIVersion, k8sVersion))
34+
f, err := os.Open(cachePath(c.folder, key))
3635
if err != nil {
3736
return nil, err
3837
}
@@ -42,8 +41,12 @@ func (c *onDisk) Get(resourceKind, resourceAPIVersion, k8sVersion string) (inter
4241
}
4342

4443
// Set adds a JSON schema to the schema cache
45-
func (c *onDisk) Set(resourceKind, resourceAPIVersion, k8sVersion string, schema interface{}) error {
44+
func (c *onDisk) Set(key string, schema any) error {
4645
c.Lock()
4746
defer c.Unlock()
48-
return os.WriteFile(cachePath(c.folder, resourceKind, resourceAPIVersion, k8sVersion), schema.([]byte), 0644)
47+
48+
if _, err := os.Stat(cachePath(c.folder, key)); os.IsNotExist(err) {
49+
return os.WriteFile(cachePath(c.folder, key), schema.([]byte), 0644)
50+
}
51+
return nil
4952
}

pkg/loader/file.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package loader
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"fmt"
7+
"github.com/santhosh-tekuri/jsonschema/v6"
8+
"github.com/yannh/kubeconform/pkg/cache"
9+
"io"
10+
gourl "net/url"
11+
"os"
12+
"path/filepath"
13+
"runtime"
14+
"strings"
15+
)
16+
17+
// FileLoader loads json file url.
18+
type FileLoader struct {
19+
cache cache.Cache
20+
}
21+
22+
func (l FileLoader) Load(url string) (any, error) {
23+
path, err := l.ToFile(url)
24+
if err != nil {
25+
return nil, err
26+
}
27+
if l.cache != nil {
28+
if cached, err := l.cache.Get(path); err == nil {
29+
return jsonschema.UnmarshalJSON(bytes.NewReader(cached.([]byte)))
30+
}
31+
}
32+
33+
f, err := os.Open(path)
34+
if err != nil {
35+
if os.IsNotExist(err) {
36+
msg := fmt.Sprintf("could not open file %s", path)
37+
return nil, NewNotFoundError(errors.New(msg))
38+
}
39+
return nil, err
40+
}
41+
defer f.Close()
42+
43+
content, err := io.ReadAll(f)
44+
if err != nil {
45+
return nil, err
46+
}
47+
48+
if l.cache != nil {
49+
if err = l.cache.Set(path, content); err != nil {
50+
return nil, fmt.Errorf("failed to write cache to disk: %s", err)
51+
}
52+
}
53+
54+
return jsonschema.UnmarshalJSON(bytes.NewReader(content))
55+
}
56+
57+
// ToFile is helper method to convert file url to file path.
58+
func (l FileLoader) ToFile(url string) (string, error) {
59+
u, err := gourl.Parse(url)
60+
if err != nil {
61+
return "", err
62+
}
63+
if u.Scheme != "file" {
64+
return url, nil
65+
}
66+
path := u.Path
67+
if runtime.GOOS == "windows" {
68+
path = strings.TrimPrefix(path, "/")
69+
path = filepath.FromSlash(path)
70+
}
71+
return path, nil
72+
}
73+
74+
func NewFileLoader(cache cache.Cache) *FileLoader {
75+
return &FileLoader{
76+
cache: cache,
77+
}
78+
}

pkg/loader/http.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package loader
2+
3+
import (
4+
"bytes"
5+
"crypto/tls"
6+
"errors"
7+
"fmt"
8+
"github.com/hashicorp/go-retryablehttp"
9+
"github.com/santhosh-tekuri/jsonschema/v6"
10+
"github.com/yannh/kubeconform/pkg/cache"
11+
"io"
12+
"net/http"
13+
"time"
14+
)
15+
16+
type HTTPURLLoader struct {
17+
client http.Client
18+
cache cache.Cache
19+
}
20+
21+
func (l *HTTPURLLoader) Load(url string) (any, error) {
22+
if l.cache != nil {
23+
if cached, err := l.cache.Get(url); err == nil {
24+
return jsonschema.UnmarshalJSON(bytes.NewReader(cached.([]byte)))
25+
}
26+
}
27+
28+
resp, err := l.client.Get(url)
29+
if err != nil {
30+
msg := fmt.Sprintf("failed downloading schema at %s: %s", url, err)
31+
return nil, errors.New(msg)
32+
}
33+
defer resp.Body.Close()
34+
35+
if resp.StatusCode == http.StatusNotFound {
36+
msg := fmt.Sprintf("could not find schema at %s", url)
37+
return nil, NewNotFoundError(errors.New(msg))
38+
}
39+
40+
if resp.StatusCode != http.StatusOK {
41+
msg := fmt.Sprintf("error while downloading schema at %s - received HTTP status %d", url, resp.StatusCode)
42+
return nil, fmt.Errorf("%s", msg)
43+
}
44+
45+
body, err := io.ReadAll(resp.Body)
46+
if err != nil {
47+
msg := fmt.Sprintf("failed parsing schema from %s: %s", url, err)
48+
return nil, errors.New(msg)
49+
}
50+
51+
if l.cache != nil {
52+
if err = l.cache.Set(url, body); err != nil {
53+
return nil, fmt.Errorf("failed to write cache to disk: %s", err)
54+
}
55+
}
56+
57+
s, err := jsonschema.UnmarshalJSON(bytes.NewReader(body))
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
return s, nil
63+
}
64+
65+
func NewHTTPURLLoader(skipTLS bool, cache cache.Cache) (*HTTPURLLoader, error) {
66+
transport := &http.Transport{
67+
MaxIdleConns: 100,
68+
IdleConnTimeout: 3 * time.Second,
69+
DisableCompression: true,
70+
Proxy: http.ProxyFromEnvironment,
71+
}
72+
73+
if skipTLS {
74+
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
75+
}
76+
77+
// retriable http client
78+
retryClient := retryablehttp.NewClient()
79+
retryClient.RetryMax = 2
80+
retryClient.HTTPClient = &http.Client{Transport: transport}
81+
retryClient.Logger = nil
82+
83+
httpLoader := HTTPURLLoader{client: *retryClient.StandardClient(), cache: cache}
84+
return &httpLoader, nil
85+
}

0 commit comments

Comments
 (0)