feat(k8s): cyclonedx kbom support (#4557)

* feat: cyclonedx kbom support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: cyclonedx kbom support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sum db

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sum db

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sumdb

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sumdb

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

---------

Signed-off-by: chenk <hen.keinan@gmail.com>
This commit is contained in:
chenk
2023-06-19 13:48:26 +03:00
committed by GitHub
parent 0e01851e9e
commit 35c4262d0b
19 changed files with 1551 additions and 443 deletions

View File

@@ -43,7 +43,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg:
--exclude-nodes strings indicate the node labels that the node-collector job should exclude from scanning (example: kubernetes.io/arch:arm64,team:dev)
--exit-code int specify exit code when any security issues are found
--file-patterns strings specify config file patterns
-f, --format string format (table, json, template, sarif, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table")
-f, --format string format (table, json, cyclonedx) (default "table")
--helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)
--helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)

View File

@@ -343,3 +343,16 @@ Trivy has a native [Kubernetes Operator][operator] which continuously scans your
[operator]: https://kubernetes.io/docs/concepts/extend-kubernetes/operator/
[crd]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
[trivy-operator]: https://aquasecurity.github.io/trivy-operator/latest
## SBOM
Trivy supports the generation of Kubernetes Bill of Materials (KBOM) for kubernetes cluster control plane components, node components and addons.
## KBOM
KBOM, Kubernetes Bill of Materials, is a manifest of all the important components that make up your Kubernetes cluster Control plane components, Node Components, and Addons, including their versions and images. Which “api-server” version are you currently running? Which flavor of “kubelet” is running on each node? What kind of etcd or storage are you currently using? And most importantly are there any vulnerabilities known to affect these components? These are all questions that KBOM can help you answer.
Trivy can generate KBOM in CycloneDX format:
```sh
trivy k8s cluster --format cyclonedx
```

58
go.mod
View File

@@ -13,7 +13,7 @@ require (
github.com/NYTimes/gziphandler v1.1.1
github.com/alicebob/miniredis/v2 v2.30.3
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
github.com/aquasecurity/defsec v0.89.0
github.com/aquasecurity/defsec v0.89.1-0.20230616215656-269528cc9b42
github.com/aquasecurity/go-dep-parser v0.0.0-20230614075854-30b52f543be9
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
@@ -25,7 +25,7 @@ require (
github.com/aquasecurity/tml v0.6.1
github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728
github.com/aquasecurity/trivy-kubernetes v0.5.4
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230619083756-6eb60789faeb
github.com/aws/aws-sdk-go v1.44.245
github.com/aws/aws-sdk-go-v2 v1.18.0
github.com/aws/aws-sdk-go-v2/config v1.18.25
@@ -67,6 +67,7 @@ require (
github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd
github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/mitchellh/mapstructure v1.5.0
github.com/moby/buildkit v0.11.5
github.com/open-policy-agent/opa v0.45.0
github.com/opencontainers/go-digest v1.0.0
@@ -101,7 +102,7 @@ require (
google.golang.org/protobuf v1.30.0
gopkg.in/yaml.v3 v3.0.1
gotest.tools v2.2.0+incompatible
k8s.io/api v0.26.3
k8s.io/api v0.27.2
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5
modernc.org/sqlite v1.20.3
)
@@ -126,8 +127,8 @@ require (
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/squirrel v1.5.3 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.10.0-rc.7 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
@@ -226,16 +227,16 @@ require (
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
github.com/go-gorp/gorp/v3 v3.0.5 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/spec v0.20.9 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
@@ -264,7 +265,7 @@ require (
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/hcl/v2 v2.14.1 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
@@ -280,7 +281,7 @@ require (
github.com/liamg/iamgo v0.0.9 // indirect
github.com/liamg/jfather v0.0.7 // indirect
github.com/liamg/memoryfs v1.4.3 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/magiconair/properties v1.8.7 // indirect
@@ -294,7 +295,6 @@ require (
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
@@ -328,11 +328,11 @@ require (
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rubenv/sql-migrate v1.2.0 // indirect
github.com/rubenv/sql-migrate v1.3.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/skeema/knownhosts v1.1.1 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@@ -371,17 +371,16 @@ require (
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.1.0 // indirect
helm.sh/helm/v3 v3.11.1 // indirect
k8s.io/apiextensions-apiserver v0.26.0 // indirect
k8s.io/apimachinery v0.26.3 // indirect
k8s.io/apiserver v0.26.2 // indirect
k8s.io/cli-runtime v0.26.3 // indirect
k8s.io/client-go v0.26.3 // indirect
k8s.io/component-base v0.26.3 // indirect
helm.sh/helm/v3 v3.12.1 // indirect
k8s.io/apiextensions-apiserver v0.27.2 // indirect
k8s.io/apimachinery v0.27.2 // indirect
k8s.io/apiserver v0.27.2 // indirect
k8s.io/cli-runtime v0.27.2 // indirect
k8s.io/client-go v0.27.2 // indirect
k8s.io/component-base v0.27.2 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/kubectl v0.26.3 // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
k8s.io/kubectl v0.27.2 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
@@ -392,13 +391,12 @@ require (
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
oras.land/oras-go v1.2.2 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/kustomize/api v0.12.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.13.2 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
// v1.2.0 is taken from github.com/open-policy-agent/opa v0.42.0
// v1.2.0 incompatible with github.com/docker/docker v23.0.0-rc.1+incompatible
replace oras.land/oras-go => oras.land/oras-go v1.1.1
// oras 1.2.2 is incompatible with github.com/docker/docker v23.0.0-rc.1+incompatible
replace oras.land/oras-go => oras.land/oras-go v1.2.3

152
go.sum
View File

@@ -242,19 +242,19 @@ github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible h1:juIa
github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.0/go.mod h1:tWhwTbUTndesPNeF0C900vKoq283u6zp4APT9vaF3SI=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc=
github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@@ -292,6 +292,7 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/O
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
@@ -320,8 +321,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/defsec v0.89.0 h1:5B0mJYraNa2n5zlYuShqOwRt5kqFXdVfGPRYiZJPDuw=
github.com/aquasecurity/defsec v0.89.0/go.mod h1:te+KhIV8w1pDIjTsUQwlc6xRn8gC7f+TJUiFhLlcEHM=
github.com/aquasecurity/defsec v0.89.1-0.20230616215656-269528cc9b42 h1:PGoTTb5b40hZGW+fHVLFWwUkxWQJp8HKJMf82SR61Q8=
github.com/aquasecurity/defsec v0.89.1-0.20230616215656-269528cc9b42/go.mod h1:3AgfRdHLPbT9kcAMaj6f9LX7WgihbNta8sPycrSqHTw=
github.com/aquasecurity/go-dep-parser v0.0.0-20230614075854-30b52f543be9 h1:HbSquJbXpWwv8wuoXXb0mZWzsUhDUIgFpjln4woH9YA=
github.com/aquasecurity/go-dep-parser v0.0.0-20230614075854-30b52f543be9/go.mod h1:fEMyM+83y5N9m0Deh0bmTGiiNwpceUtBA67s7WXOfvM=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
@@ -346,14 +347,15 @@ github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c h1:mFMfHmb5G
github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c/go.mod h1:s7x7CTxYeiFf6gPOakSsg4mCD93au4dbYplG4h0FGrs=
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 h1:0eS+V7SXHgqoT99tV1mtMW6HL4HdoB9qGLMCb1fZp8A=
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
github.com/aquasecurity/trivy-kubernetes v0.5.4 h1:1UwEjcIxkY+VixlV734zixStq7oNjy5C4qJ5wy1mXU8=
github.com/aquasecurity/trivy-kubernetes v0.5.4/go.mod h1:rc2mGtn71vS+FDVXS3RjEpWXR+nph6GBS6fXdqhitFc=
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230619083756-6eb60789faeb h1:5htNYck1farYXZrNfTuAgfULRQJnK73eQ+1Rj1CE8tA=
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230619083756-6eb60789faeb/go.mod h1:GCm7uq++jz7Ij8cA9mAorpKJ9/qSBCl7v6EKYA8DxJ8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
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/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
@@ -769,13 +771,15 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwC
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897 h1:E52jfcE64UG42SwLmrW0QByONfGynWuzBvm86BoB9z8=
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -788,8 +792,8 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
@@ -800,8 +804,8 @@ github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhc
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=
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
github.com/go-gorp/gorp/v3 v3.0.5 h1:PUjzYdYu3HBOh8LE+UUmRG2P0IRDak9XMeGNvaeq4Ow=
github.com/go-gorp/gorp/v3 v3.0.5/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -826,13 +830,15 @@ github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2uj
github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk=
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/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
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/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro=
github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw=
@@ -862,11 +868,10 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
@@ -1124,14 +1129,16 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
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.8/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/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU=
@@ -1203,7 +1210,9 @@ 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/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -1225,9 +1234,9 @@ github.com/liamg/jfather v0.0.7/go.mod h1:xXBGiBoiZ6tmHhfy5Jzw8sugzajwYdi6VosIpB
github.com/liamg/memoryfs v1.4.3 h1:+ChjcuPRYpjJSulD13PXDNR3JeJ5HUYKjLHyWVK0bqU=
github.com/liamg/memoryfs v1.4.3/go.mod h1:z7mfqXFQS8eSeBBsFjYLlxYRMRyiPktytvYCYTb3BSk=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
@@ -1269,6 +1278,7 @@ github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlW
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -1277,6 +1287,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@@ -1287,10 +1298,9 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
@@ -1303,7 +1313,7 @@ github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7Xn
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.4/go.mod h1:vTLESy5mRhKOs9KDp0/RATawxP1UqBmdrpVRMnpcvKQ=
github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
@@ -1369,6 +1379,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nelsam/hel/v2 v2.3.2/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w=
github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
@@ -1385,13 +1397,13 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
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.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
github.com/open-policy-agent/opa v0.45.0 h1:P5nuhVRtR+e58fk3CMMbiqr6ZFyWQPNOC3otsorGsFs=
github.com/open-policy-agent/opa v0.45.0/go.mod h1:/OnsYljNEWJ6DXeFOOnoGn8CvwZGMUS4iRqzYdJvmBI=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -1461,8 +1473,10 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1 h1:oL4IBbcqwhhNWh31bjOX8C/OCy0zs9906d/VUru+bqg=
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/poy/onpar v0.0.0-20200406201722-06f95a1c68e8/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU=
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -1513,10 +1527,12 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rubenv/sql-migrate v1.2.0 h1:fOXMPLMd41sK7Tg75SXDec15k3zg5WNV6SjuDRiNfcU=
github.com/rubenv/sql-migrate v1.2.0/go.mod h1:Z5uVnq7vrIrPmHbVFfR4YLHRZquxeHpckCnRq0P/K9Y=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rubenv/sql-migrate v1.3.1 h1:Vx+n4Du8X8VTYuXbhNxdEUoh6wiJERA0GlWocR5FrbA=
github.com/rubenv/sql-migrate v1.3.1/go.mod h1:YzG/Vh82CwyhTFXy+Mf5ahAiiEOpAlHurg+23VEzcsk=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -1537,8 +1553,9 @@ github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sigstore/rekor v1.2.1 h1:cEI4qn9IBvM7EkPQYl3YzCwCw97Mx8O2nHrv02XiI8U=
github.com/sigstore/rekor v1.2.1/go.mod h1:zcFO54qIg2G1/i0sE/nvmELUOng/n0MPjTszRYByVPo=
@@ -1572,10 +1589,12 @@ github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
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.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
@@ -1698,8 +1717,6 @@ github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0=
github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
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=
@@ -1774,6 +1791,7 @@ golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
@@ -1887,6 +1905,7 @@ golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfS
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
@@ -2062,9 +2081,11 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
@@ -2073,6 +2094,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
@@ -2088,6 +2110,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
@@ -2142,6 +2165,7 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
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-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
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=
@@ -2455,16 +2479,16 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk=
gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ=
helm.sh/helm/v3 v3.11.1 h1:cmL9fFohOoNQf+wnp2Wa0OhNFH0KFnSzEkVxi3fcc3I=
helm.sh/helm/v3 v3.11.1/go.mod h1:z/Bu/BylToGno/6dtNGuSmjRqxKq5gaH+FU0BPO+AQ8=
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
helm.sh/helm/v3 v3.12.1 h1:lzU7etZX24A6BTMXYQF3bFq0ECfD8s+fKlNBBL8AbEc=
helm.sh/helm/v3 v3.12.1/go.mod h1:qhmSY9kcX7yH1xebe+FDMZa7E5NAeZ+LvK5j1gSln48=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -2475,32 +2499,32 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU=
k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE=
k8s.io/apiextensions-apiserver v0.26.0 h1:Gy93Xo1eg2ZIkNX/8vy5xviVSxwQulsnUdQ00nEdpDo=
k8s.io/apiextensions-apiserver v0.26.0/go.mod h1:7ez0LTiyW5nq3vADtK6C3kMESxadD51Bh6uz3JOlqWQ=
k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo=
k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4=
k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo=
k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ=
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k=
k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg=
k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
k8s.io/apiserver v0.26.2 h1:Pk8lmX4G14hYqJd1poHGC08G03nIHVqdJMR0SD3IH3o=
k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8=
k8s.io/cli-runtime v0.26.3 h1:3ULe0oI28xmgeLMVXIstB+ZL5CTGvWSMVMLeHxitIuc=
k8s.io/cli-runtime v0.26.3/go.mod h1:5YEhXLV4kLt/OSy9yQwtSSNZU2Z7aTEYta1A+Jg4VC4=
k8s.io/apiserver v0.27.2 h1:p+tjwrcQEZDrEorCZV2/qE8osGTINPuS5ZNqWAvKm5E=
k8s.io/apiserver v0.27.2/go.mod h1:EsOf39d75rMivgvvwjJ3OW/u9n1/BmUMK5otEOJrb1Y=
k8s.io/cli-runtime v0.27.2 h1:9HI8gfReNujKXt16tGOAnb8b4NZ5E+e0mQQHKhFGwYw=
k8s.io/cli-runtime v0.27.2/go.mod h1:9UecpyPDTkhiYY4d9htzRqN+rKomJgyb4wi0OfrmCjw=
k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s=
k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ=
k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE=
k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ=
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
k8s.io/component-base v0.26.3 h1:oC0WMK/ggcbGDTkdcqefI4wIZRYdK3JySx9/HADpV0g=
k8s.io/component-base v0.26.3/go.mod h1:5kj1kZYwSC6ZstHJN7oHBqcJC6yyn41eR+Sqa/mQc8E=
k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo=
k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo=
k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
@@ -2511,10 +2535,10 @@ k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
k8s.io/kubectl v0.26.3 h1:bZ5SgFyeEXw6XTc1Qji0iNdtqAC76lmeIIQULg2wNXM=
k8s.io/kubectl v0.26.3/go.mod h1:02+gv7Qn4dupzN3fi/9OvqqdW+uG/4Zi56vc4Zmsp1g=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
k8s.io/kubectl v0.27.2 h1:sSBM2j94MHBFRWfHIWtEXWCicViQzZsb177rNsKBhZg=
k8s.io/kubectl v0.27.2/go.mod h1:GCOODtxPcrjh+EC611MqREkU8RjYBh10ldQCQ6zpFKw=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk=
@@ -2543,19 +2567,19 @@ modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
oras.land/oras-go v1.1.1 h1:gI00ftziRivKXaw1BdMeEoIA4uBgga33iVlOsEwefFs=
oras.land/oras-go v1.1.1/go.mod h1:n2TE1ummt9MUyprGhT+Q7kGZUF4kVUpYysPFxeV2IpQ=
oras.land/oras-go v1.2.3 h1:v8PJl+gEAntI1pJ/LCrDgsuk+1PKVavVEPsYIHFE5uY=
oras.land/oras-go v1.2.3/go.mod h1:M/uaPdYklze0Vf3AakfarnpoEckvw0ESbRdN8Z1vdJg=
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.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.13.2 h1:kejWfLeJhUsTGioDoFNJET5LQe/ajzXhJGYoU+pJsiA=
sigs.k8s.io/kustomize/api v0.13.2/go.mod h1:DUp325VVMFVcQSq+ZxyDisA8wtldwHxLZbr1g94UHsw=
sigs.k8s.io/kustomize/kyaml v0.14.1 h1:c8iibius7l24G2wVAGZn/Va2wNys03GXLjYVIcFVxKA=
sigs.k8s.io/kustomize/kyaml v0.14.1/go.mod h1:AN1/IpawKilWD7V+YvQwRGUvuUOOWpjsHu6uHwonSF4=
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.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=

View File

@@ -8,63 +8,105 @@ import (
"path/filepath"
"testing"
cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/aquasecurity/trivy/pkg/k8s/report"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/k8s/report"
"github.com/aquasecurity/trivy/pkg/types"
)
// Note: the test required k8s (kind) cluster installed.
// "mage test:k8s" will run this test.
func TestK8s(t *testing.T) {
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
t.Run("misconfig and vulnerability scan", func(t *testing.T) {
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
osArgs := []string{
"k8s",
"cluster",
"--report",
"summary",
"-q",
"--timeout",
"5m0s",
"--format",
"json",
"--components",
"workload",
"--context",
"kind-kind-test",
"--output",
outputFile,
}
osArgs := []string{
"k8s",
"cluster",
"--report",
"summary",
"-q",
"--timeout",
"5m0s",
"--format",
"json",
"--components",
"workload",
"--context",
"kind-kind-test",
"--output",
outputFile,
}
// Run Trivy
err := execute(osArgs)
require.NoError(t, err)
// Run Trivy
err := execute(osArgs)
require.NoError(t, err)
var got report.ConsolidatedReport
f, err := os.Open(outputFile)
require.NoError(t, err)
defer f.Close()
var got report.ConsolidatedReport
f, err := os.Open(outputFile)
require.NoError(t, err)
defer f.Close()
err = json.NewDecoder(f).Decode(&got)
require.NoError(t, err)
err = json.NewDecoder(f).Decode(&got)
require.NoError(t, err)
// Flatten findings
results := lo.FlatMap(got.Findings, func(resource report.Resource, _ int) []types.Result {
return resource.Results
// Flatten findings
results := lo.FlatMap(got.Findings, func(resource report.Resource, _ int) []types.Result {
return resource.Results
})
// Has vulnerabilities
assert.True(t, lo.SomeBy(results, func(r types.Result) bool {
return len(r.Vulnerabilities) > 0
}))
// Has misconfigurations
assert.True(t, lo.SomeBy(results, func(r types.Result) bool {
return len(r.Misconfigurations) > 0
}))
})
t.Run("kbom cycloneDx", func(t *testing.T) {
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
osArgs := []string{
"k8s",
"cluster",
"--format",
"cyclonedx",
"-q",
"--context",
"kind-kind-test",
"--output",
outputFile,
}
// Has vulnerabilities
assert.True(t, lo.SomeBy(results, func(r types.Result) bool {
return len(r.Vulnerabilities) > 0
}))
// Run Trivy
err := execute(osArgs)
require.NoError(t, err)
// Has misconfigurations
assert.True(t, lo.SomeBy(results, func(r types.Result) bool {
return len(r.Misconfigurations) > 0
}))
}
var got *cdx.BOM
f, err := os.Open(outputFile)
require.NoError(t, err)
defer f.Close()
err = json.NewDecoder(f).Decode(&got)
require.NoError(t, err)
assert.Equal(t, got.Metadata.Component.Name, "kind-kind-test")
assert.Equal(t, got.Metadata.Component.Type, cdx.ComponentType("container"))
// Has components
assert.True(t, len(*got.Components) > 0)
// Has dependecies
assert.True(t, lo.SomeBy(*got.Dependencies, func(r cdx.Dependency) bool {
return len(*r.Dependencies) > 0
}))
})
}

View File

@@ -28,6 +28,7 @@ import (
"github.com/aquasecurity/trivy/pkg/module"
"github.com/aquasecurity/trivy/pkg/plugin"
"github.com/aquasecurity/trivy/pkg/policy"
r "github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -896,6 +897,10 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand.
reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'
formatFlag := flag.FormatFlag
formatFlag.Usage = "format (" + strings.Join([]string{r.FormatTable, r.FormatJSON, r.FormatCycloneDX}, ", ") + ")"
reportFlagGroup.Format = &formatFlag
k8sFlags := &flag.Flags{
CacheFlagGroup: flag.NewCacheFlagGroup(),
DBFlagGroup: flag.NewDBFlagGroup(),

View File

@@ -117,10 +117,15 @@ func (o *Options) Align() {
}
// Vulnerability scanning is disabled by default for CycloneDX.
if o.Format == report.FormatCycloneDX && !viper.IsSet(ScannersFlag.ConfigName) {
if o.Format == report.FormatCycloneDX && !viper.IsSet(ScannersFlag.ConfigName) && len(o.K8sOptions.Components) == 0 { // remove K8sOptions.Components validation check when vuln scan is supported for k8s report with cycloneDX
log.Logger.Info(`"--format cyclonedx" disables security scanning. Specify "--scanners vuln" explicitly if you want to include vulnerabilities in the CycloneDX report.`)
o.Scanners = nil
}
if o.Format == report.FormatCycloneDX && len(o.K8sOptions.Components) > 0 {
log.Logger.Info(`"k8s with --format cyclonedx" disable security scanning`)
o.Scanners = nil
}
}
// RegistryOpts returns options for OCI registries

View File

@@ -11,6 +11,7 @@ import (
"github.com/aquasecurity/trivy-kubernetes/pkg/trivyk8s"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -21,16 +22,26 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err
}
var artifacts []*artifacts.Artifact
var err error
if opts.Scanners.AnyEnabled(types.MisconfigScanner) && slices.Contains(opts.Components, "infra") {
artifacts, err = trivyk8s.New(cluster, log.Logger).ListArtifactAndNodeInfo(ctx, opts.NodeCollectorNamespace, opts.ExcludeNodes, opts.Tolerations...)
switch opts.Format {
case report.FormatCycloneDX:
artifacts, err = trivyk8s.New(cluster, log.Logger).ListBomInfo(ctx)
if err != nil {
return xerrors.Errorf("get k8s artifacts with node info error: %w", err)
}
} else {
artifacts, err = trivyk8s.New(cluster, log.Logger).ListArtifacts(ctx)
if err != nil {
return xerrors.Errorf("get k8s artifacts error: %w", err)
case report.FormatJSON, report.FormatTable:
if opts.Scanners.AnyEnabled(types.MisconfigScanner) && slices.Contains(opts.Components, "infra") {
artifacts, err = trivyk8s.New(cluster, log.Logger).ListArtifactAndNodeInfo(ctx, opts.NodeCollectorNamespace, opts.ExcludeNodes, opts.Tolerations...)
if err != nil {
return xerrors.Errorf("get k8s artifacts with node info error: %w", err)
}
} else {
artifacts, err = trivyk8s.New(cluster, log.Logger).ListArtifacts(ctx)
if err != nil {
return xerrors.Errorf("get k8s artifacts error: %w", err)
}
}
default:
return xerrors.Errorf(`unknown format %q. Use "json" or "table" or "cyclonedx"`, opts.Format)
}
runner := newRunner(opts, cluster.GetCurrentContext())

View File

@@ -13,6 +13,7 @@ import (
"github.com/aquasecurity/trivy/pkg/commands/operation"
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
"github.com/aquasecurity/trivy/pkg/flag"
k8sRep "github.com/aquasecurity/trivy/pkg/k8s"
"github.com/aquasecurity/trivy/pkg/k8s/report"
"github.com/aquasecurity/trivy/pkg/k8s/scanner"
"github.com/aquasecurity/trivy/pkg/log"
@@ -88,8 +89,8 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error
}
r.flagOpts.ScanOptions.Scanners = scanners
}
rpt, err := s.Scan(ctx, artifacts)
var rpt report.Report
rpt, err = s.Scan(ctx, artifacts)
if err != nil {
return xerrors.Errorf("k8s scan error: %w", err)
}
@@ -110,13 +111,14 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error
})
}
if err := report.Write(rpt, report.Option{
if err := k8sRep.Write(rpt, report.Option{
Format: r.flagOpts.Format,
Report: r.flagOpts.ReportFormat,
Output: r.flagOpts.Output,
Severities: r.flagOpts.Severities,
Components: r.flagOpts.Components,
Scanners: r.flagOpts.ScanOptions.Scanners,
APIVersion: r.flagOpts.AppVersion,
}); err != nil {
return xerrors.Errorf("unable to write results: %w", err)
}

View File

@@ -0,0 +1,30 @@
package report
import (
"io"
cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
)
// CycloneDXWriter implements types.Writer
type CycloneDXWriter struct {
encoder cdx.BOMEncoder
marshaler *core.CycloneDX
}
// NewCycloneDXWriter constract new CycloneDXWriter
func NewCycloneDXWriter(output io.Writer, format cdx.BOMFileFormat, appVersion string, opts ...core.Option) CycloneDXWriter {
encoder := cdx.NewBOMEncoder(output, format)
encoder.SetPretty(true)
return CycloneDXWriter{
encoder: encoder,
marshaler: core.NewCycloneDX(appVersion, opts...),
}
}
func (w CycloneDXWriter) Write(component *core.Component) error {
bom := w.marshaler.Marshal(component)
return w.encoder.Encode(bom)
}

View File

@@ -19,18 +19,19 @@ func (jw JSONWriter) Write(report Report) error {
var err error
switch jw.Report {
case allReport:
case AllReport:
output, err = json.MarshalIndent(report, "", " ")
case summaryReport:
if err != nil {
return xerrors.Errorf("failed to write json: %w", err)
}
case SummaryReport:
output, err = json.MarshalIndent(report.consolidate(), "", " ")
if err != nil {
return xerrors.Errorf("failed to write json: %w", err)
}
default:
return xerrors.Errorf(`report %q not supported. Use "summary" or "all"`, jw.Report)
}
if err != nil {
return xerrors.Errorf("failed to marshal json: %w", err)
}
if _, err = fmt.Fprintln(jw.Output, string(output)); err != nil {
return xerrors.Errorf("failed to write json: %w", err)
}

View File

@@ -7,22 +7,18 @@ import (
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"golang.org/x/xerrors"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/report/table"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
"github.com/aquasecurity/trivy/pkg/types"
)
const (
allReport = "all"
summaryReport = "summary"
tableFormat = "table"
jsonFormat = "json"
AllReport = "all"
SummaryReport = "summary"
workloadComponent = "workload"
infraComponent = "infra"
@@ -36,13 +32,15 @@ type Option struct {
ColumnHeading []string
Scanners types.Scanners
Components []string
APIVersion string
}
// Report represents a kubernetes scan report
type Report struct {
SchemaVersion int `json:",omitempty"`
ClusterName string
Resources []Resource `json:",omitempty"`
Resources []Resource `json:",omitempty"`
RootComponent *core.Component `json:"-"`
name string
}
@@ -125,54 +123,16 @@ type Writer interface {
Write(Report) error
}
// Write writes the results in the give format
func Write(report Report, option Option) error {
report.printErrors()
switch option.Format {
case jsonFormat:
jwriter := JSONWriter{
Output: option.Output,
Report: option.Report,
}
return jwriter.Write(report)
case tableFormat:
separatedReports := separateMisconfigReports(report, option.Scanners, option.Components)
if option.Report == summaryReport {
target := fmt.Sprintf("Summary Report for %s", report.ClusterName)
table.RenderTarget(option.Output, target, table.IsOutputToTerminal(option.Output))
}
for _, r := range separatedReports {
writer := &TableWriter{
Output: option.Output,
Report: option.Report,
Severities: option.Severities,
ColumnHeading: ColumnHeading(option.Scanners, option.Components, r.columns),
}
if err := writer.Write(r.report); err != nil {
return err
}
}
return nil
default:
return xerrors.Errorf(`unknown format %q. Use "json" or "table"`, option.Format)
}
}
type reports struct {
report Report
columns []string
Report Report
Columns []string
}
// separateMisconfigReports returns 3 reports based on scanners and components flags,
// SeparateMisconfigReports returns 3 reports based on scanners and components flags,
// - misconfiguration report
// - rbac report
// - infra checks report
func separateMisconfigReports(k8sReport Report, scanners types.Scanners, components []string) []reports {
func SeparateMisconfigReports(k8sReport Report, scanners types.Scanners, components []string) []reports {
workloadMisconfig := make([]Resource, 0)
infraMisconfig := make([]Resource, 0)
@@ -221,21 +181,21 @@ func separateMisconfigReports(k8sReport Report, scanners types.Scanners, compone
len(workloadMisconfig) > 0) ||
len(workloadVulnerabilities) > 0 {
r = append(r, reports{
report: workloadReport,
columns: WorkloadColumns(),
Report: workloadReport,
Columns: WorkloadColumns(),
})
}
}
if scanners.Enabled(types.RBACScanner) && len(rbacAssessment) > 0 {
r = append(r, reports{
report: Report{
Report: Report{
SchemaVersion: 0,
ClusterName: k8sReport.ClusterName,
Resources: rbacAssessment,
name: "RBAC Assessment",
},
columns: RoleColumns(),
Columns: RoleColumns(),
})
}
@@ -244,13 +204,13 @@ func separateMisconfigReports(k8sReport Report, scanners types.Scanners, compone
len(infraMisconfig) > 0 {
r = append(r, reports{
report: Report{
Report: Report{
SchemaVersion: 0,
ClusterName: k8sReport.ClusterName,
Resources: infraMisconfig,
name: "Infra Assessment",
},
columns: InfraColumns(),
Columns: InfraColumns(),
})
}
@@ -293,7 +253,7 @@ func CreateResource(artifact *artifacts.Artifact, report types.Report, err error
return r
}
func (r Report) printErrors() {
func (r Report) PrintErrors() {
for _, resource := range r.Resources {
if resource.Error != "" {
log.Logger.Errorf("Error during vulnerabilities or misconfiguration scan: %s", resource.Error)

View File

@@ -1,9 +1,6 @@
package report
import (
"bytes"
"regexp"
"strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -564,238 +561,15 @@ func Test_separateMisconfigReports(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reports := separateMisconfigReports(tt.k8sReport, tt.scanners, tt.components)
reports := SeparateMisconfigReports(tt.k8sReport, tt.scanners, tt.components)
assert.Equal(t, len(tt.expectedReports), len(reports))
for i := range reports {
assert.Equal(t, len(tt.expectedReports[i].Resources), len(reports[i].report.Resources))
assert.Equal(t, len(tt.expectedReports[i].Resources), len(reports[i].Report.Resources))
for j, m := range tt.expectedReports[i].Resources {
assert.Equal(t, m.Kind, reports[i].report.Resources[j].Kind)
assert.Equal(t, m.Kind, reports[i].Report.Resources[j].Kind)
}
}
})
}
}
func TestReportWrite_Summary(t *testing.T) {
allSeverities := []dbTypes.Severity{
dbTypes.SeverityUnknown,
dbTypes.SeverityLow,
dbTypes.SeverityMedium,
dbTypes.SeverityHigh,
dbTypes.SeverityCritical,
}
tests := []struct {
name string
report Report
opt Option
scanners types.Scanners
components []string
severities []dbTypes.Severity
expectedOutput string
}{
{
name: "Only config, all serverities",
report: Report{
ClusterName: "test",
Resources: []Resource{deployOrionWithMisconfigs},
},
scanners: types.Scanners{types.MisconfigScanner},
components: []string{workloadComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬──────────────┬───────────────────┐
│ Namespace │ Resource │ Misconfigurations │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼──────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/orion │ 1 │ 2 │ 1 │ 2 │ 1 │
└───────────┴──────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only vuln, all serverities",
report: Report{
ClusterName: "test",
Resources: []Resource{deployOrionWithVulns},
},
scanners: types.Scanners{types.VulnerabilityScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬──────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼──────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/orion │ 2 │ 1 │ 2 │ 1 │ 1 │
└───────────┴──────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only rbac, all serverities",
report: Report{
ClusterName: "test",
Resources: []Resource{roleWithMisconfig},
},
scanners: types.Scanners{types.RBACScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
RBAC Assessment
┌───────────┬─────────────────────────────────────────────────────┬───────────────────┐
│ Namespace │ Resource │ RBAC Assessment │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼─────────────────────────────────────────────────────┼───┼───┼───┼───┼───┤
│ default │ Role/system::leader-locking-kube-controller-manager │ │ │ 1 │ │ │
└───────────┴─────────────────────────────────────────────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only secret, all serverities",
report: Report{
ClusterName: "test",
Resources: []Resource{deployLuaWithSecrets},
},
scanners: types.Scanners{types.SecretScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬────────────┬───────────────────┐
│ Namespace │ Resource │ Secrets │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/lua │ 1 │ │ 1 │ │ │
└───────────┴────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, only infra and serverities",
report: Report{
ClusterName: "test",
Resources: []Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{types.MisconfigScanner},
components: []string{infraComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Infra Assessment
┌─────────────┬────────────────────┬─────────────────────────────┐
│ Namespace │ Resource │ Kubernetes Infra Assessment │
│ │ ├─────┬─────┬─────┬─────┬─────┤
│ │ │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼─────┼─────┼─────┼─────┼─────┤
│ kube-system │ Pod/kube-apiserver │ │ │ 1 │ 1 │ │
└─────────────┴────────────────────┴─────┴─────┴─────┴─────┴─────┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, vuln,config,secret and serverities",
report: Report{
ClusterName: "test",
Resources: []Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{
types.VulnerabilityScanner,
types.MisconfigScanner,
types.SecretScanner,
},
components: []string{workloadComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌─────────────┬────────────────────┬───────────────────┬───────────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │
│ │ ├───┬───┬───┬───┬───┼───┬───┬───┬───┬───┼───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│ kube-system │ Pod/kube-apiserver │ │ │ │ │ │ │ 1 │ 1 │ 1 │ │ │ │ │ │ │
└─────────────┴────────────────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, all scanners and serverities",
report: Report{
ClusterName: "test",
Resources: []Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{
types.MisconfigScanner,
types.VulnerabilityScanner,
types.RBACScanner,
types.SecretScanner,
},
components: []string{
workloadComponent,
infraComponent,
},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌─────────────┬────────────────────┬───────────────────┬───────────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │
│ │ ├───┬───┬───┬───┬───┼───┬───┬───┬───┬───┼───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│ kube-system │ Pod/kube-apiserver │ │ │ │ │ │ │ 1 │ 1 │ 1 │ │ │ │ │ │ │
└─────────────┴────────────────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN
Infra Assessment
┌─────────────┬────────────────────┬─────────────────────────────┐
│ Namespace │ Resource │ Kubernetes Infra Assessment │
│ │ ├─────┬─────┬─────┬─────┬─────┤
│ │ │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼─────┼─────┼─────┼─────┼─────┤
│ kube-system │ Pod/kube-apiserver │ │ │ 1 │ 1 │ │
└─────────────┴────────────────────┴─────┴─────┴─────┴─────┴─────┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
output := bytes.Buffer{}
opt := Option{
Format: "table",
Report: "summary",
Output: &output,
Scanners: tc.scanners,
Severities: tc.severities,
Components: tc.components,
}
Write(tc.report, opt)
assert.Equal(t, tc.expectedOutput, stripAnsi(output.String()), tc.name)
})
}
}
const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
var ansiRegexp = regexp.MustCompile(ansi)
func stripAnsi(str string) string {
return strings.TrimSpace(ansiRegexp.ReplaceAllString(str, ""))
}

View File

@@ -41,7 +41,7 @@ func InfraColumns() []string {
func (tw TableWriter) Write(report Report) error {
switch tw.Report {
case allReport:
case AllReport:
t := pkgReport.Writer{Output: tw.Output, Severities: tw.Severities, ShowMessageOnce: &sync.Once{}}
for _, r := range report.Resources {
if r.Report.Results.Failed() {
@@ -51,7 +51,7 @@ func (tw TableWriter) Write(report Report) error {
}
}
}
case summaryReport:
case SummaryReport:
writer := NewSummaryWriter(tw.Output, tw.Severities, tw.ColumnHeading)
return writer.Write(report)
default:

View File

@@ -1,16 +1,33 @@
package scanner
import (
"bytes"
"context"
"fmt"
"strings"
"golang.org/x/xerrors"
ms "github.com/mitchellh/mapstructure"
"github.com/package-url/packageurl-go"
"github.com/aquasecurity/go-version/pkg/version"
cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
"github.com/aquasecurity/trivy-kubernetes/pkg/bom"
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
"github.com/aquasecurity/trivy/pkg/digest"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/k8s/report"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/parallel"
"github.com/aquasecurity/trivy/pkg/purl"
rep "github.com/aquasecurity/trivy/pkg/report"
cyc "github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
"github.com/aquasecurity/trivy/pkg/scanner/local"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -47,6 +64,17 @@ func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact)
log.Fatal(xerrors.Errorf("can't enable logger error: %w", err))
}
}()
if s.opts.Format == rep.FormatCycloneDX {
rootComponent, err := clusterInfoToReportResources(artifactsData, s.cluster)
if err != nil {
return report.Report{}, err
}
return report.Report{
SchemaVersion: 0,
RootComponent: rootComponent,
}, nil
}
var resources []report.Resource
type scanResult struct {
@@ -89,6 +117,7 @@ func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact)
ClusterName: s.cluster,
Resources: resources,
}, nil
}
func (s *Scanner) scanVulns(ctx context.Context, artifact *artifacts.Artifact) ([]report.Resource, error) {
@@ -143,3 +172,169 @@ func (s *Scanner) filter(ctx context.Context, r types.Report, artifact *artifact
}
return report.CreateResource(artifact, r, nil), nil
}
const (
golang = "golang"
oci = "oci"
kubelet = "k8s.io/kubelet"
pod = "PodInfo"
nodeInfo = "NodeInfo"
nodeCoreComponents = "node-core-components"
)
func clusterInfoToReportResources(allArtifact []*artifacts.Artifact, clusterName string) (*core.Component, error) {
coreComponents := make([]*core.Component, 0)
for _, artifact := range allArtifact {
switch artifact.Kind {
case pod:
var comp bom.Component
err := ms.Decode(artifact.RawResource, &comp)
if err != nil {
return nil, err
}
imageComponents := make([]*core.Component, 0)
for _, c := range comp.Containers {
name := fmt.Sprintf("%s/%s", c.Registry, c.Repository)
cDigest := c.Digest
if strings.Index(c.Digest, string(digest.SHA256)) == -1 {
cDigest = fmt.Sprintf("%s:%s", string(digest.SHA256), cDigest)
}
version := sanitizedVersion(c.Version)
imagePURL, err := purl.NewPackageURL(purl.TypeOCI, types.Metadata{
RepoDigests: []string{
fmt.Sprintf("%s@%s", name, cDigest),
},
}, ftypes.Package{})
if err != nil {
return nil, xerrors.Errorf("failed to create PURL: %w", err)
}
imageComponents = append(imageComponents, &core.Component{
PackageURL: &imagePURL,
Type: cdx.ComponentTypeContainer,
Name: name,
Version: cDigest,
Properties: map[string]string{
cyc.PropertyPkgID: fmt.Sprintf("%s:%s", name, version),
cyc.PropertyPkgType: oci,
},
})
}
rootComponent := &core.Component{
Name: comp.Name,
Type: cdx.ComponentTypeApplication,
Properties: comp.Properties,
Components: imageComponents,
}
coreComponents = append(coreComponents, rootComponent)
case nodeInfo:
var nf bom.NodeInfo
err := ms.Decode(artifact.RawResource, &nf)
if err != nil {
return nil, err
}
coreComponents = append(coreComponents, nodeComponent(nf))
default:
return nil, fmt.Errorf("resource kind %s is not supported", artifact.Kind)
}
}
rootComponent := &core.Component{
Name: clusterName,
Type: cdx.ComponentTypeContainer,
Components: coreComponents,
}
return rootComponent, nil
}
func sanitizedVersion(version string) string {
return strings.TrimPrefix(version, "v")
}
func osNameVersion(name string) (string, string) {
var buffer bytes.Buffer
var v string
var err error
parts := strings.Split(name, " ")
for _, p := range parts {
_, err = version.Parse(p)
if err != nil {
buffer.WriteString(p + " ")
continue
}
v = p
break
}
return strings.ToLower(strings.TrimSpace(buffer.String())), v
}
func runtimeNameVersion(name string) (string, string) {
parts := strings.Split(name, "://")
if len(parts) == 2 {
name := parts[0]
switch parts[0] {
case "cri-o":
name = "github.com/cri-o/cri-o"
case "containerd":
name = "github.com/containerd/containerd"
case "cri-dockerd":
name = "github.com/Mirantis/cri-dockerd"
}
return name, parts[1]
}
return "", ""
}
func nodeComponent(nf bom.NodeInfo) *core.Component {
osName, osVersion := osNameVersion(nf.OsImage)
runtimeName, runtimeVersion := runtimeNameVersion(nf.ContainerRuntimeVersion)
kubeletVersion := sanitizedVersion(nf.KubeletVersion)
return &core.Component{
Type: cdx.ComponentTypeContainer,
Name: nf.NodeName,
Properties: nf.Properties,
Components: []*core.Component{
{
Type: cdx.ComponentTypeOS,
Name: osName,
Version: osVersion,
Properties: map[string]string{
"Class": types.ClassOSPkg,
"Type": osName,
},
},
{
Type: cdx.ComponentTypeApplication,
Name: nodeCoreComponents,
Properties: map[string]string{
"Class": types.ClassLangPkg,
"Type": golang,
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeLibrary,
Name: kubelet,
Version: kubeletVersion,
Properties: map[string]string{
cyc.PropertyPkgType: golang,
},
PackageURL: &purl.PackageURL{
PackageURL: *packageurl.NewPackageURL(golang, "", kubelet, kubeletVersion, packageurl.Qualifiers{}, ""),
},
},
{
Type: cdx.ComponentTypeLibrary,
Name: runtimeName,
Version: runtimeVersion,
Properties: map[string]string{
cyc.PropertyPkgType: golang,
},
PackageURL: &purl.PackageURL{
PackageURL: *packageurl.NewPackageURL(golang, "", runtimeName, runtimeVersion, packageurl.Qualifiers{}, ""),
},
},
},
},
},
}
}

View File

@@ -0,0 +1,246 @@
package scanner
import (
"context"
"sort"
"testing"
cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/package-url/packageurl-go"
"github.com/aquasecurity/trivy/pkg/flag"
cyc "github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
"github.com/stretchr/testify/assert"
)
func TestK8sClusterInfoReport(t *testing.T) {
flagOpts := flag.Options{ReportOptions: flag.ReportOptions{Format: "cyclonedx"}}
tests := []struct {
name string
clusterName string
artifacts []*artifacts.Artifact
want *core.Component
}{
{
name: "test cluster info with resources",
clusterName: "test-cluster",
artifacts: []*artifacts.Artifact{
{
Namespace: "kube-system",
Kind: "PodInfo",
Name: "kube-apiserver-kind-control-plane",
RawResource: map[string]interface{}{
"Containers": []interface{}{map[string]interface{}{
"Digest": "18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
"ID": "kube-apiserver:v1.21.1",
"Registry": "k8s.gcr.io",
"Repository": "kube-apiserver",
"Version": "v1.21.1",
},
},
"Properties": map[string]string{
"ControlPlaneComponents": "kube-apiserver",
},
"Name": "kube-apiserver-kind-control-plane",
"Namespace": "kube-system",
},
},
{
Kind: "NodeInfo",
Name: "kind-control-plane",
RawResource: map[string]interface{}{
"ContainerRuntimeVersion": "containerd://1.5.2",
"Hostname": "kind-control-plane",
"KubeProxyVersion": "6.2.13-300.fc38.aarch64",
"KubeletVersion": "v1.21.1",
"NodeName": "kind-control-plane",
"OsImage": "Ubuntu 21.04",
"Properties": map[string]string{
"Architecture": "arm64",
"HostName": "kind-control-plane",
"KernelVersion": "6.2.15-300.fc38.aarch64",
"NodeRole": "master",
"OperatingSystem": "linux",
},
},
},
},
want: &core.Component{
Type: cdx.ComponentTypeContainer,
Name: "test-cluster",
Components: []*core.Component{
{
Type: cdx.ComponentTypeApplication,
Name: "kube-apiserver-kind-control-plane",
Properties: map[string]string{
"ControlPlaneComponents": "kube-apiserver",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeContainer,
Name: "k8s.gcr.io/kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Type: "oci",
Name: "kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
Qualifiers: packageurl.Qualifiers{
{
Key: "repository_url",
Value: "k8s.gcr.io/kube-apiserver",
},
{
Key: "arch",
},
},
},
},
Properties: map[string]string{
cyc.PropertyPkgID: "k8s.gcr.io/kube-apiserver:1.21.1",
cyc.PropertyPkgType: "oci",
},
},
},
},
{
Type: cdx.ComponentTypeContainer,
Name: "kind-control-plane",
Properties: map[string]string{
"Architecture": "arm64",
"HostName": "kind-control-plane",
"KernelVersion": "6.2.15-300.fc38.aarch64",
"NodeRole": "master",
"OperatingSystem": "linux",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeOS,
Name: "ubuntu",
Version: "21.04",
Properties: map[string]string{
"Class": "os-pkgs",
"Type": "ubuntu",
},
},
{
Type: cdx.ComponentTypeApplication,
Name: "node-core-components",
Properties: map[string]string{
"Class": "lang-pkgs",
"Type": "golang",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeLibrary,
Name: "k8s.io/kubelet",
Version: "1.21.1",
Properties: map[string]string{
"PkgType": "golang",
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Type: "golang",
Name: "k8s.io/kubelet",
Version: "1.21.1",
Qualifiers: packageurl.Qualifiers{},
},
},
},
{
Type: cdx.ComponentTypeLibrary,
Name: "github.com/containerd/containerd",
Version: "1.5.2",
Properties: map[string]string{
cyc.PropertyPkgType: "golang",
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Type: "golang",
Name: "github.com/containerd/containerd",
Version: "1.5.2",
Qualifiers: packageurl.Qualifiers{},
},
},
},
},
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.TODO()
runner, err := cmd.NewRunner(ctx, flagOpts)
assert.NoError(t, err)
scanner := NewScanner(tt.clusterName, runner, flagOpts)
got, err := scanner.Scan(ctx, tt.artifacts)
sortNodeComponents(got.RootComponent)
sortNodeComponents(tt.want)
assert.Equal(t, tt.want, got.RootComponent)
})
}
}
func sortNodeComponents(component *core.Component) {
nodeComp := findComponentByName(component, "node-core-components")
sort.Slice(nodeComp.Components, func(i, j int) bool {
return nodeComp.Components[i].Name < nodeComp.Components[j].Name
})
}
func findComponentByName(component *core.Component, compName string) *core.Component {
if component.Name == compName {
return component
}
var fComp *core.Component
for _, comp := range component.Components {
fComp = findComponentByName(comp, compName)
}
return fComp
}
func TestTestOsNameVersion(t *testing.T) {
tests := []struct {
name string
nameVersion string
compName string
compVersion string
}{
{
name: "valid version",
nameVersion: "ubuntu 20.04",
compName: "ubuntu",
compVersion: "20.04",
},
{
name: "valid sem version",
nameVersion: "ubuntu 20.04.1",
compName: "ubuntu",
compVersion: "20.04.1",
},
{
name: "non valid version",
nameVersion: "ubuntu",
compName: "ubuntu",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
name, version := osNameVersion(tt.nameVersion)
assert.Equal(t, name, tt.compName)
assert.Equal(t, version, tt.compVersion)
})
}
}

56
pkg/k8s/writer.go Normal file
View File

@@ -0,0 +1,56 @@
package k8s
import (
"fmt"
"github.com/aquasecurity/trivy/pkg/k8s/report"
cdx "github.com/CycloneDX/cyclonedx-go"
rp "github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/report/table"
)
type Writer interface {
Write(report.Report) error
}
// Write writes the results in the give format
func Write(k8sreport report.Report, option report.Option) error {
k8sreport.PrintErrors()
switch option.Format {
case rp.FormatJSON:
jwriter := report.JSONWriter{
Output: option.Output,
Report: option.Report,
}
return jwriter.Write(k8sreport)
case rp.FormatTable:
separatedReports := report.SeparateMisconfigReports(k8sreport, option.Scanners, option.Components)
if option.Report == report.SummaryReport {
target := fmt.Sprintf("Summary Report for %s", k8sreport.ClusterName)
table.RenderTarget(option.Output, target, table.IsOutputToTerminal(option.Output))
}
for _, r := range separatedReports {
writer := &report.TableWriter{
Output: option.Output,
Report: option.Report,
Severities: option.Severities,
ColumnHeading: report.ColumnHeading(option.Scanners, option.Components, r.Columns),
}
if err := writer.Write(r.Report); err != nil {
return err
}
}
return nil
case rp.FormatCycloneDX:
w := report.NewCycloneDXWriter(option.Output, cdx.BOMFileFormatJSON, option.APIVersion)
return w.Write(k8sreport.RootComponent)
}
return nil
}

409
pkg/k8s/writer_test.go Normal file
View File

@@ -0,0 +1,409 @@
package k8s
import (
"bytes"
"regexp"
"strings"
"testing"
"github.com/stretchr/testify/assert"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/k8s/report"
"github.com/aquasecurity/trivy/pkg/types"
)
const (
AllReport = "all"
SummaryReport = "summary"
tableFormat = "table"
jsonFormat = "json"
cycloneDXFormat = "cyclonedx"
workloadComponent = "workload"
infraComponent = "infra"
)
var (
roleWithMisconfig = report.Resource{
Namespace: "default",
Kind: "Role",
Name: "system::leader-locking-kube-controller-manager",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "ID100",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
},
},
},
}
apiseverPodWithMisconfigAndInfra = report.Resource{
Namespace: "kube-system",
Kind: "Pod",
Name: "kube-apiserver",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "KSV-ID100",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "KSV-ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
{
ID: "KSV-ID102",
Status: types.StatusFailure,
Severity: "HIGH",
},
{
ID: "KCV-ID100",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "KCV-ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
},
},
},
}
deployLuaWithSecrets = report.Resource{
Namespace: "default",
Kind: "Deploy",
Name: "lua",
Results: types.Results{
{
Secrets: []ftypes.SecretFinding{
{
RuleID: "secret1",
Severity: "CRITICAL",
},
{
RuleID: "secret2",
Severity: "MEDIUM",
},
},
},
},
}
deployOrionWithMisconfigs = report.Resource{
Namespace: "default",
Kind: "Deploy",
Name: "orion",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "ID100",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
{
ID: "ID102",
Status: types.StatusFailure,
Severity: "HIGH",
},
{
ID: "ID103",
Status: types.StatusFailure,
Severity: "CRITICAL",
},
{
ID: "ID104",
Status: types.StatusFailure,
Severity: "UNKNOWN",
},
{
ID: "ID105",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "ID106",
Status: types.StatusFailure,
Severity: "HIGH",
},
},
},
},
}
deployOrionWithVulns = report.Resource{
Namespace: "default",
Kind: "Deploy",
Name: "orion",
Results: types.Results{
{
Vulnerabilities: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2022-1111",
Vulnerability: dbTypes.Vulnerability{Severity: "LOW"},
},
{
VulnerabilityID: "CVE-2022-2222",
Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
{
VulnerabilityID: "CVE-2022-3333",
Vulnerability: dbTypes.Vulnerability{Severity: "HIGH"},
},
{
VulnerabilityID: "CVE-2022-4444",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-5555",
Vulnerability: dbTypes.Vulnerability{Severity: "UNKNOWN"},
},
{
VulnerabilityID: "CVE-2022-6666",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-7777",
Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
},
},
},
}
)
func TestReportWrite_Summary(t *testing.T) {
allSeverities := []dbTypes.Severity{
dbTypes.SeverityUnknown,
dbTypes.SeverityLow,
dbTypes.SeverityMedium,
dbTypes.SeverityHigh,
dbTypes.SeverityCritical,
}
tests := []struct {
name string
report report.Report
opt report.Option
scanners types.Scanners
components []string
severities []dbTypes.Severity
expectedOutput string
}{
{
name: "Only config, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{deployOrionWithMisconfigs},
},
scanners: types.Scanners{types.MisconfigScanner},
components: []string{workloadComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬──────────────┬───────────────────┐
│ Namespace │ Resource │ Misconfigurations │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼──────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/orion │ 1 │ 2 │ 1 │ 2 │ 1 │
└───────────┴──────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only vuln, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{deployOrionWithVulns},
},
scanners: types.Scanners{types.VulnerabilityScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬──────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼──────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/orion │ 2 │ 1 │ 2 │ 1 │ 1 │
└───────────┴──────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only rbac, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{roleWithMisconfig},
},
scanners: types.Scanners{types.RBACScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
RBAC Assessment
┌───────────┬─────────────────────────────────────────────────────┬───────────────────┐
│ Namespace │ Resource │ RBAC Assessment │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼─────────────────────────────────────────────────────┼───┼───┼───┼───┼───┤
│ default │ Role/system::leader-locking-kube-controller-manager │ │ │ 1 │ │ │
└───────────┴─────────────────────────────────────────────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only secret, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{deployLuaWithSecrets},
},
scanners: types.Scanners{types.SecretScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬────────────┬───────────────────┐
│ Namespace │ Resource │ Secrets │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/lua │ 1 │ │ 1 │ │ │
└───────────┴────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, only infra and serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{types.MisconfigScanner},
components: []string{infraComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Infra Assessment
┌─────────────┬────────────────────┬─────────────────────────────┐
│ Namespace │ Resource │ Kubernetes Infra Assessment │
│ │ ├─────┬─────┬─────┬─────┬─────┤
│ │ │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼─────┼─────┼─────┼─────┼─────┤
│ kube-system │ Pod/kube-apiserver │ │ │ 1 │ 1 │ │
└─────────────┴────────────────────┴─────┴─────┴─────┴─────┴─────┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, vuln,config,secret and serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{
types.VulnerabilityScanner,
types.MisconfigScanner,
types.SecretScanner,
},
components: []string{workloadComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌─────────────┬────────────────────┬───────────────────┬───────────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │
│ │ ├───┬───┬───┬───┬───┼───┬───┬───┬───┬───┼───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│ kube-system │ Pod/kube-apiserver │ │ │ │ │ │ │ 1 │ 1 │ 1 │ │ │ │ │ │ │
└─────────────┴────────────────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, all scanners and serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{
types.MisconfigScanner,
types.VulnerabilityScanner,
types.RBACScanner,
types.SecretScanner,
},
components: []string{
workloadComponent,
infraComponent,
},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌─────────────┬────────────────────┬───────────────────┬───────────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │
│ │ ├───┬───┬───┬───┬───┼───┬───┬───┬───┬───┼───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│ kube-system │ Pod/kube-apiserver │ │ │ │ │ │ │ 1 │ 1 │ 1 │ │ │ │ │ │ │
└─────────────┴────────────────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN
Infra Assessment
┌─────────────┬────────────────────┬─────────────────────────────┐
│ Namespace │ Resource │ Kubernetes Infra Assessment │
│ │ ├─────┬─────┬─────┬─────┬─────┤
│ │ │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼─────┼─────┼─────┼─────┼─────┤
│ kube-system │ Pod/kube-apiserver │ │ │ 1 │ 1 │ │
└─────────────┴────────────────────┴─────┴─────┴─────┴─────┴─────┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
output := bytes.Buffer{}
opt := report.Option{
Format: "table",
Report: "summary",
Output: &output,
Scanners: tc.scanners,
Severities: tc.severities,
Components: tc.components,
}
Write(tc.report, opt)
assert.Equal(t, tc.expectedOutput, stripAnsi(output.String()), tc.name)
})
}
}
const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
var ansiRegexp = regexp.MustCompile(ansi)
func stripAnsi(str string) string {
return strings.TrimSpace(ansiRegexp.ReplaceAllString(str, ""))
}

View File

@@ -0,0 +1,337 @@
package core_test
import (
"fmt"
"testing"
"time"
"github.com/aquasecurity/trivy/pkg/digest"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/google/uuid"
"github.com/package-url/packageurl-go"
"github.com/stretchr/testify/assert"
fake "k8s.io/utils/clock/testing"
)
func TestMarshaler_CoreComponent(t *testing.T) {
noDepRefs := []string{}
tests := []struct {
name string
rootComponent *core.Component
want *cdx.BOM
}{
{
name: "marshal CoreComponent",
rootComponent: &core.Component{
Type: cdx.ComponentTypeContainer,
Name: "test-cluster",
Components: []*core.Component{
{
Type: cdx.ComponentTypeApplication,
Name: "kube-apiserver-kind-control-plane",
Properties: map[string]string{
"control_plane_components": "kube-apiserver",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeContainer,
Name: "k8s.gcr.io/kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Type: "oci",
Name: "kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
Qualifiers: packageurl.Qualifiers{
{
Key: "repository_url",
Value: "k8s.gcr.io/kube-apiserver",
},
{
Key: "arch",
},
},
},
},
Hashes: []digest.Digest{"sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f"},
Properties: map[string]string{
"PkgID": "k8s.gcr.io/kube-apiserver:1.21.1",
"PkgType": "oci",
},
},
},
},
{
Type: cdx.ComponentTypeContainer,
Name: "kind-control-plane",
Properties: map[string]string{
"architecture": "arm64",
"host_name": "kind-control-plane",
"kernel_version": "6.2.13-300.fc38.aarch64",
"node_role": "master",
"operating_system": "linux",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeOS,
Name: "ubuntu",
Version: "21.04",
Properties: map[string]string{
"Class": "os-pkgs",
"Type": "ubuntu",
},
},
{
Type: cdx.ComponentTypeApplication,
Name: "node-core-components",
Properties: map[string]string{
"Class": "lang-pkgs",
"Type": "golang",
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeLibrary,
Name: "kubelet",
Version: "1.21.1",
Properties: map[string]string{
"PkgType": "golang",
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Type: "golang",
Name: "kubelet",
Version: "1.21.1",
Qualifiers: packageurl.Qualifiers{},
},
},
},
{
Type: cdx.ComponentTypeLibrary,
Name: "containerd",
Version: "1.5.2",
Properties: map[string]string{
"PkgType": "golang",
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Type: "golang",
Name: "containerd",
Version: "1.5.2",
Qualifiers: packageurl.Qualifiers{},
},
},
},
},
},
},
},
},
},
want: &cdx.BOM{
XMLNS: "http://cyclonedx.org/schema/bom/1.4",
BOMFormat: "CycloneDX",
SerialNumber: "urn:uuid:3ff14136-e09f-4df9-80ea-000000000001",
SpecVersion: cdx.SpecVersion1_4,
Version: 1,
Metadata: &cdx.Metadata{
Timestamp: "2021-08-25T12:20:30+00:00",
Tools: &[]cdx.Tool{
{
Name: "trivy",
Vendor: "aquasecurity",
Version: "dev",
},
},
Component: &cdx.Component{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000002",
Name: "test-cluster",
Properties: &[]cdx.Property{},
Type: cdx.ComponentTypeContainer,
},
},
Vulnerabilities: &[]cdx.Vulnerability{},
Components: &[]cdx.Component{
{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000003",
Type: "application",
Name: "kube-apiserver-kind-control-plane",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:control_plane_components",
Value: "kube-apiserver",
},
},
},
{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000004",
Type: "container",
Name: "kind-control-plane",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:architecture",
Value: "arm64",
},
{
Name: "aquasecurity:trivy:host_name",
Value: "kind-control-plane",
},
{
Name: "aquasecurity:trivy:kernel_version",
Value: "6.2.13-300.fc38.aarch64",
},
{
Name: "aquasecurity:trivy:node_role",
Value: "master",
},
{
Name: "aquasecurity:trivy:operating_system",
Value: "linux",
},
},
},
{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000005",
Type: "operating-system",
Name: "ubuntu",
Version: "21.04",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:Class",
Value: "os-pkgs",
},
{
Name: "aquasecurity:trivy:Type",
Value: "ubuntu",
},
},
},
{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000006",
Type: "application",
Name: "node-core-components",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:Class",
Value: "lang-pkgs",
},
{
Name: "aquasecurity:trivy:Type",
Value: "golang",
},
},
},
{
BOMRef: "pkg:golang/containerd@1.5.2",
Type: "library",
Name: "containerd",
Version: "1.5.2",
PackageURL: "pkg:golang/containerd@1.5.2",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:PkgType",
Value: "golang",
},
},
},
{
BOMRef: "pkg:golang/kubelet@1.21.1",
Type: "library",
Name: "kubelet",
Version: "1.21.1",
PackageURL: "pkg:golang/kubelet@1.21.1",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:PkgType",
Value: "golang",
},
},
},
{
BOMRef: "pkg:oci/kube-apiserver@sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f?repository_url=k8s.gcr.io%2Fkube-apiserver&arch=",
Hashes: &[]cdx.Hash{
{
Algorithm: "SHA-256",
Value: "18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
},
},
Type: "container",
Name: "k8s.gcr.io/kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
PackageURL: "pkg:oci/kube-apiserver@sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f?repository_url=k8s.gcr.io%2Fkube-apiserver&arch=",
Properties: &[]cdx.Property{
{
Name: "aquasecurity:trivy:PkgID",
Value: "k8s.gcr.io/kube-apiserver:1.21.1",
},
{
Name: "aquasecurity:trivy:PkgType",
Value: "oci",
},
},
},
},
Dependencies: &[]cdx.Dependency{
{
Ref: "3ff14136-e09f-4df9-80ea-000000000002",
Dependencies: &[]string{
"3ff14136-e09f-4df9-80ea-000000000003",
"3ff14136-e09f-4df9-80ea-000000000004",
},
},
{
Ref: "3ff14136-e09f-4df9-80ea-000000000003",
Dependencies: &[]string{"pkg:oci/kube-apiserver@sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f?repository_url=k8s.gcr.io%2Fkube-apiserver&arch="},
},
{
Ref: "3ff14136-e09f-4df9-80ea-000000000004",
Dependencies: &[]string{
"3ff14136-e09f-4df9-80ea-000000000005",
"3ff14136-e09f-4df9-80ea-000000000006",
},
},
{
Ref: "3ff14136-e09f-4df9-80ea-000000000005",
Dependencies: &noDepRefs,
},
{
Ref: "3ff14136-e09f-4df9-80ea-000000000006",
Dependencies: &[]string{
"pkg:golang/containerd@1.5.2",
"pkg:golang/kubelet@1.21.1",
},
},
{
Ref: "pkg:golang/containerd@1.5.2",
Dependencies: &noDepRefs,
},
{
Ref: "pkg:golang/kubelet@1.21.1",
Dependencies: &noDepRefs,
},
{
Ref: "pkg:oci/kube-apiserver@sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f?repository_url=k8s.gcr.io%2Fkube-apiserver&arch=",
Dependencies: &noDepRefs,
},
},
},
},
}
clock := fake.NewFakeClock(time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var count int
newUUID := func() uuid.UUID {
count++
return uuid.Must(uuid.Parse(fmt.Sprintf("3ff14136-e09f-4df9-80ea-%012d", count)))
}
marshaler := core.NewCycloneDX("dev", core.WithClock(clock), core.WithNewUUID(newUUID))
got := marshaler.Marshal(tt.rootComponent)
assert.Equal(t, tt.want, got)
})
}
}