├── .github └── workflows │ ├── main.yml │ └── site.yml ├── .gitignore ├── .goreleaser.yml ├── Dockerfile ├── Dockerfile-alpine ├── Dockerfile.bats ├── LICENSE ├── Makefile ├── Readme.md ├── acceptance-nonetwork.bats ├── acceptance.bats ├── bin └── .gitignore ├── cmd └── kubeconform │ └── main.go ├── examples └── main.go ├── fixtures ├── blank.yaml ├── cache │ ├── 603105c17f981119fec20ae25cfb97ff6dd99114a875ae841ef965d9345667e3 │ ├── 6dc6142c64b944d783a3e783526114da8e747a14a11d8b32dd1f12e2d89a8330 │ └── 6dd0c06492c957fe2118a16dae1c5b9e76be072b527a9a45fd1044bd54237334 ├── comment.yaml ├── crd_schema.yaml ├── duplicate_property.yaml ├── duplicates-non-namespaced.yaml ├── duplicates-skipped-kinds.yaml ├── duplicates-with-namespace-default.yaml ├── duplicates-with-namespace.yaml ├── duplicates.yaml ├── extra_property.yaml ├── folder │ ├── multi_valid.yaml │ └── valid.yaml ├── full_domain_group.yaml ├── generate_name.yaml ├── grafana-alert-rule-group-sample.yaml ├── grafanaalertrulegroup_v1beta1.json ├── httpproxy.yaml ├── int_or_string.yaml ├── invalid.yaml ├── junit.xsd ├── list_empty_valid.yaml ├── list_invalid.yaml ├── list_valid.yaml ├── missing_apiversion.yaml ├── missing_kind.yaml ├── missing_kind_value.yaml ├── multi_invalid.yaml ├── multi_invalid_resources.yaml ├── multi_valid.yaml ├── multi_valid_source.yaml ├── multi_with_list.yaml ├── null_array.yaml ├── null_string.yaml ├── quantity.yaml ├── registry │ ├── sagemaker.aws.amazon.com_trainingjobs.yaml │ └── trainingjob-sagemaker-v1.json ├── same-kind-different-api.yaml ├── same-object-different-namespace-default.yaml ├── same-object-different-namespace.yaml ├── test_crd.yaml ├── unconventional_keys.yaml ├── valid.json ├── valid.yaml ├── valid_large.yaml └── valid_version.yaml ├── go.mod ├── go.sum ├── pkg ├── cache │ ├── cache.go │ ├── inmemory.go │ └── ondisk.go ├── config │ ├── config.go │ └── config_test.go ├── loader │ ├── file.go │ ├── http.go │ ├── http_test.go │ └── loaders.go ├── output │ ├── json.go │ ├── json_test.go │ ├── junit.go │ ├── junit_test.go │ ├── output.go │ ├── pretty.go │ ├── pretty_test.go │ ├── tap.go │ ├── tap_test.go │ ├── text.go │ └── text_test.go ├── registry │ ├── http.go │ ├── local.go │ ├── registry.go │ └── registry_test.go ├── resource │ ├── files.go │ ├── files_test.go │ ├── resource.go │ ├── resource_test.go │ ├── stream.go │ └── stream_test.go └── validator │ ├── validator.go │ └── validator_test.go ├── scripts ├── Dockerfile.bats ├── Makefile ├── acceptance.bats ├── fixtures │ ├── prometheus-operator-0prometheusCustomResourceDefinition.yaml │ ├── prometheus_v1-denyRootAdditionalProperties.json │ └── prometheus_v1-expected.json ├── openapi2jsonschema.py └── requirements.txt ├── site ├── archetypes │ └── default.md ├── config.toml ├── content │ ├── about.md │ └── docs │ │ ├── crd-support.md │ │ ├── installation.md │ │ ├── json-schema-conversion.md │ │ ├── overview.md │ │ ├── usage-as-github-action.md │ │ ├── usage.md │ │ └── using-as-a-go-module.md ├── public │ ├── about │ │ └── index.html │ ├── categories │ │ └── index.xml │ ├── css │ │ ├── prism.css │ │ └── style.css │ ├── docs │ │ ├── crd-support │ │ │ └── index.html │ │ ├── index.xml │ │ ├── installation │ │ │ └── index.html │ │ ├── json-schema-conversion │ │ │ └── index.html │ │ ├── usage-as-github-action │ │ │ └── index.html │ │ ├── usage │ │ │ └── index.html │ │ └── using-as-a-go-module │ │ │ └── index.html │ ├── index.html │ ├── index.xml │ ├── installation │ │ └── index.html │ ├── js │ │ └── prism.js │ ├── sitemap.xml │ └── tags │ │ ├── about │ │ └── index.xml │ │ ├── cloudfront │ │ └── index.xml │ │ ├── index.xml │ │ ├── installation │ │ └── index.xml │ │ ├── kubeconform │ │ └── index.xml │ │ ├── lambdaedge │ │ └── index.xml │ │ └── usage │ │ └── index.xml └── themes │ └── kubeconform │ ├── LICENSE │ ├── archetypes │ └── default.md │ ├── layouts │ ├── 404.html │ ├── _default │ │ ├── baseof.html │ │ ├── list.html │ │ └── single.html │ ├── index.html │ ├── partials │ │ ├── footer.html │ │ ├── head.html │ │ ├── header.html │ │ └── menu.html │ └── shortcodes │ │ ├── prism.html │ │ └── rawhtml.html │ ├── static │ ├── css │ │ ├── prism.css │ │ └── style.css │ └── js │ │ └── prism.js │ └── theme.toml └── vendor ├── github.com ├── hashicorp │ ├── go-cleanhttp │ │ ├── LICENSE │ │ ├── README.md │ │ ├── cleanhttp.go │ │ ├── doc.go │ │ └── handlers.go │ └── go-retryablehttp │ │ ├── .gitignore │ │ ├── .go-version │ │ ├── CHANGELOG.md │ │ ├── CODEOWNERS │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── cert_error_go119.go │ │ ├── cert_error_go120.go │ │ ├── client.go │ │ └── roundtripper.go └── santhosh-tekuri │ └── jsonschema │ └── v6 │ ├── .gitmodules │ ├── .golangci.yml │ ├── .pre-commit-hooks.yaml │ ├── LICENSE │ ├── README.md │ ├── compiler.go │ ├── content.go │ ├── draft.go │ ├── format.go │ ├── go.work │ ├── kind │ └── kind.go │ ├── loader.go │ ├── metaschemas │ ├── draft-04 │ │ └── schema │ ├── draft-06 │ │ └── schema │ ├── draft-07 │ │ └── schema │ └── draft │ │ ├── 2019-09 │ │ ├── meta │ │ │ ├── applicator │ │ │ ├── content │ │ │ ├── core │ │ │ ├── format │ │ │ ├── meta-data │ │ │ └── validation │ │ └── schema │ │ └── 2020-12 │ │ ├── meta │ │ ├── applicator │ │ ├── content │ │ ├── core │ │ ├── format-annotation │ │ ├── format-assertion │ │ ├── meta-data │ │ ├── unevaluated │ │ └── validation │ │ └── schema │ ├── objcompiler.go │ ├── output.go │ ├── position.go │ ├── root.go │ ├── roots.go │ ├── schema.go │ ├── util.go │ ├── validator.go │ └── vocab.go ├── golang.org └── x │ └── text │ ├── LICENSE │ ├── PATENTS │ ├── feature │ └── plural │ │ ├── common.go │ │ ├── message.go │ │ ├── plural.go │ │ └── tables.go │ ├── internal │ ├── catmsg │ │ ├── catmsg.go │ │ ├── codec.go │ │ └── varint.go │ ├── format │ │ ├── format.go │ │ └── parser.go │ ├── internal.go │ ├── language │ │ ├── common.go │ │ ├── compact.go │ │ ├── compact │ │ │ ├── compact.go │ │ │ ├── language.go │ │ │ ├── parents.go │ │ │ ├── tables.go │ │ │ └── tags.go │ │ ├── compose.go │ │ ├── coverage.go │ │ ├── language.go │ │ ├── lookup.go │ │ ├── match.go │ │ ├── parse.go │ │ ├── tables.go │ │ └── tags.go │ ├── match.go │ ├── number │ │ ├── common.go │ │ ├── decimal.go │ │ ├── format.go │ │ ├── number.go │ │ ├── pattern.go │ │ ├── roundingmode_string.go │ │ └── tables.go │ ├── stringset │ │ └── set.go │ └── tag │ │ └── tag.go │ ├── language │ ├── coverage.go │ ├── doc.go │ ├── language.go │ ├── match.go │ ├── parse.go │ ├── tables.go │ └── tags.go │ └── message │ ├── catalog.go │ ├── catalog │ ├── catalog.go │ ├── dict.go │ ├── go19.go │ └── gopre19.go │ ├── doc.go │ ├── format.go │ ├── message.go │ └── print.go ├── modules.txt └── sigs.k8s.io └── yaml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── OWNERS ├── README.md ├── RELEASE.md ├── SECURITY_CONTACTS ├── code-of-conduct.md ├── fields.go ├── goyaml.v2 ├── LICENSE ├── LICENSE.libyaml ├── NOTICE ├── OWNERS ├── README.md ├── apic.go ├── decode.go ├── emitterc.go ├── encode.go ├── parserc.go ├── readerc.go ├── resolve.go ├── scannerc.go ├── sorter.go ├── writerc.go ├── yaml.go ├── yamlh.go └── yamlprivateh.go ├── yaml.go └── yaml_go110.go /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: push 3 | jobs: 4 | kubeconform-test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: checkout 8 | uses: actions/checkout@v4 9 | 10 | - name: test 11 | run: make docker-test 12 | 13 | - name: build 14 | run: make goreleaser-build-static 15 | 16 | - name: acceptance-test 17 | run: make docker-acceptance 18 | 19 | openapi2jsonschema-test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: checkout 23 | uses: actions/checkout@v4 24 | 25 | - name: test 26 | working-directory: ./scripts 27 | run: make docker-test docker-acceptance 28 | 29 | goreleaser: 30 | runs-on: ubuntu-latest 31 | needs: 32 | - kubeconform-test 33 | - openapi2jsonschema-test 34 | if: startsWith(github.ref, 'refs/tags/v') 35 | steps: 36 | - name: checkout 37 | uses: actions/checkout@v4 38 | with: 39 | fetch-depth: 0 # https://github.com/goreleaser/goreleaser-action/issues/56 40 | 41 | - uses: docker/setup-qemu-action@v3 42 | - uses: docker/setup-buildx-action@v3 43 | 44 | - name: goreleaser 45 | run: | 46 | echo "${{ github.token }}" | docker login https://ghcr.io -u ${GITHUB_ACTOR} --password-stdin 47 | GITHUB_ACTOR=$(echo ${GITHUB_ACTOR} | tr '[:upper:]' '[:lower:]') 48 | GIT_OWNER=${GITHUB_ACTOR} make release 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | -------------------------------------------------------------------------------- /.github/workflows/site.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | push: 4 | paths: 5 | - 'site/**' 6 | branches: 7 | - master 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup Hugo 16 | uses: peaceiris/actions-hugo@v2 17 | with: 18 | hugo-version: '0.83.1' 19 | 20 | - name: Build 21 | run: hugo --minify 22 | working-directory: site 23 | 24 | - name: Deploy 25 | uses: peaceiris/actions-gh-pages@v3 26 | if: github.ref == 'refs/heads/master' 27 | with: 28 | publish_dir: ./site/public 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | cname: kubeconform.mandragor.org 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | bin/ 3 | .idea/ 4 | **/*.pyc 5 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: kubeconform 2 | builds: 3 | - main: ./cmd/kubeconform 4 | env: 5 | - CGO_ENABLED=0 6 | - GOFLAGS = -mod=vendor 7 | - GO111MODULE = on 8 | - GIT_OWNER = yannh 9 | goos: 10 | - windows 11 | - linux 12 | - darwin 13 | goarch: 14 | - 386 15 | - amd64 16 | - arm 17 | - arm64 18 | flags: 19 | - -trimpath 20 | - -tags=netgo 21 | - -a 22 | ldflags: 23 | - -extldflags "-static" 24 | - -X main.version={{.Tag}} 25 | 26 | archives: 27 | - format: tar.gz 28 | format_overrides: 29 | - goos: windows 30 | format: zip 31 | name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" 32 | 33 | dockers: 34 | - image_templates: 35 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-amd64' 36 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-amd64' 37 | dockerfile: Dockerfile 38 | use: buildx 39 | build_flag_templates: 40 | - "--pull" 41 | - "--platform=linux/amd64" 42 | goos: linux 43 | goarch: amd64 44 | - image_templates: 45 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-arm64' 46 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-arm64' 47 | dockerfile: Dockerfile 48 | use: buildx 49 | build_flag_templates: 50 | - "--pull" 51 | - "--platform=linux/arm64" 52 | goos: linux 53 | goarch: arm64 54 | - image_templates: 55 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-amd64-alpine' 56 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-amd64-alpine' 57 | dockerfile: Dockerfile-alpine 58 | use: buildx 59 | build_flag_templates: 60 | - "--pull" 61 | - "--platform=linux/amd64" 62 | goos: linux 63 | goarch: amd64 64 | - image_templates: 65 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-arm64-alpine' 66 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-arm64-alpine' 67 | dockerfile: Dockerfile-alpine 68 | use: buildx 69 | build_flag_templates: 70 | - "--pull" 71 | - "--platform=linux/arm64" 72 | goos: linux 73 | goarch: arm64 74 | 75 | docker_manifests: 76 | - name_template: 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}' 77 | image_templates: 78 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-amd64' 79 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-arm64' 80 | - name_template: 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest' 81 | image_templates: 82 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-amd64' 83 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-arm64' 84 | - name_template: 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-alpine' 85 | image_templates: 86 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-amd64-alpine' 87 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:latest-arm64-alpine' 88 | - name_template: 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-alpine' 89 | image_templates: 90 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-amd64-alpine' 91 | - 'ghcr.io/{{.Env.GIT_OWNER}}/kubeconform:{{ .Tag }}-arm64-alpine' 92 | 93 | checksum: 94 | name_template: 'CHECKSUMS' 95 | 96 | snapshot: 97 | name_template: "{{ .Tag }}-next" 98 | 99 | changelog: 100 | sort: asc 101 | filters: 102 | exclude: 103 | - '^test:' 104 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21.3 as certs 2 | RUN apk add ca-certificates 3 | 4 | FROM scratch AS kubeconform 5 | LABEL org.opencontainers.image.authors="Yann Hamon " \ 6 | org.opencontainers.image.source="https://github.com/yannh/kubeconform/" \ 7 | org.opencontainers.image.description="A Kubernetes manifests validation tool" \ 8 | org.opencontainers.image.documentation="https://github.com/yannh/kubeconform/" \ 9 | org.opencontainers.image.licenses="Apache License 2.0" \ 10 | org.opencontainers.image.title="kubeconform" \ 11 | org.opencontainers.image.url="https://github.com/yannh/kubeconform/" 12 | COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt 13 | COPY kubeconform / 14 | ENTRYPOINT ["/kubeconform"] 15 | -------------------------------------------------------------------------------- /Dockerfile-alpine: -------------------------------------------------------------------------------- 1 | FROM alpine:3.20.2 2 | 3 | LABEL org.opencontainers.image.authors="Yann Hamon " \ 4 | org.opencontainers.image.source="https://github.com/yannh/kubeconform/" \ 5 | org.opencontainers.image.description="A Kubernetes manifests validation tool" \ 6 | org.opencontainers.image.documentation="https://github.com/yannh/kubeconform/" \ 7 | org.opencontainers.image.licenses="Apache License 2.0" \ 8 | org.opencontainers.image.title="kubeconform" \ 9 | org.opencontainers.image.url="https://github.com/yannh/kubeconform/" 10 | RUN apk add ca-certificates 11 | COPY kubeconform / 12 | ENTRYPOINT ["/kubeconform"] 13 | -------------------------------------------------------------------------------- /Dockerfile.bats: -------------------------------------------------------------------------------- 1 | FROM bats/bats:1.11.0 2 | RUN apk --no-cache add ca-certificates parallel libxml2-utils 3 | COPY bin/kubeconform /code/bin/ 4 | COPY acceptance.bats acceptance-nonetwork.bats /code/ 5 | COPY fixtures /code/fixtures 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | RELEASE_VERSION ?= latest 4 | 5 | .PHONY: local-test local-build local-build-static docker-test docker-build docker-build-static build-bats docker-acceptance release update-deps build-single-target 6 | 7 | local-test: 8 | go test -race ./... -count=1 9 | 10 | local-build: 11 | git config --global --add safe.directory $$PWD 12 | go build -o bin/ ./... 13 | 14 | local-build-static: 15 | CGO_ENABLED=0 GOFLAGS=-mod=vendor GOOS=linux GOARCH=amd64 GO111MODULE=on go build -trimpath -tags=netgo -ldflags "-extldflags=\"-static\"" -a -o bin/ ./... 16 | 17 | # These only used for development. Release artifacts and docker images are produced by goreleaser. 18 | docker-test: 19 | docker run -t -v $$PWD:/go/src/github.com/yannh/kubeconform -w /go/src/github.com/yannh/kubeconform golang:1.24.3 make local-test 20 | 21 | docker-build: 22 | docker run -t -v $$PWD:/go/src/github.com/yannh/kubeconform -w /go/src/github.com/yannh/kubeconform golang:1.24.3 make local-build 23 | 24 | docker-build-static: 25 | docker run -t -v $$PWD:/go/src/github.com/yannh/kubeconform -w /go/src/github.com/yannh/kubeconform golang:1.24.3 make local-build-static 26 | 27 | build-bats: 28 | docker build -t bats -f Dockerfile.bats . 29 | 30 | docker-acceptance: build-bats 31 | docker run -t bats -p acceptance.bats 32 | docker run --network none -t bats -p acceptance-nonetwork.bats 33 | 34 | goreleaser-build-static: 35 | docker run -t -e GOOS=linux -e GOARCH=amd64 -v $$PWD:/go/src/github.com/yannh/kubeconform -w /go/src/github.com/yannh/kubeconform goreleaser/goreleaser:v2.9.0 build --clean --single-target --snapshot 36 | cp dist/kubeconform_linux_amd64_v1/kubeconform bin/ 37 | 38 | release: 39 | docker run -e GITHUB_TOKEN -e GIT_OWNER -t -v /var/run/docker.sock:/var/run/docker.sock -v $$PWD:/go/src/github.com/yannh/kubeconform -w /go/src/github.com/yannh/kubeconform goreleaser/goreleaser:v2.9.0 release --clean 40 | 41 | update-deps: 42 | go get -u ./... 43 | go mod tidy 44 | 45 | update-junit-xsd: 46 | curl https://raw.githubusercontent.com/junit-team/junit5/main/platform-tests/src/test/resources/jenkins-junit.xsd > fixtures/junit.xsd 47 | -------------------------------------------------------------------------------- /acceptance-nonetwork.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | @test "Fail when parsing a valid Kubernetes config YAML file without network access" { 4 | run bin/kubeconform fixtures/valid.yaml 5 | [ "$status" -eq 1 ] 6 | } 7 | 8 | @test "Pass when parsing a valid config YAML file without network access, with cache" { 9 | run bin/kubeconform -cache fixtures/cache/ fixtures/valid.yaml 10 | [ "$status" -eq 0 ] 11 | } 12 | 13 | @test "Pass when parsing a Custom Resource and using a local schema registry with appropriate CRD" { 14 | run bin/kubeconform -schema-location './fixtures/registry/{{ .ResourceKind }}{{ .KindSuffix }}.json' fixtures/test_crd.yaml 15 | [ "$status" -eq 0 ] 16 | } 17 | 18 | @test "Pass when parsing a Custom Resource and specifying several local registries, the last one having the appropriate CRD" { 19 | run bin/kubeconform -schema-location 'fixtures/{{ .ResourceKind }}.json' -schema-location './fixtures/registry/{{ .ResourceKind }}{{ .KindSuffix }}.json' fixtures/test_crd.yaml 20 | [ "$status" -eq 0 ] 21 | } 22 | 23 | @test "Pass when using a cached schema with external references" { 24 | run bin/kubeconform -cache fixtures/cache -summary -schema-location 'https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{ .NormalizedKubernetesVersion }}{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json' fixtures/valid.yaml 25 | [ "$status" -eq 0 ] 26 | } 27 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | kubeconform 2 | -------------------------------------------------------------------------------- /examples/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // WARNING: API of Kubeconform is still under development and not yet 4 | // considered stable 5 | 6 | import ( 7 | "github.com/yannh/kubeconform/pkg/validator" 8 | "log" 9 | "os" 10 | ) 11 | 12 | func main() { 13 | filepath := "../fixtures/valid.yaml" 14 | f, err := os.Open(filepath) 15 | if err != nil { 16 | log.Fatalf("failed opening %s: %s", filepath, err) 17 | } 18 | 19 | v, err := validator.New(nil, validator.Opts{Strict: true}) 20 | if err != nil { 21 | log.Fatalf("failed initializing validator: %s", err) 22 | } 23 | for i, res := range v.Validate(filepath, f) { // A file might contain multiple resources 24 | // File starts with ---, the parser assumes a first empty resource 25 | if res.Status == validator.Invalid { 26 | log.Fatalf("resource %d in file %s is not valid: %s", i, filepath, res.Err) 27 | } 28 | if res.Status == validator.Error { 29 | log.Fatalf("error while processing resource %d in file %s: %s", i, filepath, res.Err) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fixtures/blank.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yannh/kubeconform/e65429b1e5990dd019ebb7b5642dcd22a3e9cd13/fixtures/blank.yaml -------------------------------------------------------------------------------- /fixtures/cache/603105c17f981119fec20ae25cfb97ff6dd99114a875ae841ef965d9345667e3: -------------------------------------------------------------------------------- 1 | { 2 | "description": "ReplicationController represents the configuration of a replication controller.", 3 | "properties": { 4 | "apiVersion": { 5 | "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", 6 | "type": [ 7 | "string", 8 | "null" 9 | ], 10 | "enum": [ 11 | "v1" 12 | ] 13 | }, 14 | "kind": { 15 | "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", 16 | "type": [ 17 | "string", 18 | "null" 19 | ], 20 | "enum": [ 21 | "ReplicationController" 22 | ] 23 | }, 24 | "metadata": { 25 | "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/_definitions.json#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", 26 | "description": "If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" 27 | }, 28 | "spec": { 29 | "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/_definitions.json#/definitions/io.k8s.api.core.v1.ReplicationControllerSpec", 30 | "description": "Spec defines the specification of the desired behavior of the replication controller. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" 31 | }, 32 | "status": { 33 | "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/_definitions.json#/definitions/io.k8s.api.core.v1.ReplicationControllerStatus", 34 | "description": "Status is the most recently observed status of the replication controller. This data may be out of date by some window of time. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" 35 | } 36 | }, 37 | "type": "object", 38 | "x-kubernetes-group-version-kind": [ 39 | { 40 | "group": "", 41 | "kind": "ReplicationController", 42 | "version": "v1" 43 | } 44 | ], 45 | "$schema": "http://json-schema.org/schema#" 46 | } -------------------------------------------------------------------------------- /fixtures/comment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Arbitrary comment 3 | 4 | -------------------------------------------------------------------------------- /fixtures/duplicate_property.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | name: nginx-ds 6 | spec: 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | k8s-app: nginx-ds 11 | template: 12 | spec: 13 | containers: 14 | - image: envoy 15 | name: envoy 16 | containers: 17 | - image: nginx 18 | name: nginx 19 | -------------------------------------------------------------------------------- /fixtures/duplicates-non-namespaced.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in same namespace, resource of non-namespaced kind 2 | 3 | apiVersion: v1 4 | kind: PersistentVolume 5 | metadata: 6 | name: pv0003 7 | spec: 8 | capacity: 9 | storage: 5Gi 10 | volumeMode: Filesystem 11 | accessModes: 12 | - ReadWriteOnce 13 | persistentVolumeReclaimPolicy: Recycle 14 | storageClassName: slow 15 | mountOptions: 16 | - hard 17 | - nfsvers=4.1 18 | nfs: 19 | path: /tmp 20 | server: 172.17.0.2 21 | --- 22 | apiVersion: v1 23 | kind: PersistentVolume 24 | metadata: 25 | name: pv0003 26 | spec: 27 | capacity: 28 | storage: 5Gi 29 | volumeMode: Filesystem 30 | accessModes: 31 | - ReadWriteOnce 32 | persistentVolumeReclaimPolicy: Recycle 33 | storageClassName: slow 34 | mountOptions: 35 | - hard 36 | - nfsvers=4.1 37 | nfs: 38 | path: /tmp 39 | server: 172.17.0.2 40 | -------------------------------------------------------------------------------- /fixtures/duplicates-skipped-kinds.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in same namespace, but of a kind configured to be skipped 2 | 3 | apiVersion: v1 4 | kind: SkipThisKind 5 | metadata: 6 | name: "identical" 7 | spec: 8 | replicas: 2 9 | selector: 10 | app: nginx 11 | template: 12 | metadata: 13 | name: nginx 14 | labels: 15 | app: nginx 16 | spec: 17 | containers: 18 | - name: nginx 19 | image: nginx 20 | ports: 21 | - containerPort: 80 22 | --- 23 | apiVersion: v1 24 | kind: SkipThisKind 25 | metadata: 26 | name: "identical" 27 | spec: 28 | replicas: 2 29 | selector: 30 | app: nginx 31 | template: 32 | metadata: 33 | name: nginx 34 | labels: 35 | app: nginx 36 | spec: 37 | containers: 38 | - name: nginx 39 | image: nginx 40 | ports: 41 | - containerPort: 80 42 | -------------------------------------------------------------------------------- /fixtures/duplicates-with-namespace-default.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in same namespace (one of them not given, i.e. will use default namespace as passed to kubeval) 2 | 3 | apiVersion: v1 4 | kind: ReplicationController 5 | metadata: 6 | name: "bob" 7 | namespace: the-default-namespace 8 | spec: 9 | replicas: 2 10 | selector: 11 | app: nginx 12 | template: 13 | metadata: 14 | name: nginx 15 | labels: 16 | app: nginx 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx 21 | ports: 22 | - containerPort: 80 23 | --- 24 | apiVersion: v1 25 | kind: ReplicationController 26 | metadata: 27 | name: "bob" 28 | # namespace not given 29 | spec: 30 | replicas: 2 31 | selector: 32 | app: nginx 33 | template: 34 | metadata: 35 | name: nginx 36 | labels: 37 | app: nginx 38 | spec: 39 | containers: 40 | - name: nginx 41 | image: nginx 42 | ports: 43 | - containerPort: 80 44 | -------------------------------------------------------------------------------- /fixtures/duplicates-with-namespace.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in same namespace 2 | 3 | apiVersion: v1 4 | kind: ReplicationController 5 | metadata: 6 | name: "bob" 7 | namespace: x 8 | spec: 9 | replicas: 2 10 | selector: 11 | app: nginx 12 | template: 13 | metadata: 14 | name: nginx 15 | labels: 16 | app: nginx 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx 21 | ports: 22 | - containerPort: 80 23 | --- 24 | apiVersion: v1 25 | kind: ReplicationController 26 | metadata: 27 | name: "bob" 28 | namespace: x 29 | spec: 30 | replicas: 2 31 | selector: 32 | app: nginx 33 | template: 34 | metadata: 35 | name: nginx 36 | labels: 37 | app: nginx 38 | spec: 39 | containers: 40 | - name: nginx 41 | image: nginx 42 | ports: 43 | - containerPort: 80 44 | -------------------------------------------------------------------------------- /fixtures/duplicates.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in same namespace 2 | 3 | apiVersion: v1 4 | kind: ReplicationController 5 | metadata: 6 | name: "bob" 7 | spec: 8 | replicas: 2 9 | selector: 10 | app: nginx 11 | template: 12 | metadata: 13 | name: nginx 14 | labels: 15 | app: nginx 16 | spec: 17 | containers: 18 | - name: nginx 19 | image: nginx 20 | ports: 21 | - containerPort: 80 22 | --- 23 | apiVersion: v1 24 | kind: ReplicationController 25 | metadata: 26 | name: "bob" 27 | spec: 28 | replicas: 2 29 | selector: 30 | app: nginx 31 | template: 32 | metadata: 33 | name: nginx 34 | labels: 35 | app: nginx 36 | spec: 37 | containers: 38 | - name: nginx 39 | image: nginx 40 | ports: 41 | - containerPort: 80 42 | -------------------------------------------------------------------------------- /fixtures/extra_property.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | name: nginx-ds 6 | spec: 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | k8s-app: nginx-ds 11 | template: 12 | spec: 13 | containers: 14 | - image: nginx 15 | name: nginx 16 | -------------------------------------------------------------------------------- /fixtures/folder/valid.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: "bob" 5 | spec: 6 | replicas: 2 7 | selector: 8 | app: nginx 9 | template: 10 | metadata: 11 | name: nginx 12 | labels: 13 | app: nginx 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx 18 | ports: 19 | - containerPort: 80 20 | -------------------------------------------------------------------------------- /fixtures/full_domain_group.yaml: -------------------------------------------------------------------------------- 1 | kind: RoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: tiller-binding 5 | namespace: dev2 6 | subjects: 7 | - kind: ServiceAccount 8 | name: tiller 9 | namespace: dev2 10 | roleRef: 11 | kind: Role 12 | name: tiller-manager 13 | apiGroup: rbac.authorization.k8s.io 14 | -------------------------------------------------------------------------------- /fixtures/generate_name.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | generateName: pi- 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: pi 10 | image: perl 11 | command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] 12 | restartPolicy: Never 13 | backoffLimit: 4 -------------------------------------------------------------------------------- /fixtures/grafana-alert-rule-group-sample.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: grafana.integreatly.org/v1beta1 3 | kind: GrafanaAlertRuleGroup 4 | metadata: 5 | name: grafanaalertrulegroup-sample 6 | spec: 7 | folderRef: test-folder 8 | instanceSelector: 9 | matchLabels: 10 | dashboards: "grafana" 11 | interval: 5m 12 | rules: 13 | - condition: B 14 | data: 15 | - datasourceUid: grafanacloud-demoinfra-prom 16 | model: 17 | datasource: 18 | type: prometheus 19 | uid: grafanacloud-demoinfra-prom 20 | editorMode: code 21 | expr: weather_temp_c{} 22 | instant: true 23 | intervalMs: 1000 24 | legendFormat: __auto 25 | maxDataPoints: 43200 26 | range: false 27 | refId: A 28 | refId: A 29 | relativeTimeRange: 30 | from: 600 31 | - datasourceUid: __expr__ 32 | model: 33 | conditions: 34 | - evaluator: 35 | params: 36 | - 0 37 | type: lt 38 | operator: 39 | type: and 40 | query: 41 | params: 42 | - C 43 | reducer: 44 | params: [] 45 | type: last 46 | type: query 47 | datasource: 48 | type: __expr__ 49 | uid: __expr__ 50 | expression: A 51 | intervalMs: 1000 52 | maxDataPoints: 43200 53 | refId: B 54 | type: threshold 55 | refId: B 56 | relativeTimeRange: 57 | from: 600 58 | execErrState: Error 59 | for: 5m0s 60 | noDataState: NoData 61 | title: Temperature below zero 62 | uid: 4843de5c-4f8a-4af0-9509-23526a04faf8 63 | -------------------------------------------------------------------------------- /fixtures/httpproxy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: projectcontour.io/v1 2 | kind: HTTPProxy 3 | metadata: 4 | name: basic 5 | spec: 6 | virtualhost: 7 | fqdn: foo-basic.example.com 8 | routes: 9 | - conditions: 10 | - prefix: / 11 | services: 12 | - name: s1 13 | port: 80 14 | -------------------------------------------------------------------------------- /fixtures/int_or_string.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | task: monitoring 6 | # For use as a Cluster add-on (https://github.com/kubernetes/kubernetes/tree/master/cluster/addons) 7 | # If you are NOT using this as an addon, you should comment out this line. 8 | kubernetes.io/cluster-service: 'true' 9 | kubernetes.io/name: Heapster 10 | name: heapster 11 | namespace: kube-system 12 | spec: 13 | ports: 14 | - port: 80 15 | targetPort: 8082 16 | selector: 17 | k8s-app: heapster 18 | -------------------------------------------------------------------------------- /fixtures/invalid.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: "bob" 5 | spec: 6 | replicas: asd" 7 | selector: 8 | app: nginx 9 | templates: 10 | metadata: 11 | name: nginx 12 | labels: 13 | app: nginx 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx 18 | ports: 19 | - containerPort: 80 20 | -------------------------------------------------------------------------------- /fixtures/list_empty_valid.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: List 4 | items: [] -------------------------------------------------------------------------------- /fixtures/list_invalid.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: List 3 | items: 4 | - apiVersion: v1 5 | kind: Service 6 | metadata: 7 | name: redis-master 8 | labels: 9 | app: redis 10 | tier: backend 11 | role: master 12 | spec: 13 | ports: 14 | # the port that this service should serve on 15 | - port: 6379 16 | targetPort: 6379 17 | selector: 18 | app: redis 19 | tier: backend 20 | role: master 21 | - apiVersion: v1 22 | kind: ReplicationController 23 | metadata: 24 | name: "bob" 25 | spec: 26 | replicas: asd" 27 | selector: 28 | app: nginx 29 | templates: 30 | metadata: 31 | name: nginx 32 | labels: 33 | app: nginx 34 | spec: 35 | containers: 36 | - name: nginx 37 | image: nginx 38 | ports: 39 | - containerPort: 80 -------------------------------------------------------------------------------- /fixtures/missing_apiversion.yaml: -------------------------------------------------------------------------------- 1 | kind: ReplicationController 2 | metadata: 3 | name: "bob" 4 | spec: 5 | replicas: 2 6 | selector: 7 | app: nginx 8 | template: 9 | metadata: 10 | name: nginx 11 | labels: 12 | app: nginx 13 | spec: 14 | containers: 15 | - name: nginx 16 | image: nginx 17 | ports: 18 | - containerPort: 80 19 | -------------------------------------------------------------------------------- /fixtures/missing_kind.yaml: -------------------------------------------------------------------------------- 1 | key: value 2 | -------------------------------------------------------------------------------- /fixtures/missing_kind_value.yaml: -------------------------------------------------------------------------------- 1 | kind: 2 | -------------------------------------------------------------------------------- /fixtures/multi_invalid_resources.yaml: -------------------------------------------------------------------------------- 1 | kind: 2 | --- 3 | kind: 4 | --- 5 | kind: 6 | --- 7 | kind: 8 | --- 9 | kind: 10 | -------------------------------------------------------------------------------- /fixtures/multi_with_list.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: redis-master 6 | labels: 7 | app: redis 8 | tier: backend 9 | role: master 10 | spec: 11 | ports: 12 | # the port that this service should serve on 13 | - port: 6379 14 | targetPort: 6379 15 | selector: 16 | app: redis 17 | tier: backend 18 | role: master 19 | --- 20 | apiVersion: v1 21 | kind: List 22 | items: 23 | - apiVersion: v1 24 | kind: Namespace 25 | metadata: 26 | name: b -------------------------------------------------------------------------------- /fixtures/null_array.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | labels: 5 | k8s-app: kubernetes-dashboard 6 | name: kubernetes-dashboard 7 | namespace: kube-system 8 | spec: 9 | replicas: 1 10 | revisionHistoryLimit: 10 11 | selector: 12 | matchLabels: 13 | k8s-app: kubernetes-dashboard 14 | template: 15 | metadata: 16 | labels: 17 | k8s-app: kubernetes-dashboard 18 | spec: 19 | containers: 20 | - name: kubernetes-dashboard 21 | image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.6.1 22 | ports: 23 | - containerPort: 9090 24 | protocol: TCP 25 | args: 26 | # Uncomment the following line to manually specify Kubernetes API server Host 27 | # If not specified, Dashboard will attempt to auto discover the API server and connect 28 | # to it. Uncomment only if the default does not work. 29 | # - --apiserver-host=http://my-address:port 30 | livenessProbe: 31 | httpGet: 32 | path: / 33 | port: 9090 34 | initialDelaySeconds: 30 35 | timeoutSeconds: 30 36 | serviceAccountName: kubernetes-dashboard 37 | # Comment the following tolerations if Dashboard must not be deployed on master 38 | tolerations: 39 | - key: node-role.kubernetes.io/master 40 | effect: NoSchedule 41 | -------------------------------------------------------------------------------- /fixtures/null_string.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | annotations: 5 | kompose.service.type: LoadBalancer 6 | creationTimestamp: null 7 | labels: 8 | io.kompose.service: frontend 9 | name: frontend 10 | spec: 11 | ports: 12 | - name: "80" 13 | port: 80 14 | targetPort: 80 15 | selector: 16 | io.kompose.service: frontend 17 | type: LoadBalancer 18 | status: 19 | loadBalancer: {} 20 | -------------------------------------------------------------------------------- /fixtures/quantity.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: LimitRange 3 | metadata: 4 | name: mem-limit-range 5 | spec: 6 | limits: 7 | - default: 8 | memory: 512Mi 9 | defaultRequest: 10 | memory: 256000 11 | type: Container 12 | -------------------------------------------------------------------------------- /fixtures/same-kind-different-api.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in same namespace, and having the same kind, but 2 | # of different API (apps/v1 vs. apps/v1beta1). This is important when CRDs 3 | # introduce overlapping `metadata:name` values, e.g. `Deployment` in 4 | # `my-awesome-cd-tool.io/v1` (contrived scenario). 5 | 6 | 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | metadata: 10 | name: nginx-deployment 11 | labels: 12 | app: nginx 13 | spec: 14 | replicas: 3 15 | selector: 16 | matchLabels: 17 | app: nginx 18 | template: 19 | metadata: 20 | labels: 21 | app: nginx 22 | spec: 23 | containers: 24 | - name: nginx 25 | image: nginx:1.7.9 26 | ports: 27 | - containerPort: 80 28 | --- 29 | apiVersion: apps/v1beta1 30 | kind: Deployment 31 | metadata: 32 | name: nginx-deployment 33 | labels: 34 | app: nginx 35 | spec: 36 | replicas: 3 37 | selector: 38 | matchLabels: 39 | app: nginx 40 | template: 41 | metadata: 42 | labels: 43 | app: nginx 44 | spec: 45 | containers: 46 | - name: nginx 47 | image: nginx:1.7.9 48 | ports: 49 | - containerPort: 80 50 | -------------------------------------------------------------------------------- /fixtures/same-object-different-namespace-default.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in different namespace, one of them being the configured default namespace 2 | 3 | apiVersion: v1 4 | kind: ReplicationController 5 | metadata: 6 | name: "bob" 7 | namespace: a 8 | spec: 9 | replicas: 2 10 | selector: 11 | app: nginx 12 | template: 13 | metadata: 14 | name: nginx 15 | labels: 16 | app: nginx 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx 21 | ports: 22 | - containerPort: 80 23 | --- 24 | apiVersion: v1 25 | kind: ReplicationController 26 | metadata: 27 | name: "bob" 28 | namespace: the-default-namespace 29 | spec: 30 | replicas: 2 31 | selector: 32 | app: nginx 33 | template: 34 | metadata: 35 | name: nginx 36 | labels: 37 | app: nginx 38 | spec: 39 | containers: 40 | - name: nginx 41 | image: nginx 42 | ports: 43 | - containerPort: 80 44 | -------------------------------------------------------------------------------- /fixtures/same-object-different-namespace.yaml: -------------------------------------------------------------------------------- 1 | # Two objects with same name in different namespace 2 | 3 | apiVersion: v1 4 | kind: ReplicationController 5 | metadata: 6 | name: "bob" 7 | namespace: a 8 | spec: 9 | replicas: 2 10 | selector: 11 | app: nginx 12 | template: 13 | metadata: 14 | name: nginx 15 | labels: 16 | app: nginx 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx 21 | ports: 22 | - containerPort: 80 23 | --- 24 | apiVersion: v1 25 | kind: ReplicationController 26 | metadata: 27 | name: "bob" 28 | namespace: b 29 | spec: 30 | replicas: 2 31 | selector: 32 | app: nginx 33 | template: 34 | metadata: 35 | name: nginx 36 | labels: 37 | app: nginx 38 | spec: 39 | containers: 40 | - name: nginx 41 | image: nginx 42 | ports: 43 | - containerPort: 80 44 | -------------------------------------------------------------------------------- /fixtures/test_crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: sagemaker.aws.amazon.com/v1 2 | kind: TrainingJob 3 | metadata: 4 | name: xgboost-mnist-debugger 5 | spec: 6 | hyperParameters: 7 | - name: max_depth 8 | value: "5" 9 | - name: eta 10 | value: "0.2" 11 | - name: gamma 12 | value: "4" 13 | - name: min_child_weight 14 | value: "6" 15 | - name: silent 16 | value: "0" 17 | - name: objective 18 | value: reg:squarederror 19 | - name: subsample 20 | value: "0.7" 21 | - name: num_round 22 | value: "51" 23 | algorithmSpecification: 24 | trainingImage: 246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-xgboost:0.90-2-cpu-py3 25 | trainingInputMode: File 26 | roleArn: arn:aws:iam::123456789012:role/service-role/AmazonSageMaker-ExecutionRole 27 | region: us-west-2 28 | outputDataConfig: 29 | s3OutputPath: s3://my-bucket/xgboost-debugger/output 30 | resourceConfig: 31 | instanceCount: 1 32 | instanceType: ml.m4.xlarge 33 | volumeSizeInGB: 5 34 | stoppingCondition: 35 | maxRuntimeInSeconds: 86400 36 | inputDataConfig: 37 | - channelName: train 38 | dataSource: 39 | s3DataSource: 40 | s3DataType: S3Prefix 41 | s3Uri: s3://my-bucket/xgboost-debugger/train 42 | s3DataDistributionType: FullyReplicated 43 | contentType: libsvm 44 | compressionType: None 45 | - channelName: validation 46 | dataSource: 47 | s3DataSource: 48 | s3DataType: S3Prefix 49 | s3Uri: s3://my-bucket/xgboost-debugger/validation 50 | s3DataDistributionType: FullyReplicated 51 | contentType: libsvm 52 | compressionType: None 53 | debugHookConfig: 54 | s3OutputPath: s3://my-bucket/xgboost-debugger/hookconfig 55 | collectionConfigurations: 56 | - collectionName: feature_importance 57 | collectionParameters: 58 | - name: save_interval 59 | value: "5" 60 | - collectionName: losses 61 | collectionParameters: 62 | - name: save_interval" 63 | value: "500" 64 | - collectionName: average_shap 65 | collectionParameters: 66 | - name: save_interval 67 | value: "5" 68 | - collectionName: metrics 69 | collectionParameters: 70 | - name: save_interval 71 | value: "5" 72 | debugRuleConfigurations: 73 | - ruleConfigurationName: LossNotDecreasing 74 | ruleEvaluatorImage: 895741380848.dkr.ecr.us-west-2.amazonaws.com/sagemaker-debugger-rules:latest 75 | ruleParameters: 76 | - name: collection_names 77 | value: metrics 78 | - name: num_steps 79 | value: "10" 80 | - name: rule_to_invoke 81 | value: LossNotDecreasing -------------------------------------------------------------------------------- /fixtures/unconventional_keys.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: unconventional-keys 5 | data: 6 | 5: "integer" 7 | 3.14: "float" 8 | true: "boolean" 9 | -------------------------------------------------------------------------------- /fixtures/valid.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "v1", 3 | "kind": "ReplicationController", 4 | "metadata": { 5 | "name": "bob" 6 | }, 7 | "spec": { 8 | "replicas": 2, 9 | "selector": { 10 | "app": "nginx" 11 | }, 12 | "template": { 13 | "metadata": { 14 | "name": "nginx", 15 | "labels": { 16 | "app": "nginx" 17 | } 18 | }, 19 | "spec": { 20 | "containers": [ 21 | { 22 | "name": "nginx", 23 | "image": "nginx", 24 | "ports": [ 25 | { 26 | "containerPort": 80 27 | } 28 | ] 29 | } 30 | ] 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /fixtures/valid.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: "bob" 5 | spec: 6 | replicas: 2 7 | selector: 8 | app: nginx 9 | template: 10 | metadata: 11 | name: nginx 12 | labels: 13 | app: nginx 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx 18 | ports: 19 | - containerPort: 80 20 | -------------------------------------------------------------------------------- /fixtures/valid_version.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v1 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: my-app-hpa 5 | spec: 6 | minReplicas: 100 7 | maxReplicas: 300 8 | scaleTargetRef: 9 | apiVersion: extensions/v1beta1 10 | kind: Deployment 11 | name: my-app 12 | targetCPUUtilizationPercentage: 15 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/yannh/kubeconform 2 | 3 | go 1.24 4 | 5 | require ( 6 | github.com/hashicorp/go-retryablehttp v0.7.7 7 | github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 8 | golang.org/x/text v0.25.0 9 | sigs.k8s.io/yaml v1.4.0 10 | ) 11 | 12 | require github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 13 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 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= 3 | github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= 4 | github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 5 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 6 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 7 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 8 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 9 | github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= 10 | github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= 11 | github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= 12 | github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= 13 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 14 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 15 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 16 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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= 19 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 20 | 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= 23 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 24 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 25 | sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= 26 | sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 27 | -------------------------------------------------------------------------------- /pkg/cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | type Cache interface { 4 | Get(key string) (any, error) 5 | Set(key string, schema any) error 6 | } 7 | -------------------------------------------------------------------------------- /pkg/cache/inmemory.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // SchemaCache is a cache for downloaded schemas, so each file is only retrieved once 9 | // It is different from pkg/registry/http_cache.go in that: 10 | // - This cache caches the parsed Schemas 11 | type inMemory struct { 12 | sync.RWMutex 13 | schemas map[string]any 14 | } 15 | 16 | // New creates a new cache for downloaded schemas 17 | func NewInMemoryCache() Cache { 18 | return &inMemory{ 19 | schemas: make(map[string]any), 20 | } 21 | } 22 | 23 | // Get retrieves the JSON schema given a resource signature 24 | func (c *inMemory) Get(key string) (any, error) { 25 | c.RLock() 26 | defer c.RUnlock() 27 | schema, ok := c.schemas[key] 28 | 29 | if !ok { 30 | return nil, fmt.Errorf("schema not found in in-memory cache") 31 | } 32 | 33 | return schema, nil 34 | } 35 | 36 | // Set adds a JSON schema to the schema cache 37 | func (c *inMemory) Set(key string, schema any) error { 38 | c.Lock() 39 | defer c.Unlock() 40 | c.schemas[key] = schema 41 | 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /pkg/cache/ondisk.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | "io" 7 | "os" 8 | "path" 9 | "sync" 10 | ) 11 | 12 | type onDisk struct { 13 | sync.RWMutex 14 | folder string 15 | } 16 | 17 | // New creates a new cache for downloaded schemas 18 | func NewOnDiskCache(cache string) Cache { 19 | return &onDisk{ 20 | folder: cache, 21 | } 22 | } 23 | 24 | func cachePath(folder, key string) string { 25 | hash := sha256.Sum256([]byte(key)) 26 | return path.Join(folder, hex.EncodeToString(hash[:])) 27 | } 28 | 29 | // Get retrieves the JSON schema given a resource signature 30 | func (c *onDisk) Get(key string) (any, error) { 31 | c.RLock() 32 | defer c.RUnlock() 33 | 34 | f, err := os.Open(cachePath(c.folder, key)) 35 | if err != nil { 36 | return nil, err 37 | } 38 | defer f.Close() 39 | 40 | return io.ReadAll(f) 41 | } 42 | 43 | // Set adds a JSON schema to the schema cache 44 | func (c *onDisk) Set(key string, schema any) error { 45 | c.Lock() 46 | defer c.Unlock() 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 52 | } 53 | -------------------------------------------------------------------------------- /pkg/loader/file.go: -------------------------------------------------------------------------------- 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 | 28 | f, err := os.Open(path) 29 | if err != nil { 30 | if os.IsNotExist(err) { 31 | msg := fmt.Sprintf("could not open file %s", path) 32 | return nil, NewNotFoundError(errors.New(msg)) 33 | } 34 | return nil, err 35 | } 36 | defer f.Close() 37 | 38 | content, err := io.ReadAll(f) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | return jsonschema.UnmarshalJSON(bytes.NewReader(content)) 44 | } 45 | 46 | // ToFile is helper method to convert file url to file path. 47 | func (l FileLoader) ToFile(url string) (string, error) { 48 | u, err := gourl.Parse(url) 49 | if err != nil { 50 | return "", err 51 | } 52 | if u.Scheme != "file" { 53 | return url, nil 54 | } 55 | path := u.Path 56 | if runtime.GOOS == "windows" { 57 | path = strings.TrimPrefix(path, "/") 58 | path = filepath.FromSlash(path) 59 | } 60 | return path, nil 61 | } 62 | 63 | func NewFileLoader() *FileLoader { 64 | return &FileLoader{} 65 | } 66 | -------------------------------------------------------------------------------- /pkg/loader/http.go: -------------------------------------------------------------------------------- 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, NewNonJSONResponseError(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 | } 86 | -------------------------------------------------------------------------------- /pkg/loader/loaders.go: -------------------------------------------------------------------------------- 1 | package loader 2 | 3 | // NotFoundError is returned when the registry does not contain a schema for the resource 4 | type NotFoundError struct { 5 | err error 6 | } 7 | 8 | func NewNotFoundError(err error) *NotFoundError { 9 | return &NotFoundError{err} 10 | } 11 | func (e *NotFoundError) Error() string { return e.err.Error() } 12 | func (e *NotFoundError) Retryable() bool { return false } 13 | 14 | type NonJSONResponseError struct { 15 | err error 16 | } 17 | 18 | func NewNonJSONResponseError(err error) *NotFoundError { 19 | return &NotFoundError{err} 20 | } 21 | func (e *NonJSONResponseError) Error() string { return e.err.Error() } 22 | func (e *NonJSONResponseError) Retryable() bool { return false } 23 | -------------------------------------------------------------------------------- /pkg/output/output.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "github.com/yannh/kubeconform/pkg/validator" 8 | ) 9 | 10 | type Output interface { 11 | Write(validator.Result) error 12 | Flush() error 13 | } 14 | 15 | func New(w io.Writer, outputFormat string, printSummary, isStdin, verbose bool) (Output, error) { 16 | switch { 17 | case outputFormat == "json": 18 | return jsonOutput(w, printSummary, isStdin, verbose), nil 19 | case outputFormat == "junit": 20 | return junitOutput(w, printSummary, isStdin, verbose), nil 21 | case outputFormat == "pretty": 22 | return prettyOutput(w, printSummary, isStdin, verbose), nil 23 | case outputFormat == "tap": 24 | return tapOutput(w, printSummary, isStdin, verbose), nil 25 | case outputFormat == "text": 26 | return textOutput(w, printSummary, isStdin, verbose), nil 27 | default: 28 | return nil, fmt.Errorf("'outputFormat' must be 'json', 'junit', 'pretty', 'tap' or 'text'") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pkg/output/pretty_test.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/yannh/kubeconform/pkg/resource" 8 | "github.com/yannh/kubeconform/pkg/validator" 9 | ) 10 | 11 | func TestPrettyTextWrite(t *testing.T) { 12 | for _, testCase := range []struct { 13 | name string 14 | withSummary bool 15 | isStdin bool 16 | verbose bool 17 | results []validator.Result 18 | expect string 19 | }{ 20 | { 21 | "a single deployment, no summary, no verbose", 22 | false, 23 | false, 24 | false, 25 | []validator.Result{}, 26 | "", 27 | }, 28 | { 29 | "a single deployment, summary, no verbose", 30 | true, 31 | false, 32 | false, 33 | []validator.Result{ 34 | { 35 | Resource: resource.Resource{ 36 | Path: "deployment.yml", 37 | Bytes: []byte(`apiVersion: apps/v1 38 | kind: Deployment 39 | metadata: 40 | name: "my-app" 41 | `), 42 | }, 43 | Status: validator.Valid, 44 | Err: nil, 45 | }, 46 | }, 47 | "Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0, Skipped: 0\n", 48 | }, 49 | { 50 | "a single deployment, verbose, with summary", 51 | true, 52 | false, 53 | true, 54 | []validator.Result{ 55 | { 56 | Resource: resource.Resource{ 57 | Path: "deployment.yml", 58 | Bytes: []byte(`apiVersion: apps/v1 59 | kind: Deployment 60 | metadata: 61 | name: "my-app" 62 | `), 63 | }, 64 | Status: validator.Valid, 65 | Err: nil, 66 | }, 67 | }, 68 | "\033[32m✔\033[0m deployment.yml: \033[32mDeployment my-app is valid\033[0m\n" + 69 | "Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0, Skipped: 0\n", 70 | }, 71 | } { 72 | w := new(bytes.Buffer) 73 | o := prettyOutput(w, testCase.withSummary, testCase.isStdin, testCase.verbose) 74 | 75 | for _, res := range testCase.results { 76 | o.Write(res) 77 | } 78 | o.Flush() 79 | 80 | if w.String() != testCase.expect { 81 | t.Errorf("%s - expected, but got:\n%s\n%s\n", testCase.name, testCase.expect, w) 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /pkg/output/tap.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "github.com/yannh/kubeconform/pkg/validator" 8 | ) 9 | 10 | type tapo struct { 11 | w io.Writer 12 | withSummary bool 13 | verbose bool 14 | results []validator.Result 15 | nValid, nInvalid, nErrors, nSkipped int 16 | index int 17 | } 18 | 19 | func tapOutput(w io.Writer, withSummary bool, isStdin, verbose bool) Output { 20 | return &tapo{ 21 | w: w, 22 | withSummary: withSummary, 23 | verbose: verbose, 24 | results: []validator.Result{}, 25 | nValid: 0, 26 | nInvalid: 0, 27 | nErrors: 0, 28 | nSkipped: 0, 29 | } 30 | } 31 | 32 | // JSON.Write will only write when JSON.Flush has been called 33 | func (o *tapo) Write(res validator.Result) error { 34 | o.index++ 35 | 36 | if o.index == 1 { 37 | fmt.Fprintf(o.w, "TAP version 13\n") 38 | } 39 | 40 | switch res.Status { 41 | case validator.Valid: 42 | sig, _ := res.Resource.Signature() 43 | fmt.Fprintf(o.w, "ok %d - %s (%s)\n", o.index, res.Resource.Path, sig.QualifiedName()) 44 | 45 | case validator.Invalid: 46 | sig, _ := res.Resource.Signature() 47 | fmt.Fprintf(o.w, "not ok %d - %s (%s): %s\n", o.index, res.Resource.Path, sig.QualifiedName(), res.Err.Error()) 48 | 49 | case validator.Empty: 50 | fmt.Fprintf(o.w, "ok %d - %s (empty)\n", o.index, res.Resource.Path) 51 | 52 | case validator.Error: 53 | fmt.Fprintf(o.w, "not ok %d - %s: %s\n", o.index, res.Resource.Path, res.Err.Error()) 54 | 55 | case validator.Skipped: 56 | sig, _ := res.Resource.Signature() 57 | fmt.Fprintf(o.w, "ok %d - %s (%s) # skip\n", o.index, res.Resource.Path, sig.QualifiedName()) 58 | } 59 | 60 | return nil 61 | } 62 | 63 | // Flush outputs the results as JSON 64 | func (o *tapo) Flush() error { 65 | fmt.Fprintf(o.w, "1..%d\n", o.index) 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /pkg/output/tap_test.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/yannh/kubeconform/pkg/resource" 8 | "github.com/yannh/kubeconform/pkg/validator" 9 | ) 10 | 11 | func TestTapWrite(t *testing.T) { 12 | for _, testCase := range []struct { 13 | name string 14 | withSummary bool 15 | isStdin bool 16 | verbose bool 17 | results []validator.Result 18 | expect string 19 | }{ 20 | { 21 | "a single deployment, summary, no verbose", 22 | true, 23 | false, 24 | false, 25 | []validator.Result{ 26 | { 27 | Resource: resource.Resource{ 28 | Path: "deployment.yml", 29 | Bytes: []byte(`apiVersion: apps/v1 30 | kind: Deployment 31 | metadata: 32 | name: "my-app" 33 | `), 34 | }, 35 | Status: validator.Valid, 36 | Err: nil, 37 | }, 38 | }, 39 | "TAP version 13\nok 1 - deployment.yml (apps/v1/Deployment//my-app)\n1..1\n", 40 | }, 41 | { 42 | "a single deployment, verbose, with summary", 43 | true, 44 | false, 45 | true, 46 | []validator.Result{ 47 | { 48 | Resource: resource.Resource{ 49 | Path: "deployment.yml", 50 | Bytes: []byte(`apiVersion: apps/v1 51 | kind: Deployment 52 | metadata: 53 | name: "my-app" 54 | `), 55 | }, 56 | Status: validator.Valid, 57 | Err: nil, 58 | }, 59 | }, 60 | "TAP version 13\nok 1 - deployment.yml (apps/v1/Deployment//my-app)\n1..1\n", 61 | }, 62 | } { 63 | w := new(bytes.Buffer) 64 | o := tapOutput(w, testCase.withSummary, testCase.isStdin, testCase.verbose) 65 | 66 | for _, res := range testCase.results { 67 | o.Write(res) 68 | } 69 | o.Flush() 70 | 71 | if w.String() != testCase.expect { 72 | t.Errorf("%s - expected:, got:\n%s\n%s", testCase.name, testCase.expect, w) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /pkg/output/text.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "sync" 7 | 8 | "github.com/yannh/kubeconform/pkg/validator" 9 | ) 10 | 11 | type texto struct { 12 | sync.Mutex 13 | w io.Writer 14 | withSummary bool 15 | isStdin bool 16 | verbose bool 17 | files map[string]bool 18 | nValid, nInvalid, nErrors, nSkipped int 19 | } 20 | 21 | // Text will output the results of the validation as a texto 22 | func textOutput(w io.Writer, withSummary, isStdin, verbose bool) Output { 23 | return &texto{ 24 | w: w, 25 | withSummary: withSummary, 26 | isStdin: isStdin, 27 | verbose: verbose, 28 | files: map[string]bool{}, 29 | nValid: 0, 30 | nInvalid: 0, 31 | nErrors: 0, 32 | nSkipped: 0, 33 | } 34 | } 35 | 36 | func (o *texto) Write(result validator.Result) error { 37 | o.Lock() 38 | defer o.Unlock() 39 | 40 | var err error 41 | 42 | sig, _ := result.Resource.Signature() 43 | 44 | o.files[result.Resource.Path] = true 45 | switch result.Status { 46 | case validator.Valid: 47 | if o.verbose { 48 | _, err = fmt.Fprintf(o.w, "%s - %s %s is valid\n", result.Resource.Path, sig.Kind, sig.Name) 49 | } 50 | o.nValid++ 51 | case validator.Invalid: 52 | _, err = fmt.Fprintf(o.w, "%s - %s %s is invalid: %s\n", result.Resource.Path, sig.Kind, sig.Name, result.Err) 53 | o.nInvalid++ 54 | case validator.Error: 55 | if sig.Kind != "" && sig.Name != "" { 56 | _, err = fmt.Fprintf(o.w, "%s - %s %s failed validation: %s\n", result.Resource.Path, sig.Kind, sig.Name, result.Err) 57 | } else { 58 | _, err = fmt.Fprintf(o.w, "%s - failed validation: %s\n", result.Resource.Path, result.Err) 59 | } 60 | o.nErrors++ 61 | case validator.Skipped: 62 | if o.verbose { 63 | _, err = fmt.Fprintf(o.w, "%s - %s %s skipped\n", result.Resource.Path, sig.Name, sig.Kind) 64 | } 65 | o.nSkipped++ 66 | case validator.Empty: // sent to ensure we count the filename as parsed 67 | } 68 | 69 | return err 70 | } 71 | 72 | func (o *texto) Flush() error { 73 | var err error 74 | if o.withSummary { 75 | nFiles := len(o.files) 76 | nResources := o.nValid + o.nInvalid + o.nErrors + o.nSkipped 77 | resourcesPlural := "" 78 | if nResources > 1 { 79 | resourcesPlural = "s" 80 | } 81 | filesPlural := "" 82 | if nFiles > 1 { 83 | filesPlural = "s" 84 | } 85 | if o.isStdin { 86 | _, err = fmt.Fprintf(o.w, "Summary: %d resource%s found parsing stdin - Valid: %d, Invalid: %d, Errors: %d, Skipped: %d\n", nResources, resourcesPlural, o.nValid, o.nInvalid, o.nErrors, o.nSkipped) 87 | } else { 88 | _, err = fmt.Fprintf(o.w, "Summary: %d resource%s found in %d file%s - Valid: %d, Invalid: %d, Errors: %d, Skipped: %d\n", nResources, resourcesPlural, nFiles, filesPlural, o.nValid, o.nInvalid, o.nErrors, o.nSkipped) 89 | } 90 | } 91 | 92 | return err 93 | } 94 | -------------------------------------------------------------------------------- /pkg/output/text_test.go: -------------------------------------------------------------------------------- 1 | package output 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/yannh/kubeconform/pkg/resource" 8 | "github.com/yannh/kubeconform/pkg/validator" 9 | ) 10 | 11 | func TestTextWrite(t *testing.T) { 12 | for _, testCase := range []struct { 13 | name string 14 | withSummary bool 15 | isStdin bool 16 | verbose bool 17 | results []validator.Result 18 | expect string 19 | }{ 20 | { 21 | "a single deployment, no summary, no verbose", 22 | false, 23 | false, 24 | false, 25 | []validator.Result{}, 26 | "", 27 | }, 28 | { 29 | "a single deployment, summary, no verbose", 30 | true, 31 | false, 32 | false, 33 | []validator.Result{ 34 | { 35 | Resource: resource.Resource{ 36 | Path: "deployment.yml", 37 | Bytes: []byte(`apiVersion: apps/v1 38 | kind: Deployment 39 | metadata: 40 | name: "my-app" 41 | `), 42 | }, 43 | Status: validator.Valid, 44 | Err: nil, 45 | }, 46 | }, 47 | "Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0, Skipped: 0\n", 48 | }, 49 | { 50 | "a single deployment, verbose, with summary", 51 | true, 52 | false, 53 | true, 54 | []validator.Result{ 55 | { 56 | Resource: resource.Resource{ 57 | Path: "deployment.yml", 58 | Bytes: []byte(`apiVersion: apps/v1 59 | kind: Deployment 60 | metadata: 61 | name: "my-app" 62 | `), 63 | }, 64 | Status: validator.Valid, 65 | Err: nil, 66 | }, 67 | }, 68 | `deployment.yml - Deployment my-app is valid 69 | Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0, Skipped: 0 70 | `, 71 | }, 72 | } { 73 | w := new(bytes.Buffer) 74 | o := textOutput(w, testCase.withSummary, testCase.isStdin, testCase.verbose) 75 | 76 | for _, res := range testCase.results { 77 | o.Write(res) 78 | } 79 | o.Flush() 80 | 81 | if w.String() != testCase.expect { 82 | t.Errorf("%s - expected: %s, got: %s", testCase.name, testCase.expect, w) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /pkg/registry/http.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | "github.com/santhosh-tekuri/jsonschema/v6" 5 | ) 6 | 7 | // SchemaRegistry is a file repository (local or remote) that contains JSON schemas for Kubernetes resources 8 | type SchemaRegistry struct { 9 | schemaPathTemplate string 10 | strict bool 11 | debug bool 12 | loader jsonschema.URLLoader 13 | } 14 | 15 | func newHTTPRegistry(schemaPathTemplate string, loader jsonschema.URLLoader, strict bool, debug bool) (*SchemaRegistry, error) { 16 | return &SchemaRegistry{ 17 | schemaPathTemplate: schemaPathTemplate, 18 | strict: strict, 19 | loader: loader, 20 | debug: debug, 21 | }, nil 22 | } 23 | 24 | // DownloadSchema downloads the schema for a particular resource from an HTTP server 25 | func (r SchemaRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, any, error) { 26 | url, err := schemaPath(r.schemaPathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict) 27 | if err != nil { 28 | return "", nil, err 29 | } 30 | 31 | resp, err := r.loader.Load(url) 32 | 33 | return url, resp, err 34 | } 35 | -------------------------------------------------------------------------------- /pkg/registry/local.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | "github.com/santhosh-tekuri/jsonschema/v6" 5 | ) 6 | 7 | type LocalRegistry struct { 8 | pathTemplate string 9 | strict bool 10 | debug bool 11 | loader jsonschema.URLLoader 12 | } 13 | 14 | // NewLocalSchemas creates a new "registry", that will serve schemas from files, given a list of schema filenames 15 | func newLocalRegistry(pathTemplate string, loader jsonschema.URLLoader, strict bool, debug bool) (*LocalRegistry, error) { 16 | return &LocalRegistry{ 17 | pathTemplate, 18 | strict, 19 | debug, 20 | loader, 21 | }, nil 22 | } 23 | 24 | // DownloadSchema retrieves the schema from a file for the resource 25 | func (r LocalRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, any, error) { 26 | schemaFile, err := schemaPath(r.pathTemplate, resourceKind, resourceAPIVersion, k8sVersion, r.strict) 27 | if err != nil { 28 | return schemaFile, []byte{}, nil 29 | } 30 | 31 | s, err := r.loader.Load(schemaFile) 32 | return schemaFile, s, err 33 | } 34 | -------------------------------------------------------------------------------- /pkg/registry/registry.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/yannh/kubeconform/pkg/cache" 7 | "github.com/yannh/kubeconform/pkg/loader" 8 | "os" 9 | "strings" 10 | "text/template" 11 | ) 12 | 13 | type Manifest struct { 14 | Kind, Version string 15 | } 16 | 17 | // Registry is an interface that should be implemented by any source of Kubernetes schemas 18 | type Registry interface { 19 | DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (string, any, error) 20 | } 21 | 22 | func schemaPath(tpl, resourceKind, resourceAPIVersion, k8sVersion string, strict bool) (string, error) { 23 | normalisedVersion := k8sVersion 24 | if normalisedVersion != "master" { 25 | normalisedVersion = "v" + normalisedVersion 26 | } 27 | 28 | strictSuffix := "" 29 | if strict { 30 | strictSuffix = "-strict" 31 | } 32 | 33 | groupParts := strings.Split(resourceAPIVersion, "/") 34 | versionParts := strings.Split(groupParts[0], ".") 35 | 36 | kindSuffix := "-" + strings.ToLower(versionParts[0]) 37 | if len(groupParts) > 1 { 38 | kindSuffix += "-" + strings.ToLower(groupParts[1]) 39 | } 40 | 41 | tmpl, err := template.New("tpl").Parse(tpl) 42 | if err != nil { 43 | return "", err 44 | } 45 | 46 | tplData := struct { 47 | NormalizedKubernetesVersion string 48 | StrictSuffix string 49 | ResourceKind string 50 | ResourceAPIVersion string 51 | Group string 52 | KindSuffix string 53 | }{ 54 | normalisedVersion, 55 | strictSuffix, 56 | strings.ToLower(resourceKind), 57 | groupParts[len(groupParts)-1], 58 | groupParts[0], 59 | kindSuffix, 60 | } 61 | 62 | var buf bytes.Buffer 63 | err = tmpl.Execute(&buf, tplData) 64 | if err != nil { 65 | return "", err 66 | } 67 | 68 | return buf.String(), nil 69 | } 70 | 71 | func New(schemaLocation string, cacheFolder string, strict bool, skipTLS bool, debug bool) (Registry, error) { 72 | if schemaLocation == "default" { 73 | schemaLocation = "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json" 74 | } 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 75 | schemaLocation += "/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json" 76 | } 77 | 78 | // try to compile the schemaLocation template to ensure it is valid 79 | if _, err := schemaPath(schemaLocation, "Deployment", "v1", "master", true); err != nil { 80 | return nil, fmt.Errorf("failed initialising schema location registry: %s", err) 81 | } 82 | 83 | var c cache.Cache = nil 84 | if cacheFolder != "" { 85 | fi, err := os.Stat(cacheFolder) 86 | if err != nil { 87 | return nil, fmt.Errorf("failed opening cache folder %s: %s", cacheFolder, err) 88 | } 89 | if !fi.IsDir() { 90 | return nil, fmt.Errorf("cache folder %s is not a directory", err) 91 | } 92 | 93 | c = cache.NewOnDiskCache(cacheFolder) 94 | } 95 | 96 | if strings.HasPrefix(schemaLocation, "http") { 97 | httpLoader, err := loader.NewHTTPURLLoader(skipTLS, c) 98 | if err != nil { 99 | return nil, fmt.Errorf("failed creating HTTP loader: %s", err) 100 | } 101 | return newHTTPRegistry(schemaLocation, httpLoader, strict, debug) 102 | } 103 | 104 | fileLoader := loader.NewFileLoader() 105 | return newLocalRegistry(schemaLocation, fileLoader, strict, debug) 106 | } 107 | -------------------------------------------------------------------------------- /pkg/registry/registry_test.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSchemaPath(t *testing.T) { 8 | for i, testCase := range []struct { 9 | tpl, resourceKind, resourceAPIVersion, k8sVersion, expected string 10 | strict bool 11 | errExpected error 12 | }{ 13 | { 14 | "https://kubernetesjsonschema.dev/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json", 15 | "Deployment", 16 | "apps/v1", 17 | "1.16.0", 18 | "https://kubernetesjsonschema.dev/v1.16.0-standalone-strict/deployment-apps-v1.json", 19 | true, 20 | nil, 21 | }, 22 | { 23 | "https://kubernetesjsonschema.dev/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json", 24 | "Deployment", 25 | "apps/v1", 26 | "1.16.0", 27 | "https://kubernetesjsonschema.dev/v1.16.0-standalone/deployment-apps-v1.json", 28 | false, 29 | nil, 30 | }, 31 | { 32 | "https://kubernetesjsonschema.dev/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json", 33 | "Service", 34 | "v1", 35 | "1.18.0", 36 | "https://kubernetesjsonschema.dev/v1.18.0-standalone/service-v1.json", 37 | false, 38 | nil, 39 | }, 40 | { 41 | "https://kubernetesjsonschema.dev/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json", 42 | "Service", 43 | "v1", 44 | "master", 45 | "https://kubernetesjsonschema.dev/master-standalone/service-v1.json", 46 | false, 47 | nil, 48 | }, 49 | } { 50 | got, err := schemaPath(testCase.tpl, testCase.resourceKind, testCase.resourceAPIVersion, testCase.k8sVersion, testCase.strict) 51 | if err != testCase.errExpected { 52 | t.Errorf("%d - got error %s, expected %s", i+1, err, testCase.errExpected) 53 | } 54 | if got != testCase.expected { 55 | t.Errorf("%d - got %s, expected %s", i+1, got, testCase.expected) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pkg/resource/resource_test.go: -------------------------------------------------------------------------------- 1 | package resource_test 2 | 3 | import ( 4 | "log" 5 | "reflect" 6 | "testing" 7 | 8 | "sigs.k8s.io/yaml" 9 | 10 | "github.com/yannh/kubeconform/pkg/resource" 11 | ) 12 | 13 | func TestSignatureFromBytes(t *testing.T) { 14 | testCases := []struct { 15 | name string 16 | have []byte 17 | want resource.Signature 18 | err error 19 | }{ 20 | { 21 | name: "valid deployment", 22 | have: []byte(` 23 | apiVersion: apps/v1 24 | kind: Deployment 25 | metadata: 26 | name: myService 27 | namespace: default 28 | labels: 29 | app: myService 30 | spec: 31 | `), 32 | want: resource.Signature{ 33 | Kind: "Deployment", 34 | Version: "apps/v1", 35 | Namespace: "default", 36 | }, 37 | err: nil, 38 | }, 39 | } 40 | 41 | for _, testCase := range testCases { 42 | res := resource.Resource{Bytes: testCase.have} 43 | sig, err := res.Signature() 44 | if err != nil && err.Error() != testCase.err.Error() { 45 | t.Errorf("test \"%s\" - received error: %s", testCase.name, err) 46 | } 47 | if sig.Version != testCase.want.Version || 48 | sig.Kind != testCase.want.Kind || 49 | sig.Namespace != testCase.want.Namespace { 50 | t.Errorf("test \"%s\": received %+v, expected %+v", testCase.name, sig, testCase.want) 51 | } 52 | } 53 | } 54 | 55 | func TestSignatureFromMap(t *testing.T) { 56 | testCases := []struct { 57 | b string 58 | s resource.Signature 59 | }{ 60 | { 61 | "apiVersion: v1\nkind: ReplicationController\nmetadata:\n name: \"bob\"\nspec:\n replicas: 2\n", 62 | resource.Signature{ 63 | Kind: "ReplicationController", 64 | Version: "v1", 65 | Namespace: "", 66 | Name: "bob", 67 | }, 68 | }, 69 | } 70 | 71 | for i, testCase := range testCases { 72 | res := resource.Resource{ 73 | Path: "foo", 74 | Bytes: []byte(testCase.b), 75 | } 76 | 77 | var r map[string]interface{} 78 | if err := yaml.Unmarshal(res.Bytes, &r); err != nil { 79 | log.Fatal(err) 80 | } 81 | 82 | res.SignatureFromMap(r) 83 | sig, _ := res.Signature() 84 | if !reflect.DeepEqual(*sig, testCase.s) { 85 | t.Errorf("test %d - for resource %s, expected %+v, got %+v", i+1, testCase.b, testCase.s, sig) 86 | } 87 | } 88 | } 89 | 90 | func TestResources(t *testing.T) { 91 | testCases := []struct { 92 | b string 93 | expected int 94 | }{ 95 | { 96 | ` 97 | apiVersion: v1 98 | kind: List 99 | `, 100 | 0, 101 | }, 102 | { 103 | ` 104 | apiVersion: v1 105 | kind: List 106 | Items: [] 107 | `, 108 | 0, 109 | }, 110 | { 111 | ` 112 | apiVersion: v1 113 | kind: List 114 | Items: 115 | - apiVersion: v1 116 | kind: ReplicationController 117 | metadata: 118 | name: "bob" 119 | spec: 120 | replicas: 2 121 | `, 122 | 1, 123 | }, 124 | { 125 | ` 126 | apiVersion: v1 127 | kind: List 128 | Items: 129 | - apiVersion: v1 130 | kind: ReplicationController 131 | metadata: 132 | name: "bob" 133 | spec: 134 | replicas: 2 135 | - apiVersion: v1 136 | kind: ReplicationController 137 | metadata: 138 | name: "Jim" 139 | spec: 140 | replicas: 2 141 | `, 142 | 2, 143 | }, 144 | } 145 | 146 | for i, testCase := range testCases { 147 | res := resource.Resource{ 148 | Path: "foo", 149 | Bytes: []byte(testCase.b), 150 | } 151 | 152 | subres := res.Resources() 153 | if len(subres) != testCase.expected { 154 | t.Errorf("test %d: expected to find %d resources, found %d", i, testCase.expected, len(subres)) 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /pkg/resource/stream.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "io" 8 | ) 9 | 10 | // SplitYAMLDocument is a bufio.SplitFunc for splitting a YAML document into individual documents. 11 | // 12 | // This is from Kubernetes' 'pkg/util/yaml'.splitYAMLDocument, which is unfortunately 13 | // not exported. 14 | func SplitYAMLDocument(data []byte, atEOF bool) (advance int, token []byte, err error) { 15 | const yamlSeparator = "\n---" 16 | if atEOF && len(data) == 0 { 17 | return 0, nil, nil 18 | } 19 | sep := len([]byte(yamlSeparator)) 20 | if i := bytes.Index(data, []byte(yamlSeparator)); i >= 0 { 21 | // We have a potential document terminator 22 | i += sep 23 | after := data[i:] 24 | if len(after) == 0 { 25 | // we can't read any more characters 26 | if atEOF { 27 | return len(data), data[:len(data)-sep], nil 28 | } 29 | return 0, nil, nil 30 | } 31 | if j := bytes.IndexByte(after, '\n'); j >= 0 { 32 | return i + j + 1, data[0 : i-sep], nil 33 | } 34 | return 0, nil, nil 35 | } 36 | // If we're at EOF, we have a final, non-terminated line. Return it. 37 | if atEOF { 38 | return len(data), data, nil 39 | } 40 | // Request more data. 41 | return 0, nil, nil 42 | } 43 | 44 | // FromStream reads resources from a byte stream, usually here stdin 45 | func FromStream(ctx context.Context, path string, r io.Reader) (<-chan Resource, <-chan error) { 46 | resources := make(chan Resource) 47 | errors := make(chan error) 48 | 49 | go func() { 50 | const initialBufSize = 4 * 1024 * 1024 // Start with 4MB 51 | const maxBufSize = 256 * 1024 * 1024 // Start with 4MB 52 | 53 | scanner := bufio.NewScanner(r) 54 | buf := make([]byte, initialBufSize) 55 | scanner.Buffer(buf, maxBufSize) // Resize up to 256MB 56 | scanner.Split(SplitYAMLDocument) 57 | 58 | SCAN: 59 | for scanner.Scan() { 60 | select { 61 | case <-ctx.Done(): 62 | break SCAN 63 | default: 64 | } 65 | res := Resource{Path: path, Bytes: scanner.Bytes()} 66 | for _, subres := range res.Resources() { 67 | resources <- subres 68 | } 69 | } 70 | 71 | close(resources) 72 | close(errors) 73 | }() 74 | 75 | return resources, errors 76 | } 77 | -------------------------------------------------------------------------------- /scripts/Dockerfile.bats: -------------------------------------------------------------------------------- 1 | FROM python:3.9.7-alpine3.14 2 | RUN apk --no-cache add bats 3 | COPY requirements.txt /code/ 4 | RUN pip install -r /code/requirements.txt 5 | COPY fixtures /code/fixtures 6 | COPY acceptance.bats openapi2jsonschema.py /code/ 7 | WORKDIR /code 8 | -------------------------------------------------------------------------------- /scripts/Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # This is really early days 4 | 5 | test: build-python-bats docker-test docker-acceptance 6 | 7 | build-python-bats: 8 | docker build -t python-bats -f Dockerfile.bats . 9 | 10 | docker-test: build-python-bats 11 | docker run --entrypoint "/usr/local/bin/pytest" -t python-bats openapi2jsonschema.py 12 | 13 | docker-acceptance: build-python-bats 14 | docker run --entrypoint "/usr/bin/bats" -t python-bats /code/acceptance.bats 15 | -------------------------------------------------------------------------------- /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | pyyaml 2 | pytest 3 | -------------------------------------------------------------------------------- /site/archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /site/config.toml: -------------------------------------------------------------------------------- 1 | baseURL = 'http://kubeconform.mandragor.org/' 2 | languageCode = 'en-us' 3 | title = 'Kubeconform - Fast Kubernetes manifests validation!' 4 | theme = 'kubeconform' 5 | contentDir = "content" 6 | staticDir = ["static"] -------------------------------------------------------------------------------- /site/content/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "About" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "About"] 6 | --- 7 | 8 | Kubeconform is a Kubernetes manifests validation tool. Build it into your CI to validate your Kubernetes 9 | configuration! 10 | 11 | It is inspired by, contains code from and is designed to stay close to 12 | [Kubeval](https://github.com/instrumenta/kubeval), but with the following improvements: 13 | * **high performance**: will validate & download manifests over multiple routines, caching 14 | downloaded files in memory 15 | * configurable list of **remote, or local schemas locations**, enabling validating Kubernetes 16 | custom resources (CRDs) and offline validation capabilities 17 | * uses by default a [self-updating fork](https://github.com/yannh/kubernetes-json-schema) of the schemas registry maintained 18 | by the [kubernetes-json-schema](https://github.com/instrumenta/kubernetes-json-schema) project - which guarantees 19 | up-to-date **schemas for all recent versions of Kubernetes**. -------------------------------------------------------------------------------- /site/content/docs/crd-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Custom Resources support" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "Usage"] 6 | weight: 4 7 | --- 8 | 9 | When the `-schema-location` parameter is not used, or set to "default", kubeconform will default to downloading 10 | schemas from `https://github.com/yannh/kubernetes-json-schema`. Kubeconform however supports passing one, or multiple, 11 | schemas locations - HTTP(s) URLs, or local filesystem paths, in which case it will lookup for schema definitions 12 | in each of them, in order, stopping as soon as a matching file is found. 13 | 14 | * If the -schema-location value does not end with '.json', Kubeconform will assume filenames / a file 15 | structure identical to that of kubernetesjsonschema.dev or github.com/yannh/kubernetes-json-schema. 16 | * if the -schema-location value ends with '.json' - Kubeconform assumes the value is a Go templated 17 | string that indicates how to search for JSON schemas. 18 | * the -schema-location value of "default" is an alias for https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json. 19 | Both following command lines are equivalent: 20 | 21 | {{< prism >}}$ ./bin/kubeconform fixtures/valid.yaml 22 | $ ./bin/kubeconform -schema-location default fixtures/valid.yaml 23 | $ ./bin/kubeconform -schema-location 'https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json' fixtures/valid.yaml 24 | {{< /prism >}} 25 | 26 | To support validating CRDs, we need to convert OpenAPI files to JSON schema, storing the JSON schemas 27 | in a local folder - for example schemas. Then we specify this folder as an additional registry to lookup: 28 | 29 | {{< prism >}}# If the resource Kind is not found in kubernetesjsonschema.dev, also lookup in the schemas/ folder for a matching file 30 | $ ./bin/kubeconform -schema-location default -schema-location 'schemas/{{ .ResourceKind }}{{ .KindSuffix }}.json' fixtures/custom-resource.yaml 31 | {{< /prism >}} 32 | 33 | You can validate Openshift manifests using a custom schema location. Set the OpenShift version to validate 34 | against using -kubernetes-version. 35 | 36 | {{< prism >}}$ ./bin/kubeconform -kubernetes-version 3.8.0 -schema-location 'https://raw.githubusercontent.com/garethr/openshift-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}.json' -summary fixtures/valid.yaml 37 | Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0 Skipped: 0 38 | {{< /prism >}} 39 | 40 | Here are the variables you can use in -schema-location: 41 | * *NormalizedKubernetesVersion* - Kubernetes Version, prefixed by v 42 | * *StrictSuffix* - "-strict" or "" depending on whether validation is running in strict mode or not 43 | * *ResourceKind* - Kind of the Kubernetes Resource 44 | * *ResourceAPIVersion* - Version of API used for the resource - "v1" in "apiVersion: monitoring.coreos.com/v1" 45 | * *KindSuffix* - suffix computed from apiVersion - for compatibility with Kubeval schema registries 46 | -------------------------------------------------------------------------------- /site/content/docs/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Installation" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "Installation"] 6 | weight: 2 7 | --- 8 | 9 | ## Linux 10 | 11 | Download the latest release from our [release page](https://github.com/yannh/kubeconform/releases). 12 | 13 | For example, for Linux on x86_64 architecture: 14 | 15 | {{< prism >}}curl -L https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz | tar xvzf - && \ 16 | sudo mv kubeconform /usr/local/bin/ 17 | {{< /prism >}} 18 | 19 | 20 | ## MacOs 21 | 22 | Kubeconform is available to install using [Homebrew](https://brew.sh/): 23 | {{< prism >}}$ brew install kubeconform 24 | {{< /prism >}} 25 | 26 | ## Windows 27 | 28 | Download the latest release from our [release page](https://github.com/yannh/kubeconform/releases). -------------------------------------------------------------------------------- /site/content/docs/json-schema-conversion.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "OpenAPI to JSON Schema conversion" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "Usage"] 6 | weight: 5 7 | --- 8 | 9 | Kubeconform uses JSON schemas to validate Kubernetes resources. For custom resources, the CustomResourceDefinition 10 | first needs to be converted to JSON Schema. A script is provided to convert these CustomResourceDefinitions 11 | to JSON schema. Here is an example how to use it: 12 | 13 | {{< prism >}}#!/bin/bash 14 | $ ./scripts/openapi2jsonschema.py https://raw.githubusercontent.com/aws/amazon-sagemaker-operator-for-k8s/master/config/crd/bases/sagemaker.aws.amazon.com_trainingjobs.yaml 15 | JSON schema written to trainingjob_v1.json 16 | {{< /prism >}} 17 | 18 | The `FILENAME_FORMAT` environment variable can be used to change the output file name (Available variables: `kind`, `group`, `version`) (Default: `{kind}_{version}`). 19 | 20 | {{< prism >}}$ export FILENAME_FORMAT='{kind}-{group}-{version}' 21 | $ ./scripts/openapi2jsonschema.py https://raw.githubusercontent.com/aws/amazon-sagemaker-operator-for-k8s/master/config/crd/bases/sagemaker.aws.amazon.com_trainingjobs.yaml 22 | JSON schema written to trainingjob-sagemaker-v1.json 23 | {{< /prism >}} 24 | 25 | Some CRD schemas do not have explicit validation for fields implicitly validated by the Kubernetes API like `apiVersion`, `kind`, and `metadata`, thus additional properties are allowed at the root of the JSON schema by default, if this is not desired the `DENY_ROOT_ADDITIONAL_PROPERTIES` environment variable can be set to any non-empty value. -------------------------------------------------------------------------------- /site/content/docs/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Overview" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "Overview"] 6 | weight: 1 7 | --- 8 | 9 | Kubeconform is a Kubernetes manifests validation tool, and checks whether your Kubernetes manifests 10 | are valid, according to Kubernetes resources definitions. 11 | 12 | It is inspired by, contains code from and is designed to stay close to 13 | [Kubeval](https://github.com/instrumenta/kubeval), but with the following improvements: 14 | * **high performance**: will validate & download manifests over multiple routines, caching 15 | downloaded files in memory 16 | * configurable list of **remote, or local schemas locations**, enabling validating Kubernetes 17 | custom resources (CRDs) and offline validation capabilities 18 | * uses by default a [self-updating fork](https://github.com/yannh/kubernetes-json-schema) of the schemas registry maintained 19 | by the [kubernetes-json-schema](https://github.com/instrumenta/kubernetes-json-schema) project - which guarantees 20 | up-to-date **schemas for all recent versions of Kubernetes**. 21 | * improved logging: support for more formats (Tap, Junit, JSON). 22 | 23 | ### A small overview of Kubernetes manifest validation 24 | 25 | Kubernetes's API is described using the [OpenAPI (formerly swagger) specification](https://www.openapis.org), 26 | in a [file](https://github.com/kubernetes/kubernetes/blob/master/api/openapi-spec/swagger.json) checked into 27 | the main Kubernetes repository. 28 | 29 | Because of the state of the tooling to perform validation against OpenAPI schemas, projects usually convert 30 | the OpenAPI schemas to [JSON schemas](https://json-schema.org/) first. Kubeval relies on 31 | [instrumenta/OpenApi2JsonSchema](https://github.com/instrumenta/openapi2jsonschema) to convert Kubernetes' Swagger file 32 | and break it down into multiple JSON schemas, stored in github at 33 | [instrumenta/kubernetes-json-schema](https://github.com/instrumenta/kubernetes-json-schema) and published on 34 | [kubernetesjsonschema.dev](https://kubernetesjsonschema.dev/). 35 | 36 | Kubeconform relies on [a fork of kubernetes-json-schema](https://github.com/yannh/kubernetes-json-schema/) 37 | that is more aggressively kept up-to-date, and contains schemas for all recent versions of Kubernetes. 38 | 39 | ### Limits of Kubeconform validation 40 | 41 | Kubeconform, similarly to kubeval, only validates manifests using the OpenAPI specifications. In some 42 | cases, the Kubernetes controllers might perform additional validation - so that manifests passing kubeval 43 | validation would still error when being deployed. See for example these bugs against kubeval: 44 | [#253](https://github.com/instrumenta/kubeval/issues/253) 45 | [#256](https://github.com/instrumenta/kubeval/issues/256) 46 | [#257](https://github.com/instrumenta/kubeval/issues/257) 47 | [#259](https://github.com/instrumenta/kubeval/issues/259). The validation logic mentioned in these 48 | bug reports is not part of Kubernetes' OpenAPI spec, and therefore kubeconform/kubeval will not detect the 49 | configuration errors. -------------------------------------------------------------------------------- /site/content/docs/usage-as-github-action.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Github Action" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "Usage"] 6 | weight: 6 7 | --- 8 | 9 | Kubeconform is publishes Docker Images to Github's new Container Registry, ghcr.io. These images 10 | can be used directly in a Github Action, once logged in using a [_Github Token_](https://github.blog/changelog/2021-03-24-packages-container-registry-now-supports-github_token/). 11 | 12 | {{< prism >}}name: kubeconform 13 | on: push 14 | jobs: 15 | kubeconform: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: login to Github Packages 19 | run: echo "${{ github.token }}" | docker login https://ghcr.io -u ${GITHUB_ACTOR} --password-stdin 20 | - uses: actions/checkout@v2 21 | - uses: docker://ghcr.io/yannh/kubeconform:master 22 | with: 23 | entrypoint: '/kubeconform' 24 | args: "-summary -output json kubeconfigs/" 25 | {{< /prism >}} 26 | 27 | _Note on pricing_: Kubeconform relies on Github Container Registry which is currently in Beta. During that period, 28 | [bandwidth is free](https://docs.github.com/en/packages/guides/about-github-container-registry). After that period, 29 | bandwidth costs might be applicable. Since bandwidth from Github Packages within Github Actions is free, I expect 30 | Github Container Registry to also be usable for free within Github Actions in the future. If that were not to be the 31 | case, I might publish the Docker image to a different platform. -------------------------------------------------------------------------------- /site/content/docs/usage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Usage" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "Usage"] 6 | weight: 3 7 | --- 8 | 9 | {{< prism >}}$ ./bin/kubeconform -h 10 | Usage: ./bin/kubeconform [OPTION]... [FILE OR FOLDER]... 11 | -cache string 12 | cache schemas downloaded via HTTP to this folder 13 | -cpu-prof string 14 | debug - log CPU profiling to file 15 | -exit-on-error 16 | immediately stop execution when the first error is encountered 17 | -h show help information 18 | -ignore-filename-pattern value 19 | regular expression specifying paths to ignore (can be specified multiple times) 20 | -ignore-missing-schemas 21 | skip files with missing schemas instead of failing 22 | -insecure-skip-tls-verify 23 | disable verification of the server's SSL certificate. This will make your HTTPS connections insecure 24 | -kubernetes-version string 25 | version of Kubernetes to validate against, e.g.: 1.18.0 (default "master") 26 | -n int 27 | number of goroutines to run concurrently (default 4) 28 | -output string 29 | output format - json, junit, tap, text (default "text") 30 | -reject string 31 | comma-separated list of kinds to reject 32 | -schema-location value 33 | override schemas location search path (can be specified multiple times) 34 | -skip string 35 | comma-separated list of kinds to ignore 36 | -strict 37 | disallow additional properties not in schema or duplicated keys 38 | -summary 39 | print a summary at the end (ignored for junit output) 40 | -v show version information 41 | -verbose 42 | print results for all resources (ignored for tap and junit output) 43 | {{< /prism >}} 44 | 45 | ### Validating a single, valid file 46 | 47 | {{< prism >}}$ ./bin/kubeconform fixtures/valid.yaml 48 | $ echo $? 49 | 0 50 | {{< /prism >}} 51 | 52 | ### Validating a single invalid file, setting output to json, and printing a summary 53 | {{< prism >}}$ ./bin/kubeconform -summary -output json fixtures/invalid.yaml 54 | { 55 | "resources": [ 56 | { 57 | "filename": "fixtures/invalid.yaml", 58 | "kind": "ReplicationController", 59 | "version": "v1", 60 | "status": "INVALID", 61 | "msg": "Additional property templates is not allowed - Invalid type. Expected: [integer,null], given: string" 62 | } 63 | ], 64 | "summary": { 65 | "valid": 0, 66 | "invalid": 1, 67 | "errors": 0, 68 | "skipped": 0 69 | } 70 | } 71 | $ echo $? 72 | 1 73 | {{< /prism >}} 74 | 75 | ### Passing manifests via Stdin 76 | {{< prism >}}cat fixtures/valid.yaml | ./bin/kubeconform -summary 77 | Summary: 1 resource found parsing stdin - Valid: 1, Invalid: 0, Errors: 0 Skipped: 0 78 | {{< /prism >}} 79 | 80 | ### Validating a folder, increasing the number of parallel workers 81 | {{< prism >}}$ ./bin/kubeconform -summary -n 16 fixtures 82 | fixtures/crd_schema.yaml - CustomResourceDefinition trainingjobs.sagemaker.aws.amazon.com failed validation: could not find schema for CustomResourceDefinition 83 | fixtures/invalid.yaml - ReplicationController bob is invalid: Invalid type. Expected: [integer,null], given: string 84 | [...] 85 | Summary: 65 resources found in 34 files - Valid: 55, Invalid: 2, Errors: 8 Skipped: 0 86 | {{< /prism >}} 87 | -------------------------------------------------------------------------------- /site/content/docs/using-as-a-go-module.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Kubeconform as a Go module" 3 | date: 2021-07-02T00:00:00Z 4 | draft: false 5 | tags: ["Kubeconform", "Usage"] 6 | weight: 7 7 | --- 8 | 9 | **Warning**: This is a work-in-progress, the interface is not yet considered stable. Feedback is encouraged. 10 | 11 | Kubeconform contains a package that can be used as a library. 12 | An example of usage can be found in [examples/main.go](https://github.com/yannh/kubeconform/tree/master/examples/main.go) 13 | 14 | Additional documentation on [pkg.go.dev](https://pkg.go.dev/github.com/yannh/kubeconform/pkg/validator) -------------------------------------------------------------------------------- /site/public/about/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kubeconform - Fast Kubernetes manifests validation! | About 6 | 7 | 8 |
18 |
19 | 23 |
24 |

About

25 |

Kubeconform is a Kubernetes manifests validation tool. Build it into your CI to validate your Kubernetes 26 | configuration!

27 |

It is inspired by, contains code from and is designed to stay close to 28 | Kubeval, but with the following improvements:

29 |
    30 |
  • high performance: will validate & download manifests over multiple routines, caching 31 | downloaded files in memory
  • 32 |
  • configurable list of remote, or local schemas locations, enabling validating Kubernetes 33 | custom resources (CRDs) and offline validation capabilities
  • 34 |
  • uses by default a self-updating fork of the schemas registry maintained 35 | by the kubernetes-json-schema project - which guarantees 36 | up-to-date schemas for all recent versions of Kubernetes.
  • 37 |
38 |
39 | 43 | 44 |
45 |
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /site/public/categories/index.xml: -------------------------------------------------------------------------------- 1 | Categories on Kubeconform - Fast Kubernetes manifests validation!http://kubeconform.mandragor.org/categories/Recent content in Categories on Kubeconform - Fast Kubernetes manifests validation!Hugo -- gohugo.ioen-us -------------------------------------------------------------------------------- /site/public/css/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * okaidia theme for JavaScript, CSS and HTML 3 | * Loosely based on Monokai textmate theme by http://www.monokai.nl/ 4 | * @author ocodia 5 | */ 6 | 7 | code[class*="language-"], 8 | pre[class*="language-"] { 9 | color: #f8f8f2; 10 | background: none; 11 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 12 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 13 | text-align: left; 14 | white-space: pre; 15 | word-spacing: normal; 16 | word-break: normal; 17 | word-wrap: normal; 18 | line-height: 1.5; 19 | 20 | -moz-tab-size: 4; 21 | -o-tab-size: 4; 22 | tab-size: 4; 23 | 24 | -webkit-hyphens: none; 25 | -moz-hyphens: none; 26 | -ms-hyphens: none; 27 | hyphens: none; 28 | } 29 | 30 | /* Code blocks */ 31 | pre[class*="language-"] { 32 | padding: 1em; 33 | margin: .5em 0; 34 | overflow: auto; 35 | border-radius: 0.3em; 36 | } 37 | 38 | :not(pre) > code[class*="language-"], 39 | pre[class*="language-"] { 40 | background: #272822; 41 | } 42 | 43 | /* Inline code */ 44 | :not(pre) > code[class*="language-"] { 45 | padding: .1em; 46 | border-radius: .3em; 47 | white-space: normal; 48 | } 49 | 50 | .token.comment, 51 | .token.prolog, 52 | .token.doctype, 53 | .token.cdata { 54 | color: slategray; 55 | } 56 | 57 | .token.punctuation { 58 | color: #f8f8f2; 59 | } 60 | 61 | .namespace { 62 | opacity: .7; 63 | } 64 | 65 | .token.property, 66 | .token.tag, 67 | .token.constant, 68 | .token.symbol, 69 | .token.deleted { 70 | color: #f92672; 71 | } 72 | 73 | .token.boolean, 74 | .token.number { 75 | color: #ae81ff; 76 | } 77 | 78 | .token.selector, 79 | .token.attr-name, 80 | .token.string, 81 | .token.char, 82 | .token.builtin, 83 | .token.inserted { 84 | color: #a6e22e; 85 | } 86 | 87 | .token.operator, 88 | .token.entity, 89 | .token.url, 90 | .language-css .token.string, 91 | .style .token.string, 92 | .token.variable { 93 | color: #f8f8f2; 94 | } 95 | 96 | .token.atrule, 97 | .token.attr-value, 98 | .token.function, 99 | .token.class-name { 100 | color: #e6db74; 101 | } 102 | 103 | .token.keyword { 104 | color: #66d9ef; 105 | } 106 | 107 | .token.regex, 108 | .token.important { 109 | color: #fd971f; 110 | } 111 | 112 | .token.important, 113 | .token.bold { 114 | font-weight: bold; 115 | } 116 | .token.italic { 117 | font-style: italic; 118 | } 119 | 120 | .token.entity { 121 | cursor: help; 122 | } -------------------------------------------------------------------------------- /site/public/docs/installation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kubeconform - Fast Kubernetes manifests validation! | Installation 6 | 7 | 8 |
18 |
27 |
28 | 32 |
33 |

Installation

34 |

Linux

35 |

Download the latest release from our release page.

36 |

For example, for Linux on x86_64 architecture:

37 |
curl -L https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz | tar xvzf - && \
38 | sudo mv kubeconform /usr/local/bin/
39 | 
40 |

MacOs

41 |

Kubeconform is available to install using Homebrew: 42 |

$ brew install kubeconform
43 | 

44 |

Windows

45 |

Download the latest release from our release page.

46 |
47 | 51 | 52 |
53 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /site/public/docs/usage-as-github-action/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kubeconform - Fast Kubernetes manifests validation! | Github Action 6 | 7 | 8 |
18 |
27 |
28 | 32 |
33 |

Github Action

34 |

Kubeconform is publishes Docker Images to Github’s new Container Registry, ghcr.io. These images 35 | can be used directly in a Github Action, once logged in using a Github Token.

36 |
name: kubeconform
37 | on: push
38 | jobs:
39 |   kubeconform:
40 |     runs-on: ubuntu-latest
41 |     steps:
42 |       - name: login to Github Packages
43 |         run: echo "${{ github.token }}" | docker login https://ghcr.io -u ${GITHUB_ACTOR} --password-stdin
44 |       - uses: actions/checkout@v2
45 |       - uses: docker://ghcr.io/yannh/kubeconform:master
46 |         with:
47 |           entrypoint: '/kubeconform'
48 |           args: "-summary -output json kubeconfigs/"
49 | 
50 |

Note on pricing: Kubeconform relies on Github Container Registry which is currently in Beta. During that period, 51 | bandwidth is free. After that period, 52 | bandwidth costs might be applicable. Since bandwidth from Github Packages within Github Actions is free, I expect 53 | Github Container Registry to also be usable for free within Github Actions in the future. If that were not to be the 54 | case, I might publish the Docker image to a different platform.

55 |
56 | 60 | 61 |
62 |
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /site/public/docs/using-as-a-go-module/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kubeconform - Fast Kubernetes manifests validation! | Kubeconform as a Go module 6 | 7 | 8 |
18 |
27 |
28 | 32 |
33 |

Kubeconform as a Go module

34 |

Warning: This is a work-in-progress, the interface is not yet considered stable. Feedback is encouraged.

35 |

Kubeconform contains a package that can be used as a library. 36 | An example of usage can be found in examples/main.go

37 |

Additional documentation on pkg.go.dev

38 |
39 | 43 | 44 |
45 |
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /site/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Kubeconform - Fast Kubernetes manifests validation! 7 | 8 | 9 |
19 |
20 |

Validate your Kubernetes manifests instead of deploying broken configuration

21 |
$ kubeconform -summary myapp/deployment.yaml
22 | Summary: 5 resources found in 1 file - Valid: 5, Invalid: 0, Errors: 0, Skipped: 0
23 | 
24 | 25 | Get Started! 26 | 27 |
28 |
29 |

Easy-to-use

30 |

Single binary, super-easy installation for Windows, Mac & Linux. It takes seconds to get started.

31 |
32 |
33 |

Lightning fast

34 |

Kubeconform makes heavy use of Golang's concurrency capabilities, and will spread its workload across multiple cores. 35 |

36 |
37 |

Support for Kubernetes CRDs

38 |

Validate ALL your Kubernetes resources with Kubeconform's CRD support

39 |
40 |
41 |

Flexible

42 |

With support for JSON, Junit, TAP output, and leveraging the easy-to-use Docker image, you can run Kubeconform in any CI system.

43 |
44 |
45 |
46 |
49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /site/public/installation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Kubeconform - Fast Kubernetes manifests validation! | The execution model of AWS Lambda@edge with Cloudfront's two- and three-tiered architecture 7 | 8 |
9 |

Kubeconform

10 |

A FAST Kubernetes manifests validator

11 |
12 |
13 | 14 |
15 | 16 | ← Back 17 |

The execution model of AWS Lambda@edge with Cloudfront's two- and three-tiered architecture
July 2, 2021

18 | 19 |

Installation

20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /site/public/sitemap.xml: -------------------------------------------------------------------------------- 1 | http://kubeconform.mandragor.org/docs/overview/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/docs/installation/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/docs/usage/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/docs/crd-support/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/docs/json-schema-conversion/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/docs/usage-as-github-action/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/docs/using-as-a-go-module/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/tags/about/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/about/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/docs/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/tags/installation/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/tags/kubeconform/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/tags/overview/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/tags/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/tags/usage/2021-07-02T00:00:00+00:00http://kubeconform.mandragor.org/categories/ -------------------------------------------------------------------------------- /site/public/tags/about/index.xml: -------------------------------------------------------------------------------- 1 | About on Kubeconform - Fast Kubernetes manifests validation!http://kubeconform.mandragor.org/tags/about/Recent content in About on Kubeconform - Fast Kubernetes manifests validation!Hugo -- gohugo.ioen-usFri, 02 Jul 2021 00:00:00 +0000Abouthttp://kubeconform.mandragor.org/about/Fri, 02 Jul 2021 00:00:00 +0000http://kubeconform.mandragor.org/about/Kubeconform is a Kubernetes manifests validation tool. Build it into your CI to validate your Kubernetes configuration! 2 | It is inspired by, contains code from and is designed to stay close to Kubeval, but with the following improvements: 3 | high performance: will validate &amp; download manifests over multiple routines, caching downloaded files in memory configurable list of remote, or local schemas locations, enabling validating Kubernetes custom resources (CRDs) and offline validation capabilities uses by default a self-updating fork of the schemas registry maintained by the kubernetes-json-schema project - which guarantees up-to-date schemas for all recent versions of Kubernetes. -------------------------------------------------------------------------------- /site/public/tags/cloudfront/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Cloudfront on Kubeconform - Fast Kubernetes manifests validation! 5 | http://localhost/tags/cloudfront/ 6 | Recent content in Cloudfront on Kubeconform - Fast Kubernetes manifests validation! 7 | Hugo -- gohugo.io 8 | en-us 9 | Fri, 02 Jul 2021 00:00:00 +0000 10 | 11 | The execution model of AWS Lambda@edge with Cloudfront's two- and three-tiered architecture 12 | http://localhost/installation/ 13 | Fri, 02 Jul 2021 00:00:00 +0000 14 | 15 | http://localhost/installation/ 16 | Installation 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /site/public/tags/index.xml: -------------------------------------------------------------------------------- 1 | Tags on Kubeconform - Fast Kubernetes manifests validation!http://kubeconform.mandragor.org/tags/Recent content in Tags on Kubeconform - Fast Kubernetes manifests validation!Hugo -- gohugo.ioen-usFri, 02 Jul 2021 00:00:00 +0000Abouthttp://kubeconform.mandragor.org/tags/about/Fri, 02 Jul 2021 00:00:00 +0000http://kubeconform.mandragor.org/tags/about/Installationhttp://kubeconform.mandragor.org/tags/installation/Fri, 02 Jul 2021 00:00:00 +0000http://kubeconform.mandragor.org/tags/installation/Kubeconformhttp://kubeconform.mandragor.org/tags/kubeconform/Fri, 02 Jul 2021 00:00:00 +0000http://kubeconform.mandragor.org/tags/kubeconform/Overviewhttp://kubeconform.mandragor.org/tags/overview/Fri, 02 Jul 2021 00:00:00 +0000http://kubeconform.mandragor.org/tags/overview/Usagehttp://kubeconform.mandragor.org/tags/usage/Fri, 02 Jul 2021 00:00:00 +0000http://kubeconform.mandragor.org/tags/usage/ -------------------------------------------------------------------------------- /site/public/tags/installation/index.xml: -------------------------------------------------------------------------------- 1 | Installation on Kubeconform - Fast Kubernetes manifests validation!http://kubeconform.mandragor.org/tags/installation/Recent content in Installation on Kubeconform - Fast Kubernetes manifests validation!Hugo -- gohugo.ioen-usFri, 02 Jul 2021 00:00:00 +0000Installationhttp://kubeconform.mandragor.org/docs/installation/Fri, 02 Jul 2021 00:00:00 +0000http://kubeconform.mandragor.org/docs/installation/Linux Download the latest release from our release page. 2 | For example, for Linux on x86_64 architecture: 3 | curl -L https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz | tar xvzf - && \ sudo mv kubeconform /usr/local/bin/ MacOs Kubeconform is available to install using Homebrew: $ brew install kubeconform 4 | Windows Download the latest release from our release page. -------------------------------------------------------------------------------- /site/public/tags/lambdaedge/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Lambda@edge on Kubeconform - Fast Kubernetes manifests validation! 5 | http://localhost/tags/lambdaedge/ 6 | Recent content in Lambda@edge on Kubeconform - Fast Kubernetes manifests validation! 7 | Hugo -- gohugo.io 8 | en-us 9 | Fri, 02 Jul 2021 00:00:00 +0000 10 | 11 | The execution model of AWS Lambda@edge with Cloudfront's two- and three-tiered architecture 12 | http://localhost/installation/ 13 | Fri, 02 Jul 2021 00:00:00 +0000 14 | 15 | http://localhost/installation/ 16 | Installation 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /site/themes/kubeconform/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Yann Hamon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /site/themes/kubeconform/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | 3 | +++ 4 | -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/404.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yannh/kubeconform/e65429b1e5990dd019ebb7b5642dcd22a3e9cd13/site/themes/kubeconform/layouts/404.html -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{- partial "head.html" . -}} 4 | 5 |
6 | {{- partial "header.html" . -}} 7 |
8 | {{- if eq .Section "docs" -}} 9 | {{- partial "menu.html" . -}} 10 | {{- end -}} 11 |
12 | {{- block "main" . }}{{- end }} 13 |
14 |
15 | {{- partial "footer.html" . -}} 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/_default/list.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yannh/kubeconform/e65429b1e5990dd019ebb7b5642dcd22a3e9cd13/site/themes/kubeconform/layouts/_default/list.html -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | 3 | 15 | 16 |
17 |

{{ .Title }}

18 | {{ .Content }} 19 |
20 | 21 | 33 | 34 | 35 | {{ end }} -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/index.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | 3 |

Validate your Kubernetes manifests instead of deploying broken configuration

4 | 5 |
$ kubeconform -summary myapp/deployment.yaml
 6 | Summary: 5 resources found in 1 file - Valid: 5, Invalid: 0, Errors: 0, Skipped: 0
 7 | 
8 | 9 | 10 | Get Started! 11 | 12 | 13 |
14 |
15 |

Easy-to-use

16 |

Single binary, super-easy installation for Windows, Mac & Linux. It takes seconds to get started.

17 |
18 |
19 |

Lightning fast

20 |

Kubeconform makes heavy use of Golang's concurrency capabilities, and will spread its workload across multiple cores. 21 |

22 |
23 |

Support for Kubernetes CRDs

24 |

Validate ALL your Kubernetes resources with Kubeconform's CRD support

25 |
26 |
27 |

Flexible

28 |

With support for JSON, Junit, TAP output, and leveraging the easy-to-use Docker image, you can run Kubeconform in any CI system.

29 |
30 |
31 | 32 | {{ end }} 33 | -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/partials/footer.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/partials/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{- $title := print .Site.Title " | " .Title -}} 6 | {{- if .IsHome }}{{ $title = .Site.Title }}{{ end -}} 7 | 8 | {{ $title }} 9 | 10 | -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/partials/header.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/partials/menu.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/shortcodes/prism.html: -------------------------------------------------------------------------------- 1 | 2 |
{{.Inner}}
-------------------------------------------------------------------------------- /site/themes/kubeconform/layouts/shortcodes/rawhtml.html: -------------------------------------------------------------------------------- 1 | 2 | {{.Inner}} 3 | -------------------------------------------------------------------------------- /site/themes/kubeconform/static/css/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * okaidia theme for JavaScript, CSS and HTML 3 | * Loosely based on Monokai textmate theme by http://www.monokai.nl/ 4 | * @author ocodia 5 | */ 6 | 7 | code[class*="language-"], 8 | pre[class*="language-"] { 9 | color: #f8f8f2; 10 | background: none; 11 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 12 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 13 | text-align: left; 14 | white-space: pre; 15 | word-spacing: normal; 16 | word-break: normal; 17 | word-wrap: normal; 18 | line-height: 1.5; 19 | 20 | -moz-tab-size: 4; 21 | -o-tab-size: 4; 22 | tab-size: 4; 23 | 24 | -webkit-hyphens: none; 25 | -moz-hyphens: none; 26 | -ms-hyphens: none; 27 | hyphens: none; 28 | } 29 | 30 | /* Code blocks */ 31 | pre[class*="language-"] { 32 | padding: 1em; 33 | margin: .5em 0; 34 | overflow: auto; 35 | border-radius: 0.3em; 36 | } 37 | 38 | :not(pre) > code[class*="language-"], 39 | pre[class*="language-"] { 40 | background: #272822; 41 | } 42 | 43 | /* Inline code */ 44 | :not(pre) > code[class*="language-"] { 45 | padding: .1em; 46 | border-radius: .3em; 47 | white-space: normal; 48 | } 49 | 50 | .token.comment, 51 | .token.prolog, 52 | .token.doctype, 53 | .token.cdata { 54 | color: slategray; 55 | } 56 | 57 | .token.punctuation { 58 | color: #f8f8f2; 59 | } 60 | 61 | .namespace { 62 | opacity: .7; 63 | } 64 | 65 | .token.property, 66 | .token.tag, 67 | .token.constant, 68 | .token.symbol, 69 | .token.deleted { 70 | color: #f92672; 71 | } 72 | 73 | .token.boolean, 74 | .token.number { 75 | color: #ae81ff; 76 | } 77 | 78 | .token.selector, 79 | .token.attr-name, 80 | .token.string, 81 | .token.char, 82 | .token.builtin, 83 | .token.inserted { 84 | color: #a6e22e; 85 | } 86 | 87 | .token.operator, 88 | .token.entity, 89 | .token.url, 90 | .language-css .token.string, 91 | .style .token.string, 92 | .token.variable { 93 | color: #f8f8f2; 94 | } 95 | 96 | .token.atrule, 97 | .token.attr-value, 98 | .token.function, 99 | .token.class-name { 100 | color: #e6db74; 101 | } 102 | 103 | .token.keyword { 104 | color: #66d9ef; 105 | } 106 | 107 | .token.regex, 108 | .token.important { 109 | color: #fd971f; 110 | } 111 | 112 | .token.important, 113 | .token.bold { 114 | font-weight: bold; 115 | } 116 | .token.italic { 117 | font-style: italic; 118 | } 119 | 120 | .token.entity { 121 | cursor: help; 122 | } -------------------------------------------------------------------------------- /site/themes/kubeconform/theme.toml: -------------------------------------------------------------------------------- 1 | # theme.toml template for a Hugo theme 2 | # See https://github.com/gohugoio/hugoThemes#themetoml for an example 3 | 4 | name = "localhost" 5 | license = "MIT" 6 | licenselink = "https://github.com/yannh/kubeconform/themes/kubeconform/LICENSE" 7 | description = "Hugo template for kubeconform" 8 | homepage = "http://github.com/yannh/kubeconform/site/theme/kubeconform/" 9 | tags = [] 10 | features = [] 11 | min_version = "0.0.1" 12 | 13 | [author] 14 | name = "" 15 | homepage = "" 16 | 17 | # If porting an existing theme 18 | [original] 19 | name = "" 20 | homepage = "" 21 | repo = "" 22 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-cleanhttp/README.md: -------------------------------------------------------------------------------- 1 | # cleanhttp 2 | 3 | Functions for accessing "clean" Go http.Client values 4 | 5 | ------------- 6 | 7 | The Go standard library contains a default `http.Client` called 8 | `http.DefaultClient`. It is a common idiom in Go code to start with 9 | `http.DefaultClient` and tweak it as necessary, and in fact, this is 10 | encouraged; from the `http` package documentation: 11 | 12 | > The Client's Transport typically has internal state (cached TCP connections), 13 | so Clients should be reused instead of created as needed. Clients are safe for 14 | concurrent use by multiple goroutines. 15 | 16 | Unfortunately, this is a shared value, and it is not uncommon for libraries to 17 | assume that they are free to modify it at will. With enough dependencies, it 18 | can be very easy to encounter strange problems and race conditions due to 19 | manipulation of this shared value across libraries and goroutines (clients are 20 | safe for concurrent use, but writing values to the client struct itself is not 21 | protected). 22 | 23 | Making things worse is the fact that a bare `http.Client` will use a default 24 | `http.Transport` called `http.DefaultTransport`, which is another global value 25 | that behaves the same way. So it is not simply enough to replace 26 | `http.DefaultClient` with `&http.Client{}`. 27 | 28 | This repository provides some simple functions to get a "clean" `http.Client` 29 | -- one that uses the same default values as the Go standard library, but 30 | returns a client that does not share any state with other clients. 31 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go: -------------------------------------------------------------------------------- 1 | package cleanhttp 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | "runtime" 7 | "time" 8 | ) 9 | 10 | // DefaultTransport returns a new http.Transport with similar default values to 11 | // http.DefaultTransport, but with idle connections and keepalives disabled. 12 | func DefaultTransport() *http.Transport { 13 | transport := DefaultPooledTransport() 14 | transport.DisableKeepAlives = true 15 | transport.MaxIdleConnsPerHost = -1 16 | return transport 17 | } 18 | 19 | // DefaultPooledTransport returns a new http.Transport with similar default 20 | // values to http.DefaultTransport. Do not use this for transient transports as 21 | // it can leak file descriptors over time. Only use this for transports that 22 | // will be re-used for the same host(s). 23 | func DefaultPooledTransport() *http.Transport { 24 | transport := &http.Transport{ 25 | Proxy: http.ProxyFromEnvironment, 26 | DialContext: (&net.Dialer{ 27 | Timeout: 30 * time.Second, 28 | KeepAlive: 30 * time.Second, 29 | DualStack: true, 30 | }).DialContext, 31 | MaxIdleConns: 100, 32 | IdleConnTimeout: 90 * time.Second, 33 | TLSHandshakeTimeout: 10 * time.Second, 34 | ExpectContinueTimeout: 1 * time.Second, 35 | ForceAttemptHTTP2: true, 36 | MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, 37 | } 38 | return transport 39 | } 40 | 41 | // DefaultClient returns a new http.Client with similar default values to 42 | // http.Client, but with a non-shared Transport, idle connections disabled, and 43 | // keepalives disabled. 44 | func DefaultClient() *http.Client { 45 | return &http.Client{ 46 | Transport: DefaultTransport(), 47 | } 48 | } 49 | 50 | // DefaultPooledClient returns a new http.Client with similar default values to 51 | // http.Client, but with a shared Transport. Do not use this function for 52 | // transient clients as it can leak file descriptors over time. Only use this 53 | // for clients that will be re-used for the same host(s). 54 | func DefaultPooledClient() *http.Client { 55 | return &http.Client{ 56 | Transport: DefaultPooledTransport(), 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-cleanhttp/doc.go: -------------------------------------------------------------------------------- 1 | // Package cleanhttp offers convenience utilities for acquiring "clean" 2 | // http.Transport and http.Client structs. 3 | // 4 | // Values set on http.DefaultClient and http.DefaultTransport affect all 5 | // callers. This can have detrimental effects, esepcially in TLS contexts, 6 | // where client or root certificates set to talk to multiple endpoints can end 7 | // up displacing each other, leading to hard-to-debug issues. This package 8 | // provides non-shared http.Client and http.Transport structs to ensure that 9 | // the configuration will not be overwritten by other parts of the application 10 | // or dependencies. 11 | // 12 | // The DefaultClient and DefaultTransport functions disable idle connections 13 | // and keepalives. Without ensuring that idle connections are closed before 14 | // garbage collection, short-term clients/transports can leak file descriptors, 15 | // eventually leading to "too many open files" errors. If you will be 16 | // connecting to the same hosts repeatedly from the same client, you can use 17 | // DefaultPooledClient to receive a client that has connection pooling 18 | // semantics similar to http.DefaultClient. 19 | // 20 | package cleanhttp 21 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-cleanhttp/handlers.go: -------------------------------------------------------------------------------- 1 | package cleanhttp 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | "unicode" 7 | ) 8 | 9 | // HandlerInput provides input options to cleanhttp's handlers 10 | type HandlerInput struct { 11 | ErrStatus int 12 | } 13 | 14 | // PrintablePathCheckHandler is a middleware that ensures the request path 15 | // contains only printable runes. 16 | func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler { 17 | // Nil-check on input to make it optional 18 | if input == nil { 19 | input = &HandlerInput{ 20 | ErrStatus: http.StatusBadRequest, 21 | } 22 | } 23 | 24 | // Default to http.StatusBadRequest on error 25 | if input.ErrStatus == 0 { 26 | input.ErrStatus = http.StatusBadRequest 27 | } 28 | 29 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 30 | if r != nil { 31 | // Check URL path for non-printable characters 32 | idx := strings.IndexFunc(r.URL.Path, func(c rune) bool { 33 | return !unicode.IsPrint(c) 34 | }) 35 | 36 | if idx != -1 { 37 | w.WriteHeader(input.ErrStatus) 38 | return 39 | } 40 | 41 | if next != nil { 42 | next.ServeHTTP(w, r) 43 | } 44 | } 45 | 46 | return 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | *.test 4 | .vscode/ -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/.go-version: -------------------------------------------------------------------------------- 1 | 1.22.2 2 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.7.7 (May 30, 2024) 2 | 3 | BUG FIXES: 4 | 5 | - client: avoid potentially leaking URL-embedded basic authentication credentials in logs (#158) 6 | 7 | ## 0.7.6 (May 9, 2024) 8 | 9 | ENHANCEMENTS: 10 | 11 | - client: support a `RetryPrepare` function for modifying the request before retrying (#216) 12 | - client: support HTTP-date values for `Retry-After` header value (#138) 13 | - client: avoid reading entire body when the body is a `*bytes.Reader` (#197) 14 | 15 | BUG FIXES: 16 | 17 | - client: fix a broken check for invalid server certificate in go 1.20+ (#210) 18 | 19 | ## 0.7.5 (Nov 8, 2023) 20 | 21 | BUG FIXES: 22 | 23 | - client: fixes an issue where the request body is not preserved on temporary redirects or re-established HTTP/2 connections (#207) 24 | 25 | ## 0.7.4 (Jun 6, 2023) 26 | 27 | BUG FIXES: 28 | 29 | - client: fixing an issue where the Content-Type header wouldn't be sent with an empty payload when using HTTP/2 (#194) 30 | 31 | ## 0.7.3 (May 15, 2023) 32 | 33 | Initial release 34 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @hashicorp/go-retryablehttp-maintainers 2 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/Makefile: -------------------------------------------------------------------------------- 1 | default: test 2 | 3 | test: 4 | go vet ./... 5 | go test -v -race ./... 6 | 7 | updatedeps: 8 | go get -f -t -u ./... 9 | go get -f -u ./... 10 | 11 | .PHONY: default test updatedeps 12 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/README.md: -------------------------------------------------------------------------------- 1 | go-retryablehttp 2 | ================ 3 | 4 | [![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis] 5 | [![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] 6 | 7 | [travis]: http://travis-ci.org/hashicorp/go-retryablehttp 8 | [godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp 9 | 10 | The `retryablehttp` package provides a familiar HTTP client interface with 11 | automatic retries and exponential backoff. It is a thin wrapper over the 12 | standard `net/http` client library and exposes nearly the same public API. This 13 | makes `retryablehttp` very easy to drop into existing programs. 14 | 15 | `retryablehttp` performs automatic retries under certain conditions. Mainly, if 16 | an error is returned by the client (connection errors, etc.), or if a 500-range 17 | response code is received (except 501), then a retry is invoked after a wait 18 | period. Otherwise, the response is returned and left to the caller to 19 | interpret. 20 | 21 | The main difference from `net/http` is that requests which take a request body 22 | (POST/PUT et. al) can have the body provided in a number of ways (some more or 23 | less efficient) that allow "rewinding" the request body if the initial request 24 | fails so that the full request can be attempted again. See the 25 | [godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more 26 | details. 27 | 28 | Version 0.6.0 and before are compatible with Go prior to 1.12. From 0.6.1 onward, Go 1.12+ is required. 29 | From 0.6.7 onward, Go 1.13+ is required. 30 | 31 | Example Use 32 | =========== 33 | 34 | Using this library should look almost identical to what you would do with 35 | `net/http`. The most simple example of a GET request is shown below: 36 | 37 | ```go 38 | resp, err := retryablehttp.Get("/foo") 39 | if err != nil { 40 | panic(err) 41 | } 42 | ``` 43 | 44 | The returned response object is an `*http.Response`, the same thing you would 45 | usually get from `net/http`. Had the request failed one or more times, the above 46 | call would block and retry with exponential backoff. 47 | 48 | ## Getting a stdlib `*http.Client` with retries 49 | 50 | It's possible to convert a `*retryablehttp.Client` directly to a `*http.Client`. 51 | This makes use of retryablehttp broadly applicable with minimal effort. Simply 52 | configure a `*retryablehttp.Client` as you wish, and then call `StandardClient()`: 53 | 54 | ```go 55 | retryClient := retryablehttp.NewClient() 56 | retryClient.RetryMax = 10 57 | 58 | standardClient := retryClient.StandardClient() // *http.Client 59 | ``` 60 | 61 | For more usage and examples see the 62 | [pkg.go.dev](https://pkg.go.dev/github.com/hashicorp/go-retryablehttp). 63 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/cert_error_go119.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) HashiCorp, Inc. 2 | // SPDX-License-Identifier: MPL-2.0 3 | 4 | //go:build !go1.20 5 | // +build !go1.20 6 | 7 | package retryablehttp 8 | 9 | import "crypto/x509" 10 | 11 | func isCertError(err error) bool { 12 | _, ok := err.(x509.UnknownAuthorityError) 13 | return ok 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/cert_error_go120.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) HashiCorp, Inc. 2 | // SPDX-License-Identifier: MPL-2.0 3 | 4 | //go:build go1.20 5 | // +build go1.20 6 | 7 | package retryablehttp 8 | 9 | import "crypto/tls" 10 | 11 | func isCertError(err error) bool { 12 | _, ok := err.(*tls.CertificateVerificationError) 13 | return ok 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) HashiCorp, Inc. 2 | // SPDX-License-Identifier: MPL-2.0 3 | 4 | package retryablehttp 5 | 6 | import ( 7 | "errors" 8 | "net/http" 9 | "net/url" 10 | "sync" 11 | ) 12 | 13 | // RoundTripper implements the http.RoundTripper interface, using a retrying 14 | // HTTP client to execute requests. 15 | // 16 | // It is important to note that retryablehttp doesn't always act exactly as a 17 | // RoundTripper should. This is highly dependent on the retryable client's 18 | // configuration. 19 | type RoundTripper struct { 20 | // The client to use during requests. If nil, the default retryablehttp 21 | // client and settings will be used. 22 | Client *Client 23 | 24 | // once ensures that the logic to initialize the default client runs at 25 | // most once, in a single thread. 26 | once sync.Once 27 | } 28 | 29 | // init initializes the underlying retryable client. 30 | func (rt *RoundTripper) init() { 31 | if rt.Client == nil { 32 | rt.Client = NewClient() 33 | } 34 | } 35 | 36 | // RoundTrip satisfies the http.RoundTripper interface. 37 | func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { 38 | rt.once.Do(rt.init) 39 | 40 | // Convert the request to be retryable. 41 | retryableReq, err := FromRequest(req) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | // Execute the request. 47 | resp, err := rt.Client.Do(retryableReq) 48 | // If we got an error returned by standard library's `Do` method, unwrap it 49 | // otherwise we will wind up erroneously re-nesting the error. 50 | if _, ok := err.(*url.Error); ok { 51 | return resp, errors.Unwrap(err) 52 | } 53 | 54 | return resp, err 55 | } 56 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "testdata/JSON-Schema-Test-Suite"] 2 | path = testdata/JSON-Schema-Test-Suite 3 | url = https://github.com/json-schema-org/JSON-Schema-Test-Suite.git 4 | branch = main 5 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - nakedret 4 | - errname 5 | - godot 6 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | - id: jsonschema-validate 2 | name: Validate JSON against JSON Schema 3 | description: ensure json files follow specified JSON Schema 4 | entry: jv 5 | language: golang 6 | additional_dependencies: 7 | - ./cmd/jv 8 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/content.go: -------------------------------------------------------------------------------- 1 | package jsonschema 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "encoding/json" 7 | ) 8 | 9 | // Decoder specifies how to decode specific contentEncoding. 10 | type Decoder struct { 11 | // Name of contentEncoding. 12 | Name string 13 | // Decode given string to byte array. 14 | Decode func(string) ([]byte, error) 15 | } 16 | 17 | var decoders = map[string]*Decoder{ 18 | "base64": { 19 | Name: "base64", 20 | Decode: func(s string) ([]byte, error) { 21 | return base64.StdEncoding.DecodeString(s) 22 | }, 23 | }, 24 | } 25 | 26 | // MediaType specified how to validate bytes against specific contentMediaType. 27 | type MediaType struct { 28 | // Name of contentMediaType. 29 | Name string 30 | 31 | // Validate checks whether bytes conform to this mediatype. 32 | Validate func([]byte) error 33 | 34 | // UnmarshalJSON unmarshals bytes into json value. 35 | // This must be nil if this mediatype is not compatible 36 | // with json. 37 | UnmarshalJSON func([]byte) (any, error) 38 | } 39 | 40 | var mediaTypes = map[string]*MediaType{ 41 | "application/json": { 42 | Name: "application/json", 43 | Validate: func(b []byte) error { 44 | var v any 45 | return json.Unmarshal(b, &v) 46 | }, 47 | UnmarshalJSON: func(b []byte) (any, error) { 48 | return UnmarshalJSON(bytes.NewReader(b)) 49 | }, 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/go.work: -------------------------------------------------------------------------------- 1 | go 1.21.1 2 | 3 | use ( 4 | . 5 | ./cmd/jv 6 | ) 7 | 8 | replace github.com/santhosh-tekuri/jsonschema/v6 v6.0.0 => ./ 9 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/applicator: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "$id": "https://json-schema.org/draft/2019-09/meta/applicator", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2019-09/vocab/applicator": true 6 | }, 7 | "$recursiveAnchor": true, 8 | "title": "Applicator vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "additionalItems": { "$recursiveRef": "#" }, 12 | "unevaluatedItems": { "$recursiveRef": "#" }, 13 | "items": { 14 | "anyOf": [ 15 | { "$recursiveRef": "#" }, 16 | { "$ref": "#/$defs/schemaArray" } 17 | ] 18 | }, 19 | "contains": { "$recursiveRef": "#" }, 20 | "additionalProperties": { "$recursiveRef": "#" }, 21 | "unevaluatedProperties": { "$recursiveRef": "#" }, 22 | "properties": { 23 | "type": "object", 24 | "additionalProperties": { "$recursiveRef": "#" }, 25 | "default": {} 26 | }, 27 | "patternProperties": { 28 | "type": "object", 29 | "additionalProperties": { "$recursiveRef": "#" }, 30 | "propertyNames": { "format": "regex" }, 31 | "default": {} 32 | }, 33 | "dependentSchemas": { 34 | "type": "object", 35 | "additionalProperties": { 36 | "$recursiveRef": "#" 37 | } 38 | }, 39 | "propertyNames": { "$recursiveRef": "#" }, 40 | "if": { "$recursiveRef": "#" }, 41 | "then": { "$recursiveRef": "#" }, 42 | "else": { "$recursiveRef": "#" }, 43 | "allOf": { "$ref": "#/$defs/schemaArray" }, 44 | "anyOf": { "$ref": "#/$defs/schemaArray" }, 45 | "oneOf": { "$ref": "#/$defs/schemaArray" }, 46 | "not": { "$recursiveRef": "#" } 47 | }, 48 | "$defs": { 49 | "schemaArray": { 50 | "type": "array", 51 | "minItems": 1, 52 | "items": { "$recursiveRef": "#" } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/content: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "$id": "https://json-schema.org/draft/2019-09/meta/content", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2019-09/vocab/content": true 6 | }, 7 | "$recursiveAnchor": true, 8 | "title": "Content vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "contentMediaType": { "type": "string" }, 12 | "contentEncoding": { "type": "string" }, 13 | "contentSchema": { "$recursiveRef": "#" } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/core: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "$id": "https://json-schema.org/draft/2019-09/meta/core", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2019-09/vocab/core": true 6 | }, 7 | "$recursiveAnchor": true, 8 | "title": "Core vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "$id": { 12 | "type": "string", 13 | "format": "uri-reference", 14 | "$comment": "Non-empty fragments not allowed.", 15 | "pattern": "^[^#]*#?$" 16 | }, 17 | "$schema": { 18 | "type": "string", 19 | "format": "uri" 20 | }, 21 | "$anchor": { 22 | "type": "string", 23 | "pattern": "^[A-Za-z][-A-Za-z0-9.:_]*$" 24 | }, 25 | "$ref": { 26 | "type": "string", 27 | "format": "uri-reference" 28 | }, 29 | "$recursiveRef": { 30 | "type": "string", 31 | "format": "uri-reference" 32 | }, 33 | "$recursiveAnchor": { 34 | "type": "boolean", 35 | "default": false 36 | }, 37 | "$vocabulary": { 38 | "type": "object", 39 | "propertyNames": { 40 | "type": "string", 41 | "format": "uri" 42 | }, 43 | "additionalProperties": { 44 | "type": "boolean" 45 | } 46 | }, 47 | "$comment": { 48 | "type": "string" 49 | }, 50 | "$defs": { 51 | "type": "object", 52 | "additionalProperties": { "$recursiveRef": "#" }, 53 | "default": {} 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/format: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "$id": "https://json-schema.org/draft/2019-09/meta/format", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2019-09/vocab/format": true 6 | }, 7 | "$recursiveAnchor": true, 8 | "title": "Format vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "format": { "type": "string" } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/meta-data: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "$id": "https://json-schema.org/draft/2019-09/meta/meta-data", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2019-09/vocab/meta-data": true 6 | }, 7 | "$recursiveAnchor": true, 8 | "title": "Meta-data vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "title": { 12 | "type": "string" 13 | }, 14 | "description": { 15 | "type": "string" 16 | }, 17 | "default": true, 18 | "deprecated": { 19 | "type": "boolean", 20 | "default": false 21 | }, 22 | "readOnly": { 23 | "type": "boolean", 24 | "default": false 25 | }, 26 | "writeOnly": { 27 | "type": "boolean", 28 | "default": false 29 | }, 30 | "examples": { 31 | "type": "array", 32 | "items": true 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/meta/validation: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "$id": "https://json-schema.org/draft/2019-09/meta/validation", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2019-09/vocab/validation": true 6 | }, 7 | "$recursiveAnchor": true, 8 | "title": "Validation vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "multipleOf": { 12 | "type": "number", 13 | "exclusiveMinimum": 0 14 | }, 15 | "maximum": { 16 | "type": "number" 17 | }, 18 | "exclusiveMaximum": { 19 | "type": "number" 20 | }, 21 | "minimum": { 22 | "type": "number" 23 | }, 24 | "exclusiveMinimum": { 25 | "type": "number" 26 | }, 27 | "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, 28 | "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 29 | "pattern": { 30 | "type": "string", 31 | "format": "regex" 32 | }, 33 | "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, 34 | "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 35 | "uniqueItems": { 36 | "type": "boolean", 37 | "default": false 38 | }, 39 | "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, 40 | "minContains": { 41 | "$ref": "#/$defs/nonNegativeInteger", 42 | "default": 1 43 | }, 44 | "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, 45 | "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 46 | "required": { "$ref": "#/$defs/stringArray" }, 47 | "dependentRequired": { 48 | "type": "object", 49 | "additionalProperties": { 50 | "$ref": "#/$defs/stringArray" 51 | } 52 | }, 53 | "const": true, 54 | "enum": { 55 | "type": "array", 56 | "items": true 57 | }, 58 | "type": { 59 | "anyOf": [ 60 | { "$ref": "#/$defs/simpleTypes" }, 61 | { 62 | "type": "array", 63 | "items": { "$ref": "#/$defs/simpleTypes" }, 64 | "minItems": 1, 65 | "uniqueItems": true 66 | } 67 | ] 68 | } 69 | }, 70 | "$defs": { 71 | "nonNegativeInteger": { 72 | "type": "integer", 73 | "minimum": 0 74 | }, 75 | "nonNegativeIntegerDefault0": { 76 | "$ref": "#/$defs/nonNegativeInteger", 77 | "default": 0 78 | }, 79 | "simpleTypes": { 80 | "enum": [ 81 | "array", 82 | "boolean", 83 | "integer", 84 | "null", 85 | "number", 86 | "object", 87 | "string" 88 | ] 89 | }, 90 | "stringArray": { 91 | "type": "array", 92 | "items": { "type": "string" }, 93 | "uniqueItems": true, 94 | "default": [] 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2019-09/schema: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2019-09/schema", 3 | "$id": "https://json-schema.org/draft/2019-09/schema", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2019-09/vocab/core": true, 6 | "https://json-schema.org/draft/2019-09/vocab/applicator": true, 7 | "https://json-schema.org/draft/2019-09/vocab/validation": true, 8 | "https://json-schema.org/draft/2019-09/vocab/meta-data": true, 9 | "https://json-schema.org/draft/2019-09/vocab/format": false, 10 | "https://json-schema.org/draft/2019-09/vocab/content": true 11 | }, 12 | "$recursiveAnchor": true, 13 | "title": "Core and Validation specifications meta-schema", 14 | "allOf": [ 15 | {"$ref": "meta/core"}, 16 | {"$ref": "meta/applicator"}, 17 | {"$ref": "meta/validation"}, 18 | {"$ref": "meta/meta-data"}, 19 | {"$ref": "meta/format"}, 20 | {"$ref": "meta/content"} 21 | ], 22 | "type": ["object", "boolean"], 23 | "properties": { 24 | "definitions": { 25 | "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.", 26 | "type": "object", 27 | "additionalProperties": { "$recursiveRef": "#" }, 28 | "default": {} 29 | }, 30 | "dependencies": { 31 | "$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"", 32 | "type": "object", 33 | "additionalProperties": { 34 | "anyOf": [ 35 | { "$recursiveRef": "#" }, 36 | { "$ref": "meta/validation#/$defs/stringArray" } 37 | ] 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/applicator: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/applicator", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/applicator": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Applicator vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "prefixItems": { "$ref": "#/$defs/schemaArray" }, 12 | "items": { "$dynamicRef": "#meta" }, 13 | "contains": { "$dynamicRef": "#meta" }, 14 | "additionalProperties": { "$dynamicRef": "#meta" }, 15 | "properties": { 16 | "type": "object", 17 | "additionalProperties": { "$dynamicRef": "#meta" }, 18 | "default": {} 19 | }, 20 | "patternProperties": { 21 | "type": "object", 22 | "additionalProperties": { "$dynamicRef": "#meta" }, 23 | "propertyNames": { "format": "regex" }, 24 | "default": {} 25 | }, 26 | "dependentSchemas": { 27 | "type": "object", 28 | "additionalProperties": { "$dynamicRef": "#meta" }, 29 | "default": {} 30 | }, 31 | "propertyNames": { "$dynamicRef": "#meta" }, 32 | "if": { "$dynamicRef": "#meta" }, 33 | "then": { "$dynamicRef": "#meta" }, 34 | "else": { "$dynamicRef": "#meta" }, 35 | "allOf": { "$ref": "#/$defs/schemaArray" }, 36 | "anyOf": { "$ref": "#/$defs/schemaArray" }, 37 | "oneOf": { "$ref": "#/$defs/schemaArray" }, 38 | "not": { "$dynamicRef": "#meta" } 39 | }, 40 | "$defs": { 41 | "schemaArray": { 42 | "type": "array", 43 | "minItems": 1, 44 | "items": { "$dynamicRef": "#meta" } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/content: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/content", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/content": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Content vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "contentEncoding": { "type": "string" }, 12 | "contentMediaType": { "type": "string" }, 13 | "contentSchema": { "$dynamicRef": "#meta" } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/core: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/core", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/core": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Core vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "$id": { 12 | "$ref": "#/$defs/uriReferenceString", 13 | "$comment": "Non-empty fragments not allowed.", 14 | "pattern": "^[^#]*#?$" 15 | }, 16 | "$schema": { "$ref": "#/$defs/uriString" }, 17 | "$ref": { "$ref": "#/$defs/uriReferenceString" }, 18 | "$anchor": { "$ref": "#/$defs/anchorString" }, 19 | "$dynamicRef": { "$ref": "#/$defs/uriReferenceString" }, 20 | "$dynamicAnchor": { "$ref": "#/$defs/anchorString" }, 21 | "$vocabulary": { 22 | "type": "object", 23 | "propertyNames": { "$ref": "#/$defs/uriString" }, 24 | "additionalProperties": { 25 | "type": "boolean" 26 | } 27 | }, 28 | "$comment": { 29 | "type": "string" 30 | }, 31 | "$defs": { 32 | "type": "object", 33 | "additionalProperties": { "$dynamicRef": "#meta" } 34 | } 35 | }, 36 | "$defs": { 37 | "anchorString": { 38 | "type": "string", 39 | "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" 40 | }, 41 | "uriString": { 42 | "type": "string", 43 | "format": "uri" 44 | }, 45 | "uriReferenceString": { 46 | "type": "string", 47 | "format": "uri-reference" 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/format-annotation: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/format-annotation", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/format-annotation": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Format vocabulary meta-schema for annotation results", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "format": { "type": "string" } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/format-assertion: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/format-assertion", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/format-assertion": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Format vocabulary meta-schema for assertion results", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "format": { "type": "string" } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/meta-data: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/meta-data", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/meta-data": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Meta-data vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "title": { 12 | "type": "string" 13 | }, 14 | "description": { 15 | "type": "string" 16 | }, 17 | "default": true, 18 | "deprecated": { 19 | "type": "boolean", 20 | "default": false 21 | }, 22 | "readOnly": { 23 | "type": "boolean", 24 | "default": false 25 | }, 26 | "writeOnly": { 27 | "type": "boolean", 28 | "default": false 29 | }, 30 | "examples": { 31 | "type": "array", 32 | "items": true 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/unevaluated: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/unevaluated", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/unevaluated": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Unevaluated applicator vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "unevaluatedItems": { "$dynamicRef": "#meta" }, 12 | "unevaluatedProperties": { "$dynamicRef": "#meta" } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/meta/validation: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/meta/validation", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/validation": true 6 | }, 7 | "$dynamicAnchor": "meta", 8 | "title": "Validation vocabulary meta-schema", 9 | "type": ["object", "boolean"], 10 | "properties": { 11 | "type": { 12 | "anyOf": [ 13 | { "$ref": "#/$defs/simpleTypes" }, 14 | { 15 | "type": "array", 16 | "items": { "$ref": "#/$defs/simpleTypes" }, 17 | "minItems": 1, 18 | "uniqueItems": true 19 | } 20 | ] 21 | }, 22 | "const": true, 23 | "enum": { 24 | "type": "array", 25 | "items": true 26 | }, 27 | "multipleOf": { 28 | "type": "number", 29 | "exclusiveMinimum": 0 30 | }, 31 | "maximum": { 32 | "type": "number" 33 | }, 34 | "exclusiveMaximum": { 35 | "type": "number" 36 | }, 37 | "minimum": { 38 | "type": "number" 39 | }, 40 | "exclusiveMinimum": { 41 | "type": "number" 42 | }, 43 | "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, 44 | "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 45 | "pattern": { 46 | "type": "string", 47 | "format": "regex" 48 | }, 49 | "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, 50 | "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 51 | "uniqueItems": { 52 | "type": "boolean", 53 | "default": false 54 | }, 55 | "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, 56 | "minContains": { 57 | "$ref": "#/$defs/nonNegativeInteger", 58 | "default": 1 59 | }, 60 | "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, 61 | "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 62 | "required": { "$ref": "#/$defs/stringArray" }, 63 | "dependentRequired": { 64 | "type": "object", 65 | "additionalProperties": { 66 | "$ref": "#/$defs/stringArray" 67 | } 68 | } 69 | }, 70 | "$defs": { 71 | "nonNegativeInteger": { 72 | "type": "integer", 73 | "minimum": 0 74 | }, 75 | "nonNegativeIntegerDefault0": { 76 | "$ref": "#/$defs/nonNegativeInteger", 77 | "default": 0 78 | }, 79 | "simpleTypes": { 80 | "enum": [ 81 | "array", 82 | "boolean", 83 | "integer", 84 | "null", 85 | "number", 86 | "object", 87 | "string" 88 | ] 89 | }, 90 | "stringArray": { 91 | "type": "array", 92 | "items": { "type": "string" }, 93 | "uniqueItems": true, 94 | "default": [] 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/metaschemas/draft/2020-12/schema: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://json-schema.org/draft/2020-12/schema", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/2020-12/vocab/core": true, 6 | "https://json-schema.org/draft/2020-12/vocab/applicator": true, 7 | "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, 8 | "https://json-schema.org/draft/2020-12/vocab/validation": true, 9 | "https://json-schema.org/draft/2020-12/vocab/meta-data": true, 10 | "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, 11 | "https://json-schema.org/draft/2020-12/vocab/content": true 12 | }, 13 | "$dynamicAnchor": "meta", 14 | "title": "Core and Validation specifications meta-schema", 15 | "allOf": [ 16 | {"$ref": "meta/core"}, 17 | {"$ref": "meta/applicator"}, 18 | {"$ref": "meta/unevaluated"}, 19 | {"$ref": "meta/validation"}, 20 | {"$ref": "meta/meta-data"}, 21 | {"$ref": "meta/format-annotation"}, 22 | {"$ref": "meta/content"} 23 | ], 24 | "type": ["object", "boolean"], 25 | "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.", 26 | "properties": { 27 | "definitions": { 28 | "$comment": "\"definitions\" has been replaced by \"$defs\".", 29 | "type": "object", 30 | "additionalProperties": { "$dynamicRef": "#meta" }, 31 | "deprecated": true, 32 | "default": {} 33 | }, 34 | "dependencies": { 35 | "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.", 36 | "type": "object", 37 | "additionalProperties": { 38 | "anyOf": [ 39 | { "$dynamicRef": "#meta" }, 40 | { "$ref": "meta/validation#/$defs/stringArray" } 41 | ] 42 | }, 43 | "deprecated": true, 44 | "default": {} 45 | }, 46 | "$recursiveAnchor": { 47 | "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".", 48 | "$ref": "meta/core#/$defs/anchorString", 49 | "deprecated": true 50 | }, 51 | "$recursiveRef": { 52 | "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".", 53 | "$ref": "meta/core#/$defs/uriReferenceString", 54 | "deprecated": true 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/position.go: -------------------------------------------------------------------------------- 1 | package jsonschema 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | // Position tells possible tokens in json. 9 | type Position interface { 10 | collect(v any, ptr jsonPointer) map[jsonPointer]any 11 | } 12 | 13 | // -- 14 | 15 | type AllProp struct{} 16 | 17 | func (AllProp) collect(v any, ptr jsonPointer) map[jsonPointer]any { 18 | obj, ok := v.(map[string]any) 19 | if !ok { 20 | return nil 21 | } 22 | m := map[jsonPointer]any{} 23 | for pname, pvalue := range obj { 24 | m[ptr.append(pname)] = pvalue 25 | } 26 | return m 27 | } 28 | 29 | // -- 30 | 31 | type AllItem struct{} 32 | 33 | func (AllItem) collect(v any, ptr jsonPointer) map[jsonPointer]any { 34 | arr, ok := v.([]any) 35 | if !ok { 36 | return nil 37 | } 38 | m := map[jsonPointer]any{} 39 | for i, item := range arr { 40 | m[ptr.append(strconv.Itoa(i))] = item 41 | } 42 | return m 43 | } 44 | 45 | // -- 46 | 47 | type Prop string 48 | 49 | func (p Prop) collect(v any, ptr jsonPointer) map[jsonPointer]any { 50 | obj, ok := v.(map[string]any) 51 | if !ok { 52 | return nil 53 | } 54 | pvalue, ok := obj[string(p)] 55 | if !ok { 56 | return nil 57 | } 58 | return map[jsonPointer]any{ 59 | ptr.append(string(p)): pvalue, 60 | } 61 | } 62 | 63 | // -- 64 | 65 | type Item int 66 | 67 | func (i Item) collect(v any, ptr jsonPointer) map[jsonPointer]any { 68 | arr, ok := v.([]any) 69 | if !ok { 70 | return nil 71 | } 72 | if i < 0 || int(i) >= len(arr) { 73 | return nil 74 | } 75 | return map[jsonPointer]any{ 76 | ptr.append(strconv.Itoa(int(i))): arr[int(i)], 77 | } 78 | } 79 | 80 | // -- 81 | 82 | // SchemaPath tells where to look for subschema inside keyword. 83 | type SchemaPath []Position 84 | 85 | func schemaPath(path string) SchemaPath { 86 | var sp SchemaPath 87 | for _, tok := range strings.Split(path, "/") { 88 | var pos Position 89 | switch tok { 90 | case "*": 91 | pos = AllProp{} 92 | case "[]": 93 | pos = AllItem{} 94 | default: 95 | if i, err := strconv.Atoi(tok); err == nil { 96 | pos = Item(i) 97 | } else { 98 | pos = Prop(tok) 99 | } 100 | } 101 | sp = append(sp, pos) 102 | } 103 | return sp 104 | } 105 | 106 | func (sp SchemaPath) collect(v any, ptr jsonPointer) map[jsonPointer]any { 107 | if len(sp) == 0 { 108 | return map[jsonPointer]any{ 109 | ptr: v, 110 | } 111 | } 112 | p, sp := sp[0], sp[1:] 113 | m := p.collect(v, ptr) 114 | mm := map[jsonPointer]any{} 115 | for ptr, v := range m { 116 | m = sp.collect(v, ptr) 117 | for k, v := range m { 118 | mm[k] = v 119 | } 120 | } 121 | return mm 122 | } 123 | 124 | func (sp SchemaPath) String() string { 125 | var sb strings.Builder 126 | for _, pos := range sp { 127 | if sb.Len() != 0 { 128 | sb.WriteByte('/') 129 | } 130 | switch pos := pos.(type) { 131 | case AllProp: 132 | sb.WriteString("*") 133 | case AllItem: 134 | sb.WriteString("[]") 135 | case Prop: 136 | sb.WriteString(string(pos)) 137 | case Item: 138 | sb.WriteString(strconv.Itoa(int(pos))) 139 | } 140 | } 141 | return sb.String() 142 | } 143 | -------------------------------------------------------------------------------- /vendor/github.com/santhosh-tekuri/jsonschema/v6/vocab.go: -------------------------------------------------------------------------------- 1 | package jsonschema 2 | 3 | // CompilerContext provides helpers for 4 | // compiling a [Vocabulary]. 5 | type CompilerContext struct { 6 | c *objCompiler 7 | } 8 | 9 | func (ctx *CompilerContext) Enqueue(schPath []string) *Schema { 10 | ptr := ctx.c.up.ptr 11 | for _, tok := range schPath { 12 | ptr = ptr.append(tok) 13 | } 14 | return ctx.c.enqueuePtr(ptr) 15 | } 16 | 17 | // Vocabulary defines a set of keywords, their syntax and 18 | // their semantics. 19 | type Vocabulary struct { 20 | // URL identifier for this Vocabulary. 21 | URL string 22 | 23 | // Schema that is used to validate the keywords that is introduced by this 24 | // vocabulary. 25 | Schema *Schema 26 | 27 | // Subschemas lists the possible locations of subschemas introduced by 28 | // this vocabulary. 29 | Subschemas []SchemaPath 30 | 31 | // Compile compiles the keywords(introduced by this vocabulary) in obj into [SchemaExt]. 32 | // If obj does not contain any keywords introduced by this vocabulary, nil SchemaExt must 33 | // be returned. 34 | Compile func(ctx *CompilerContext, obj map[string]any) (SchemaExt, error) 35 | } 36 | 37 | // -- 38 | 39 | // SchemaExt is compled form of vocabulary. 40 | type SchemaExt interface { 41 | // Validate validates v against and errors if any are reported 42 | // to ctx. 43 | Validate(ctx *ValidatorContext, v any) 44 | } 45 | 46 | // ValidatorContext provides helpers for 47 | // validating with [SchemaExt]. 48 | type ValidatorContext struct { 49 | vd *validator 50 | } 51 | 52 | // Validate validates v with sch. vpath gives path of v from current context value. 53 | func (ctx *ValidatorContext) Validate(sch *Schema, v any, vpath []string) error { 54 | switch len(vpath) { 55 | case 0: 56 | return ctx.vd.validateSelf(sch, "", false) 57 | case 1: 58 | return ctx.vd.validateVal(sch, v, vpath[0]) 59 | default: 60 | return ctx.vd.validateValue(sch, v, vpath) 61 | } 62 | } 63 | 64 | // EvaluatedProp marks given property of current object as evaluated. 65 | func (ctx *ValidatorContext) EvaluatedProp(pname string) { 66 | delete(ctx.vd.uneval.props, pname) 67 | } 68 | 69 | // EvaluatedItem marks items at given index of current array as evaluated. 70 | func (ctx *ValidatorContext) EvaluatedItem(index int) { 71 | delete(ctx.vd.uneval.items, index) 72 | } 73 | 74 | // AddError reports validation-error of given kind. 75 | func (ctx *ValidatorContext) AddError(k ErrorKind) { 76 | ctx.vd.addError(k) 77 | } 78 | 79 | // AddErrors reports validation-errors of given kind. 80 | func (ctx *ValidatorContext) AddErrors(errors []*ValidationError, k ErrorKind) { 81 | ctx.vd.addErrors(errors, k) 82 | } 83 | 84 | // AddErr reports the given err. This is typically used to report 85 | // the error created by subschema validation. 86 | // 87 | // NOTE that err must be of type *ValidationError. 88 | func (ctx *ValidatorContext) AddErr(err error) { 89 | ctx.vd.addErr(err) 90 | } 91 | 92 | func (ctx *ValidatorContext) Equals(v1, v2 any) (bool, error) { 93 | b, k := equals(v1, v2) 94 | if k != nil { 95 | return false, ctx.vd.error(k) 96 | } 97 | return b, nil 98 | } 99 | 100 | func (ctx *ValidatorContext) Duplicates(arr []any) (int, int, error) { 101 | i, j, k := duplicates(arr) 102 | if k != nil { 103 | return -1, -1, ctx.vd.error(k) 104 | } 105 | return i, j, nil 106 | } 107 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/feature/plural/common.go: -------------------------------------------------------------------------------- 1 | // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. 2 | 3 | package plural 4 | 5 | // Form defines a plural form. 6 | // 7 | // Not all languages support all forms. Also, the meaning of each form varies 8 | // per language. It is important to note that the name of a form does not 9 | // necessarily correspond one-to-one with the set of numbers. For instance, 10 | // for Croation, One matches not only 1, but also 11, 21, etc. 11 | // 12 | // Each language must at least support the form "other". 13 | type Form byte 14 | 15 | const ( 16 | Other Form = iota 17 | Zero 18 | One 19 | Two 20 | Few 21 | Many 22 | ) 23 | 24 | var countMap = map[string]Form{ 25 | "other": Other, 26 | "zero": Zero, 27 | "one": One, 28 | "two": Two, 29 | "few": Few, 30 | "many": Many, 31 | } 32 | 33 | type pluralCheck struct { 34 | // category: 35 | // 3..7: opID 36 | // 0..2: category 37 | cat byte 38 | setID byte 39 | } 40 | 41 | // opID identifies the type of operand in the plural rule, being i, n or f. 42 | // (v, w, and t are treated as filters in our implementation.) 43 | type opID byte 44 | 45 | const ( 46 | opMod opID = 0x1 // is '%' used? 47 | opNotEqual opID = 0x2 // using "!=" to compare 48 | opI opID = 0 << 2 // integers after taking the absolute value 49 | opN opID = 1 << 2 // full number (must be integer) 50 | opF opID = 2 << 2 // fraction 51 | opV opID = 3 << 2 // number of visible digits 52 | opW opID = 4 << 2 // number of visible digits without trailing zeros 53 | opBretonM opID = 5 << 2 // hard-wired rule for Breton 54 | opItalian800 opID = 6 << 2 // hard-wired rule for Italian 55 | opAzerbaijan00s opID = 7 << 2 // hard-wired rule for Azerbaijan 56 | ) 57 | const ( 58 | // Use this plural form to indicate the next rule needs to match as well. 59 | // The last condition in the list will have the correct plural form. 60 | andNext = 0x7 61 | formMask = 0x7 62 | 63 | opShift = 3 64 | 65 | // numN indicates the maximum integer, or maximum mod value, for which we 66 | // have inclusion masks. 67 | numN = 100 68 | // The common denominator of the modulo that is taken. 69 | maxMod = 100 70 | ) 71 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/catmsg/varint.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package catmsg 6 | 7 | // This file implements varint encoding analogous to the one in encoding/binary. 8 | // We need a string version of this function, so we add that here and then add 9 | // the rest for consistency. 10 | 11 | import "errors" 12 | 13 | var ( 14 | errIllegalVarint = errors.New("catmsg: illegal varint") 15 | errVarintTooLarge = errors.New("catmsg: varint too large for uint64") 16 | ) 17 | 18 | const maxVarintBytes = 10 // maximum length of a varint 19 | 20 | // encodeUint encodes x as a variable-sized integer into buf and returns the 21 | // number of bytes written. buf must be at least maxVarintBytes long 22 | func encodeUint(buf []byte, x uint64) (n int) { 23 | for ; x > 127; n++ { 24 | buf[n] = 0x80 | uint8(x&0x7F) 25 | x >>= 7 26 | } 27 | buf[n] = uint8(x) 28 | n++ 29 | return n 30 | } 31 | 32 | func decodeUintString(s string) (x uint64, size int, err error) { 33 | i := 0 34 | for shift := uint(0); shift < 64; shift += 7 { 35 | if i >= len(s) { 36 | return 0, i, errIllegalVarint 37 | } 38 | b := uint64(s[i]) 39 | i++ 40 | x |= (b & 0x7F) << shift 41 | if b&0x80 == 0 { 42 | return x, i, nil 43 | } 44 | } 45 | return 0, i, errVarintTooLarge 46 | } 47 | 48 | func decodeUint(b []byte) (x uint64, size int, err error) { 49 | i := 0 50 | for shift := uint(0); shift < 64; shift += 7 { 51 | if i >= len(b) { 52 | return 0, i, errIllegalVarint 53 | } 54 | c := uint64(b[i]) 55 | i++ 56 | x |= (c & 0x7F) << shift 57 | if c&0x80 == 0 { 58 | return x, i, nil 59 | } 60 | } 61 | return 0, i, errVarintTooLarge 62 | } 63 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/format/format.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package format contains types for defining language-specific formatting of 6 | // values. 7 | // 8 | // This package is internal now, but will eventually be exposed after the API 9 | // settles. 10 | package format // import "golang.org/x/text/internal/format" 11 | 12 | import ( 13 | "fmt" 14 | 15 | "golang.org/x/text/language" 16 | ) 17 | 18 | // State represents the printer state passed to custom formatters. It provides 19 | // access to the fmt.State interface and the sentence and language-related 20 | // context. 21 | type State interface { 22 | fmt.State 23 | 24 | // Language reports the requested language in which to render a message. 25 | Language() language.Tag 26 | 27 | // TODO: consider this and removing rune from the Format method in the 28 | // Formatter interface. 29 | // 30 | // Verb returns the format variant to render, analogous to the types used 31 | // in fmt. Use 'v' for the default or only variant. 32 | // Verb() rune 33 | 34 | // TODO: more info: 35 | // - sentence context such as linguistic features passed by the translator. 36 | } 37 | 38 | // Formatter is analogous to fmt.Formatter. 39 | type Formatter interface { 40 | Format(state State, verb rune) 41 | } 42 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/internal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package internal contains non-exported functionality that are used by 6 | // packages in the text repository. 7 | package internal // import "golang.org/x/text/internal" 8 | 9 | import ( 10 | "sort" 11 | 12 | "golang.org/x/text/language" 13 | ) 14 | 15 | // SortTags sorts tags in place. 16 | func SortTags(tags []language.Tag) { 17 | sort.Sort(sorter(tags)) 18 | } 19 | 20 | type sorter []language.Tag 21 | 22 | func (s sorter) Len() int { 23 | return len(s) 24 | } 25 | 26 | func (s sorter) Swap(i, j int) { 27 | s[i], s[j] = s[j], s[i] 28 | } 29 | 30 | func (s sorter) Less(i, j int) bool { 31 | return s[i].String() < s[j].String() 32 | } 33 | 34 | // UniqueTags sorts and filters duplicate tags in place and returns a slice with 35 | // only unique tags. 36 | func UniqueTags(tags []language.Tag) []language.Tag { 37 | if len(tags) <= 1 { 38 | return tags 39 | } 40 | SortTags(tags) 41 | k := 0 42 | for i := 1; i < len(tags); i++ { 43 | if tags[k].String() < tags[i].String() { 44 | k++ 45 | tags[k] = tags[i] 46 | } 47 | } 48 | return tags[:k+1] 49 | } 50 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/common.go: -------------------------------------------------------------------------------- 1 | // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. 2 | 3 | package language 4 | 5 | // This file contains code common to the maketables.go and the package code. 6 | 7 | // AliasType is the type of an alias in AliasMap. 8 | type AliasType int8 9 | 10 | const ( 11 | Deprecated AliasType = iota 12 | Macro 13 | Legacy 14 | 15 | AliasTypeUnknown AliasType = -1 16 | ) 17 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/compact.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | // CompactCoreInfo is a compact integer with the three core tags encoded. 8 | type CompactCoreInfo uint32 9 | 10 | // GetCompactCore generates a uint32 value that is guaranteed to be unique for 11 | // different language, region, and script values. 12 | func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) { 13 | if t.LangID > langNoIndexOffset { 14 | return 0, false 15 | } 16 | cci |= CompactCoreInfo(t.LangID) << (8 + 12) 17 | cci |= CompactCoreInfo(t.ScriptID) << 12 18 | cci |= CompactCoreInfo(t.RegionID) 19 | return cci, true 20 | } 21 | 22 | // Tag generates a tag from c. 23 | func (c CompactCoreInfo) Tag() Tag { 24 | return Tag{ 25 | LangID: Language(c >> 20), 26 | RegionID: Region(c & 0x3ff), 27 | ScriptID: Script(c>>12) & 0xff, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/compact/compact.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package compact defines a compact representation of language tags. 6 | // 7 | // Common language tags (at least all for which locale information is defined 8 | // in CLDR) are assigned a unique index. Each Tag is associated with such an 9 | // ID for selecting language-related resources (such as translations) as well 10 | // as one for selecting regional defaults (currency, number formatting, etc.) 11 | // 12 | // It may want to export this functionality at some point, but at this point 13 | // this is only available for use within x/text. 14 | package compact // import "golang.org/x/text/internal/language/compact" 15 | 16 | import ( 17 | "sort" 18 | "strings" 19 | 20 | "golang.org/x/text/internal/language" 21 | ) 22 | 23 | // ID is an integer identifying a single tag. 24 | type ID uint16 25 | 26 | func getCoreIndex(t language.Tag) (id ID, ok bool) { 27 | cci, ok := language.GetCompactCore(t) 28 | if !ok { 29 | return 0, false 30 | } 31 | i := sort.Search(len(coreTags), func(i int) bool { 32 | return cci <= coreTags[i] 33 | }) 34 | if i == len(coreTags) || coreTags[i] != cci { 35 | return 0, false 36 | } 37 | return ID(i), true 38 | } 39 | 40 | // Parent returns the ID of the parent or the root ID if id is already the root. 41 | func (id ID) Parent() ID { 42 | return parents[id] 43 | } 44 | 45 | // Tag converts id to an internal language Tag. 46 | func (id ID) Tag() language.Tag { 47 | if int(id) >= len(coreTags) { 48 | return specialTags[int(id)-len(coreTags)] 49 | } 50 | return coreTags[id].Tag() 51 | } 52 | 53 | var specialTags []language.Tag 54 | 55 | func init() { 56 | tags := strings.Split(specialTagsStr, " ") 57 | specialTags = make([]language.Tag, len(tags)) 58 | for i, t := range tags { 59 | specialTags[i] = language.MustParse(t) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/coverage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | // BaseLanguages returns the list of all supported base languages. It generates 8 | // the list by traversing the internal structures. 9 | func BaseLanguages() []Language { 10 | base := make([]Language, 0, NumLanguages) 11 | for i := 0; i < langNoIndexOffset; i++ { 12 | // We included "und" already for the value 0. 13 | if i != nonCanonicalUnd { 14 | base = append(base, Language(i)) 15 | } 16 | } 17 | i := langNoIndexOffset 18 | for _, v := range langNoIndex { 19 | for k := 0; k < 8; k++ { 20 | if v&1 == 1 { 21 | base = append(base, Language(i)) 22 | } 23 | v >>= 1 24 | i++ 25 | } 26 | } 27 | return base 28 | } 29 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/language/tags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package language 6 | 7 | // MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed. 8 | // It simplifies safe initialization of Tag values. 9 | func MustParse(s string) Tag { 10 | t, err := Parse(s) 11 | if err != nil { 12 | panic(err) 13 | } 14 | return t 15 | } 16 | 17 | // MustParseBase is like ParseBase, but panics if the given base cannot be parsed. 18 | // It simplifies safe initialization of Base values. 19 | func MustParseBase(s string) Language { 20 | b, err := ParseBase(s) 21 | if err != nil { 22 | panic(err) 23 | } 24 | return b 25 | } 26 | 27 | // MustParseScript is like ParseScript, but panics if the given script cannot be 28 | // parsed. It simplifies safe initialization of Script values. 29 | func MustParseScript(s string) Script { 30 | scr, err := ParseScript(s) 31 | if err != nil { 32 | panic(err) 33 | } 34 | return scr 35 | } 36 | 37 | // MustParseRegion is like ParseRegion, but panics if the given region cannot be 38 | // parsed. It simplifies safe initialization of Region values. 39 | func MustParseRegion(s string) Region { 40 | r, err := ParseRegion(s) 41 | if err != nil { 42 | panic(err) 43 | } 44 | return r 45 | } 46 | 47 | // Und is the root language. 48 | var Und Tag 49 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/match.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package internal 6 | 7 | // This file contains matchers that implement CLDR inheritance. 8 | // 9 | // See https://unicode.org/reports/tr35/#Locale_Inheritance. 10 | // 11 | // Some of the inheritance described in this document is already handled by 12 | // the cldr package. 13 | 14 | import ( 15 | "golang.org/x/text/language" 16 | ) 17 | 18 | // TODO: consider if (some of the) matching algorithm needs to be public after 19 | // getting some feel about what is generic and what is specific. 20 | 21 | // NewInheritanceMatcher returns a matcher that matches based on the inheritance 22 | // chain. 23 | // 24 | // The matcher uses canonicalization and the parent relationship to find a 25 | // match. The resulting match will always be either Und or a language with the 26 | // same language and script as the requested language. It will not match 27 | // languages for which there is understood to be mutual or one-directional 28 | // intelligibility. 29 | // 30 | // A Match will indicate an Exact match if the language matches after 31 | // canonicalization and High if the matched tag is a parent. 32 | func NewInheritanceMatcher(t []language.Tag) *InheritanceMatcher { 33 | tags := &InheritanceMatcher{make(map[language.Tag]int)} 34 | for i, tag := range t { 35 | ct, err := language.All.Canonicalize(tag) 36 | if err != nil { 37 | ct = tag 38 | } 39 | tags.index[ct] = i 40 | } 41 | return tags 42 | } 43 | 44 | type InheritanceMatcher struct { 45 | index map[language.Tag]int 46 | } 47 | 48 | func (m InheritanceMatcher) Match(want ...language.Tag) (language.Tag, int, language.Confidence) { 49 | for _, t := range want { 50 | ct, err := language.All.Canonicalize(t) 51 | if err != nil { 52 | ct = t 53 | } 54 | conf := language.Exact 55 | for { 56 | if index, ok := m.index[ct]; ok { 57 | return ct, index, conf 58 | } 59 | if ct == language.Und { 60 | break 61 | } 62 | ct = ct.Parent() 63 | conf = language.High 64 | } 65 | } 66 | return language.Und, 0, language.No 67 | } 68 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/number/common.go: -------------------------------------------------------------------------------- 1 | // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. 2 | 3 | package number 4 | 5 | import ( 6 | "unicode/utf8" 7 | 8 | "golang.org/x/text/internal/language/compact" 9 | ) 10 | 11 | // A system identifies a CLDR numbering system. 12 | type system byte 13 | 14 | type systemData struct { 15 | id system 16 | digitSize byte // number of UTF-8 bytes per digit 17 | zero [utf8.UTFMax]byte // UTF-8 sequence of zero digit. 18 | } 19 | 20 | // A SymbolType identifies a symbol of a specific kind. 21 | type SymbolType int 22 | 23 | const ( 24 | SymDecimal SymbolType = iota 25 | SymGroup 26 | SymList 27 | SymPercentSign 28 | SymPlusSign 29 | SymMinusSign 30 | SymExponential 31 | SymSuperscriptingExponent 32 | SymPerMille 33 | SymInfinity 34 | SymNan 35 | SymTimeSeparator 36 | 37 | NumSymbolTypes 38 | ) 39 | 40 | const hasNonLatnMask = 0x8000 41 | 42 | // symOffset is an offset into altSymData if the bit indicated by hasNonLatnMask 43 | // is not 0 (with this bit masked out), and an offset into symIndex otherwise. 44 | // 45 | // TODO: this type can be a byte again if we use an indirection into altsymData 46 | // and introduce an alt -> offset slice (the length of this will be number of 47 | // alternatives plus 1). This also allows getting rid of the compactTag field 48 | // in altSymData. In total this will save about 1K. 49 | type symOffset uint16 50 | 51 | type altSymData struct { 52 | compactTag compact.ID 53 | symIndex symOffset 54 | system system 55 | } 56 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/number/roundingmode_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type RoundingMode"; DO NOT EDIT. 2 | 3 | package number 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[ToNearestEven-0] 12 | _ = x[ToNearestZero-1] 13 | _ = x[ToNearestAway-2] 14 | _ = x[ToPositiveInf-3] 15 | _ = x[ToNegativeInf-4] 16 | _ = x[ToZero-5] 17 | _ = x[AwayFromZero-6] 18 | _ = x[numModes-7] 19 | } 20 | 21 | const _RoundingMode_name = "ToNearestEvenToNearestZeroToNearestAwayToPositiveInfToNegativeInfToZeroAwayFromZeronumModes" 22 | 23 | var _RoundingMode_index = [...]uint8{0, 13, 26, 39, 52, 65, 71, 83, 91} 24 | 25 | func (i RoundingMode) String() string { 26 | if i >= RoundingMode(len(_RoundingMode_index)-1) { 27 | return "RoundingMode(" + strconv.FormatInt(int64(i), 10) + ")" 28 | } 29 | return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]] 30 | } 31 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/stringset/set.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package stringset provides a way to represent a collection of strings 6 | // compactly. 7 | package stringset 8 | 9 | import "sort" 10 | 11 | // A Set holds a collection of strings that can be looked up by an index number. 12 | type Set struct { 13 | // These fields are exported to allow for code generation. 14 | 15 | Data string 16 | Index []uint16 17 | } 18 | 19 | // Elem returns the string with index i. It panics if i is out of range. 20 | func (s *Set) Elem(i int) string { 21 | return s.Data[s.Index[i]:s.Index[i+1]] 22 | } 23 | 24 | // Len returns the number of strings in the set. 25 | func (s *Set) Len() int { 26 | return len(s.Index) - 1 27 | } 28 | 29 | // Search returns the index of the given string or -1 if it is not in the set. 30 | // The Set must have been created with strings in sorted order. 31 | func Search(s *Set, str string) int { 32 | // TODO: optimize this if it gets used a lot. 33 | n := len(s.Index) - 1 34 | p := sort.Search(n, func(i int) bool { 35 | return s.Elem(i) >= str 36 | }) 37 | if p == n || str != s.Elem(p) { 38 | return -1 39 | } 40 | return p 41 | } 42 | 43 | // A Builder constructs Sets. 44 | type Builder struct { 45 | set Set 46 | index map[string]int 47 | } 48 | 49 | // NewBuilder returns a new and initialized Builder. 50 | func NewBuilder() *Builder { 51 | return &Builder{ 52 | set: Set{ 53 | Index: []uint16{0}, 54 | }, 55 | index: map[string]int{}, 56 | } 57 | } 58 | 59 | // Set creates the set created so far. 60 | func (b *Builder) Set() Set { 61 | return b.set 62 | } 63 | 64 | // Index returns the index for the given string, which must have been added 65 | // before. 66 | func (b *Builder) Index(s string) int { 67 | return b.index[s] 68 | } 69 | 70 | // Add adds a string to the index. Strings that are added by a single Add will 71 | // be stored together, unless they match an existing string. 72 | func (b *Builder) Add(ss ...string) { 73 | // First check if the string already exists. 74 | for _, s := range ss { 75 | if _, ok := b.index[s]; ok { 76 | continue 77 | } 78 | b.index[s] = len(b.set.Index) - 1 79 | b.set.Data += s 80 | x := len(b.set.Data) 81 | if x > 0xFFFF { 82 | panic("Index too > 0xFFFF") 83 | } 84 | b.set.Index = append(b.set.Index, uint16(x)) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/internal/tag/tag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package tag contains functionality handling tags and related data. 6 | package tag // import "golang.org/x/text/internal/tag" 7 | 8 | import "sort" 9 | 10 | // An Index converts tags to a compact numeric value. 11 | // 12 | // All elements are of size 4. Tags may be up to 4 bytes long. Excess bytes can 13 | // be used to store additional information about the tag. 14 | type Index string 15 | 16 | // Elem returns the element data at the given index. 17 | func (s Index) Elem(x int) string { 18 | return string(s[x*4 : x*4+4]) 19 | } 20 | 21 | // Index reports the index of the given key or -1 if it could not be found. 22 | // Only the first len(key) bytes from the start of the 4-byte entries will be 23 | // considered for the search and the first match in Index will be returned. 24 | func (s Index) Index(key []byte) int { 25 | n := len(key) 26 | // search the index of the first entry with an equal or higher value than 27 | // key in s. 28 | index := sort.Search(len(s)/4, func(i int) bool { 29 | return cmp(s[i*4:i*4+n], key) != -1 30 | }) 31 | i := index * 4 32 | if cmp(s[i:i+len(key)], key) != 0 { 33 | return -1 34 | } 35 | return index 36 | } 37 | 38 | // Next finds the next occurrence of key after index x, which must have been 39 | // obtained from a call to Index using the same key. It returns x+1 or -1. 40 | func (s Index) Next(key []byte, x int) int { 41 | if x++; x*4 < len(s) && cmp(s[x*4:x*4+len(key)], key) == 0 { 42 | return x 43 | } 44 | return -1 45 | } 46 | 47 | // cmp returns an integer comparing a and b lexicographically. 48 | func cmp(a Index, b []byte) int { 49 | n := len(a) 50 | if len(b) < n { 51 | n = len(b) 52 | } 53 | for i, c := range b[:n] { 54 | switch { 55 | case a[i] > c: 56 | return 1 57 | case a[i] < c: 58 | return -1 59 | } 60 | } 61 | switch { 62 | case len(a) < len(b): 63 | return -1 64 | case len(a) > len(b): 65 | return 1 66 | } 67 | return 0 68 | } 69 | 70 | // Compare returns an integer comparing a and b lexicographically. 71 | func Compare(a string, b []byte) int { 72 | return cmp(Index(a), b) 73 | } 74 | 75 | // FixCase reformats b to the same pattern of cases as form. 76 | // If returns false if string b is malformed. 77 | func FixCase(form string, b []byte) bool { 78 | if len(form) != len(b) { 79 | return false 80 | } 81 | for i, c := range b { 82 | if form[i] <= 'Z' { 83 | if c >= 'a' { 84 | c -= 'z' - 'Z' 85 | } 86 | if c < 'A' || 'Z' < c { 87 | return false 88 | } 89 | } else { 90 | if c <= 'Z' { 91 | c += 'z' - 'Z' 92 | } 93 | if c < 'a' || 'z' < c { 94 | return false 95 | } 96 | } 97 | b[i] = c 98 | } 99 | return true 100 | } 101 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/message/catalog.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package message 6 | 7 | // TODO: some types in this file will need to be made public at some time. 8 | // Documentation and method names will reflect this by using the exported name. 9 | 10 | import ( 11 | "golang.org/x/text/language" 12 | "golang.org/x/text/message/catalog" 13 | ) 14 | 15 | // MatchLanguage reports the matched tag obtained from language.MatchStrings for 16 | // the Matcher of the DefaultCatalog. 17 | func MatchLanguage(preferred ...string) language.Tag { 18 | c := DefaultCatalog 19 | tag, _ := language.MatchStrings(c.Matcher(), preferred...) 20 | return tag 21 | } 22 | 23 | // DefaultCatalog is used by SetString. 24 | var DefaultCatalog catalog.Catalog = defaultCatalog 25 | 26 | var defaultCatalog = catalog.NewBuilder() 27 | 28 | // SetString calls SetString on the initial default Catalog. 29 | func SetString(tag language.Tag, key string, msg string) error { 30 | return defaultCatalog.SetString(tag, key, msg) 31 | } 32 | 33 | // Set calls Set on the initial default Catalog. 34 | func Set(tag language.Tag, key string, msg ...catalog.Message) error { 35 | return defaultCatalog.Set(tag, key, msg...) 36 | } 37 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/message/catalog/dict.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package catalog 6 | 7 | import ( 8 | "sync" 9 | 10 | "golang.org/x/text/internal" 11 | "golang.org/x/text/internal/catmsg" 12 | "golang.org/x/text/language" 13 | ) 14 | 15 | // TODO: 16 | // Dictionary returns a Dictionary that returns the first Message, using the 17 | // given language tag, that matches: 18 | // 1. the last one registered by one of the Set methods 19 | // 2. returned by one of the Loaders 20 | // 3. repeat from 1. using the parent language 21 | // This approach allows messages to be underspecified. 22 | // func (c *Catalog) Dictionary(tag language.Tag) (Dictionary, error) { 23 | // // TODO: verify dictionary exists. 24 | // return &dict{&c.index, tag}, nil 25 | // } 26 | 27 | type dict struct { 28 | s *store 29 | tag language.Tag // TODO: make compact tag. 30 | } 31 | 32 | func (d *dict) Lookup(key string) (data string, ok bool) { 33 | return d.s.lookup(d.tag, key) 34 | } 35 | 36 | func (b *Builder) lookup(tag language.Tag, key string) (data string, ok bool) { 37 | return b.index.lookup(tag, key) 38 | } 39 | 40 | func (c *Builder) set(tag language.Tag, key string, s *store, msg ...Message) error { 41 | data, err := catmsg.Compile(tag, &dict{&c.macros, tag}, firstInSequence(msg)) 42 | 43 | s.mutex.Lock() 44 | defer s.mutex.Unlock() 45 | 46 | m := s.index[tag] 47 | if m == nil { 48 | m = msgMap{} 49 | if s.index == nil { 50 | s.index = map[language.Tag]msgMap{} 51 | } 52 | c.matcher = nil 53 | s.index[tag] = m 54 | } 55 | 56 | m[key] = data 57 | return err 58 | } 59 | 60 | func (c *Builder) Matcher() language.Matcher { 61 | c.index.mutex.RLock() 62 | m := c.matcher 63 | c.index.mutex.RUnlock() 64 | if m != nil { 65 | return m 66 | } 67 | 68 | c.index.mutex.Lock() 69 | if c.matcher == nil { 70 | c.matcher = language.NewMatcher(c.unlockedLanguages()) 71 | } 72 | m = c.matcher 73 | c.index.mutex.Unlock() 74 | return m 75 | } 76 | 77 | type store struct { 78 | mutex sync.RWMutex 79 | index map[language.Tag]msgMap 80 | } 81 | 82 | type msgMap map[string]string 83 | 84 | func (s *store) lookup(tag language.Tag, key string) (data string, ok bool) { 85 | s.mutex.RLock() 86 | defer s.mutex.RUnlock() 87 | 88 | for ; ; tag = tag.Parent() { 89 | if msgs, ok := s.index[tag]; ok { 90 | if msg, ok := msgs[key]; ok { 91 | return msg, true 92 | } 93 | } 94 | if tag == language.Und { 95 | break 96 | } 97 | } 98 | return "", false 99 | } 100 | 101 | // Languages returns all languages for which the Catalog contains variants. 102 | func (b *Builder) Languages() []language.Tag { 103 | s := &b.index 104 | s.mutex.RLock() 105 | defer s.mutex.RUnlock() 106 | 107 | return b.unlockedLanguages() 108 | } 109 | 110 | func (b *Builder) unlockedLanguages() []language.Tag { 111 | s := &b.index 112 | if len(s.index) == 0 { 113 | return nil 114 | } 115 | tags := make([]language.Tag, 0, len(s.index)) 116 | _, hasFallback := s.index[b.options.fallback] 117 | offset := 0 118 | if hasFallback { 119 | tags = append(tags, b.options.fallback) 120 | offset = 1 121 | } 122 | for t := range s.index { 123 | if t != b.options.fallback { 124 | tags = append(tags, t) 125 | } 126 | } 127 | internal.SortTags(tags[offset:]) 128 | return tags 129 | } 130 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/message/catalog/go19.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build go1.9 6 | 7 | package catalog 8 | 9 | import "golang.org/x/text/internal/catmsg" 10 | 11 | // A Message holds a collection of translations for the same phrase that may 12 | // vary based on the values of substitution arguments. 13 | type Message = catmsg.Message 14 | 15 | type firstInSequence = catmsg.FirstOf 16 | -------------------------------------------------------------------------------- /vendor/golang.org/x/text/message/catalog/gopre19.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build !go1.9 6 | 7 | package catalog 8 | 9 | import "golang.org/x/text/internal/catmsg" 10 | 11 | // A Message holds a collection of translations for the same phrase that may 12 | // vary based on the values of substitution arguments. 13 | type Message interface { 14 | catmsg.Message 15 | } 16 | 17 | func firstInSequence(m []Message) catmsg.Message { 18 | a := []catmsg.Message{} 19 | for _, m := range m { 20 | a = append(a, m) 21 | } 22 | return catmsg.FirstOf(a) 23 | } 24 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/hashicorp/go-cleanhttp v0.5.2 2 | ## explicit; go 1.13 3 | github.com/hashicorp/go-cleanhttp 4 | # github.com/hashicorp/go-retryablehttp v0.7.7 5 | ## explicit; go 1.19 6 | github.com/hashicorp/go-retryablehttp 7 | # github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 8 | ## explicit; go 1.21 9 | github.com/santhosh-tekuri/jsonschema/v6 10 | github.com/santhosh-tekuri/jsonschema/v6/kind 11 | # golang.org/x/text v0.25.0 12 | ## explicit; go 1.23.0 13 | golang.org/x/text/feature/plural 14 | golang.org/x/text/internal 15 | golang.org/x/text/internal/catmsg 16 | golang.org/x/text/internal/format 17 | golang.org/x/text/internal/language 18 | golang.org/x/text/internal/language/compact 19 | golang.org/x/text/internal/number 20 | golang.org/x/text/internal/stringset 21 | golang.org/x/text/internal/tag 22 | golang.org/x/text/language 23 | golang.org/x/text/message 24 | golang.org/x/text/message/catalog 25 | # sigs.k8s.io/yaml v1.4.0 26 | ## explicit; go 1.12 27 | sigs.k8s.io/yaml 28 | sigs.k8s.io/yaml/goyaml.v2 29 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX leaves these everywhere on SMB shares 2 | ._* 3 | 4 | # Eclipse files 5 | .classpath 6 | .project 7 | .settings/** 8 | 9 | # Idea files 10 | .idea/** 11 | .idea/ 12 | 13 | # Emacs save files 14 | *~ 15 | 16 | # Vim-related files 17 | [._]*.s[a-w][a-z] 18 | [._]s[a-w][a-z] 19 | *.un~ 20 | Session.vim 21 | .netrwhist 22 | 23 | # Go test binaries 24 | *.test 25 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | arch: arm64 3 | dist: focal 4 | go: 1.15.x 5 | script: 6 | - diff -u <(echo -n) <(gofmt -d *.go) 7 | - diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON) 8 | - GO111MODULE=on go vet . 9 | - GO111MODULE=on go test -v -race ./... 10 | - git diff --exit-code 11 | install: 12 | - GO111MODULE=off go get golang.org/x/lint/golint 13 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt: 4 | 5 | _As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._ 6 | 7 | ## Getting Started 8 | 9 | We have full documentation on how to get started contributing here: 10 | 11 | 14 | 15 | - [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests 16 | - [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing) 17 | - [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers 18 | 19 | ## Mentorship 20 | 21 | - [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers! 22 | 23 | 32 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - dims 5 | - jpbetz 6 | - smarterclayton 7 | - deads2k 8 | - sttts 9 | - liggitt 10 | reviewers: 11 | - dims 12 | - thockin 13 | - jpbetz 14 | - smarterclayton 15 | - wojtek-t 16 | - deads2k 17 | - derekwaynecarr 18 | - mikedanese 19 | - liggitt 20 | - sttts 21 | - tallclair 22 | labels: 23 | - sig/api-machinery 24 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | The `yaml` Project is released on an as-needed basis. The process is as follows: 4 | 5 | 1. An issue is proposing a new release with a changelog since the last release 6 | 1. All [OWNERS](OWNERS) must LGTM this release 7 | 1. An OWNER runs `git tag -s $VERSION` and inserts the changelog and pushes the tag with `git push $VERSION` 8 | 1. The release issue is closed 9 | 1. An announcement email is sent to `kubernetes-dev@googlegroups.com` with the subject `[ANNOUNCE] kubernetes-template-project $VERSION is released` 10 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/SECURITY_CONTACTS: -------------------------------------------------------------------------------- 1 | # Defined below are the security contacts for this repo. 2 | # 3 | # They are the contact point for the Product Security Team to reach out 4 | # to for triaging and handling of incoming issues. 5 | # 6 | # The below names agree to abide by the 7 | # [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) 8 | # and will be removed and replaced if they violate that agreement. 9 | # 10 | # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE 11 | # INSTRUCTIONS AT https://kubernetes.io/security/ 12 | 13 | cjcullen 14 | jessfraz 15 | liggitt 16 | philips 17 | tallclair 18 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Community Code of Conduct 2 | 3 | Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/goyaml.v2/LICENSE.libyaml: -------------------------------------------------------------------------------- 1 | The following files were ported to Go from C files of libyaml, and thus 2 | are still covered by their original copyright and license: 3 | 4 | apic.go 5 | emitterc.go 6 | parserc.go 7 | readerc.go 8 | scannerc.go 9 | writerc.go 10 | yamlh.go 11 | yamlprivateh.go 12 | 13 | Copyright (c) 2006 Kirill Simonov 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/goyaml.v2/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/goyaml.v2/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - dims 5 | - jpbetz 6 | - smarterclayton 7 | - deads2k 8 | - sttts 9 | - liggitt 10 | - natasha41575 11 | - knverey 12 | reviewers: 13 | - dims 14 | - thockin 15 | - jpbetz 16 | - smarterclayton 17 | - deads2k 18 | - derekwaynecarr 19 | - mikedanese 20 | - liggitt 21 | - sttts 22 | - tallclair 23 | labels: 24 | - sig/api-machinery 25 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/goyaml.v2/sorter.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "reflect" 5 | "unicode" 6 | ) 7 | 8 | type keyList []reflect.Value 9 | 10 | func (l keyList) Len() int { return len(l) } 11 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 12 | func (l keyList) Less(i, j int) bool { 13 | a := l[i] 14 | b := l[j] 15 | ak := a.Kind() 16 | bk := b.Kind() 17 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 18 | a = a.Elem() 19 | ak = a.Kind() 20 | } 21 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 22 | b = b.Elem() 23 | bk = b.Kind() 24 | } 25 | af, aok := keyFloat(a) 26 | bf, bok := keyFloat(b) 27 | if aok && bok { 28 | if af != bf { 29 | return af < bf 30 | } 31 | if ak != bk { 32 | return ak < bk 33 | } 34 | return numLess(a, b) 35 | } 36 | if ak != reflect.String || bk != reflect.String { 37 | return ak < bk 38 | } 39 | ar, br := []rune(a.String()), []rune(b.String()) 40 | for i := 0; i < len(ar) && i < len(br); i++ { 41 | if ar[i] == br[i] { 42 | continue 43 | } 44 | al := unicode.IsLetter(ar[i]) 45 | bl := unicode.IsLetter(br[i]) 46 | if al && bl { 47 | return ar[i] < br[i] 48 | } 49 | if al || bl { 50 | return bl 51 | } 52 | var ai, bi int 53 | var an, bn int64 54 | if ar[i] == '0' || br[i] == '0' { 55 | for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { 56 | if ar[j] != '0' { 57 | an = 1 58 | bn = 1 59 | break 60 | } 61 | } 62 | } 63 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 64 | an = an*10 + int64(ar[ai]-'0') 65 | } 66 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 67 | bn = bn*10 + int64(br[bi]-'0') 68 | } 69 | if an != bn { 70 | return an < bn 71 | } 72 | if ai != bi { 73 | return ai < bi 74 | } 75 | return ar[i] < br[i] 76 | } 77 | return len(ar) < len(br) 78 | } 79 | 80 | // keyFloat returns a float value for v if it is a number/bool 81 | // and whether it is a number/bool or not. 82 | func keyFloat(v reflect.Value) (f float64, ok bool) { 83 | switch v.Kind() { 84 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 85 | return float64(v.Int()), true 86 | case reflect.Float32, reflect.Float64: 87 | return v.Float(), true 88 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 89 | return float64(v.Uint()), true 90 | case reflect.Bool: 91 | if v.Bool() { 92 | return 1, true 93 | } 94 | return 0, true 95 | } 96 | return 0, false 97 | } 98 | 99 | // numLess returns whether a < b. 100 | // a and b must necessarily have the same kind. 101 | func numLess(a, b reflect.Value) bool { 102 | switch a.Kind() { 103 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 104 | return a.Int() < b.Int() 105 | case reflect.Float32, reflect.Float64: 106 | return a.Float() < b.Float() 107 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 108 | return a.Uint() < b.Uint() 109 | case reflect.Bool: 110 | return !a.Bool() && b.Bool() 111 | } 112 | panic("not a number") 113 | } 114 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/goyaml.v2/writerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | // Set the writer error and return false. 4 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 5 | emitter.error = yaml_WRITER_ERROR 6 | emitter.problem = problem 7 | return false 8 | } 9 | 10 | // Flush the output buffer. 11 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 12 | if emitter.write_handler == nil { 13 | panic("write handler not set") 14 | } 15 | 16 | // Check if the buffer is empty. 17 | if emitter.buffer_pos == 0 { 18 | return true 19 | } 20 | 21 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 22 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 23 | } 24 | emitter.buffer_pos = 0 25 | return true 26 | } 27 | -------------------------------------------------------------------------------- /vendor/sigs.k8s.io/yaml/yaml_go110.go: -------------------------------------------------------------------------------- 1 | // This file contains changes that are only compatible with go 1.10 and onwards. 2 | 3 | //go:build go1.10 4 | // +build go1.10 5 | 6 | /* 7 | Copyright 2021 The Kubernetes Authors. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | */ 21 | 22 | package yaml 23 | 24 | import "encoding/json" 25 | 26 | // DisallowUnknownFields configures the JSON decoder to error out if unknown 27 | // fields come along, instead of dropping them by default. 28 | func DisallowUnknownFields(d *json.Decoder) *json.Decoder { 29 | d.DisallowUnknownFields() 30 | return d 31 | } 32 | --------------------------------------------------------------------------------