From e2335d7e647155b3b9367367c1a11a9c97b116ec Mon Sep 17 00:00:00 2001 From: Martin Kluska Date: Wed, 21 May 2025 11:26:46 +0200 Subject: [PATCH] PoC handle 429 coming from rawgithubuser by passing auth header --- cmd/kubeconform/main.go | 1 + pkg/config/config.go | 2 ++ pkg/loader/http.go | 25 ++++++++++++++++++++----- pkg/loader/http_test.go | 2 +- pkg/registry/registry.go | 9 +++++---- pkg/validator/validator.go | 14 ++++++++------ 6 files changed, 37 insertions(+), 16 deletions(-) diff --git a/cmd/kubeconform/main.go b/cmd/kubeconform/main.go index d1ae4b3..6ad19c7 100644 --- a/cmd/kubeconform/main.go +++ b/cmd/kubeconform/main.go @@ -80,6 +80,7 @@ func kubeconform(cfg config.Config) int { var v validator.Validator v, err = validator.New(cfg.SchemaLocations, validator.Opts{ Cache: cfg.Cache, + AuthToken: cfg.AuthToken, Debug: cfg.Debug, SkipTLS: cfg.SkipTLS, SkipKinds: cfg.SkipKinds, diff --git a/pkg/config/config.go b/pkg/config/config.go index b7df0f4..ea0ee7d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -10,6 +10,7 @@ import ( type Config struct { Cache string `yaml:"cache" json:"cache"` + AuthToken string `yaml:"authToken" json:"authToken"` Debug bool `yaml:"debug" json:"debug"` ExitOnError bool `yaml:"exitOnError" json:"exitOnError"` Files []string `yaml:"files" json:"files"` @@ -98,6 +99,7 @@ func FromFlags(progName string, args []string) (Config, string, error) { 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.StringVar(&c.Cache, "cache", "", "cache schemas downloaded via HTTP to this folder") + flags.StringVar(&c.AuthToken, "auth-token", "", "token used to fetch github data") flags.BoolVar(&c.Help, "h", false, "show help information") flags.BoolVar(&c.Version, "v", false, "show version information") flags.Usage = func() { diff --git a/pkg/loader/http.go b/pkg/loader/http.go index 91eee88..d5bb834 100644 --- a/pkg/loader/http.go +++ b/pkg/loader/http.go @@ -14,8 +14,9 @@ import ( ) type HTTPURLLoader struct { - client http.Client - cache cache.Cache + client http.Client + cache cache.Cache + authToken string } func (l *HTTPURLLoader) Load(url string) (any, error) { @@ -25,7 +26,17 @@ func (l *HTTPURLLoader) Load(url string) (any, error) { } } - resp, err := l.client.Get(url) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + msg := fmt.Sprintf("Error creating request: %s", err) + return nil, errors.New(msg) + } + + if l.authToken != "i" { + req.Header.Set("Authorization", "Bearer "+l.authToken) + } + + resp, err := l.client.Do(req) if err != nil { msg := fmt.Sprintf("failed downloading schema at %s: %s", url, err) return nil, errors.New(msg) @@ -62,7 +73,7 @@ func (l *HTTPURLLoader) Load(url string) (any, error) { return s, nil } -func NewHTTPURLLoader(skipTLS bool, cache cache.Cache) (*HTTPURLLoader, error) { +func NewHTTPURLLoader(skipTLS bool, cache cache.Cache, authToken string) (*HTTPURLLoader, error) { transport := &http.Transport{ MaxIdleConns: 100, IdleConnTimeout: 3 * time.Second, @@ -80,6 +91,10 @@ func NewHTTPURLLoader(skipTLS bool, cache cache.Cache) (*HTTPURLLoader, error) { retryClient.HTTPClient = &http.Client{Transport: transport} retryClient.Logger = nil - httpLoader := HTTPURLLoader{client: *retryClient.StandardClient(), cache: cache} + httpLoader := HTTPURLLoader{ + client: *retryClient.StandardClient(), + cache: cache, + authToken: authToken, + } return &httpLoader, nil } diff --git a/pkg/loader/http_test.go b/pkg/loader/http_test.go index 0846bf8..d517659 100644 --- a/pkg/loader/http_test.go +++ b/pkg/loader/http_test.go @@ -195,7 +195,7 @@ func TestHTTPURLLoader_Load_Retries(t *testing.T) { defer server.Close() // Create HTTPURLLoader - loader, _ := NewHTTPURLLoader(false, nil) + loader, _ := NewHTTPURLLoader(false, nil, "") fullurl := server.URL + tt.url // Call Load and handle errors diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go index dd965c3..7d0c041 100644 --- a/pkg/registry/registry.go +++ b/pkg/registry/registry.go @@ -3,11 +3,12 @@ package registry import ( "bytes" "fmt" - "github.com/yannh/kubeconform/pkg/cache" - "github.com/yannh/kubeconform/pkg/loader" "os" "strings" "text/template" + + "github.com/yannh/kubeconform/pkg/cache" + "github.com/yannh/kubeconform/pkg/loader" ) type Manifest struct { @@ -68,7 +69,7 @@ func schemaPath(tpl, resourceKind, resourceAPIVersion, k8sVersion string, strict return buf.String(), nil } -func New(schemaLocation string, cacheFolder string, strict bool, skipTLS bool, debug bool) (Registry, error) { +func New(schemaLocation string, cacheFolder string, strict bool, skipTLS bool, debug bool, authToken string) (Registry, error) { if schemaLocation == "default" { schemaLocation = "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json" } else if !strings.HasSuffix(schemaLocation, "json") { // If we dont specify a full templated path, we assume the paths of our fork of kubernetes-json-schema @@ -94,7 +95,7 @@ func New(schemaLocation string, cacheFolder string, strict bool, skipTLS bool, d } if strings.HasPrefix(schemaLocation, "http") { - httpLoader, err := loader.NewHTTPURLLoader(skipTLS, c) + httpLoader, err := loader.NewHTTPURLLoader(skipTLS, c, authToken) if err != nil { return nil, fmt.Errorf("failed creating HTTP loader: %s", err) } diff --git a/pkg/validator/validator.go b/pkg/validator/validator.go index 2412ac8..88d01ee 100644 --- a/pkg/validator/validator.go +++ b/pkg/validator/validator.go @@ -5,6 +5,11 @@ import ( "context" "errors" "fmt" + "io" + "os" + "strings" + "time" + jsonschema "github.com/santhosh-tekuri/jsonschema/v6" "github.com/yannh/kubeconform/pkg/cache" "github.com/yannh/kubeconform/pkg/loader" @@ -12,11 +17,7 @@ import ( "github.com/yannh/kubeconform/pkg/resource" "golang.org/x/text/language" "golang.org/x/text/message" - "io" - "os" "sigs.k8s.io/yaml" - "strings" - "time" ) // Different types of validation results @@ -58,6 +59,7 @@ type Validator interface { // Opts contains a set of options for the validator. type Opts struct { Cache string // Cache schemas downloaded via HTTP to this folder + AuthToken string // Cache schemas downloaded via HTTP to this folder Debug bool // Debug infos will be print here SkipTLS bool // skip TLS validation when downloading from an HTTP Schema Registry SkipKinds map[string]struct{} // List of resource Kinds to ignore @@ -77,7 +79,7 @@ func New(schemaLocations []string, opts Opts) (Validator, error) { registries := []registry.Registry{} for _, schemaLocation := range schemaLocations { - reg, err := registry.New(schemaLocation, opts.Cache, opts.Strict, opts.SkipTLS, opts.Debug) + reg, err := registry.New(schemaLocation, opts.Cache, opts.Strict, opts.SkipTLS, opts.Debug, opts.AuthToken) if err != nil { return nil, err } @@ -108,7 +110,7 @@ func New(schemaLocations []string, opts Opts) (Validator, error) { filecache = cache.NewOnDiskCache(opts.Cache) } - httpLoader, err := loader.NewHTTPURLLoader(false, filecache) + httpLoader, err := loader.NewHTTPURLLoader(false, filecache, opts.AuthToken) if err != nil { return nil, fmt.Errorf("failed creating HTTP loader: %s", err) }