From f753fc91f2f5f999ae5ee424710e25161fe51518 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Thu, 6 May 2021 14:01:20 -0400 Subject: [PATCH] Support multi-resource templates (#524) * able to run multi-resource tests * start passing resource provider through * working end-to-end * better support for go templating * fix tests * delint * add test * add json annotations * remove panics * fix annotation * fix for groupkinds * add comment * add docs * change jsonSchema field to schemaString * rename check * add pdb to tests * add ingress to tests * update deps * fix up policy import * update go * fix check name * funk it up * better docs --- .circleci/config.yml | 2 +- Dockerfile | 2 +- checks/missingPodDisruptionBudget.yaml | 39 +++ ...hanZero.yaml => pdbDisruptionsIsZero.yaml} | 2 +- docs/changelog.md | 9 + docs/checks/reliability.md | 1 + docs/customization/custom-checks.md | 183 +++++++++++++- examples/config.yaml | 4 + go.mod | 21 +- go.sum | 239 ++++++------------ pkg/config/checks.go | 60 +++++ pkg/config/config_test.go | 7 +- pkg/config/schema.go | 130 +++++++--- pkg/kube/resources.go | 42 ++- pkg/kube/resources_test.go | 12 +- pkg/validator/arbitrary_test.go | 8 +- pkg/validator/container_test.go | 14 +- pkg/validator/controller_test.go | 18 +- pkg/validator/fullaudit.go | 10 +- pkg/validator/pod_test.go | 10 +- pkg/validator/schema.go | 137 +++++----- pkg/validator/schema_test.go | 4 +- pkg/validator/summary.go | 6 +- pkg/webhook/webhook.go | 3 +- .../failure.bad-name.yaml | 20 ++ .../missingPodDisruptionBudget/failure.yaml | 10 + .../success.many.yaml | 40 +++ .../missingPodDisruptionBudget/success.yaml | 20 ++ test/fixtures.go | 14 + test/schema_test.go | 28 +- 30 files changed, 723 insertions(+), 372 deletions(-) create mode 100644 checks/missingPodDisruptionBudget.yaml rename checks/{pdbDisruptionsAllowedGreaterThanZero.yaml => pdbDisruptionsIsZero.yaml} (92%) create mode 100644 pkg/config/checks.go create mode 100644 test/checks/missingPodDisruptionBudget/failure.bad-name.yaml create mode 100644 test/checks/missingPodDisruptionBudget/failure.yaml create mode 100644 test/checks/missingPodDisruptionBudget/success.many.yaml create mode 100644 test/checks/missingPodDisruptionBudget/success.yaml diff --git a/.circleci/config.yml b/.circleci/config.yml index 067bfe03..05a850d1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,7 +147,7 @@ jobs: test: working_directory: /go/src/github.com/fairwindsops/polaris/ docker: - - image: circleci/golang:1.13 + - image: circleci/golang:1.16 steps: - checkout - *set_environment_variables diff --git a/Dockerfile b/Dockerfile index 2f6b5bde..512a8ea4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.13 AS build-env +FROM golang:1.16 AS build-env WORKDIR /go/src/github.com/fairwindsops/polaris/ ENV GO111MODULE=on diff --git a/checks/missingPodDisruptionBudget.yaml b/checks/missingPodDisruptionBudget.yaml new file mode 100644 index 00000000..83729c8c --- /dev/null +++ b/checks/missingPodDisruptionBudget.yaml @@ -0,0 +1,39 @@ +successMessage: A PodDisruptionBudget is attached +failureMessage: Should have a PodDisruptionBudget +category: Reliability +target: Controller +controllers: + include: + - Deployment +schema: + '$schema': http://json-schema.org/draft-07/schema + type: object + properties: + metadata: + type: object + properties: + labels: + type: object + minProperties: 1 +additionalSchemaStrings: + policy/PodDisruptionBudget: | + type: object + properties: + spec: + type: object + required: ["selector"] + properties: + selector: + type: object + required: ["matchLabels"] + properties: + matchLabels: + type: object + anyOf: + {{ range $key, $value := .metadata.labels }} + - properties: + "{{ $key }}": + type: string + const: {{ $value }} + required: ["{{ $key }}"] + {{ end }} diff --git a/checks/pdbDisruptionsAllowedGreaterThanZero.yaml b/checks/pdbDisruptionsIsZero.yaml similarity index 92% rename from checks/pdbDisruptionsAllowedGreaterThanZero.yaml rename to checks/pdbDisruptionsIsZero.yaml index e59a7801..fd15b8a8 100644 --- a/checks/pdbDisruptionsAllowedGreaterThanZero.yaml +++ b/checks/pdbDisruptionsIsZero.yaml @@ -1,7 +1,7 @@ successMessage: disruptionsAllowed is greater than zero failureMessage: disruptionsAllowed is not greater than zero category: Reliability -target: PodDisruptionBudget +target: policy/PodDisruptionBudget schema: '$schema': http://json-schema.org/draft-07/schema type: object diff --git a/docs/changelog.md b/docs/changelog.md index 139883fe..7970bc70 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,15 @@ sidebarDepth: 0 --- +## 4.0.0 +* Add support for arbitrary resources, like Ingress or PodDisruptionBudget +* Add support check templating (see docs) +* Add support for multi-resource checks (see docs) + +### Breaking Changes +* In custom checks, `jsonSchema` is now `schemaString` +* Check `pdbDisruptionsAllowedGreaterThanZero` is now called `pdbDisruptionsIsZero` + ## 3.2.0 * Add `--format=pretty` option for CLI output diff --git a/docs/checks/reliability.md b/docs/checks/reliability.md index 4578a368..a585848a 100644 --- a/docs/checks/reliability.md +++ b/docs/checks/reliability.md @@ -11,6 +11,7 @@ key | default | description `pullPolicyNotAlways` | `warning` | Fails when an image pull policy is not `always`. `priorityClassNotSet` | `ignore` | Fails when a priorityClassName is not set for a pod. `multipleReplicasForDeployment` | `ignore` | Fails when there is only one replica for a deployment. +`missingPodDisruptionBudget` | `ignore` ## Background diff --git a/docs/customization/custom-checks.md b/docs/customization/custom-checks.md index 11679892..16547d40 100644 --- a/docs/customization/custom-checks.md +++ b/docs/customization/custom-checks.md @@ -1,16 +1,24 @@ # Custom Checks -If you'd like to create your own checks, you can use [JSON Schema](https://json-schema.org/). For example, -to disallow images from quay.io: + +If you'd like to create your own checks, you can use [JSON Schema](https://json-schema.org/). +This is how built-in Polaris checks are defined as well - you can see all the built-in checks +in the [checks folder](https://github.com/FairwindsOps/polaris/tree/master/checks) for examples. + +If you write a check that could be useful for others, feel free to open a PR to add it in! + +## Basic Example +For example, to disallow images from quay.io: ```yaml checks: imageRegistry: warning + customChecks: imageRegistry: successMessage: Image comes from allowed registries failureMessage: Image should not be from disallowed registry - category: Images - target: Container # target can be "Container" or "Pod" + category: Security + target: Container schema: '$schema': http://json-schema.org/draft-07/schema type: object @@ -21,6 +29,168 @@ customChecks: pattern: ^quay.io ``` +## Available Options +All custom checks should go under the `customChecks` field in your Polaris config, keyed by the +check ID. Note that you'll also have to set its severity in the `checks` section of your Polaris config. + +* `successMessage` - the message to show when the check succeeds +* `failureMessage` - the message to show when the check fails +* `category` - one of `Security`, `Efficiency`, or `Reliability` +* `target` - specifies the type of resource to check. This can be: + * a group and kind, e.g. `apps/Deployment` or `networking.k8s.io/Ingress` + * `Controller`, to check _any_ resource that contains a pod spec (e.g. Deployments, CronJobs, StatefulSets), as well as naked Pods + * `Pod`, same as `Controller`, but the schema applies to the Pod spec rather than the top-level controller + * `Container` same as `Controller`, but the schema applies to all Container specs rather than the top-level controller +* `controllers` - if `target` is `Controller`, `Pod` or `Container`, you can use this to change which types of controllers are checked +* `controllers.include` - _only_ check these controllers +* `controllers.exclude` - check all controllers except these +* `containers` - if `target` is `Container`, you can use this to decide if `initContainers`, `containers`, or both should be checked +* `containers.exclude` - can be set to a list including `initContainer` or `container` +* `schema` - the JSON Schema to check against, as a YAML object +* `schemaString` - this JSON Schema to check against, as a YAML or JSON string. See [Templating](#templating) below + * Note: only _one_ of `schema` and `schemaString` can be specified. +* `additionalSchemas` - see [Multi-Resource Checks](#multi-resource-checks) below +* `additionalSchemaStrings` - see [Multi-Resource Checks](#multi-resource-checks) below + * Note: only _one_ of `additionalSchemas` and `additionalSchemaStrings` can be specified. + +## Checking CPU and Memory +We extend JSON Schema with `resourceMinimum` and `resourceMaximum` fields to help compare memory and CPU resource +strings like `1000m` and `1G`. Here's an example check that memory and CPU falls within a certain range. +```yaml +customChecks: + resourceLimits: + containers: + exclude: + - initContainer + successMessage: Resource limits are within the required range + failureMessage: Resource limits should be within the required range + category: Resources + target: Container + schema: + '$schema': http://json-schema.org/draft-07/schema + type: object + required: + - resources + properties: + resources: + type: object + required: + - limits + properties: + limits: + type: object + required: + - memory + - cpu + properties: + memory: + type: string + resourceMinimum: 100M + resourceMaximum: 6G + cpu: + type: string + resourceMinimum: 100m + resourceMaximum: "2" +``` + +## Templating +You can also utilize go templating in your JSON schema in order to match one field against another. +E.g. here is the built-in check to ensure that the `name` annotation matches the object's name: +```yaml +successMessage: Label app.kubernetes.io/name matches metadata.name +failureMessage: Label app.kubernetes.io/name must match metadata.name +target: Controller +schema: + '$schema': http://json-schema.org/draft-07/schema + type: object + properties: + metadata: + type: object + required: ["labels"] + properties: + labels: + type: object + required: ["app.kubernetes.io/name"] + properties: + app.kubernetes.io/name: + const: "{{ .metadata.name }}" +``` + +You can also use the full [Go template syntax](https://golang.org/pkg/text/template/), though +you may need to specify your schema as a string in order to use concepts like `range`. E.g. +this check ensures that at least one of the object's labels is present in `matchLabels`: +```yaml +schemaString: | + type: object + properties: + spec: + type: object + required: ["selector"] + properties: + selector: + type: object + required: ["matchLabels"] + properties: + matchLabels: + type: object + anyOf: + {{ range $key, $value := .metadata.labels }} + - properties: + "{{ $key }}": + type: string + const: {{ $value }} + required: ["{{ $key }}"] + {{ end }} +``` + +## Multi-Resource Checks +You can write checks that span multiple resources. This is helpful for ensuring e.g. +that every Deployment has a PDB or an HPA associated with it. + +Here's the check to ensure that every Deployment has a PDB: +```yaml +successMessage: A PodDisruptionBudget is attached +failureMessage: Should have a PodDisruptionBudget +category: Reliability +target: Controller +controllers: + include: + - Deployment +schema: + '$schema': http://json-schema.org/draft-07/schema + type: object + properties: + metadata: + type: object + properties: + labels: + type: object + minProperties: 1 +additionalSchemaStrings: + policy/PodDisruptionBudget: | + type: object + properties: + spec: + type: object + required: ["selector"] + properties: + selector: + type: object + required: ["matchLabels"] + properties: + matchLabels: + type: object + anyOf: + {{ range $key, $value := .metadata.labels }} + - properties: + "{{ $key }}": + type: string + const: {{ $value }} + required: ["{{ $key }}"] + {{ end }} +``` + +## JSON vs YAML Schemas can also be specified as JSON strings instead of YAML, for easier copy/pasting: ```yaml customChecks: @@ -32,8 +202,3 @@ customChecks: } ``` -We extend JSON Schema with `resourceMinimum` and `resourceMaximum` fields to help compare memory and CPU resource -strings like `1000m` and `1G`. You can see an example in [the extended config](https://github.com/FairwindsOps/polaris/tree/master/examples/config-full.yaml) - -There are additional examples in the [checks folder](https://github.com/FairwindsOps/polaris/tree/master/checks). - diff --git a/examples/config.yaml b/examples/config.yaml index 8e0b0fa3..87997f2a 100644 --- a/examples/config.yaml +++ b/examples/config.yaml @@ -6,6 +6,10 @@ checks: pullPolicyNotAlways: warning readinessProbeMissing: warning livenessProbeMissing: warning + metadataAndNameMismatched: ignore + pdbDisruptionsIsZero: warning + missingPodDisruptionBudget: ignore + # efficiency cpuRequestsMissing: warning cpuLimitsMissing: warning diff --git a/go.mod b/go.mod index a116b305..dcee9846 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/fairwindsops/polaris -go 1.13 +go 1.15 require ( cloud.google.com/go v0.74.0 // indirect @@ -10,12 +10,8 @@ require ( github.com/gobuffalo/packr/v2 v2.8.1 github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.1.3 // indirect - github.com/googleapis/gnostic v0.5.3 // indirect github.com/gorilla/mux v1.8.0 - github.com/imdario/mergo v0.3.11 // indirect github.com/karrick/godirwalk v1.16.1 // indirect - github.com/kr/pretty v0.2.1 // indirect - github.com/prometheus/client_golang v1.9.0 // indirect github.com/qri-io/jsonschema v0.1.1 github.com/rogpeppe/go-internal v1.6.2 // indirect github.com/sirupsen/logrus v1.8.1 @@ -23,17 +19,10 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.7.0 github.com/thoas/go-funk v0.7.0 - go.uber.org/zap v1.16.0 // indirect - golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect - golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect - golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 // indirect - golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect - golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 - k8s.io/api v0.20.4 - k8s.io/apimachinery v0.20.4 - k8s.io/client-go v0.20.4 - k8s.io/component-base v0.20.1 // indirect - sigs.k8s.io/controller-runtime v0.7.0 + k8s.io/api v0.21.0 + k8s.io/apimachinery v0.21.0 + k8s.io/client-go v0.21.0 + sigs.k8s.io/controller-runtime v0.9.0-alpha.1 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index a36a64af..8b285437 100644 --- a/go.sum +++ b/go.sum @@ -6,7 +6,6 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= @@ -40,31 +39,18 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest v0.11.15 h1:S5SDFpmgoVyvMEOcULyEDlYFrdPmu6Wl0Ic+shkEwzg= github.com/Azure/go-autorest/autorest v0.11.15/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/adal v0.9.10 h1:r6fZHMaHD8B6LDCn0o5vyBFHIHrM6Ywwx7mb49lPItI= github.com/Azure/go-autorest/autorest/adal v0.9.10/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -72,23 +58,19 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -96,7 +78,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -107,7 +88,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -138,15 +118,13 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -177,10 +155,7 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -194,53 +169,18 @@ github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.3.0 h1:q4c+kbcR0d5rSurhBR8dIgieOaYpXtsdTYfx22Cu6rs= -github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/zapr v0.2.0 h1:v6Ji8yBW77pva6NkJKQdHLAJKrIJKRHz0RXwPqCHSR4= -github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= +github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobuffalo/logger v1.0.3 h1:YaXOTHNPCvkqqA7w05A4v0k2tCdpr+sgFlgINbQ6gqc= @@ -255,6 +195,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -325,9 +267,8 @@ github.com/google/uuid v1.1.3/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.3 h1:2qsuRm+bzgwSIKikigPASa2GhW8H2Dn4Qq7UxD8K/48= -github.com/googleapis/gnostic v0.5.3/go.mod h1:TRWw1s4gxBGjSe301Dai3c7wXJAZy57+/6tawkOvqHQ= +github.com/googleapis/gnostic v0.5.4 h1:ynbQIWjLw7iv6HAFdixb30U7Uvcmx+f4KlLJpmhkTK0= +github.com/googleapis/gnostic v0.5.4/go.mod h1:TRWw1s4gxBGjSe301Dai3c7wXJAZy57+/6tawkOvqHQ= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -373,7 +314,6 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -397,6 +337,7 @@ github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -406,21 +347,17 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= @@ -453,6 +390,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -472,6 +410,8 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -484,16 +424,16 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= -github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -576,10 +516,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= -github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -592,8 +528,6 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= @@ -623,13 +557,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/thoas/go-funk v0.7.0 h1:GmirKrs6j6zJbhJIficOsz2aAI7700KsU/5YrdHRM1Y= github.com/thoas/go-funk v0.7.0/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -640,10 +572,7 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -665,28 +594,23 @@ go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -721,12 +645,12 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -735,7 +659,6 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -765,10 +688,10 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -800,7 +723,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -831,25 +753,24 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg= -golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -862,17 +783,13 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -883,7 +800,6 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -915,10 +831,11 @@ golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= @@ -928,6 +845,11 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2 h1:vEtypaVub6UvKkiXZ2xx9QIvp9TL7sI7xp7vdi2kezA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -997,6 +919,7 @@ google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1035,6 +958,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1072,57 +997,45 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= -k8s.io/api v0.20.1 h1:ud1c3W3YNzGd6ABJlbFfKXBKXO+1KdGfcgGGNgFR03E= -k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= -k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw= -k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= -k8s.io/api v0.20.4 h1:xZjKidCirayzX6tHONRQyTNDVIR55TYVqgATqo6ZULY= -k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= -k8s.io/apiextensions-apiserver v0.19.2 h1:oG84UwiDsVDu7dlsGQs5GySmQHCzMhknfhFExJMz9tA= -k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg= -k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.20.1 h1:LAhz8pKbgR8tUwn7boK+b2HZdt7MiTu2mkYtFMUjTRQ= -k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg= -k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.4 h1:vhxQ0PPUUU2Ns1b9r4/UFp13UPs8cw2iOoTjnY9faa0= -k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= -k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= -k8s.io/client-go v0.20.1 h1:Qquik0xNFbK9aUG92pxHYsyfea5/RPO9o9bSywNor+M= -k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= -k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ= -k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= -k8s.io/client-go v0.20.4 h1:85crgh1IotNkLpKYKZHVNI1JT86nr/iDCvq2iWKsql4= -k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= -k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= -k8s.io/component-base v0.19.2 h1:jW5Y9RcZTb79liEhW3XDVTW7MuvEGP0tQZnfSX6/+gs= -k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo= -k8s.io/component-base v0.20.1 h1:6OQaHr205NSl24t5wOF2IhdrlxZTWEZwuGlLvBgaeIg= -k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/api v0.21.0-beta.1/go.mod h1:8A+GKfJYDnFlmsIqnwi7z2l5+GwI3fbIdAkPu3xiZKA= +k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y= +k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= +k8s.io/apiextensions-apiserver v0.21.0-beta.1 h1:qUvWURtH6TZCabcYEGKVydU4f17qso00ZtSPodbQdEo= +k8s.io/apiextensions-apiserver v0.21.0-beta.1/go.mod h1:vluMqsJ5+hPgM9UtBhkFSGrfD86KUac9yeKVqpGBZz0= +k8s.io/apimachinery v0.21.0-beta.1/go.mod h1:ZaN7d/yx5I8h2mk8Nu08sdLigsmkt4flkTxCTc9LElI= +k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA= +k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= +k8s.io/apiserver v0.21.0-beta.1/go.mod h1:nl/H4DPS1abtRhCj8bhosbyU9XOgnMt0QFK3fAFEhSE= +k8s.io/client-go v0.21.0-beta.1/go.mod h1:SsWZEBajlozcXLnUS7OD47n9MtuzduVt02GMQO2/DIA= +k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag= +k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= +k8s.io/code-generator v0.21.0-beta.1/go.mod h1:IpCUojpiKp25KNB3/UbEeElznqpQUMvhAOUoC7AbISY= +k8s.io/component-base v0.21.0-beta.1 h1:1p2rRyBgoXuCD0rZrG07jXCfkvSnHo0aGCoNCbyhQhY= +k8s.io/component-base v0.21.0-beta.1/go.mod h1:WPMZyV0sNk3ruzA8cWt1EO2KWAnLDK2docEC14JWbTM= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 h1:0T5IaWHO3sJTEmCP6mUlBvMukxPKUQWqiI/YuiBNMiQ= +k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= -sigs.k8s.io/controller-runtime v0.7.0 h1:bU20IBBEPccWz5+zXpLnpVsgBYxqclaHu1pVDl/gEt8= -sigs.k8s.io/controller-runtime v0.7.0/go.mod h1:pJ3YBrJiAqMAZKi6UVGuE98ZrroV1p+pIhoHsMm9wdU= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/controller-runtime v0.9.0-alpha.1 h1:yIYTxDHQfcrYWO1hjZvHhjkGY1fYFo1k07FzlTono4E= +sigs.k8s.io/controller-runtime v0.9.0-alpha.1/go.mod h1:BARxVvgj+8Ihw9modUvYh7/OJmjxuBtLK8P36jdf7rY= sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/pkg/config/checks.go b/pkg/config/checks.go new file mode 100644 index 00000000..5258401d --- /dev/null +++ b/pkg/config/checks.go @@ -0,0 +1,60 @@ +package config + +import ( + "github.com/gobuffalo/packr/v2" + "github.com/sirupsen/logrus" +) + +var ( + // BuiltInChecks contains the checks that come pre-installed w/ Polaris + BuiltInChecks = map[string]SchemaCheck{} + schemaBox = (*packr.Box)(nil) + // We explicitly set the order to avoid thrash in the + // tests as we migrate toward JSON schema + checkOrder = []string{ + // Controller Checks + "multipleReplicasForDeployment", + // Pod checks + "hostIPCSet", + "hostPIDSet", + "hostNetworkSet", + // Container checks + "memoryLimitsMissing", + "memoryRequestsMissing", + "cpuLimitsMissing", + "cpuRequestsMissing", + "readinessProbeMissing", + "livenessProbeMissing", + "pullPolicyNotAlways", + "tagNotSpecified", + "hostPortSet", + "runAsRootAllowed", + "runAsPrivileged", + "notReadOnlyRootFilesystem", + "privilegeEscalationAllowed", + "dangerousCapabilities", + "insecureCapabilities", + "priorityClassNotSet", + // Other checks + "tlsSettingsMissing", + "pdbDisruptionsIsZero", + "metadataAndNameMismatched", + "missingPodDisruptionBudget", + } +) + +func init() { + schemaBox = packr.New("Schemas", "../../checks") + for _, checkID := range checkOrder { + contents, err := schemaBox.Find(checkID + ".yaml") + if err != nil { + panic(err) + } + check, err := ParseCheck(checkID, contents) + if err != nil { + logrus.Errorf("Error while parsing check %s", checkID) + panic(err) + } + BuiltInChecks[checkID] = check + } +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 8b165b6f..cd741749 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -154,10 +154,11 @@ func TestConfigWithCustomChecks(t *testing.T) { parsedConf, err := Parse([]byte(confCustomChecks)) assert.NoError(t, err, "Expected no error when parsing YAML config") assert.Equal(t, 1, len(parsedConf.CustomChecks)) - isValid, _, err := parsedConf.CustomChecks["foo"].CheckObject(valid) + check, err := parsedConf.CustomChecks["foo"].TemplateForResource(map[string]interface{}{}) + isValid, _, err := check.CheckObject(valid) assert.NoError(t, err) assert.Equal(t, true, isValid) - isValid, _, err = parsedConf.CustomChecks["foo"].CheckObject(invalid) + isValid, _, err = check.CheckObject(invalid) assert.NoError(t, err) assert.Equal(t, false, isValid) @@ -169,7 +170,7 @@ func TestConfigWithCustomChecks(t *testing.T) { if !assert.Equal(t, true, isValid) { fmt.Println(problems[0].PropertyPath, problems[0].InvalidValue, problems[0].Message) } - isValid, _, err = parsedConf.CustomChecks["foo"].CheckObject(invalid) + isValid, _, err = check.CheckObject(invalid) assert.NoError(t, err) assert.Equal(t, false, isValid) } diff --git a/pkg/config/schema.go b/pkg/config/schema.go index 4a33d10b..6babae6a 100644 --- a/pkg/config/schema.go +++ b/pkg/config/schema.go @@ -3,6 +3,7 @@ package config import ( "bytes" "encoding/json" + "errors" "fmt" "io" "strings" @@ -36,35 +37,46 @@ var HandledTargets = []TargetKind{ // SchemaCheck is a Polaris check that runs using JSON Schema type SchemaCheck struct { - ID string `yaml:"id" json:"id"` - Category string `yaml:"category" json:"category"` - SuccessMessage string `yaml:"successMessage" json:"successMessage"` - FailureMessage string `yaml:"failureMessage" json:"failureMessage"` - Controllers includeExcludeList `yaml:"controllers" json:"controllers"` - Containers includeExcludeList `yaml:"containers" json:"containers"` - Target TargetKind `yaml:"target" json:"target"` - SchemaTarget TargetKind `yaml:"schemaTarget" json:"schemaTarget"` - Schema map[string]interface{} `yaml:"schema" json:"schema"` - SchemaString string `yaml:"jsonSchema" json:"jsonSchema"` - Validator jsonschema.RootSchema `yaml:"-"` + ID string `yaml:"id" json:"id"` + Category string `yaml:"category" json:"category"` + SuccessMessage string `yaml:"successMessage" json:"successMessage"` + FailureMessage string `yaml:"failureMessage" json:"failureMessage"` + Controllers includeExcludeList `yaml:"controllers" json:"controllers"` + Containers includeExcludeList `yaml:"containers" json:"containers"` + Target TargetKind `yaml:"target" json:"target"` + SchemaTarget TargetKind `yaml:"schemaTarget" json:"schemaTarget"` + Schema map[string]interface{} `yaml:"schema" json:"schema"` + SchemaString string `yaml:"schemaString" json:"schemaString"` + Validator jsonschema.RootSchema `yaml:"-" json:"-"` + AdditionalSchemas map[string]map[string]interface{} `yaml:"additionalSchemas" json:"additionalSchemas"` + AdditionalSchemaStrings map[string]string `yaml:"additionalSchemaStrings" json:"additionalSchemaStrings"` + AdditionalValidators map[string]jsonschema.RootSchema `yaml:"-" json:"-"` } type resourceMinimum string type resourceMaximum string -// ParseCheck parses a check from a byte array -func ParseCheck(id string, rawBytes []byte) (SchemaCheck, error) { - reader := bytes.NewReader(rawBytes) - check := SchemaCheck{} +func unmarshalYAMLOrJSON(raw []byte, dest interface{}) error { + reader := bytes.NewReader(raw) d := k8sYaml.NewYAMLOrJSONDecoder(reader, 4096) for { - if err := d.Decode(&check); err != nil { + if err := d.Decode(dest); err != nil { if err == io.EOF { break } - return check, fmt.Errorf("Decoding schema check failed: %v", err) + return fmt.Errorf("Decoding schema check failed: %v", err) } } + return nil +} + +// ParseCheck parses a check from a byte array +func ParseCheck(id string, rawBytes []byte) (SchemaCheck, error) { + check := SchemaCheck{} + err := unmarshalYAMLOrJSON(rawBytes, &check) + if err != nil { + return check, err + } check.Initialize(id) return check, nil } @@ -155,27 +167,63 @@ func (check *SchemaCheck) Initialize(id string) error { } check.SchemaString = string(jsonBytes) } - err := json.Unmarshal([]byte(check.SchemaString), &check.Validator) - return err + for kind, schema := range check.AdditionalSchemas { + jsonBytes, err := json.Marshal(schema) + if err != nil { + return err + } + check.AdditionalSchemaStrings[kind] = string(jsonBytes) + } + check.Schema = map[string]interface{}{} + check.AdditionalSchemas = map[string]map[string]interface{}{} + return nil } // TemplateForResource fills out a check's templated fields given a particular resource func (check SchemaCheck) TemplateForResource(res interface{}) (*SchemaCheck, error) { newCheck := check // Make a copy of the check, since we're going to modify the schema - tmpl := template.New(newCheck.ID) - tmpl, err := tmpl.Parse(newCheck.SchemaString) + + templateStrings := map[string]string{ + "": newCheck.SchemaString, + } + for kind, schema := range newCheck.AdditionalSchemaStrings { + templateStrings[kind] = schema + } + newCheck.SchemaString = "" + newCheck.AdditionalSchemaStrings = map[string]string{} + + for kind, tmplString := range templateStrings { + tmpl := template.New(newCheck.ID) + tmpl, err := tmpl.Parse(tmplString) + if err != nil { + return nil, err + } + w := bytes.Buffer{} + err = tmpl.Execute(&w, res) + if err != nil { + return nil, err + } + + if kind == "" { + newCheck.SchemaString = w.String() + } else { + newCheck.AdditionalSchemaStrings[kind] = w.String() + } + } + + newCheck.AdditionalValidators = map[string]jsonschema.RootSchema{} + for kind, schemaStr := range newCheck.AdditionalSchemaStrings { + val := jsonschema.RootSchema{} + err := unmarshalYAMLOrJSON([]byte(schemaStr), &val) + if err != nil { + return nil, err + } + newCheck.AdditionalValidators[kind] = val + } + err := unmarshalYAMLOrJSON([]byte(newCheck.SchemaString), &newCheck.Validator) if err != nil { return nil, err } - - w := bytes.Buffer{} - err = tmpl.Execute(&w, res) - if err != nil { - return nil, err - } - - newCheck.SchemaString = w.String() - newCheck.Initialize(newCheck.ID) return &newCheck, err } @@ -205,6 +253,28 @@ func (check SchemaCheck) CheckObject(obj interface{}) (bool, []jsonschema.ValErr return len(errs) == 0, errs, err } +// CheckAdditionalObjects looks for an object that passes the specified additional schema +func (check SchemaCheck) CheckAdditionalObjects(groupkind string, objects []interface{}) (bool, error) { + val, ok := check.AdditionalValidators[groupkind] + if !ok { + return false, errors.New("No validator found for " + groupkind) + } + for _, obj := range objects { + bytes, err := json.Marshal(obj) + if err != nil { + return false, err + } + errs, err := val.ValidateBytes(bytes) + if err != nil { + return false, err + } + if len(errs) == 0 { + return true, nil + } + } + return false, nil +} + // IsActionable decides if this check applies to a particular target func (check SchemaCheck) IsActionable(target TargetKind, kind string, isInit bool) bool { if funk.Contains(HandledTargets, target) { diff --git a/pkg/kube/resources.go b/pkg/kube/resources.go index 1978119a..5c86ba4c 100644 --- a/pkg/kube/resources.go +++ b/pkg/kube/resources.go @@ -43,7 +43,9 @@ type ResourceProvider struct { type resourceKindMap map[string][]GenericResource func (rkm resourceKindMap) addResource(r GenericResource) { - rkm[r.Kind] = append(rkm[r.Kind], r) + gvk := r.Resource.GroupVersionKind() + key := gvk.Group + "/" + gvk.Kind + rkm[key] = append(rkm[key], r) } func (rkm resourceKindMap) addResources(rs []GenericResource) { @@ -73,11 +75,24 @@ func (rkm resourceKindMap) GetNumberOfControllers() int { } // This is here for backward compatibility reasons -func maybeTransformKindIntoGroupKind(k conf.TargetKind) string { +func maybeTransformKindIntoGroupKind(k string) string { if k == "Ingress" { return "networking.k8s.io/Ingress" + } else if k == "PodDisruptionBudget" { + return "policy/PodDisruptionBudget" } - return "" + return k +} + +func parseGroupKind(gk string) schema.GroupKind { + i := strings.Index(gk, "/") + if i == -1 { + return schema.GroupKind{Kind: gk} + } + + group := gk[:i] + kind := gk[i+1:] + return schema.GroupKind{Group: group, Kind: kind} } func newResourceProvider(version, sourceType, sourceName string) ResourceProvider { @@ -248,16 +263,29 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac return nil, err } restMapper := restmapper.NewDiscoveryRESTMapper(resources) + allChecks := []conf.SchemaCheck{} + for _, check := range c.CustomChecks { + allChecks = append(allChecks, check) + } + for _, check := range conf.BuiltInChecks { + allChecks = append(allChecks, check) + } var additionalKinds []conf.TargetKind - for _, check := range c.CustomChecks { - if !funk.Contains(conf.HandledTargets, check.Target) { - additionalKinds = append(additionalKinds, check.Target) + for _, check := range allChecks { + neededKinds := []conf.TargetKind{check.Target} + for key := range check.AdditionalSchemas { + neededKinds = append(neededKinds, conf.TargetKind(key)) + } + for _, kind := range neededKinds { + if !funk.Contains(conf.HandledTargets, kind) { + additionalKinds = append(additionalKinds, kind) + } } } for _, kind := range additionalKinds { - groupKind := schema.ParseGroupKind(maybeTransformKindIntoGroupKind(kind)) + groupKind := parseGroupKind(maybeTransformKindIntoGroupKind(string(kind))) mapping, err := (restMapper).RESTMapping(groupKind) if err != nil { logrus.Warnf("Error retrieving mapping of Kind %s because of error: %v", kind, err) diff --git a/pkg/kube/resources_test.go b/pkg/kube/resources_test.go index feec39ea..3ecf2877 100644 --- a/pkg/kube/resources_test.go +++ b/pkg/kube/resources_test.go @@ -3,7 +3,6 @@ package kube import ( "bytes" "context" - "fmt" "io/ioutil" "testing" "time" @@ -29,8 +28,7 @@ func TestGetResourcesFromPath(t *testing.T) { assert.Equal(t, "two", provider.Namespaces[0].ObjectMeta.Name) namespaceCount := map[string]int{} - for kind, resources := range provider.Resources { - fmt.Println("found", kind, len(resources)) + for _, resources := range provider.Resources { for _, controller := range resources { namespaceCount[controller.ObjectMeta.GetNamespace()]++ } @@ -52,8 +50,8 @@ func TestGetMultipleResourceFromSingleFile(t *testing.T) { assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes") - assert.Equal(t, 1, len(resources.Resources["Deployment"]), "Should have one controller") - assert.Equal(t, "dashboard", resources.Resources["Deployment"][0].PodSpec.Containers[0].Name) + assert.Equal(t, 1, len(resources.Resources["extensions/Deployment"]), "Should have one controller") + assert.Equal(t, "dashboard", resources.Resources["extensions/Deployment"][0].PodSpec.Containers[0].Name) assert.Equal(t, 2, len(resources.Namespaces), "Should have a namespace") assert.Equal(t, "polaris", resources.Namespaces[0].ObjectMeta.Name) @@ -75,8 +73,8 @@ func TestAddResourcesFromReader(t *testing.T) { assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes") - assert.Equal(t, 1, len(resources.Resources["Deployment"]), "Should have one controller") - assert.Equal(t, "dashboard", resources.Resources["Deployment"][0].PodSpec.Containers[0].Name) + assert.Equal(t, 1, len(resources.Resources["extensions/Deployment"]), "Should have one controller") + assert.Equal(t, "dashboard", resources.Resources["extensions/Deployment"][0].PodSpec.Containers[0].Name) assert.Equal(t, 2, len(resources.Namespaces), "Should have a namespace") assert.Equal(t, "polaris", resources.Namespaces[0].ObjectMeta.Name) diff --git a/pkg/validator/arbitrary_test.go b/pkg/validator/arbitrary_test.go index d45b4d9b..e0b321f3 100644 --- a/pkg/validator/arbitrary_test.go +++ b/pkg/validator/arbitrary_test.go @@ -29,18 +29,18 @@ import ( func TestValidatePDB(t *testing.T) { c := conf.Configuration{ Checks: map[string]conf.Severity{ - "pdbDisruptionsAllowedGreaterThanZero": conf.SeverityWarning, + "pdbDisruptionsIsZero": conf.SeverityWarning, }, } pdb := unstructured.Unstructured{} res, err := kube.NewGenericResourceFromUnstructured(&pdb) res.Kind = "PodDisruptionBudget" - actualResult, err := applyNonControllerSchemaChecks(&c, res) + actualResult, err := applyNonControllerSchemaChecks(&c, nil, res) if err != nil { panic(err) } - results := actualResult.Results["pdbDisruptionsAllowedGreaterThanZero"] + results := actualResult.Results["pdbDisruptionsIsZero"] assert.False(t, results.Success) assert.Equal(t, conf.SeverityWarning, results.Severity) @@ -76,7 +76,7 @@ func TestValidateIngress(t *testing.T) { } res.Kind = "Ingress" - actualResult, err := applyNonControllerSchemaChecks(&c, res) + actualResult, err := applyNonControllerSchemaChecks(&c, nil, res) if err != nil { panic(err) } diff --git a/pkg/validator/container_test.go b/pkg/validator/container_test.go index f450a85c..62c3820a 100644 --- a/pkg/validator/container_test.go +++ b/pkg/validator/container_test.go @@ -69,7 +69,7 @@ func testValidateWithWorkload(t *testing.T, container *corev1.Container, resourc assert.NoError(t, err, "Expected no error when parsing config") var results ResultSet - results, err = applyContainerSchemaChecks(&parsedConf, workload, container, false) + results, err = applyContainerSchemaChecks(&parsedConf, nil, workload, container, false) if err != nil { panic(err) } @@ -93,7 +93,7 @@ func TestValidateResourcesEmptyConfig(t *testing.T) { Name: "Empty", } - results, err := applyContainerSchemaChecks(&conf.Configuration{}, getEmptyWorkload(t, ""), container, false) + results, err := applyContainerSchemaChecks(&conf.Configuration{}, nil, getEmptyWorkload(t, ""), container, false) if err != nil { panic(err) } @@ -190,7 +190,7 @@ func TestValidateHealthChecks(t *testing.T) { for idx, tt := range testCases { t.Run(tt.name, func(t *testing.T) { controller := getEmptyWorkload(t, "") - results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.probes}, controller, tt.container, tt.isInit) + results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.probes}, nil, controller, tt.container, tt.isInit) if err != nil { panic(err) } @@ -304,7 +304,7 @@ func TestValidateImage(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { controller := getEmptyWorkload(t, "") - results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.image}, controller, tt.container, false) + results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.image}, nil, controller, tt.container, false) if err != nil { panic(err) } @@ -421,7 +421,7 @@ func TestValidateNetworking(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { controller := getEmptyWorkload(t, "") - results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.networkConf}, controller, tt.container, false) + results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.networkConf}, nil, controller, tt.container, false) if err != nil { panic(err) } @@ -926,7 +926,7 @@ func TestValidateSecurity(t *testing.T) { t.Run(tt.name, func(t *testing.T) { workload, err := kube.NewGenericResourceFromPod(corev1.Pod{Spec: *tt.pod}, nil) assert.NoError(t, err) - results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.securityConf}, workload, tt.container, false) + results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.securityConf}, nil, workload, tt.container, false) if err != nil { panic(err) } @@ -1071,7 +1071,7 @@ func TestValidateRunAsRoot(t *testing.T) { t.Run(tt.name, func(t *testing.T) { workload, err := kube.NewGenericResourceFromPod(corev1.Pod{Spec: *tt.pod}, nil) assert.NoError(t, err) - results, err := applyContainerSchemaChecks(&config, workload, tt.container, false) + results, err := applyContainerSchemaChecks(&config, nil, workload, tt.container, false) if err != nil { panic(err) } diff --git a/pkg/validator/controller_test.go b/pkg/validator/controller_test.go index 00a3d3ad..eb37bbf6 100644 --- a/pkg/validator/controller_test.go +++ b/pkg/validator/controller_test.go @@ -49,7 +49,7 @@ func TestValidateController(t *testing.T) { } var actualResult Result - actualResult, err = applyControllerSchemaChecks(&c, deployment) + actualResult, err = applyControllerSchemaChecks(&c, nil, deployment) if err != nil { panic(err) } @@ -73,7 +73,7 @@ func TestControllerLevelChecks(t *testing.T) { Category: "Reliability", } for _, controller := range res.Resources["Deployment"] { - actualResult, err := applyControllerSchemaChecks(&c, controller) + actualResult, err := applyControllerSchemaChecks(&c, nil, controller) if err != nil { panic(err) } @@ -137,7 +137,7 @@ func TestSkipHealthChecks(t *testing.T) { "livenessProbeMissing": {ID: "livenessProbeMissing", Message: "Liveness probe should be configured", Success: false, Severity: "warning", Category: "Reliability"}, } var actualResult Result - actualResult, err = applyControllerSchemaChecks(&c, deployment) + actualResult, err = applyControllerSchemaChecks(&c, nil, deployment) if err != nil { panic(err) } @@ -156,7 +156,7 @@ func TestSkipHealthChecks(t *testing.T) { Dangers: uint(0), } expectedResults = ResultSet{} - actualResult, err = applyControllerSchemaChecks(&c, job) + actualResult, err = applyControllerSchemaChecks(&c, nil, job) if err != nil { panic(err) } @@ -174,7 +174,7 @@ func TestSkipHealthChecks(t *testing.T) { Dangers: uint(0), } expectedResults = ResultSet{} - actualResult, err = applyControllerSchemaChecks(&c, cronjob) + actualResult, err = applyControllerSchemaChecks(&c, nil, cronjob) if err != nil { panic(err) } @@ -210,7 +210,7 @@ func TestControllerExemptions(t *testing.T) { resources := []kube.GenericResource{workload} var actualResults []Result - actualResults, err = ApplyAllSchemaChecksToAllResources(&c, resources) + actualResults, err = ApplyAllSchemaChecksToAllResources(&c, nil, resources) if err != nil { panic(err) } @@ -221,7 +221,7 @@ func TestControllerExemptions(t *testing.T) { c.Exemptions = []conf.Exemption{{ Namespace: "foo", }} - actualResults, err = ApplyAllSchemaChecksToAllResources(&c, resources) + actualResults, err = ApplyAllSchemaChecksToAllResources(&c, nil, resources) if err != nil { panic(err) } @@ -233,7 +233,7 @@ func TestControllerExemptions(t *testing.T) { resources[0].ObjectMeta.SetAnnotations(map[string]string{ exemptionAnnotationKey: "true", }) - actualResults, err = ApplyAllSchemaChecksToAllResources(&c, resources) + actualResults, err = ApplyAllSchemaChecksToAllResources(&c, nil, resources) if err != nil { panic(err) } @@ -242,7 +242,7 @@ func TestControllerExemptions(t *testing.T) { assert.EqualValues(t, expectedExemptSum, actualResults[0].GetSummary()) c.DisallowExemptions = true - actualResults, err = ApplyAllSchemaChecksToAllResources(&c, resources) + actualResults, err = ApplyAllSchemaChecksToAllResources(&c, nil, resources) if err != nil { panic(err) } diff --git a/pkg/validator/fullaudit.go b/pkg/validator/fullaudit.go index e0ef255a..e8a3b804 100644 --- a/pkg/validator/fullaudit.go +++ b/pkg/validator/fullaudit.go @@ -22,13 +22,9 @@ func RunAudit(config conf.Configuration, kubeResources *kube.ResourceProvider, o displayName = kubeResources.SourceName } - results := []Result{} - for _, resources := range kubeResources.Resources { - kindResults, err := ApplyAllSchemaChecksToAllResources(&config, resources) - if err != nil { - return AuditData{}, err - } - results = append(results, kindResults...) + results, err := ApplyAllSchemaChecksToResourceProvider(&config, kubeResources) + if err != nil { + return AuditData{}, err } auditData := AuditData{ diff --git a/pkg/validator/pod_test.go b/pkg/validator/pod_test.go index 996780aa..0efc262e 100644 --- a/pkg/validator/pod_test.go +++ b/pkg/validator/pod_test.go @@ -50,7 +50,7 @@ func TestValidatePod(t *testing.T) { "hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"}, } - actualPodResult, err := applyControllerSchemaChecks(&c, deployment) + actualPodResult, err := applyControllerSchemaChecks(&c, nil, deployment) if err != nil { panic(err) } @@ -85,7 +85,7 @@ func TestInvalidIPCPod(t *testing.T) { "hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"}, } - actualPodResult, err := applyControllerSchemaChecks(&c, workload) + actualPodResult, err := applyControllerSchemaChecks(&c, nil, workload) if err != nil { panic(err) } @@ -121,7 +121,7 @@ func TestInvalidNetworkPod(t *testing.T) { "hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"}, } - actualPodResult, err := applyControllerSchemaChecks(&c, workload) + actualPodResult, err := applyControllerSchemaChecks(&c, nil, workload) if err != nil { panic(err) } @@ -157,7 +157,7 @@ func TestInvalidPIDPod(t *testing.T) { "hostNetworkSet": {ID: "hostNetworkSet", Message: "Host network is not configured", Success: true, Severity: "warning", Category: "Security"}, } - actualPodResult, err := applyControllerSchemaChecks(&c, workload) + actualPodResult, err := applyControllerSchemaChecks(&c, nil, workload) if err != nil { panic(err) } @@ -200,7 +200,7 @@ func TestExemption(t *testing.T) { "hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"}, } - actualPodResult, err := applyControllerSchemaChecks(&c, workload) + actualPodResult, err := applyControllerSchemaChecks(&c, nil, workload) if err != nil { panic(err) } diff --git a/pkg/validator/schema.go b/pkg/validator/schema.go index 7d9638a2..c27e48f3 100644 --- a/pkg/validator/schema.go +++ b/pkg/validator/schema.go @@ -5,8 +5,8 @@ import ( "sort" "strings" - "github.com/gobuffalo/packr/v2" "github.com/qri-io/jsonschema" + "github.com/thoas/go-funk" corev1 "k8s.io/api/core/v1" metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -14,62 +14,12 @@ import ( "github.com/fairwindsops/polaris/pkg/kube" ) -var ( - schemaBox = (*packr.Box)(nil) - builtInChecks = map[string]config.SchemaCheck{} - // We explicitly set the order to avoid thrash in the - // tests as we migrate toward JSON schema - checkOrder = []string{ - // Controller Checks - "multipleReplicasForDeployment", - // Pod checks - "hostIPCSet", - "hostPIDSet", - "hostNetworkSet", - // Container checks - "memoryLimitsMissing", - "memoryRequestsMissing", - "cpuLimitsMissing", - "cpuRequestsMissing", - "readinessProbeMissing", - "livenessProbeMissing", - "pullPolicyNotAlways", - "tagNotSpecified", - "hostPortSet", - "runAsRootAllowed", - "runAsPrivileged", - "notReadOnlyRootFilesystem", - "privilegeEscalationAllowed", - "dangerousCapabilities", - "insecureCapabilities", - "priorityClassNotSet", - // Other checks - "tlsSettingsMissing", - "pdbDisruptionsAllowedGreaterThanZero", - "metadataAndNameMismatched", - } -) - type schemaTestCase struct { - Target config.TargetKind - Resource kube.GenericResource - IsInitContianer bool - Container *corev1.Container -} - -func init() { - schemaBox = packr.New("Schemas", "../../checks") - for _, checkID := range checkOrder { - contents, err := schemaBox.Find(checkID + ".yaml") - if err != nil { - panic(err) - } - check, err := config.ParseCheck(checkID, contents) - if err != nil { - panic(err) - } - builtInChecks[checkID] = check - } + Target config.TargetKind + Resource kube.GenericResource + IsInitContianer bool + Container *corev1.Container + ResourceProvider *kube.ResourceProvider } func resolveCheck(conf *config.Configuration, checkID string, test schemaTestCase) (*config.SchemaCheck, error) { @@ -78,7 +28,7 @@ func resolveCheck(conf *config.Configuration, checkID string, test schemaTestCas } check, ok := conf.CustomChecks[checkID] if !ok { - check, ok = builtInChecks[checkID] + check, ok = config.BuiltInChecks[checkID] } if !ok { return nil, fmt.Errorf("Check %s not found", checkID) @@ -139,11 +89,24 @@ func hasExemptionAnnotation(objMeta metaV1.Object, checkID string) bool { return false } +// ApplyAllSchemaChecksToResourceProvider applies all available checks to a ResourceProvider +func ApplyAllSchemaChecksToResourceProvider(conf *config.Configuration, resourceProvider *kube.ResourceProvider) ([]Result, error) { + results := []Result{} + for _, resources := range resourceProvider.Resources { + kindResults, err := ApplyAllSchemaChecksToAllResources(conf, resourceProvider, resources) + if err != nil { + return results, err + } + results = append(results, kindResults...) + } + return results, nil +} + // ApplyAllSchemaChecksToAllResources applies available checks to a list of resources -func ApplyAllSchemaChecksToAllResources(conf *config.Configuration, resources []kube.GenericResource) ([]Result, error) { +func ApplyAllSchemaChecksToAllResources(conf *config.Configuration, resourceProvider *kube.ResourceProvider, resources []kube.GenericResource) ([]Result, error) { results := []Result{} for _, resource := range resources { - result, err := ApplyAllSchemaChecks(conf, resource) + result, err := ApplyAllSchemaChecks(conf, resourceProvider, resource) if err != nil { return results, err } @@ -153,37 +116,37 @@ func ApplyAllSchemaChecksToAllResources(conf *config.Configuration, resources [] } // ApplyAllSchemaChecks applies available checks to a single resource -func ApplyAllSchemaChecks(conf *config.Configuration, resource kube.GenericResource) (Result, error) { +func ApplyAllSchemaChecks(conf *config.Configuration, resourceProvider *kube.ResourceProvider, resource kube.GenericResource) (Result, error) { if resource.PodSpec == nil { - return applyNonControllerSchemaChecks(conf, resource) + return applyNonControllerSchemaChecks(conf, resourceProvider, resource) } - return applyControllerSchemaChecks(conf, resource) + return applyControllerSchemaChecks(conf, resourceProvider, resource) } -func applyNonControllerSchemaChecks(conf *config.Configuration, resource kube.GenericResource) (Result, error) { +func applyNonControllerSchemaChecks(conf *config.Configuration, resourceProvider *kube.ResourceProvider, resource kube.GenericResource) (Result, error) { finalResult := Result{ Kind: resource.Kind, Name: resource.ObjectMeta.GetName(), Namespace: resource.ObjectMeta.GetNamespace(), } - resultSet, err := applyTopLevelSchemaChecks(conf, resource, false) + resultSet, err := applyTopLevelSchemaChecks(conf, resourceProvider, resource, false) finalResult.Results = resultSet return finalResult, err } -func applyControllerSchemaChecks(conf *config.Configuration, resource kube.GenericResource) (Result, error) { +func applyControllerSchemaChecks(conf *config.Configuration, resourceProvider *kube.ResourceProvider, resource kube.GenericResource) (Result, error) { finalResult := Result{ Kind: resource.Kind, Name: resource.ObjectMeta.GetName(), Namespace: resource.ObjectMeta.GetNamespace(), } - resultSet, err := applyTopLevelSchemaChecks(conf, resource, true) + resultSet, err := applyTopLevelSchemaChecks(conf, resourceProvider, resource, true) if err != nil { return finalResult, err } finalResult.Results = resultSet - podRS, err := applyPodSchemaChecks(conf, resource) + podRS, err := applyPodSchemaChecks(conf, resourceProvider, resource) if err != nil { return finalResult, err } @@ -194,7 +157,7 @@ func applyControllerSchemaChecks(conf *config.Configuration, resource kube.Gener finalResult.PodResult = &podRes for _, container := range resource.PodSpec.InitContainers { - results, err := applyContainerSchemaChecks(conf, resource, &container, true) + results, err := applyContainerSchemaChecks(conf, resourceProvider, resource, &container, true) if err != nil { return finalResult, err } @@ -205,7 +168,7 @@ func applyControllerSchemaChecks(conf *config.Configuration, resource kube.Gener podRes.ContainerResults = append(podRes.ContainerResults, cRes) } for _, container := range resource.PodSpec.Containers { - results, err := applyContainerSchemaChecks(conf, resource, &container, false) + results, err := applyContainerSchemaChecks(conf, resourceProvider, resource, &container, false) if err != nil { return finalResult, err } @@ -219,9 +182,10 @@ func applyControllerSchemaChecks(conf *config.Configuration, resource kube.Gener return finalResult, nil } -func applyTopLevelSchemaChecks(conf *config.Configuration, res kube.GenericResource, isController bool) (ResultSet, error) { +func applyTopLevelSchemaChecks(conf *config.Configuration, resources *kube.ResourceProvider, res kube.GenericResource, isController bool) (ResultSet, error) { test := schemaTestCase{ - Resource: res, + ResourceProvider: resources, + Resource: res, } if isController { test.Target = config.TargetController @@ -229,20 +193,22 @@ func applyTopLevelSchemaChecks(conf *config.Configuration, res kube.GenericResou return applySchemaChecks(conf, test) } -func applyPodSchemaChecks(conf *config.Configuration, controller kube.GenericResource) (ResultSet, error) { +func applyPodSchemaChecks(conf *config.Configuration, resources *kube.ResourceProvider, controller kube.GenericResource) (ResultSet, error) { test := schemaTestCase{ - Target: config.TargetPod, - Resource: controller, + Target: config.TargetPod, + ResourceProvider: resources, + Resource: controller, } return applySchemaChecks(conf, test) } -func applyContainerSchemaChecks(conf *config.Configuration, controller kube.GenericResource, container *corev1.Container, isInit bool) (ResultSet, error) { +func applyContainerSchemaChecks(conf *config.Configuration, resources *kube.ResourceProvider, controller kube.GenericResource, container *corev1.Container, isInit bool) (ResultSet, error) { test := schemaTestCase{ - Target: config.TargetContainer, - Resource: controller, - Container: container, - IsInitContianer: isInit, + Target: config.TargetContainer, + ResourceProvider: resources, + Resource: controller, + Container: container, + IsInitContianer: isInit, } return applySchemaChecks(conf, test) } @@ -290,6 +256,19 @@ func applySchemaCheck(conf *config.Configuration, checkID string, test schemaTes if err != nil { return nil, err } + for groupkind := range check.AdditionalValidators { + if !passes { + break + } + resources := test.ResourceProvider.Resources[groupkind] + objects := funk.Map(resources, func(res kube.GenericResource) interface{} { + return res.Resource.Object + }).([]interface{}) + passes, err = check.CheckAdditionalObjects(groupkind, objects) + if err != nil { + return nil, err + } + } result := makeResult(conf, check, passes, issues) return &result, nil } diff --git a/pkg/validator/schema_test.go b/pkg/validator/schema_test.go index bdea8e99..7e8add4a 100644 --- a/pkg/validator/schema_test.go +++ b/pkg/validator/schema_test.go @@ -144,14 +144,14 @@ func TestValidateResourcesInit(t *testing.T) { assert.NoError(t, err, "Expected no error when parsing config") var results ResultSet - results, err = applyContainerSchemaChecks(&parsedConf, controller, emptyContainer, false) + results, err = applyContainerSchemaChecks(&parsedConf, nil, controller, emptyContainer, false) if err != nil { panic(err) } assert.Equal(t, uint(1), results.GetSummary().Dangers) assert.Equal(t, uint(1), results.GetSummary().Warnings) - results, err = applyContainerSchemaChecks(&parsedConf, controller, emptyContainer, true) + results, err = applyContainerSchemaChecks(&parsedConf, nil, controller, emptyContainer, true) if err != nil { panic(err) } diff --git a/pkg/validator/summary.go b/pkg/validator/summary.go index 2b63d1e7..ed455584 100644 --- a/pkg/validator/summary.go +++ b/pkg/validator/summary.go @@ -124,10 +124,8 @@ func (c Result) GetSummaryByCategory() CountSummaryByCategory { // GetSummary summarizes AuditData func (a AuditData) GetSummary() CountSummary { summary := CountSummary{} - for _, ctrlResult := range a.Results { - if ctrlResult.PodResult != nil { - summary.AddSummary(ctrlResult.GetSummary()) - } + for _, res := range a.Results { + summary.AddSummary(res.GetSummary()) } return summary } diff --git a/pkg/webhook/webhook.go b/pkg/webhook/webhook.go index ec6b4a30..50d8a72c 100644 --- a/pkg/webhook/webhook.go +++ b/pkg/webhook/webhook.go @@ -105,7 +105,8 @@ func (v *Validator) handleInternal(req admission.Request) (*validator.PodResult, } controller.Kind = req.AdmissionRequest.Kind.Kind var controllerResult validator.Result - controllerResult, err = validator.ApplyAllSchemaChecks(&v.Config, controller) + // TODO: consider enabling multi-resource checks + controllerResult, err = validator.ApplyAllSchemaChecks(&v.Config, nil, controller) if err != nil { return nil, err } diff --git a/test/checks/missingPodDisruptionBudget/failure.bad-name.yaml b/test/checks/missingPodDisruptionBudget/failure.bad-name.yaml new file mode 100644 index 00000000..c53bc20c --- /dev/null +++ b/test/checks/missingPodDisruptionBudget/failure.bad-name.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zookeeper + labels: + app: zookeeper +spec: + containers: + - name: zookeeper + image: zookeeper +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: zk-pdb +spec: + minAvailable: 2 + selector: + matchLabels: + app: asdfasf diff --git a/test/checks/missingPodDisruptionBudget/failure.yaml b/test/checks/missingPodDisruptionBudget/failure.yaml new file mode 100644 index 00000000..2cf875d7 --- /dev/null +++ b/test/checks/missingPodDisruptionBudget/failure.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zookeeper + labels: + app: zookeeper +spec: + containers: + - name: zookeeper + image: zookeeper diff --git a/test/checks/missingPodDisruptionBudget/success.many.yaml b/test/checks/missingPodDisruptionBudget/success.many.yaml new file mode 100644 index 00000000..8e7099da --- /dev/null +++ b/test/checks/missingPodDisruptionBudget/success.many.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zookeeper + labels: + app.kubernetes.io/name: zookeeper +spec: + containers: + - name: zookeeper + image: zookeeper +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: zookeeper-pdb +spec: + minAvailable: 2 + selector: + matchLabels: + app.kubernetes.io/name: zookeeper +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: abcd-pdb +spec: + minAvailable: 2 + selector: + matchLabels: + app.kubernetes.io/name: abcd +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: fghi-pdb +spec: + minAvailable: 2 + selector: + matchLabels: + app.kubernetes.io/name: fghi diff --git a/test/checks/missingPodDisruptionBudget/success.yaml b/test/checks/missingPodDisruptionBudget/success.yaml new file mode 100644 index 00000000..1b4ce34b --- /dev/null +++ b/test/checks/missingPodDisruptionBudget/success.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: zookeeper + labels: + app.kubernetes.io/name: zookeeper +spec: + containers: + - name: zookeeper + image: zookeeper +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: zookeeper-pdb +spec: + minAvailable: 2 + selector: + matchLabels: + app.kubernetes.io/name: zookeeper diff --git a/test/fixtures.go b/test/fixtures.go index fa5d57a2..586e932b 100644 --- a/test/fixtures.go +++ b/test/fixtures.go @@ -10,6 +10,7 @@ import ( batchv1beta1 "k8s.io/api/batch/v1beta1" corev1 "k8s.io/api/core/v1" extv1beta1 "k8s.io/api/extensions/v1beta1" + policyv1beta1 "k8s.io/api/policy/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -162,6 +163,7 @@ func SetupTestAPI(objects ...runtime.Object) (kubernetes.Interface, dynamic.Inte scheme := runtime.NewScheme() appsv1.AddToScheme(scheme) corev1.AddToScheme(scheme) + policyv1beta1.AddToScheme(scheme) fake.AddToScheme(scheme) dynamicClient := dynamicFake.NewSimpleDynamicClient(scheme, objects...) k := fake.NewSimpleClientset(objects...) @@ -207,6 +209,18 @@ func SetupTestAPI(objects ...runtime.Object) (kubernetes.Interface, dynamic.Inte {Name: "statefulsets/scale", Namespaced: true, Kind: "Scale", Group: "apps", Version: "v1beta1"}, }, }, + { + GroupVersion: "networking.k8s.io/v1", + APIResources: []metav1.APIResource{ + {Name: "ingresses", Namespaced: true, Kind: "Ingress", Version: "v1"}, + }, + }, + { + GroupVersion: policyv1beta1.SchemeGroupVersion.String(), + APIResources: []metav1.APIResource{ + {Name: "poddisruptionbudgets", Namespaced: true, Kind: "PodDisruptionBudget", Version: "v1"}, + }, + }, } return k, dynamicClient } diff --git a/test/schema_test.go b/test/schema_test.go index 38086ed3..96a41de0 100644 --- a/test/schema_test.go +++ b/test/schema_test.go @@ -18,10 +18,10 @@ import ( var testCases = []testCase{} type testCase struct { - check string - filename string - input []byte - failure bool + check string + filename string + resources *kube.ResourceProvider + failure bool } func init() { @@ -39,15 +39,15 @@ func init() { panic(err) } for _, tc := range cases { - body, err := ioutil.ReadFile(checkDir + "/" + tc.Name()) + resources, err := kube.CreateResourceProviderFromPath(checkDir + "/" + tc.Name()) if err != nil { panic(err) } testCases = append(testCases, testCase{ - filename: tc.Name(), - check: check, - input: body, - failure: strings.Contains(tc.Name(), "failure"), + filename: tc.Name(), + check: check, + resources: resources, + failure: strings.Contains(tc.Name(), "failure"), }) } } @@ -55,20 +55,16 @@ func init() { func TestChecks(t *testing.T) { for _, tc := range testCases { - res, err := kube.NewGenericResourceFromBytes(tc.input) - if err != nil { - fmt.Println("error parsing", string(tc.input)) - panic(err) - } c, err := config.Parse([]byte("checks:\n " + tc.check + ": danger")) if err != nil { panic(err) } - result, err := validator.ApplyAllSchemaChecks(&c, res) + results, err := validator.ApplyAllSchemaChecksToResourceProvider(&c, tc.resources) if err != nil { panic(err) } - summary := result.GetSummary() + auditData := validator.AuditData{Results: results} + summary := auditData.GetSummary() total := summary.Successes + summary.Dangers msg := fmt.Sprintf("Check %s ran %d times instead of 1", tc.check, total) if assert.Equal(t, uint(1), total, msg) {