mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-08-29 22:17:16 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80662bd203 | ||
|
|
5705f81911 | ||
|
|
b4e3d40f4b | ||
|
|
cea0ca7fa8 | ||
|
|
69bed16e4f | ||
|
|
5b173cf4a7 | ||
|
|
0a0720a26c | ||
|
|
fa3504c350 | ||
|
|
4020000d68 | ||
|
|
ab7eeccfb0 | ||
|
|
78a16fa0ea | ||
|
|
b26c4be8d6 | ||
|
|
aada33f0e9 | ||
|
|
7b88c48a6e | ||
|
|
ded260ee19 | ||
|
|
3e9c270ac7 | ||
|
|
bf6e41566d | ||
|
|
ededabf00f | ||
|
|
3df9d35c57 | ||
|
|
a90c3b0f12 | ||
|
|
d19b0769b4 | ||
|
|
97f25cd7d1 | ||
|
|
03331147ca | ||
|
|
d44138bead | ||
|
|
eb21b030c2 | ||
|
|
3061756a55 | ||
|
|
2964280976 |
@@ -21,3 +21,4 @@ main
|
||||
|
||||
*-packr.go
|
||||
dist
|
||||
.vscode
|
||||
@@ -1,5 +1,15 @@
|
||||
# x.x.x (next release)
|
||||
|
||||
# 1.1.0
|
||||
* Add namespace filter in UI
|
||||
* Add priorityClass check
|
||||
* Support reading from STDIN
|
||||
* Ensure severity is set for all custom checks
|
||||
* Support audit files which use \r or \r\n as newline character
|
||||
* Add option to exempt an entire controller from checks via config file
|
||||
* Fixed case where parent resources trigger error
|
||||
* Fixed UI zero-state
|
||||
|
||||
# 1.0.3
|
||||
* Fixed case where parent resources trigger error
|
||||
* Fixed dashboard link when `--base-path` is set
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[![Version][version-image]][version-link] [![CircleCI][circleci-image]][circleci-link] [![Go Report Card][goreport-image]][goreport-link]
|
||||
</div>
|
||||
|
||||
[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=1.0.3&color=239922
|
||||
[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=1.1.0&color=239922
|
||||
[version-link]: https://github.com/FairwindsOps/polaris
|
||||
|
||||
[goreport-image]: https://goreportcard.com/badge/github.com/FairwindsOps/polaris
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
successMessage: Priority class has been set
|
||||
failureMessage: Priority class should be set
|
||||
category: Security
|
||||
target: Pod
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- priorityClassName
|
||||
+21
-44
@@ -14,21 +14,7 @@ metadata:
|
||||
labels:
|
||||
app: polaris
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris-view
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
---
|
||||
# Source: polaris/templates/rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
@@ -46,6 +32,23 @@ rules:
|
||||
- 'get'
|
||||
- 'list'
|
||||
---
|
||||
# Source: polaris/templates/rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris-view
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
---
|
||||
# Source: polaris/templates/rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
@@ -60,7 +63,6 @@ subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
|
||||
---
|
||||
# Source: polaris/templates/dashboard.service.yaml
|
||||
apiVersion: v1
|
||||
@@ -107,7 +109,7 @@ spec:
|
||||
- command:
|
||||
- polaris
|
||||
- dashboard
|
||||
image: 'quay.io/fairwinds/polaris:1.0'
|
||||
image: 'quay.io/fairwinds/polaris:1.1'
|
||||
imagePullPolicy: 'Always'
|
||||
name: dashboard
|
||||
ports:
|
||||
@@ -126,8 +128,8 @@ spec:
|
||||
periodSeconds: 20
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
cpu: 150m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
@@ -142,28 +144,3 @@ spec:
|
||||
serviceAccountName: polaris
|
||||
nodeSelector:
|
||||
tolerations:
|
||||
---
|
||||
# Source: polaris/templates/audit.job.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/audit.rbac.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/configmap.yaml
|
||||
|
||||
|
||||
---
|
||||
# Source: polaris/templates/ingress.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.deployment.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.rbac.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.secret.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.service.yaml
|
||||
|
||||
|
||||
+45
-59
@@ -5,6 +5,15 @@ kind: Namespace
|
||||
metadata:
|
||||
name: polaris
|
||||
---
|
||||
# Source: polaris/templates/rbac.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
---
|
||||
# Source: polaris/templates/webhook.secret.yaml
|
||||
# The name of this secret is static as it is populated by the webhook pod.
|
||||
apiVersion: v1
|
||||
@@ -19,29 +28,6 @@ stringData:
|
||||
cert.pem: ''
|
||||
---
|
||||
# Source: polaris/templates/rbac.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris-view
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
@@ -59,22 +45,6 @@ rules:
|
||||
- 'get'
|
||||
- 'list'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: polaris
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
|
||||
---
|
||||
# Source: polaris/templates/webhook.rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
@@ -101,6 +71,39 @@ rules:
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
# Source: polaris/templates/rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris-view
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: view
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
---
|
||||
# Source: polaris/templates/rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: polaris
|
||||
labels:
|
||||
app: polaris
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: polaris
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
---
|
||||
# Source: polaris/templates/webhook.rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
@@ -116,6 +119,7 @@ subjects:
|
||||
name: polaris
|
||||
namespace: polaris
|
||||
---
|
||||
# Source: polaris/templates/webhook.rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: Role
|
||||
metadata:
|
||||
@@ -133,6 +137,7 @@ rules:
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
# Source: polaris/templates/webhook.rbac.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
@@ -194,7 +199,7 @@ spec:
|
||||
command:
|
||||
- polaris
|
||||
- webhook
|
||||
image: 'quay.io/fairwinds/polaris:1.0'
|
||||
image: 'quay.io/fairwinds/polaris:1.1'
|
||||
imagePullPolicy: 'Always'
|
||||
ports:
|
||||
- containerPort: 9876
|
||||
@@ -248,22 +253,3 @@ spec:
|
||||
secretName: polaris-webhook
|
||||
- name: cr-logs
|
||||
emptyDir: {}
|
||||
---
|
||||
# Source: polaris/templates/audit.job.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/audit.rbac.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/configmap.yaml
|
||||
|
||||
|
||||
---
|
||||
# Source: polaris/templates/dashboard.deployment.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/dashboard.service.yaml
|
||||
|
||||
---
|
||||
# Source: polaris/templates/ingress.yaml
|
||||
|
||||
|
||||
@@ -149,6 +149,7 @@ Both the dashboard and audits can run against a local directory or YAML file
|
||||
rather than a cluster:
|
||||
```bash
|
||||
polaris audit --audit-path ./deploy/
|
||||
cat pod.yaml | polaris audit --audit-path -
|
||||
```
|
||||
|
||||
#### Running with CI/CD
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
checks:
|
||||
# reliability
|
||||
multipleReplicasForDeployment: warning
|
||||
priorityClassNotSet: warning
|
||||
# resources
|
||||
cpuRequestsMissing: warning
|
||||
cpuLimitsMissing: warning
|
||||
@@ -9,7 +10,6 @@ checks:
|
||||
# images
|
||||
tagNotSpecified: danger
|
||||
pullPolicyNotAlways: ignore
|
||||
imageRegistry: warning
|
||||
# healthChecks
|
||||
readinessProbeMissing: warning
|
||||
livenessProbeMissing: warning
|
||||
@@ -25,6 +25,9 @@ checks:
|
||||
runAsPrivileged: danger
|
||||
dangerousCapabilities: danger
|
||||
insecureCapabilities: warning
|
||||
# custom
|
||||
resourceLimits: warning
|
||||
imageRegistry: danger
|
||||
|
||||
exemptions:
|
||||
- controllerNames:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
checks:
|
||||
# reliability
|
||||
multipleReplicasForDeployment: ignore
|
||||
priorityClassNotSet: ignore
|
||||
# resources
|
||||
cpuRequestsMissing: warning
|
||||
cpuLimitsMissing: warning
|
||||
|
||||
@@ -3,8 +3,8 @@ module github.com/fairwindsops/polaris
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.56.0
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12
|
||||
cloud.google.com/go v0.58.0
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.7.0
|
||||
git.apache.org/thrift.git v0.12.0 // indirect
|
||||
github.com/Azure/go-autorest v12.4.3+incompatible
|
||||
github.com/Azure/go-autorest/autorest v0.10.0 // indirect
|
||||
@@ -40,7 +40,7 @@ require (
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/imdario/mergo v0.3.9
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/json-iterator/go v1.1.9
|
||||
github.com/json-iterator/go v1.1.10
|
||||
github.com/karrick/godirwalk v1.15.6
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3
|
||||
github.com/markbates/oncer v1.0.0
|
||||
@@ -53,39 +53,39 @@ require (
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/prometheus/client_golang v1.6.0
|
||||
github.com/prometheus/client_golang v1.7.0
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/common v0.10.0
|
||||
github.com/prometheus/procfs v0.0.11
|
||||
github.com/prometheus/procfs v0.1.3
|
||||
github.com/qri-io/jsonschema v0.1.1
|
||||
github.com/rogpeppe/go-internal v1.6.0
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/stretchr/testify v1.6.1
|
||||
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a
|
||||
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179
|
||||
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f
|
||||
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2
|
||||
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe
|
||||
go.opencensus.io v0.22.3
|
||||
go.opencensus.io v0.22.4
|
||||
go.uber.org/atomic v1.6.0
|
||||
go.uber.org/multierr v1.5.0
|
||||
go.uber.org/zap v1.15.0
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299
|
||||
golang.org/x/text v0.3.2
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1
|
||||
golang.org/x/text v0.3.3
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
||||
golang.org/x/tools v0.0.0-20200520220537-cf2d1e09c845
|
||||
google.golang.org/api v0.25.0
|
||||
golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6
|
||||
google.golang.org/api v0.28.0
|
||||
google.golang.org/appengine v1.6.6
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884
|
||||
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482
|
||||
google.golang.org/grpc v1.29.1
|
||||
gopkg.in/inf.v0 v0.9.1
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
k8s.io/api v0.0.0-20181213150558-05914d821849
|
||||
k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93
|
||||
|
||||
@@ -10,21 +10,32 @@ cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
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=
|
||||
cloud.google.com/go v0.56.0 h1:WRz29PgAsVEyPSDHyk+0fpEkwEFyfhHn+JbksT6gIL4=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.58.0 h1:vtAfVc723K3xKq1BQydk/FyCldnaNFhGhpJxaJzgRMQ=
|
||||
cloud.google.com/go v0.58.0/go.mod h1:W+9FnSUw6nhVwXlFcp1eL+krq5+HQUJeUogSeJZZiWg=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJmQxLUh6ey1eJhwyc=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.7.0 h1:BEfdCTXfMV30tLZD8c9n64V/tIZX5+9sXiuFLnrr1k8=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.7.0/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/Azure/go-autorest v1.1.1 h1:4G9tVCqooRY3vDTB2bA1Z01PlSALtnUbji0AfzthUSs=
|
||||
@@ -224,6 +235,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -231,6 +243,7 @@ github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
@@ -239,6 +252,7 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
@@ -249,6 +263,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -260,6 +275,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -315,7 +332,10 @@ github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwK
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
|
||||
@@ -399,6 +419,8 @@ github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
|
||||
github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
|
||||
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
|
||||
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
@@ -423,6 +445,10 @@ github.com/prometheus/procfs v0.0.0-20190519111021-9935e8e0588d/go.mod h1:TjEm7z
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
|
||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.1.0 h1:jhMy6QXfi3y2HEzFoyuCj40z4OZIIHHPtFyCMftmvKA=
|
||||
github.com/prometheus/procfs v0.1.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/qri-io/jsonpointer v0.1.0 h1:OcTtTmorodUCRc2CZhj/ZwOET8zVj6uo0ArEmzoThZI=
|
||||
github.com/qri-io/jsonpointer v0.1.0/go.mod h1:DnJPaYgiKu56EuDp8TU5wFLdZIcAnb/uH9v37ZaMV64=
|
||||
@@ -489,6 +515,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
@@ -514,7 +542,10 @@ go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
@@ -588,6 +619,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
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/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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=
|
||||
@@ -617,8 +650,14 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -675,20 +714,29 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -741,14 +789,22 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
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-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-20200518172458-c79c01b1c51c h1:ZRonYJXo3PhAXRjx2yu3CH6xkANNzT6qBTixDpDmKFY=
|
||||
golang.org/x/tools v0.0.0-20200518172458-c79c01b1c51c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200519205726-57a9e4404bf7 h1:nm4zDh9WvH4jiuUpMY5RUsvOwrtTVVAsUaCdLW71hfY=
|
||||
golang.org/x/tools v0.0.0-20200519205726-57a9e4404bf7/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200520220537-cf2d1e09c845 h1:F4gQH8TKyCccYDuNHX5TfZwiM8QWnPbSPUFE96qvGbs=
|
||||
golang.org/x/tools v0.0.0-20200520220537-cf2d1e09c845/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6 h1:5Y8c5HBW6hBYnGEE3AbJPV0R8RsQmg1/eaJrpvasns0=
|
||||
golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
@@ -766,9 +822,16 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA=
|
||||
google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.26.0 h1:VJZ8h6E8ip82FRpQl848c5vAadxlTXrUh8RzQzSRm08=
|
||||
google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0 h1:jMF5hhVfMkTZwHW1SDpKq5CkgWLXOb31Foaca9Zr3oM=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -799,8 +862,18 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece h1:1YM0uhfumvoDu9sx8+RyWwTI63zoCQvI23IYFRlvte0=
|
||||
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -815,6 +888,7 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@@ -822,8 +896,12 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -845,6 +923,8 @@ gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -857,6 +937,8 @@ honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXe
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
||||
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.0.0-20181213150558-05914d821849 h1:WZFcFPXmLR7g5CxQNmjWv0mg8qulJLxDghbzS4pQtzY=
|
||||
k8s.io/api v0.0.0-20181213150558-05914d821849/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
|
||||
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
const (
|
||||
// Version represents the current release version of Polaris
|
||||
Version = "1.0.3"
|
||||
Version = "1.1.0"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
+13
-1
@@ -16,6 +16,7 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -92,6 +93,17 @@ func Parse(rawBytes []byte) (Configuration, error) {
|
||||
return conf, err
|
||||
}
|
||||
conf.CustomChecks[key] = check
|
||||
if _, ok := conf.Checks[key]; !ok {
|
||||
return conf, fmt.Errorf("no severity specified for custom check %s. Please add the following to your configuration:\n\nchecks:\n %s: warning # or danger/ignore\n\nto enable your check", key, key)
|
||||
}
|
||||
}
|
||||
return conf, nil
|
||||
return conf, conf.Validate()
|
||||
}
|
||||
|
||||
// Validate checks if a config is valid
|
||||
func (c Configuration) Validate() error {
|
||||
if len(c.Checks) == 0 {
|
||||
return errors.New("No checks were enabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -74,6 +74,21 @@ customChecks:
|
||||
}
|
||||
`
|
||||
|
||||
var confCustomChecksMissing = `
|
||||
customChecks:
|
||||
foo:
|
||||
successMessage: Security context is set
|
||||
failureMessage: Security context should be set
|
||||
category: Security
|
||||
target: Container
|
||||
schema:
|
||||
'$schema': http://json-schema.org/draft-07/schema
|
||||
type: object
|
||||
required:
|
||||
- securityContext
|
||||
|
||||
`
|
||||
|
||||
func TestParseError(t *testing.T) {
|
||||
_, err := Parse([]byte(confInvalid))
|
||||
expectedErr := "Decoding config failed: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type config.Configuration"
|
||||
@@ -154,6 +169,11 @@ func TestConfigWithCustomChecks(t *testing.T) {
|
||||
assert.Equal(t, false, isValid)
|
||||
}
|
||||
|
||||
func TestCustomChecksMissingSeverity(t *testing.T) {
|
||||
_, err := Parse([]byte(confCustomChecksMissing))
|
||||
assert.Error(t, err, "Expected error when check has no severity set")
|
||||
}
|
||||
|
||||
func testParsedConfig(t *testing.T, config *Configuration) {
|
||||
assert.Equal(t, SeverityWarning, config.Checks["cpuRequestsMissing"])
|
||||
assert.Equal(t, Severity(""), config.Checks["cpuLimitsMissing"])
|
||||
|
||||
@@ -12,6 +12,7 @@ func (conf Configuration) IsActionable(ruleID, controllerName string) bool {
|
||||
if conf.DisallowExemptions {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, example := range conf.Exemptions {
|
||||
for _, rule := range example.Rules {
|
||||
if rule != ruleID {
|
||||
@@ -23,6 +24,13 @@ func (conf Configuration) IsActionable(ruleID, controllerName string) bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(example.Rules) == 0 {
|
||||
for _, controller := range example.ControllerNames {
|
||||
if strings.HasPrefix(controllerName, controller) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 FairwindsOps Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var confExemptRuleTest = `
|
||||
checks:
|
||||
ANY: warning
|
||||
OTHER: warning
|
||||
exemptions:
|
||||
- controllerNames:
|
||||
- test
|
||||
rules:
|
||||
- ANY
|
||||
`
|
||||
|
||||
var confExemptTest = `
|
||||
checks:
|
||||
ANY: warning
|
||||
exemptions:
|
||||
- controllerNames:
|
||||
- test
|
||||
`
|
||||
|
||||
func TestInclusiveExemption(t *testing.T) {
|
||||
parsedConf, _ := Parse([]byte(confExemptTest))
|
||||
applicable := parsedConf.IsActionable("ANY", "test")
|
||||
applicableOtherController := parsedConf.IsActionable("ANY", "other")
|
||||
|
||||
assert.False(t, applicable, "Expected all checks to be exempted when their controller is specified.")
|
||||
assert.True(t, applicableOtherController, "Expected checks to only be exempted when their controller is specified.")
|
||||
}
|
||||
|
||||
func TestIndividualRuleException(t *testing.T) {
|
||||
parsedConf, _ := Parse([]byte(confExemptRuleTest))
|
||||
applicable := parsedConf.IsActionable("ANY", "test")
|
||||
applicableOtherRule := parsedConf.IsActionable("OTHER", "test")
|
||||
applicableOtherRuleOtherController := parsedConf.IsActionable("OTHER", "other")
|
||||
applicableRuleOtherController := parsedConf.IsActionable("ANY", "other")
|
||||
|
||||
assert.False(t, applicable, "Expected all checks to be exempted when their controller and rule are specified.")
|
||||
assert.True(t, applicableOtherRule, "Expected checks to only be exempted when their controller and rule are specified.")
|
||||
assert.True(t, applicableOtherRuleOtherController, "Expected checks to only be exempted when their controller and rule are specified.")
|
||||
assert.True(t, applicableRuleOtherController, "Expected checks to only be exempted when their controller and rule are specified.")
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.filters .title,
|
||||
.card h3 {
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
@@ -168,7 +169,7 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .caret-expander {
|
||||
.resource-info .caret-expander {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
@@ -179,16 +180,16 @@
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info.expanded .caret-expander {
|
||||
.resource-info.expanded .caret-expander {
|
||||
background-image: url('../images/caret-bottom.svg');
|
||||
background-position: center 2px;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .expandable-content {
|
||||
.resource-info .expandable-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info.expanded .expandable-content {
|
||||
.resource-info.expanded .expandable-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -316,3 +317,46 @@ a.more-info:hover {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
.filters .title {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.filters .caret-expander {
|
||||
margin-bottom: 2px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.filters input[type="checkbox"] {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
|
||||
.filters input[type="submit"] {
|
||||
padding: 4px 10px;
|
||||
box-shadow: none;
|
||||
background-color: #23103A;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
width: 100px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
form.namespace-list {
|
||||
line-height: 20px;
|
||||
margin: 5px 35px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.namespace-row {
|
||||
display: flex;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.namespace-row label {
|
||||
margin-left: 4px;
|
||||
font-size: 20px;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
$(function () {
|
||||
|
||||
// Check selected namespace options on page load
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const currentNamespaces = urlParams.getAll('ns');
|
||||
currentNamespaces.forEach(ns => {
|
||||
$(`input#namespace-${ns}`).prop('checked', true);
|
||||
});
|
||||
|
||||
// Handle new filter submissions
|
||||
$('#namespaceFiltersForm').on('submit', e => {
|
||||
e.preventDefault();
|
||||
let newParams = new URLSearchParams();
|
||||
$('#namespaceFiltersForm input[type="checkbox"]').each((index, checkbox) => {
|
||||
if (checkbox.checked) {
|
||||
newParams.append('ns', checkbox.name);
|
||||
}
|
||||
});
|
||||
window.location = new URL(`?${newParams.toString()}`, window.location).toString();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -81,10 +81,11 @@ func GetMarkdownBox() *packr.Box {
|
||||
|
||||
// templateData is passed to the dashboard HTML template
|
||||
type templateData struct {
|
||||
BasePath string
|
||||
Config config.Configuration
|
||||
AuditData validator.AuditData
|
||||
JSON template.JS
|
||||
BasePath string
|
||||
Config config.Configuration
|
||||
AuditData validator.AuditData
|
||||
FilteredAuditData validator.AuditData
|
||||
JSON template.JS
|
||||
}
|
||||
|
||||
// GetBaseTemplate puts together the dashboard template. Individual pieces can be overridden before rendering.
|
||||
@@ -150,6 +151,16 @@ func getConfigForQuery(base config.Configuration, query url.Values) config.Confi
|
||||
return c
|
||||
}
|
||||
|
||||
func stripUnselectedNamespaces(data *validator.AuditData, selectedNamespaces []string) {
|
||||
newResults := []validator.ControllerResult{}
|
||||
for _, res := range data.Results {
|
||||
if stringInSlice(res.Namespace, selectedNamespaces) {
|
||||
newResults = append(newResults, res)
|
||||
}
|
||||
}
|
||||
data.Results = newResults
|
||||
}
|
||||
|
||||
// GetRouter returns a mux router serving all routes necessary for the dashboard
|
||||
func GetRouter(c config.Configuration, auditPath string, port int, basePath string, auditData *validator.AuditData) *mux.Router {
|
||||
router := mux.NewRouter().PathPrefix(basePath).Subrouter()
|
||||
@@ -237,11 +248,18 @@ func MainHandler(w http.ResponseWriter, r *http.Request, c config.Configuration,
|
||||
return
|
||||
}
|
||||
|
||||
filteredAuditData := auditData
|
||||
namespaces := r.URL.Query()["ns"]
|
||||
if len(namespaces) > 0 {
|
||||
stripUnselectedNamespaces(&filteredAuditData, namespaces)
|
||||
}
|
||||
|
||||
data := templateData{
|
||||
BasePath: basePath,
|
||||
AuditData: auditData,
|
||||
JSON: template.JS(jsonData),
|
||||
Config: c,
|
||||
BasePath: basePath,
|
||||
AuditData: auditData,
|
||||
FilteredAuditData: filteredAuditData,
|
||||
JSON: template.JS(jsonData),
|
||||
Config: c,
|
||||
}
|
||||
tmpl, err := GetBaseTemplate("main")
|
||||
if err != nil {
|
||||
|
||||
@@ -23,11 +23,21 @@ import (
|
||||
)
|
||||
|
||||
func getWarningWidth(counts validator.CountSummary, fullWidth int) uint {
|
||||
return uint(float64(counts.Successes+counts.Warnings) / float64(counts.Successes+counts.Warnings+counts.Dangers) * float64(fullWidth))
|
||||
denom := counts.Successes + counts.Warnings + counts.Dangers
|
||||
if denom == 0 {
|
||||
return uint(0)
|
||||
}
|
||||
res := float64(counts.Successes+counts.Warnings) / float64(denom) * float64(fullWidth)
|
||||
return uint(res)
|
||||
}
|
||||
|
||||
func getSuccessWidth(counts validator.CountSummary, fullWidth int) uint {
|
||||
return uint(float64(counts.Successes) / float64(counts.Successes+counts.Warnings+counts.Dangers) * float64(fullWidth))
|
||||
denom := counts.Successes + counts.Warnings + counts.Dangers
|
||||
if denom == 0 {
|
||||
return uint(0)
|
||||
}
|
||||
res := float64(counts.Successes) / float64(denom) * float64(fullWidth)
|
||||
return uint(res)
|
||||
}
|
||||
|
||||
func getGrade(counts validator.CountSummary) string {
|
||||
@@ -161,3 +171,12 @@ func getCategoryInfo(category string) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func stringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
<div class="cluster-score">
|
||||
<div class="score-details">
|
||||
<div class="weather"><i class="fas {{ getWeatherIcon .AuditData.GetSummary }}"></i></div>
|
||||
<div class="sailing">{{ getWeatherText .AuditData.GetSummary }}</div>
|
||||
<div class="scores"><span>Grade: </span><strong>{{ getGrade .AuditData.GetSummary }}</strong></div>
|
||||
<div class="scores"><span>Score: </span><strong>{{ .AuditData.GetSummary.GetScore }}%</strong></div>
|
||||
<div class="sailing">{{ getWeatherText .FilteredAuditData.GetSummary }}</div>
|
||||
<div class="scores"><span>Grade: </span><strong>{{ getGrade .FilteredAuditData.GetSummary }}</strong></div>
|
||||
<div class="scores"><span>Score: </span><strong>{{ .FilteredAuditData.GetSummary.GetScore }}%</strong></div>
|
||||
<p class="score-description">
|
||||
Score is the percentage of passing checks. Warnings get half the weight of dangerous checks.
|
||||
</p>
|
||||
@@ -26,21 +26,21 @@
|
||||
<li class="success">
|
||||
<i class="message-icon fas fa-check"></i>
|
||||
<div class="message-group">
|
||||
<span class="count"> {{ .AuditData.GetSummary.Successes }}</span>
|
||||
<span class="count"> {{ .FilteredAuditData.GetSummary.Successes }}</span>
|
||||
<span class="message"> passing checks</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="failure warning">
|
||||
<i class="message-icon fas fa-exclamation"></i>
|
||||
<div class="message-group">
|
||||
<span class="count"> {{ .AuditData.GetSummary.Warnings }}</span>
|
||||
<span class="count"> {{ .FilteredAuditData.GetSummary.Warnings }}</span>
|
||||
<span class="message"> warning checks</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="failure danger">
|
||||
<i class="message-icon fas fa-times"></i>
|
||||
<div class="message-group">
|
||||
<span class="count"> {{ .AuditData.GetSummary.Dangers }}</span>
|
||||
<span class="count"> {{ .FilteredAuditData.GetSummary.Dangers }}</span>
|
||||
<span class="message"> dangerous checks</span>
|
||||
</div>
|
||||
</li>
|
||||
@@ -51,23 +51,23 @@
|
||||
<div class="kubernetes-stats">
|
||||
<div class="kubernetes-stat">
|
||||
<span>Kubernetes Version:</span>
|
||||
<strong>{{.AuditData.ClusterInfo.Version}}</strong>
|
||||
<strong>{{.FilteredAuditData.ClusterInfo.Version}}</strong>
|
||||
</div>
|
||||
<div class="kubernetes-stat">
|
||||
<span>Nodes:</span>
|
||||
<strong>{{.AuditData.ClusterInfo.Nodes}}</strong>
|
||||
<strong>{{.FilteredAuditData.ClusterInfo.Nodes}}</strong>
|
||||
</div>
|
||||
<div class="kubernetes-stat">
|
||||
<span>Namespaces:</span>
|
||||
<strong>{{.AuditData.ClusterInfo.Namespaces}}</strong>
|
||||
<strong>{{.FilteredAuditData.ClusterInfo.Namespaces}}</strong>
|
||||
</div>
|
||||
<div class="kubernetes-stat">
|
||||
<span>Controllers:</span>
|
||||
<strong>{{.AuditData.ClusterInfo.Controllers}}</strong>
|
||||
<strong>{{.FilteredAuditData.ClusterInfo.Controllers}}</strong>
|
||||
</div>
|
||||
<div class="kubernetes-stat">
|
||||
<span>Pods:</span>
|
||||
<strong>{{.AuditData.ClusterInfo.Pods}}</strong>
|
||||
<strong>{{.FilteredAuditData.ClusterInfo.Pods}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,7 +76,7 @@
|
||||
<div class="card category">
|
||||
<h3>Results by Category</h3>
|
||||
<div class="expandable-table">
|
||||
{{ range $category, $summary := .AuditData.GetSummaryByCategory }}
|
||||
{{ range $category, $summary := .FilteredAuditData.GetSummaryByCategory }}
|
||||
<div class="resource-info">
|
||||
<div class="status-bar">
|
||||
<div class="status">
|
||||
@@ -88,7 +88,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="name"><span class="caret-expander"></span>{{ $category }}<span class="category-score">Score: <strong>{{ $summary.GetScore }}%</strong></span></div>
|
||||
<div class="result-messages expandable-content">
|
||||
<div class="result-messages expandable-content">
|
||||
<p class="category-info">{{ getCategoryInfo $category }} Refer to the <a href="details/{{ getCategoryLink $category }}">Polaris documentation about {{ $category }}</a> for more information.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,7 +96,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ range $namespace, $ctrlResults := .AuditData.GetResultsByNamespace }}
|
||||
<div class="card filters">
|
||||
<div class="resource-info">
|
||||
<div class="name">
|
||||
<span class="caret-expander"></span>
|
||||
<span class="title">Filter by Namespace</span>
|
||||
</div>
|
||||
<div class="result-messages expandable-content">
|
||||
<form id="namespaceFiltersForm" class="namespace-list">
|
||||
{{ range $namespace, $ctrlResults := .AuditData.GetResultsByNamespace }}
|
||||
<div class="namespace-row">
|
||||
<input type="checkbox" name="{{ $namespace }}" id="namespace-{{ $namespace }}">
|
||||
<label for="namespace-{{ $namespace }}">{{ $namespace }}</label>
|
||||
</div>
|
||||
{{ end }}
|
||||
<input type="submit" value="Apply">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ range $namespace, $ctrlResults := .FilteredAuditData.GetResultsByNamespace }}
|
||||
<div class="card namespace">
|
||||
<h3>Namespace: <strong>{{ $namespace }}</strong></h3>
|
||||
<div class="expandable-table">
|
||||
@@ -150,6 +170,6 @@
|
||||
</div>
|
||||
</div>
|
||||
{{ end }} {{/* end range .AuditData.GetResultsByNamespace */}}
|
||||
<script src="static/js/charts.js">
|
||||
</script>
|
||||
<script src="static/js/charts.js"></script>
|
||||
<script src="static/js/filter.js"></script>
|
||||
{{end}}
|
||||
|
||||
+78
-55
@@ -2,7 +2,7 @@ package kube
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
k8sYaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -61,8 +60,14 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
|
||||
Controllers: []GenericWorkload{},
|
||||
}
|
||||
|
||||
addYaml := func(contents string) error {
|
||||
return addResourceFromString(contents, &resources)
|
||||
if directory == "-" {
|
||||
fi, err := os.Stdin.Stat()
|
||||
if err == nil && fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
|
||||
if err := addResourcesFromReader(os.Stdin, &resources); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resources, nil
|
||||
}
|
||||
}
|
||||
|
||||
visitFile := func(path string, f os.FileInfo, err error) error {
|
||||
@@ -74,18 +79,7 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
|
||||
logrus.Errorf("Error reading file: %v", path)
|
||||
return err
|
||||
}
|
||||
specs := regexp.MustCompile("\n-+\n").Split(string(contents), -1)
|
||||
for _, spec := range specs {
|
||||
if strings.TrimSpace(spec) == "" {
|
||||
continue
|
||||
}
|
||||
err = addYaml(spec)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error parsing YAML: (%v)", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return addResourcesFromYaml(string(contents), &resources)
|
||||
}
|
||||
|
||||
err := filepath.Walk(directory, visitFile)
|
||||
@@ -167,20 +161,6 @@ func CreateResourceProviderFromAPI(kube kubernetes.Interface, clusterName string
|
||||
return &api, nil
|
||||
}
|
||||
|
||||
func cacheAllObjectsOfKind(dynamicClient dynamic.Interface, groupVersionResource schema.GroupVersionResource, objectCache map[string]unstructured.Unstructured) error {
|
||||
objects, err := dynamicClient.Resource(groupVersionResource).Namespace("").List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Warnf("Error retrieving parent object API %s and Kind %s because of error: %v ", groupVersionResource.Version, groupVersionResource.Resource, err)
|
||||
return err
|
||||
}
|
||||
for idx, object := range objects.Items {
|
||||
|
||||
key := fmt.Sprintf("%s/%s/%s", object.GetKind(), object.GetNamespace(), object.GetName())
|
||||
objectCache[key] = objects.Items[idx]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadControllers loads a list of controllers from the kubeResources Pods
|
||||
func LoadControllers(pods []corev1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) ([]GenericWorkload, error) {
|
||||
interfaces := []GenericWorkload{}
|
||||
@@ -228,7 +208,71 @@ func GetPodSpec(yaml map[string]interface{}) interface{} {
|
||||
return GetPodSpec(childYaml.(map[string]interface{}))
|
||||
}
|
||||
}
|
||||
return yaml
|
||||
if _, ok := yaml["containers"]; ok {
|
||||
return yaml
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addResourcesFromReader(reader io.Reader, resources *ResourceProvider) error {
|
||||
contents, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error reading from %v: %v", reader, err)
|
||||
return err
|
||||
}
|
||||
if err := addResourcesFromYaml(string(contents), resources); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addResourcesFromYaml(contents string, resources *ResourceProvider) error {
|
||||
specs := regexp.MustCompile("[\r\n]-+[\r\n]").Split(string(contents), -1)
|
||||
for _, spec := range specs {
|
||||
if strings.TrimSpace(spec) == "" {
|
||||
continue
|
||||
}
|
||||
err := addResourceFromString(spec, resources)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error parsing YAML: (%v)", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWorkloadFromBytes parses a GenericWorkload
|
||||
func GetWorkloadFromBytes(contentBytes []byte) (*GenericWorkload, error) {
|
||||
yamlNode := make(map[string]interface{})
|
||||
err := yaml.Unmarshal(contentBytes, &yamlNode)
|
||||
if err != nil {
|
||||
logrus.Errorf("Invalid YAML: %s", string(contentBytes))
|
||||
return nil, err
|
||||
}
|
||||
finalDoc := make(map[string]interface{})
|
||||
finalDoc["metadata"] = yamlNode["metadata"]
|
||||
finalDoc["apiVersion"] = "v1"
|
||||
finalDoc["kind"] = "Pod"
|
||||
podSpec := GetPodSpec(yamlNode)
|
||||
if podSpec == nil {
|
||||
return nil, nil
|
||||
}
|
||||
finalDoc["spec"] = podSpec
|
||||
marshaledYaml, err := yaml.Marshal(finalDoc)
|
||||
if err != nil {
|
||||
logrus.Errorf("Could not marshal yaml: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
decoder := k8sYaml.NewYAMLOrJSONDecoder(bytes.NewReader(marshaledYaml), 1000)
|
||||
pod := corev1.Pod{}
|
||||
err = decoder.Decode(&pod)
|
||||
newController, err := NewGenericWorkloadFromPod(pod, yamlNode)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newController.Kind = yamlNode["kind"].(string)
|
||||
return &newController, nil
|
||||
}
|
||||
|
||||
func addResourceFromString(contents string, resources *ResourceProvider) error {
|
||||
@@ -258,32 +302,11 @@ func addResourceFromString(contents string, resources *ResourceProvider) error {
|
||||
}
|
||||
resources.Controllers = append(resources.Controllers, workload)
|
||||
} else {
|
||||
yamlNode := make(map[string]interface{})
|
||||
err = yaml.Unmarshal(contentBytes, &yamlNode)
|
||||
if err != nil {
|
||||
logrus.Errorf("Invalid YAML: %s", string(contents))
|
||||
newController, err := GetWorkloadFromBytes(contentBytes)
|
||||
if err != nil || newController == nil {
|
||||
return err
|
||||
}
|
||||
finalDoc := make(map[string]interface{})
|
||||
finalDoc["metadata"] = yamlNode["metadata"]
|
||||
finalDoc["apiVersion"] = "v1"
|
||||
finalDoc["kind"] = "Pod"
|
||||
finalDoc["spec"] = GetPodSpec(yamlNode)
|
||||
marshaledYaml, err := yaml.Marshal(finalDoc)
|
||||
if err != nil {
|
||||
logrus.Errorf("Could not marshal yaml: %v", err)
|
||||
return err
|
||||
}
|
||||
decoder := k8sYaml.NewYAMLOrJSONDecoder(bytes.NewReader(marshaledYaml), 1000)
|
||||
pod := corev1.Pod{}
|
||||
err = decoder.Decode(&pod)
|
||||
newController, err := NewGenericWorkloadFromPod(pod, yamlNode)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newController.Kind = resource.Kind
|
||||
resources.Controllers = append(resources.Controllers, newController)
|
||||
resources.Controllers = append(resources.Controllers, *newController)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package kube
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fairwindsops/polaris/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func TestGetResourcesFromPath(t *testing.T) {
|
||||
@@ -44,7 +47,7 @@ func TestGetMultipleResourceFromSingleFile(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
|
||||
|
||||
assert.Equal(t, 4, len(resources.Controllers), "Should have four controllers")
|
||||
assert.Equal(t, 1, len(resources.Controllers), "Should have one controller")
|
||||
assert.Equal(t, "dashboard", resources.Controllers[0].PodSpec.Containers[0].Name)
|
||||
|
||||
assert.Equal(t, 2, len(resources.Namespaces), "Should have a namespace")
|
||||
@@ -57,6 +60,31 @@ func TestGetMultipleResourceFromBadFile(t *testing.T) {
|
||||
assert.NotEqual(t, nil, err, "CreateResource From Path should fail with bad yaml")
|
||||
}
|
||||
|
||||
func TestAddResourcesFromReader(t *testing.T) {
|
||||
contents, err := ioutil.ReadFile("./test_files/test_2/multi.yaml")
|
||||
assert.NoError(t, err)
|
||||
reader := bytes.NewBuffer(contents)
|
||||
resources := &ResourceProvider{
|
||||
ServerVersion: "unknown",
|
||||
SourceType: "Path",
|
||||
SourceName: "-",
|
||||
Nodes: []corev1.Node{},
|
||||
Namespaces: []corev1.Namespace{},
|
||||
Controllers: []GenericWorkload{},
|
||||
}
|
||||
err = addResourcesFromReader(reader, resources)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
|
||||
|
||||
assert.Equal(t, 1, len(resources.Controllers), "Should have one controller")
|
||||
assert.Equal(t, "dashboard", resources.Controllers[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)
|
||||
assert.Equal(t, "polaris-2", resources.Namespaces[1].ObjectMeta.Name)
|
||||
}
|
||||
|
||||
func TestGetResourceFromAPI(t *testing.T) {
|
||||
k8s, dynamicInterface := test.SetupTestAPI()
|
||||
k8s = test.SetupAddControllers(k8s, "test")
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: test-service
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: test
|
||||
+24
-14
@@ -2,7 +2,6 @@ package kube
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -39,13 +38,11 @@ func NewGenericWorkloadFromPod(podResource kubeAPICoreV1.Pod, originalObject int
|
||||
}
|
||||
|
||||
// NewGenericWorkload builds a new workload for a given Pod
|
||||
func NewGenericWorkload(podResource kubeAPICoreV1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericWorkload, error) {
|
||||
func NewGenericWorkload(podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericWorkload, error) {
|
||||
workload, err := NewGenericWorkloadFromPod(podResource, nil)
|
||||
if err != nil {
|
||||
return workload, err
|
||||
}
|
||||
dynamicClient := *dynamicClientPointer
|
||||
restMapper := *restMapperPointer
|
||||
// If an owner exists then set the name to the workload.
|
||||
// This allows us to handle CRDs creating Workloads or DeploymentConfigs in OpenShift.
|
||||
owners := workload.ObjectMeta.GetOwnerReferences()
|
||||
@@ -63,22 +60,15 @@ func NewGenericWorkload(podResource kubeAPICoreV1.Pod, dynamicClientPointer *dyn
|
||||
lastKey = key
|
||||
abstractObject, ok := objectCache[key]
|
||||
if !ok {
|
||||
fqKind := schema.FromAPIVersionAndKind(firstOwner.APIVersion, firstOwner.Kind)
|
||||
mapping, err := restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
|
||||
err = cacheAllObjectsOfKind(firstOwner.APIVersion, firstOwner.Kind, dynamicClient, restMapper, objectCache)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error retrieving mapping %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
|
||||
return workload, err
|
||||
}
|
||||
|
||||
err = cacheAllObjectsOfKind(dynamicClient, mapping.Resource, objectCache)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error getting objects of Kind %s %v", firstOwner.Kind, err)
|
||||
logrus.Warnf("Error caching objects of Kind %s %v", firstOwner.Kind, err)
|
||||
return workload, nil // Note -we don't return an error so we can recover from the case where RBAC is insufficient
|
||||
}
|
||||
abstractObject, ok = objectCache[key]
|
||||
if !ok {
|
||||
logrus.Errorf("Cache missed %s again", key)
|
||||
return workload, errors.New("Could not retrieve parent object")
|
||||
return workload, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,3 +96,23 @@ func NewGenericWorkload(podResource kubeAPICoreV1.Pod, dynamicClientPointer *dyn
|
||||
}
|
||||
return workload, nil
|
||||
}
|
||||
|
||||
func cacheAllObjectsOfKind(apiVersion, kind string, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) error {
|
||||
fqKind := schema.FromAPIVersionAndKind(apiVersion, kind)
|
||||
mapping, err := (*restMapper).RESTMapping(fqKind.GroupKind(), fqKind.Version)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error retrieving mapping of API %s and Kind %s because of error: %v ", apiVersion, kind, err)
|
||||
return err
|
||||
}
|
||||
|
||||
objects, err := (*dynamicClient).Resource(mapping.Resource).Namespace("").List(kubeAPIMetaV1.ListOptions{})
|
||||
if err != nil {
|
||||
logrus.Warnf("Error retrieving parent object API %s and Kind %s because of error: %v ", mapping.Resource.Version, mapping.Resource.Resource, err)
|
||||
return err
|
||||
}
|
||||
for idx, object := range objects.Items {
|
||||
key := fmt.Sprintf("%s/%s/%s", object.GetKind(), object.GetNamespace(), object.GetName())
|
||||
objectCache[key] = objects.Items[idx]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ var (
|
||||
"privilegeEscalationAllowed",
|
||||
"dangerousCapabilities",
|
||||
"insecureCapabilities",
|
||||
"priorityClassNotSet",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package webhook
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
@@ -101,6 +102,9 @@ func (v *Validator) handleInternal(ctx context.Context, req types.Request) (*val
|
||||
return nil, err
|
||||
}
|
||||
podMap := kube.GetPodSpec(decoded)
|
||||
if podMap == nil {
|
||||
return nil, errors.New("Object does not contain pods")
|
||||
}
|
||||
encoded, err := json.Marshal(podMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
helm template $CHARTS_DIR/stable/polaris/ \
|
||||
--name polaris --namespace polaris \
|
||||
helm template polaris $CHARTS_DIR/stable/polaris/ \
|
||||
--namespace polaris \
|
||||
--set templateOnly=true \
|
||||
> deploy/dashboard.yaml
|
||||
|
||||
helm template $CHARTS_DIR/stable/polaris/ \
|
||||
--name polaris --namespace polaris \
|
||||
helm template polaris $CHARTS_DIR/stable/polaris/ \
|
||||
--namespace polaris \
|
||||
--set templateOnly=true \
|
||||
--set webhook.enable=true \
|
||||
--set dashboard.enable=false \
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
priorityClassName: high-priority
|
||||
@@ -0,0 +1,72 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/fairwindsops/polaris/pkg/config"
|
||||
"github.com/fairwindsops/polaris/pkg/kube"
|
||||
"github.com/fairwindsops/polaris/pkg/validator"
|
||||
)
|
||||
|
||||
var testCases = []testCase{}
|
||||
|
||||
type testCase struct {
|
||||
check string
|
||||
input []byte
|
||||
failure bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
_, baseDir, _, _ := runtime.Caller(0)
|
||||
baseDir = filepath.Dir(baseDir) + "/checks"
|
||||
dirs, err := ioutil.ReadDir(baseDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, dir := range dirs {
|
||||
check := dir.Name()
|
||||
checkDir := baseDir + "/" + check
|
||||
cases, err := ioutil.ReadDir(checkDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, tc := range cases {
|
||||
body, err := ioutil.ReadFile(checkDir + "/" + tc.Name())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testCases = append(testCases, testCase{
|
||||
check: check,
|
||||
input: body,
|
||||
failure: strings.Contains(tc.Name(), "failure"),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestChecks(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
workload, err := kube.GetWorkloadFromBytes(tc.input)
|
||||
assert.NoError(t, err)
|
||||
c, err := config.Parse([]byte("checks:\n " + tc.check + ": danger"))
|
||||
assert.NoError(t, err)
|
||||
result, err := validator.ValidateController(&c, *workload)
|
||||
assert.NoError(t, err)
|
||||
summary := result.GetSummary()
|
||||
if tc.failure {
|
||||
message := "Check " + tc.check + " passed unexpectedly"
|
||||
assert.Equal(t, uint(0), summary.Successes, message)
|
||||
assert.Equal(t, uint(1), summary.Dangers, message)
|
||||
} else {
|
||||
message := "Check " + tc.check + " failed unexpectedly"
|
||||
assert.Equal(t, uint(1), summary.Successes, message)
|
||||
assert.Equal(t, uint(0), summary.Dangers, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user