diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 7dc3b7f789..eeec316ac6 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -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) diff --git a/docs/docs/target/kubernetes.md b/docs/docs/target/kubernetes.md index 4b80b05925..894e9943e7 100644 --- a/docs/docs/target/kubernetes.md +++ b/docs/docs/target/kubernetes.md @@ -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 +``` \ No newline at end of file diff --git a/go.mod b/go.mod index 2cf588b952..96782863bb 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 6088c2c448..cb6b65ddb0 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/integration/k8s_test.go b/integration/k8s_test.go index 7bf16088b5..c01630d0d3 100644 --- a/integration/k8s_test.go +++ b/integration/k8s_test.go @@ -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 + })) + + }) +} \ No newline at end of file diff --git a/pkg/commands/app.go b/pkg/commands/app.go index c0bc600ce7..f80720668a 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -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(), diff --git a/pkg/flag/options.go b/pkg/flag/options.go index d51c99480e..6fc7633149 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -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 diff --git a/pkg/k8s/commands/cluster.go b/pkg/k8s/commands/cluster.go index 9a73bb25de..6715bbcdc8 100644 --- a/pkg/k8s/commands/cluster.go +++ b/pkg/k8s/commands/cluster.go @@ -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()) diff --git a/pkg/k8s/commands/run.go b/pkg/k8s/commands/run.go index a10a1b95c2..b136d074a4 100644 --- a/pkg/k8s/commands/run.go +++ b/pkg/k8s/commands/run.go @@ -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) } diff --git a/pkg/k8s/report/cyclonedx.go b/pkg/k8s/report/cyclonedx.go new file mode 100644 index 0000000000..3cd841310f --- /dev/null +++ b/pkg/k8s/report/cyclonedx.go @@ -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) +} diff --git a/pkg/k8s/report/json.go b/pkg/k8s/report/json.go index 22bc021dfe..12420c0704 100644 --- a/pkg/k8s/report/json.go +++ b/pkg/k8s/report/json.go @@ -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) } diff --git a/pkg/k8s/report/report.go b/pkg/k8s/report/report.go index ad1f53609a..4dd36cb97a 100644 --- a/pkg/k8s/report/report.go +++ b/pkg/k8s/report/report.go @@ -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) diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index 7039c99c6c..34a79d6e32 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -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, "")) -} diff --git a/pkg/k8s/report/table.go b/pkg/k8s/report/table.go index 7e856f6979..f2cf548ca1 100644 --- a/pkg/k8s/report/table.go +++ b/pkg/k8s/report/table.go @@ -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: diff --git a/pkg/k8s/scanner/scanner.go b/pkg/k8s/scanner/scanner.go index f5eae5abe9..77d0815b73 100644 --- a/pkg/k8s/scanner/scanner.go +++ b/pkg/k8s/scanner/scanner.go @@ -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{}, ""), + }, + }, + }, + }, + }, + } +} diff --git a/pkg/k8s/scanner/scanner_test.go b/pkg/k8s/scanner/scanner_test.go new file mode 100644 index 0000000000..f2105bfaaa --- /dev/null +++ b/pkg/k8s/scanner/scanner_test.go @@ -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) + }) + } +} diff --git a/pkg/k8s/writer.go b/pkg/k8s/writer.go new file mode 100644 index 0000000000..f374c6b925 --- /dev/null +++ b/pkg/k8s/writer.go @@ -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 +} diff --git a/pkg/k8s/writer_test.go b/pkg/k8s/writer_test.go new file mode 100644 index 0000000000..d747b88671 --- /dev/null +++ b/pkg/k8s/writer_test.go @@ -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, "")) +} diff --git a/pkg/sbom/cyclonedx/core/cyclonedx_test.go b/pkg/sbom/cyclonedx/core/cyclonedx_test.go new file mode 100644 index 0000000000..5a86a5667f --- /dev/null +++ b/pkg/sbom/cyclonedx/core/cyclonedx_test.go @@ -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) + }) + } +}