Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: adding private repo capability #243

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ kubeconform -kubernetes-version 3.8.0 -schema-location 'https://raw.githubuserc
Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0 Skipped: 0
```

### Schemas behind private GitHub repos

By setting the environment variable `GITHUB_TOKEN=x` you can use schemas that are behind a private repository.
See [getting a token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) for info on how to get one command line token.
> Tip: if using GitHub CLI, `gh auth token` will give a valid token.


## Integrating Kubeconform in the CI

`Kubeconform` publishes Docker Images to Github's new Container Registry (ghcr.io). These images
Expand Down
6 changes: 3 additions & 3 deletions pkg/cache/ondisk.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io/ioutil"
"io"
"os"
"path"
"sync"
Expand Down Expand Up @@ -37,12 +37,12 @@ func (c *onDisk) Get(resourceKind, resourceAPIVersion, k8sVersion string) (inter
return nil, err
}

return ioutil.ReadAll(f)
return io.ReadAll(f)
}

// Set adds a JSON schema to the schema cache
func (c *onDisk) Set(resourceKind, resourceAPIVersion, k8sVersion string, schema interface{}) error {
c.Lock()
defer c.Unlock()
return ioutil.WriteFile(cachePath(c.folder, resourceKind, resourceAPIVersion, k8sVersion), schema.([]byte), 0644)
return os.WriteFile(cachePath(c.folder, resourceKind, resourceAPIVersion, k8sVersion), schema.([]byte), 0644)
}
24 changes: 18 additions & 6 deletions pkg/registry/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"crypto/tls"
"errors"
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"os"
Expand All @@ -13,13 +13,13 @@ import (
"github.com/yannh/kubeconform/pkg/cache"
)

type httpGetter interface {
Get(url string) (resp *http.Response, err error)
type httpDoer interface {
Do(*http.Request) (resp *http.Response, err error)
}

// SchemaRegistry is a file repository (local or remote) that contains JSON schemas for Kubernetes resources
type SchemaRegistry struct {
c httpGetter
c httpDoer
schemaPathTemplate string
cache cache.Cache
strict bool
Expand Down Expand Up @@ -72,8 +72,20 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
return url, b.([]byte), nil
}
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
msg := fmt.Sprintf("failed to create http request for schemas at %s: %s", url, err)
if r.debug {
log.Println(msg)
}
return url, nil, errors.New(msg)
}

if token, exist := os.LookupEnv("KUBECONFORM_AUTH_TOKEN"); exist {
req.Header.Add("Authorization", fmt.Sprintf("token %s", token))
}

resp, err := r.c.Get(url)
resp, err := r.c.Do(req)
if err != nil {
msg := fmt.Sprintf("failed downloading schema at %s: %s", url, err)
if r.debug {
Expand All @@ -99,7 +111,7 @@ func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVers
return url, nil, fmt.Errorf(msg)
}

body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
msg := fmt.Sprintf("failed parsing schema from %s: %s", url, err)
if r.debug {
Expand Down
32 changes: 16 additions & 16 deletions pkg/registry/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,29 @@ package registry
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"net/http"
"strings"
"testing"
)

type mockHTTPGetter struct {
httpGet func(string) (*http.Response, error)
type mockHTTPDoer struct {
httpDo func(*http.Request) (*http.Response, error)
}

func newMockHTTPGetter(f func(string) (*http.Response, error)) *mockHTTPGetter {
return &mockHTTPGetter{
httpGet: f,
func newMockHTTPDoer(f func(*http.Request) (*http.Response, error)) *mockHTTPDoer {
return &mockHTTPDoer{
httpDo: f,
}
}
func (m mockHTTPGetter) Get(url string) (resp *http.Response, err error) {
return m.httpGet(url)
func (m mockHTTPDoer) Do(req *http.Request) (resp *http.Response, err error) {
return m.httpDo(req)
}

func TestDownloadSchema(t *testing.T) {
for _, testCase := range []struct {
name string
c httpGetter
c httpDoer
schemaPathTemplate string
strict bool
resourceKind, resourceAPIVersion, k8sversion string
Expand All @@ -34,7 +34,7 @@ func TestDownloadSchema(t *testing.T) {
}{
{
"error when downloading",
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
newMockHTTPDoer(func(req *http.Request) (resp *http.Response, err error) {
return nil, fmt.Errorf("failed downloading from registry")
}),
"http://kubernetesjson.dev",
Expand All @@ -47,10 +47,10 @@ func TestDownloadSchema(t *testing.T) {
},
{
"getting 404",
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
newMockHTTPDoer(func(req *http.Request) (resp *http.Response, err error) {
return &http.Response{
StatusCode: http.StatusNotFound,
Body: ioutil.NopCloser(strings.NewReader("http response mock body")),
Body: io.NopCloser(strings.NewReader("http response mock body")),
}, nil
}),
"http://kubernetesjson.dev",
Expand All @@ -63,10 +63,10 @@ func TestDownloadSchema(t *testing.T) {
},
{
"getting 503",
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
newMockHTTPDoer(func(req *http.Request) (resp *http.Response, err error) {
return &http.Response{
StatusCode: http.StatusServiceUnavailable,
Body: ioutil.NopCloser(strings.NewReader("http response mock body")),
Body: io.NopCloser(strings.NewReader("http response mock body")),
}, nil
}),
"http://kubernetesjson.dev",
Expand All @@ -79,10 +79,10 @@ func TestDownloadSchema(t *testing.T) {
},
{
"200",
newMockHTTPGetter(func(url string) (resp *http.Response, err error) {
newMockHTTPDoer(func(req *http.Request) (resp *http.Response, err error) {
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(strings.NewReader("http response mock body")),
Body: io.NopCloser(strings.NewReader("http response mock body")),
}, nil
}),
"http://kubernetesjson.dev",
Expand Down
4 changes: 2 additions & 2 deletions pkg/registry/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package registry
import (
"errors"
"fmt"
"io/ioutil"
"io"
"log"
"os"
)
Expand Down Expand Up @@ -47,7 +47,7 @@ func (r LocalRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersi
}

defer f.Close()
content, err := ioutil.ReadAll(f)
content, err := io.ReadAll(f)
if err != nil {
msg := fmt.Sprintf("failed to read schema at %s: %s", schemaFile, err)
if r.debug {
Expand Down