refactor: export useful APIs (#2108)

Co-authored-by: Jose Donizetti <jdbjunior@gmail.com>
This commit is contained in:
Teppei Fukuda
2022-05-13 22:09:20 +03:00
committed by GitHub
parent dbf4b2dec5
commit b3759f54fa
10 changed files with 389 additions and 393 deletions

View File

@@ -29,7 +29,7 @@ $ trivy k8s -n default --severity CRITICAL
Scan a cluster and generate a simple summary report. The only outputs currently supported are `all` and `summary`. The default report format is `summary` Scan a cluster and generate a simple summary report. The only outputs currently supported are `all` and `summary`. The default report format is `summary`
``` ```
$ trivy k8s $ trivy k8s
``` ```
![k8s Summary Report](../../imgs/k8s-summary.png) ![k8s Summary Report](../../imgs/k8s-summary.png)

96
go.mod
View File

@@ -13,7 +13,7 @@ require (
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492
github.com/aquasecurity/trivy-db v0.0.0-20220327074450-74195d9604b2 github.com/aquasecurity/trivy-db v0.0.0-20220510190819-8ca06716f46e
github.com/caarlos0/env/v6 v6.9.1 github.com/caarlos0/env/v6 v6.9.1
github.com/cenkalti/backoff v2.2.1+incompatible github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cheggaaa/pb/v3 v3.0.8 github.com/cheggaaa/pb/v3 v3.0.8
@@ -46,6 +46,7 @@ require (
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
google.golang.org/protobuf v1.28.0 google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/utils v0.0.0-20211116205334-6203023598ed k8s.io/utils v0.0.0-20211116205334-6203023598ed
) )
@@ -71,8 +72,6 @@ require (
github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/VividCortex/ewma v1.1.1 // indirect github.com/VividCortex/ewma v1.1.1 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/agext/levenshtein v1.2.3 // indirect github.com/agext/levenshtein v1.2.3 // indirect
@@ -96,31 +95,19 @@ require (
github.com/docker/docker-credential-helpers v0.6.4 // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect
github.com/docker/go-units v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect github.com/emirpasic/gods v1.12.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/ghodss/yaml v1.0.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-git/go-git/v5 v5.4.2 // indirect github.com/go-git/go-git/v5 v5.4.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gobwas/glob v0.2.3 // indirect github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-yaml v1.8.2 // indirect github.com/goccy/go-yaml v1.8.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect
@@ -128,11 +115,8 @@ require (
github.com/hashicorp/hcl/v2 v2.12.0 // indirect github.com/hashicorp/hcl/v2 v2.12.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/klauspost/compress v1.15.1 // indirect github.com/klauspost/compress v1.15.1 // indirect
@@ -142,9 +126,7 @@ require (
github.com/liamg/jfather v0.0.7 // indirect github.com/liamg/jfather v0.0.7 // indirect
github.com/liamg/memoryfs v1.4.1 // indirect github.com/liamg/memoryfs v1.4.1 // indirect
github.com/liamg/tml v0.6.0 github.com/liamg/tml v0.6.0
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/magiconair/properties v1.8.5 // indirect github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect
@@ -157,15 +139,11 @@ require (
github.com/moby/sys/mount v0.3.0 // indirect github.com/moby/sys/mount v0.3.0 // indirect
github.com/moby/sys/mountinfo v0.6.0 // indirect github.com/moby/sys/mountinfo v0.6.0 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/opencontainers/runc v1.1.1 // indirect github.com/opencontainers/runc v1.1.1 // indirect
github.com/owenrumney/squealer v1.0.1-0.20220510063705-c0be93f0edea // indirect github.com/owenrumney/squealer v1.0.1-0.20220510063705-c0be93f0edea // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
@@ -178,21 +156,17 @@ require (
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spdx/tools-golang v0.3.0 github.com/spdx/tools-golang v0.3.0
github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.3.0 // indirect github.com/stretchr/objx v0.3.0 // indirect
github.com/ulikunitz/xz v0.5.8 // indirect github.com/ulikunitz/xz v0.5.8 // indirect
github.com/vbatts/tar-split v0.11.2 // indirect github.com/vbatts/tar-split v0.11.2 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
github.com/yashtewari/glob-intersection v0.1.0 // indirect github.com/yashtewari/glob-intersection v0.1.0 // indirect
github.com/zclconf/go-cty v1.10.0 // indirect github.com/zclconf/go-cty v1.10.0 // indirect
github.com/zclconf/go-cty-yaml v1.0.2 // indirect github.com/zclconf/go-cty-yaml v1.0.2 // indirect
go.etcd.io/bbolt v1.3.6 // indirect go.etcd.io/bbolt v1.3.6 // indirect
go.opencensus.io v0.23.0 // indirect go.opencensus.io v0.23.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
@@ -202,7 +176,6 @@ require (
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.8 // indirect golang.org/x/tools v0.1.8 // indirect
google.golang.org/api v0.62.0 // indirect google.golang.org/api v0.62.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
@@ -210,14 +183,7 @@ require (
google.golang.org/grpc v1.46.0 // indirect google.golang.org/grpc v1.46.0 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
k8s.io/api v0.23.6 // indirect
k8s.io/apimachinery v0.23.6 // indirect
k8s.io/cli-runtime v0.23.6 // indirect
k8s.io/client-go v0.23.6 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
lukechampine.com/uint128 v1.1.1 // indirect lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.35.22 // indirect modernc.org/cc/v3 v3.35.22 // indirect
modernc.org/ccgo/v3 v3.15.1 // indirect modernc.org/ccgo/v3 v3.15.1 // indirect
@@ -228,6 +194,51 @@ require (
modernc.org/sqlite v1.14.5 // indirect modernc.org/sqlite v1.14.5 // indirect
modernc.org/strutil v1.1.1 // indirect modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect modernc.org/token v1.0.0 // indirect
)
require (
github.com/aquasecurity/table v1.5.1
github.com/aquasecurity/trivy-kubernetes v0.1.0
)
require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.23.6 // indirect
k8s.io/apimachinery v0.23.6 // indirect
k8s.io/cli-runtime v0.23.6 // indirect
k8s.io/client-go v0.23.6 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/kustomize/api v0.10.1 // indirect sigs.k8s.io/kustomize/api v0.10.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect
@@ -235,17 +246,6 @@ require (
sigs.k8s.io/yaml v1.3.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect
) )
require gopkg.in/yaml.v2 v2.4.0
require github.com/aquasecurity/trivy-kubernetes v0.1.0
require github.com/aquasecurity/table v1.5.1
require (
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
)
// To resolve CVE-2022-23648 // To resolve CVE-2022-23648
replace github.com/containerd/containerd v1.5.9 => github.com/containerd/containerd v1.5.10 replace github.com/containerd/containerd v1.5.9 => github.com/containerd/containerd v1.5.10

4
go.sum
View File

@@ -198,8 +198,8 @@ github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492/go.mod h1:
github.com/aquasecurity/table v1.5.1 h1:y05AuHM3p4BGybbGn/XbcTX3RxpyzeTXAXYMcJve4IE= github.com/aquasecurity/table v1.5.1 h1:y05AuHM3p4BGybbGn/XbcTX3RxpyzeTXAXYMcJve4IE=
github.com/aquasecurity/table v1.5.1/go.mod h1:1MFKrEPJ8NchM917BrVGvsqoXJo1OL1Ja7dF3PgUea4= github.com/aquasecurity/table v1.5.1/go.mod h1:1MFKrEPJ8NchM917BrVGvsqoXJo1OL1Ja7dF3PgUea4=
github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516 h1:moQmzbpLo5dxHQCyEhqzizsDSNrNhn/7uRTCZzo4A1o= github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516 h1:moQmzbpLo5dxHQCyEhqzizsDSNrNhn/7uRTCZzo4A1o=
github.com/aquasecurity/trivy-db v0.0.0-20220327074450-74195d9604b2 h1:q2Gza4V8uO5C1COzC2HeTbQgJIrmC6dTWaXZ8ujiWu0= github.com/aquasecurity/trivy-db v0.0.0-20220510190819-8ca06716f46e h1:NLm5KWGcnkwaUR1GODPePyhNsbuFiT6lgKYcCcW9c10=
github.com/aquasecurity/trivy-db v0.0.0-20220327074450-74195d9604b2/go.mod h1:EwiQRdzVq6k7cKOMjkss8LjWMt2FUW7NaYwE7HfZZvk= github.com/aquasecurity/trivy-db v0.0.0-20220510190819-8ca06716f46e/go.mod h1:/nULgnDeq/JMPMVwE1dmf4kWlYn++7VrM3O2naj4BHA=
github.com/aquasecurity/trivy-kubernetes v0.1.0 h1:eE7JSdqo83Kn87c86DcUIsPAtW0K9UnkkHEQ4sGI030= github.com/aquasecurity/trivy-kubernetes v0.1.0 h1:eE7JSdqo83Kn87c86DcUIsPAtW0K9UnkkHEQ4sGI030=
github.com/aquasecurity/trivy-kubernetes v0.1.0/go.mod h1:9fU3sHz/wXN5ruZ5snUEJpzm2X6pUndKucv1mz9Walc= github.com/aquasecurity/trivy-kubernetes v0.1.0/go.mod h1:9fU3sHz/wXN5ruZ5snUEJpzm2X6pUndKucv1mz9Walc=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=

View File

@@ -10,7 +10,7 @@ import (
// ConfigRun runs scan on config files // ConfigRun runs scan on config files
func ConfigRun(ctx *cli.Context) error { func ConfigRun(ctx *cli.Context) error {
opt, err := initOption(ctx) opt, err := InitOption(ctx)
if err != nil { if err != nil {
return xerrors.Errorf("option error: %w", err) return xerrors.Errorf("option error: %w", err)
} }
@@ -22,9 +22,6 @@ func ConfigRun(ctx *cli.Context) error {
opt.VulnType = nil opt.VulnType = nil
opt.SecurityChecks = []string{types.SecurityCheckConfig} opt.SecurityChecks = []string{types.SecurityCheckConfig}
// Skip downloading vulnerability DB
opt.SkipDBUpdate = true
// Run filesystem command internally // Run filesystem command internally
return Run(ctx.Context, opt, filesystemStandaloneScanner, initCache) return run(ctx.Context, opt, filesystemArtifact)
} }

View File

@@ -6,7 +6,6 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/scanner" "github.com/aquasecurity/trivy/pkg/scanner"
) )
@@ -30,39 +29,10 @@ func filesystemRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.S
// FilesystemRun runs scan on filesystem for language-specific dependencies and config files // FilesystemRun runs scan on filesystem for language-specific dependencies and config files
func FilesystemRun(ctx *cli.Context) error { func FilesystemRun(ctx *cli.Context) error {
opt, err := initOption(ctx) return Run(ctx, filesystemArtifact)
if err != nil {
return xerrors.Errorf("option error: %w", err)
}
// Disable the individual package scanning
opt.DisabledAnalyzers = analyzer.TypeIndividualPkgs
//opt.DisabledAnalyzers = append(opt.DisabledAnalyzers, analyzer.TypeSecret)
// client/server mode
if opt.RemoteAddr != "" {
return Run(ctx.Context, opt, filesystemRemoteScanner, initCache)
}
// standalone mode
return Run(ctx.Context, opt, filesystemStandaloneScanner, initCache)
} }
// RootfsRun runs scan on rootfs. // RootfsRun runs scan on rootfs.
func RootfsRun(ctx *cli.Context) error { func RootfsRun(ctx *cli.Context) error {
opt, err := initOption(ctx) return Run(ctx, rootfsArtifact)
if err != nil {
return xerrors.Errorf("option error: %w", err)
}
// Disable the lock file scanning
opt.DisabledAnalyzers = analyzer.TypeLockfiles
// client/server mode
if opt.RemoteAddr != "" {
return Run(ctx.Context, opt, filesystemRemoteScanner, initCache)
}
// standalone mode
return Run(ctx.Context, opt, filesystemStandaloneScanner, initCache)
} }

View File

@@ -6,14 +6,13 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/scanner" "github.com/aquasecurity/trivy/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
) )
// imageScanner initializes a container image scanner in standalone mode // imageStandaloneScanner initializes a container image scanner in standalone mode
// $ trivy image alpine:3.15 // $ trivy image alpine:3.15
func imageScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) { func imageStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS) dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS)
if err != nil { if err != nil {
return scanner.Scanner{}, nil, err return scanner.Scanner{}, nil, err
@@ -26,9 +25,9 @@ func imageScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, fun
return s, cleanup, nil return s, cleanup, nil
} }
// archiveScanner initializes an image archive scanner in standalone mode // archiveStandaloneScanner initializes an image archive scanner in standalone mode
// $ trivy image --input alpine.tar // $ trivy image --input alpine.tar
func archiveScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) { func archiveStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
s, err := initializeArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption) s, err := initializeArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
if err != nil { if err != nil {
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err) return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
@@ -36,9 +35,9 @@ func archiveScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, f
return s, func() {}, nil return s, func() {}, nil
} }
// remoteImageScanner initializes a container image scanner in client/server mode // imageRemoteScanner initializes a container image scanner in client/server mode
// $ trivy image --server localhost:4954 alpine:3.15 // $ trivy image --server localhost:4954 alpine:3.15
func remoteImageScanner(ctx context.Context, conf ScannerConfig) ( func imageRemoteScanner(ctx context.Context, conf ScannerConfig) (
scanner.Scanner, func(), error) { scanner.Scanner, func(), error) {
// Scan an image in Docker Engine, Docker Registry, etc. // Scan an image in Docker Engine, Docker Registry, etc.
dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS) dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS)
@@ -54,9 +53,9 @@ func remoteImageScanner(ctx context.Context, conf ScannerConfig) (
return s, cleanup, nil return s, cleanup, nil
} }
// remoteArchiveScanner initializes an image archive scanner in client/server mode // archiveRemoteScanner initializes an image archive scanner in client/server mode
// $ trivy image --server localhost:4954 --input alpine.tar // $ trivy image --server localhost:4954 --input alpine.tar
func remoteArchiveScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) { func archiveRemoteScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
// Scan tar file // Scan tar file
s, err := initializeRemoteArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption, conf.ArtifactOption) s, err := initializeRemoteArchiveScanner(ctx, conf.Target, conf.ArtifactCache, conf.RemoteOption, conf.ArtifactOption)
if err != nil { if err != nil {
@@ -67,43 +66,5 @@ func remoteArchiveScanner(ctx context.Context, conf ScannerConfig) (scanner.Scan
// ImageRun runs scan on container image // ImageRun runs scan on container image
func ImageRun(ctx *cli.Context) error { func ImageRun(ctx *cli.Context) error {
opt, err := initOption(ctx) return Run(ctx, containerImageArtifact)
if err != nil {
return xerrors.Errorf("option error: %w", err)
}
// Disable the lock file scanning
opt.DisabledAnalyzers = analyzer.TypeLockfiles
if opt.Input != "" {
return archiveImageRun(ctx.Context, opt)
}
return imageRun(ctx.Context, opt)
}
func archiveImageRun(ctx context.Context, opt Option) error {
// standalone mode
scanner := archiveScanner
if opt.RemoteAddr != "" {
// client/server mode
scanner = remoteArchiveScanner
}
// scan tar file
return Run(ctx, opt, scanner, initCache)
}
func imageRun(ctx context.Context, opt Option) error {
// standalone mode
scanner := imageScanner
if opt.RemoteAddr != "" {
// client/server mode
scanner = remoteImageScanner
}
// scan container image
return Run(ctx, opt, scanner, initCache)
} }

View File

@@ -12,10 +12,6 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/fanal/cache"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/log"
pkgReport "github.com/aquasecurity/trivy/pkg/report" pkgReport "github.com/aquasecurity/trivy/pkg/report"
k8sReport "github.com/aquasecurity/trivy/pkg/report/k8s" k8sReport "github.com/aquasecurity/trivy/pkg/report/k8s"
@@ -27,35 +23,29 @@ import (
) )
// K8sRun runs scan on kubernetes cluster // K8sRun runs scan on kubernetes cluster
func K8sRun(ctx *cli.Context) error { func K8sRun(cliCtx *cli.Context) error {
opt, err := initOption(ctx) opt, err := InitOption(cliCtx)
if err != nil { if err != nil {
return xerrors.Errorf("option error: %w", err) return xerrors.Errorf("option error: %w", err)
} }
if err = log.InitLogger(opt.Debug, true); err != nil { ctx, cancel := context.WithTimeout(cliCtx.Context, opt.Timeout)
return err defer cancel()
}
cacheClient, err := initCache(opt) defer func() {
if xerrors.Is(err, context.DeadlineExceeded) {
log.Logger.Warn("Increase --timeout value")
}
}()
runner, err := NewRunner(opt)
if err != nil { if err != nil {
if errors.Is(err, errSkipScan) { if errors.Is(err, SkipScan) {
return nil return nil
} }
return xerrors.Errorf("cache error: %w", err) return xerrors.Errorf("init error: %w", err)
}
defer cacheClient.Close()
// Disable DB update when using client/server
if opt.RemoteAddr == "" {
if err = initDB(opt); err != nil {
if errors.Is(err, errSkipScan) {
return nil
}
return xerrors.Errorf("DB error: %w", err)
}
defer db.Close()
} }
defer runner.Close()
cluster, err := k8s.GetCluster() cluster, err := k8s.GetCluster()
if err != nil { if err != nil {
@@ -65,12 +55,12 @@ func K8sRun(ctx *cli.Context) error {
trivyk8s := trivyk8s.New(cluster).Namespace(opt.KubernetesOption.Namespace) trivyk8s := trivyk8s.New(cluster).Namespace(opt.KubernetesOption.Namespace)
// list all kubernetes scannable artifacts // list all kubernetes scannable artifacts
k8sArtifacts, err := trivyk8s.ListArtifacts(ctx.Context) k8sArtifacts, err := trivyk8s.ListArtifacts(ctx)
if err != nil { if err != nil {
return xerrors.Errorf("get k8s artifacts error: %w", err) return xerrors.Errorf("get k8s artifacts error: %w", err)
} }
report, err := k8sRun(ctx, opt, cacheClient, k8sArtifacts) report, err := k8sRun(ctx, runner, opt, k8sArtifacts)
if err != nil { if err != nil {
return xerrors.Errorf("k8s scan error: %w", err) return xerrors.Errorf("k8s scan error: %w", err)
} }
@@ -88,40 +78,34 @@ func K8sRun(ctx *cli.Context) error {
return nil return nil
} }
func k8sRun(cliContext *cli.Context, opt Option, cacheClient cache.Cache, k8sArtifacts []*artifacts.Artifact) (k8sReport.Report, error) { func k8sRun(ctx context.Context, runner *Runner, opt Option, artifacts []*artifacts.Artifact) (k8sReport.Report, error) {
ctx, cancel := context.WithTimeout(cliContext.Context, opt.Timeout) opt.SecurityChecks = []string{types.SecurityCheckVulnerability, types.SecurityCheckConfig}
defer cancel()
// progress bar // progress bar
bar := pb.StartNew(len(k8sArtifacts)) bar := pb.StartNew(len(artifacts))
if opt.NoProgress { if opt.NoProgress {
bar.SetWriter(io.Discard) bar.SetWriter(io.Discard)
} }
defer bar.Finish() defer bar.Finish()
// image scanner configurations
imageScannerConfig, imageScannerOptions, err := initImageScannerConfig(ctx, opt, cacheClient)
if err != nil {
return k8sReport.Report{}, xerrors.Errorf("scanner config error: %w", err)
}
// config scanner configurations
configScannerConfig, configScannerOptions, err := initConfigScannerConfig(ctx, opt, cacheClient)
if err != nil {
return k8sReport.Report{}, xerrors.Errorf("scanner config error: %w", err)
}
vulns := make([]k8sReport.Resource, 0) vulns := make([]k8sReport.Resource, 0)
misconfigs := make([]k8sReport.Resource, 0) misconfigs := make([]k8sReport.Resource, 0)
// disable logs before scanning
err := log.InitLogger(opt.Debug, true)
if err != nil {
return k8sReport.Report{}, xerrors.Errorf("logger error: %w", err)
}
// Loops once over all artifacts, and execute scanners as necessary. Not every artifacts has an image, // Loops once over all artifacts, and execute scanners as necessary. Not every artifacts has an image,
// so image scanner is not always executed. // so image scanner is not always executed.
for _, artifact := range k8sArtifacts { for _, artifact := range artifacts {
bar.Increment() bar.Increment()
// scan images if present // scan images if present
for _, image := range artifact.Images { for _, image := range artifact.Images {
imageReport, err := k8sScan(ctx, image, imageScanner, imageScannerConfig, imageScannerOptions) opt.Target = image
imageReport, err := runner.ScanImage(ctx, opt)
if err != nil { if err != nil {
// add error to report // add error to report
log.Logger.Debugf("failed to scan image %s: %s", image, err) log.Logger.Debugf("failed to scan image %s: %s", image, err)
@@ -129,7 +113,7 @@ func k8sRun(cliContext *cli.Context, opt Option, cacheClient cache.Cache, k8sArt
continue continue
} }
imageReport, err = filter(ctx, opt, imageReport) imageReport, err = runner.Filter(ctx, opt, imageReport)
if err != nil { if err != nil {
return k8sReport.Report{}, xerrors.Errorf("filter error: %w", err) return k8sReport.Report{}, xerrors.Errorf("filter error: %w", err)
} }
@@ -138,14 +122,21 @@ func k8sRun(cliContext *cli.Context, opt Option, cacheClient cache.Cache, k8sArt
} }
// scan configurations // scan configurations
configReport, err := k8sScanConfig(ctx, configScannerConfig, configScannerOptions, artifact) configFile, err := createTempFile(artifact)
if err != nil {
return k8sReport.Report{}, xerrors.Errorf("scan error: %w", err)
}
opt.Target = configFile
configReport, err := runner.ScanFilesystem(ctx, opt)
removeFile(configFile)
if err != nil { if err != nil {
// add error to report // add error to report
log.Logger.Debugf("failed to scan config %s/%s: %s", artifact.Kind, artifact.Name, err) log.Logger.Debugf("failed to scan config %s/%s: %s", artifact.Kind, artifact.Name, err)
misconfigs = append(misconfigs, newK8sResource(artifact, configReport, err)) misconfigs = append(misconfigs, newK8sResource(artifact, configReport, err))
} }
configReport, err = filter(ctx, opt, configReport) configReport, err = runner.Filter(ctx, opt, configReport)
if err != nil { if err != nil {
return k8sReport.Report{}, xerrors.Errorf("filter error: %w", err) return k8sReport.Report{}, xerrors.Errorf("filter error: %w", err)
} }
@@ -153,6 +144,12 @@ func k8sRun(cliContext *cli.Context, opt Option, cacheClient cache.Cache, k8sArt
misconfigs = append(misconfigs, newK8sResource(artifact, configReport, nil)) misconfigs = append(misconfigs, newK8sResource(artifact, configReport, nil))
} }
// enable logs after scanning
err = log.InitLogger(opt.Debug, opt.Quiet)
if err != nil {
return k8sReport.Report{}, xerrors.Errorf("logger error: %w", err)
}
return k8sReport.Report{ return k8sReport.Report{
SchemaVersion: 0, SchemaVersion: 0,
Vulnerabilities: vulns, Vulnerabilities: vulns,
@@ -160,58 +157,6 @@ func k8sRun(cliContext *cli.Context, opt Option, cacheClient cache.Cache, k8sArt
}, nil }, nil
} }
func initImageScannerConfig(ctx context.Context, opt Option, cacheClient cache.Cache) (ScannerConfig, types.ScanOptions, error) {
// Disable the lock file scanning
opt.DisabledAnalyzers = analyzer.TypeLockfiles
return initScannerConfig(ctx, opt, cacheClient)
}
func initConfigScannerConfig(ctx context.Context, opt Option, cacheClient cache.Cache) (ScannerConfig, types.ScanOptions, error) {
// Disable OS and language analyzers
opt.DisabledAnalyzers = append(analyzer.TypeOSes, analyzer.TypeLanguages...)
// Scan only config files
opt.VulnType = nil
opt.SecurityChecks = []string{types.SecurityCheckConfig}
// Skip downloading vulnerability DB
opt.SkipDBUpdate = true
return initScannerConfig(ctx, opt, cacheClient)
}
func k8sScanConfig(ctx context.Context, config ScannerConfig, opts types.ScanOptions, a *artifacts.Artifact) (types.Report, error) {
fileName, err := createTempFile(a)
if err != nil {
return types.Report{}, xerrors.Errorf("scan error: %w", err)
}
defer removeFile(fileName)
report, err := k8sScan(ctx, fileName, filesystemStandaloneScanner, config, opts)
if err != nil {
return types.Report{}, xerrors.Errorf("scan error: %w", err)
}
return report, nil
}
func k8sScan(ctx context.Context, target string, initializeScanner InitializeScanner, config ScannerConfig, opts types.ScanOptions) (types.Report, error) {
config.Target = target
s, cleanup, err := initializeScanner(ctx, config)
if err != nil {
log.Logger.Debugf("unexpected error during scanning %s: %s", config.Target, err)
return types.Report{}, err
}
defer cleanup()
report, err := s.ScanArtifact(ctx, opts)
if err != nil {
return types.Report{}, xerrors.Errorf("artifact scan failed: %w", err)
}
return report, nil
}
func createTempFile(artifact *artifacts.Artifact) (string, error) { func createTempFile(artifact *artifacts.Artifact) (string, error) {
filename := fmt.Sprintf("%s-%s-%s-*.yaml", artifact.Namespace, artifact.Kind, artifact.Name) filename := fmt.Sprintf("%s-%s-%s-*.yaml", artifact.Namespace, artifact.Kind, artifact.Name)

View File

@@ -6,13 +6,11 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/scanner" "github.com/aquasecurity/trivy/pkg/scanner"
"github.com/aquasecurity/trivy/pkg/types"
) )
// filesystemStandaloneScanner initializes a repository scanner in standalone mode // filesystemStandaloneScanner initializes a repository scanner in standalone mode
func repositoryScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) { func repositoryStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
s, cleanup, err := initializeRepositoryScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption) s, cleanup, err := initializeRepositoryScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache, conf.ArtifactOption)
if err != nil { if err != nil {
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err) return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a filesystem scanner: %w", err)
@@ -22,16 +20,5 @@ func repositoryScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner
// RepositoryRun runs scan on repository // RepositoryRun runs scan on repository
func RepositoryRun(ctx *cli.Context) error { func RepositoryRun(ctx *cli.Context) error {
opt, err := initOption(ctx) return Run(ctx, repositoryArtifact)
if err != nil {
return xerrors.Errorf("option error: %w", err)
}
// Do not scan OS packages
opt.VulnType = []string{types.VulnTypeLibrary}
// Disable the OS analyzers and individual package analyzers
opt.DisabledAnalyzers = append(analyzer.TypeIndividualPkgs, analyzer.TypeOSes...)
return Run(ctx.Context, opt, repositoryScanner, initCache)
} }

View File

@@ -5,6 +5,7 @@ import (
"errors" "errors"
"os" "os"
"github.com/hashicorp/go-multierror"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@@ -25,9 +26,27 @@ import (
"github.com/aquasecurity/trivy/pkg/utils" "github.com/aquasecurity/trivy/pkg/utils"
) )
var defaultPolicyNamespaces = []string{"appshield", "defsec", "builtin"} type ArtifactType string
var errSkipScan = errors.New("skip subsequent processes") const (
containerImageArtifact ArtifactType = "image"
filesystemArtifact ArtifactType = "fs"
rootfsArtifact ArtifactType = "rootfs"
repositoryArtifact ArtifactType = "repo"
imageArchiveArtifact ArtifactType = "archive"
)
var (
defaultPolicyNamespaces = []string{"appshield", "defsec", "builtin"}
supportedArtifactTypes = []ArtifactType{containerImageArtifact, filesystemArtifact, rootfsArtifact,
repositoryArtifact, imageArchiveArtifact}
SkipScan = errors.New("skip subsequent processes")
)
// InitializeScanner defines the initialize function signature of scanner
type InitializeScanner func(context.Context, ScannerConfig) (scanner.Scanner, func(), error)
type ScannerConfig struct { type ScannerConfig struct {
// e.g. image name and file path // e.g. image name and file path
@@ -44,60 +63,151 @@ type ScannerConfig struct {
ArtifactOption artifact.Option ArtifactOption artifact.Option
} }
// InitializeScanner defines the initialize function signature of scanner type Runner struct {
type InitializeScanner func(context.Context, ScannerConfig) (scanner.Scanner, func(), error) cache cache.Cache
dbOpen bool
// InitCache defines cache initializer
type InitCache func(c Option) (cache.Cache, error)
// Run performs artifact scanning
func Run(ctx context.Context, opt Option, initializeScanner InitializeScanner, initCache InitCache) error {
ctx, cancel := context.WithTimeout(ctx, opt.Timeout)
defer cancel()
err := runWithTimeout(ctx, opt, initializeScanner, initCache)
if xerrors.Is(err, context.DeadlineExceeded) {
log.Logger.Warn("Increase --timeout value")
}
return err
} }
func runWithTimeout(ctx context.Context, opt Option, initializeScanner InitializeScanner, initCache InitCache) error { type runnerOption func(*Runner)
if err := log.InitLogger(opt.Debug, opt.Quiet); err != nil {
return err // WithCacheClient takes a custom cache implementation
func WithCacheClient(c cache.Cache) runnerOption {
return func(r *Runner) {
r.cache = c
}
}
// NewRunner initializes Runner that provides scanning functionalities.
// It is possible to return SkipScan and it must be handled by caller.
func NewRunner(cliOption Option, opts ...runnerOption) (*Runner, error) {
r := &Runner{}
for _, opt := range opts {
opt(r)
} }
cacheClient, err := initCache(opt) err := log.InitLogger(cliOption.Debug, cliOption.Quiet)
if err != nil { if err != nil {
if errors.Is(err, errSkipScan) { return nil, xerrors.Errorf("logger error: %w", err)
return nil }
if err = r.initCache(cliOption); err != nil {
return nil, xerrors.Errorf("cache error: %w", err)
}
if err = r.initDB(cliOption); err != nil {
return nil, xerrors.Errorf("DB error: %w", err)
}
return r, nil
}
// Close closes everything
func (r *Runner) Close() error {
var errs error
if err := r.cache.Close(); err != nil {
errs = multierror.Append(errs, err)
}
if r.dbOpen {
if err := db.Close(); err != nil {
errs = multierror.Append(errs, err)
} }
return xerrors.Errorf("cache error: %w", err)
} }
defer cacheClient.Close() return errs
}
// When scanning config files or running as client mode, it doesn't need to download the vulnerability database. func (r *Runner) ScanImage(ctx context.Context, opt Option) (types.Report, error) {
if opt.RemoteAddr == "" && slices.Contains(opt.SecurityChecks, types.SecurityCheckVulnerability) { // Disable the lock file scanning
if err = initDB(opt); err != nil { opt.DisabledAnalyzers = analyzer.TypeLockfiles
if errors.Is(err, errSkipScan) {
return nil var s InitializeScanner
} switch {
return xerrors.Errorf("DB error: %w", err) case opt.Input != "" && opt.RemoteAddr == "":
// Scan image tarball in standalone mode
s = archiveStandaloneScanner
case opt.Input != "" && opt.RemoteAddr != "":
// Scan image tarball in client/server mode
s = archiveRemoteScanner
case opt.Input == "" && opt.RemoteAddr == "":
// Scan container image in standalone mode
s = imageStandaloneScanner
case opt.Input == "" && opt.RemoteAddr != "":
// Scan container image in client/server mode
s = imageRemoteScanner
}
return r.Scan(ctx, opt, s)
}
func (r *Runner) ScanFilesystem(ctx context.Context, opt Option) (types.Report, error) {
// Disable the individual package scanning
opt.DisabledAnalyzers = append(opt.DisabledAnalyzers, analyzer.TypeIndividualPkgs...)
return r.scanFS(ctx, opt)
}
func (r *Runner) ScanRootfs(ctx context.Context, opt Option) (types.Report, error) {
// Disable the lock file scanning
opt.DisabledAnalyzers = append(opt.DisabledAnalyzers, analyzer.TypeLockfiles...)
return r.scanFS(ctx, opt)
}
func (r *Runner) scanFS(ctx context.Context, opt Option) (types.Report, error) {
var s InitializeScanner
if opt.RemoteAddr == "" {
// Scan filesystem in standalone mode
s = filesystemStandaloneScanner
} else {
// Scan filesystem in client/server mode
s = filesystemRemoteScanner
}
return r.Scan(ctx, opt, s)
}
func (r *Runner) ScanRepository(ctx context.Context, opt Option) (types.Report, error) {
// Do not scan OS packages
opt.VulnType = []string{types.VulnTypeLibrary}
// Disable the OS analyzers and individual package analyzers
opt.DisabledAnalyzers = append(analyzer.TypeIndividualPkgs, analyzer.TypeOSes...)
return r.Scan(ctx, opt, repositoryStandaloneScanner)
}
func (r *Runner) Scan(ctx context.Context, opt Option, initializeScanner InitializeScanner) (types.Report, error) {
report, err := scan(ctx, opt, initializeScanner, r.cache)
if err != nil {
return types.Report{}, xerrors.Errorf("scan error: %w", err)
}
return report, nil
}
func (r *Runner) Filter(ctx context.Context, opt Option, report types.Report) (types.Report, error) {
resultClient := initializeResultClient()
results := report.Results
for i := range results {
// Fill vulnerability info only in standalone mode
if opt.RemoteAddr == "" {
resultClient.FillVulnerabilityInfo(results[i].Vulnerabilities, results[i].Type)
} }
defer db.Close() vulns, misconfSummary, misconfs, secrets, err := resultClient.Filter(ctx, results[i].Vulnerabilities, results[i].Misconfigurations, results[i].Secrets,
opt.Severities, opt.IgnoreUnfixed, opt.IncludeNonFailures, opt.IgnoreFile, opt.IgnorePolicy)
if err != nil {
return types.Report{}, xerrors.Errorf("unable to filter vulnerabilities: %w", err)
}
results[i].Vulnerabilities = vulns
results[i].Misconfigurations = misconfs
results[i].MisconfSummary = misconfSummary
results[i].Secrets = secrets
} }
return report, nil
}
report, err := scan(ctx, opt, initializeScanner, cacheClient) func (r *Runner) Report(opt Option, report types.Report) error {
if err != nil { if err := pkgReport.Write(report, pkgReport.Option{
return xerrors.Errorf("scan error: %w", err)
}
report, err = filter(ctx, opt, report)
if err != nil {
return xerrors.Errorf("filter error: %w", err)
}
if err = pkgReport.Write(report, pkgReport.Option{
AppVersion: opt.GlobalOption.AppVersion, AppVersion: opt.GlobalOption.AppVersion,
Format: opt.Format, Format: opt.Format,
Output: opt.Output, Output: opt.Output,
@@ -109,44 +219,15 @@ func runWithTimeout(ctx context.Context, opt Option, initializeScanner Initializ
return xerrors.Errorf("unable to write results: %w", err) return xerrors.Errorf("unable to write results: %w", err)
} }
exit(opt, report.Results.Failed())
return nil return nil
} }
func initCache(c Option) (cache.Cache, error) { func (r *Runner) initDB(c Option) error {
// client/server mode // When scanning config files or running as client mode, it doesn't need to download the vulnerability database.
if c.RemoteAddr != "" { if c.RemoteAddr != "" || !slices.Contains(c.SecurityChecks, types.SecurityCheckVulnerability) {
remoteCache := tcache.NewRemoteCache(c.RemoteAddr, c.CustomHeaders, c.Insecure) return nil
return tcache.NopCache(remoteCache), nil
} }
// standalone mode
utils.SetCacheDir(c.CacheDir)
cache, err := operation.NewCache(c.CacheOption)
if err != nil {
return operation.Cache{}, xerrors.Errorf("unable to initialize the cache: %w", err)
}
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
if c.Reset {
defer cache.Close()
if err = cache.Reset(); err != nil {
return operation.Cache{}, xerrors.Errorf("cache reset error: %w", err)
}
return operation.Cache{}, errSkipScan
}
if c.ClearCache {
defer cache.Close()
if err = cache.ClearArtifacts(); err != nil {
return operation.Cache{}, xerrors.Errorf("cache clear error: %w", err)
}
return operation.Cache{}, errSkipScan
}
return cache, nil
}
func initDB(c Option) error {
// download the database file // download the database file
noProgress := c.Quiet || c.NoProgress noProgress := c.Quiet || c.NoProgress
if err := operation.DownloadDB(c.AppVersion, c.CacheDir, c.DBRepository, noProgress, c.SkipDBUpdate); err != nil { if err := operation.DownloadDB(c.AppVersion, c.CacheDir, c.DBRepository, noProgress, c.SkipDBUpdate); err != nil {
@@ -154,16 +235,121 @@ func initDB(c Option) error {
} }
if c.DownloadDBOnly { if c.DownloadDBOnly {
return errSkipScan return SkipScan
} }
if err := db.Init(c.CacheDir); err != nil { if err := db.Init(c.CacheDir); err != nil {
return xerrors.Errorf("error in vulnerability DB initialize: %w", err) return xerrors.Errorf("error in vulnerability DB initialize: %w", err)
} }
r.dbOpen = true
return nil return nil
} }
func initOption(ctx *cli.Context) (Option, error) { func (r *Runner) initCache(c Option) error {
// Skip initializing cache when custom cache is passed
if r.cache != nil {
return nil
}
// client/server mode
if c.RemoteAddr != "" {
remoteCache := tcache.NewRemoteCache(c.RemoteAddr, c.CustomHeaders, c.Insecure)
r.cache = tcache.NopCache(remoteCache)
return nil
}
// standalone mode
utils.SetCacheDir(c.CacheDir)
cache, err := operation.NewCache(c.CacheOption)
if err != nil {
return xerrors.Errorf("unable to initialize the cache: %w", err)
}
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
if c.Reset {
defer cache.Close()
if err = cache.Reset(); err != nil {
return xerrors.Errorf("cache reset error: %w", err)
}
return SkipScan
}
if c.ClearCache {
defer cache.Close()
if err = cache.ClearArtifacts(); err != nil {
return xerrors.Errorf("cache clear error: %w", err)
}
return SkipScan
}
r.cache = cache
return nil
}
// Run performs artifact scanning
func Run(cliCtx *cli.Context, artifactType ArtifactType) error {
opt, err := InitOption(cliCtx)
if err != nil {
return err
}
return run(cliCtx.Context, opt, artifactType)
}
func run(ctx context.Context, opt Option, artifactType ArtifactType) (err error) {
ctx, cancel := context.WithTimeout(ctx, opt.Timeout)
defer cancel()
defer func() {
if xerrors.Is(err, context.DeadlineExceeded) {
log.Logger.Warn("Increase --timeout value")
}
}()
runner, err := NewRunner(opt)
if err != nil {
if errors.Is(err, SkipScan) {
return nil
}
return xerrors.Errorf("init error: %w", err)
}
defer runner.Close()
var report types.Report
switch artifactType {
case containerImageArtifact, imageArchiveArtifact:
if report, err = runner.ScanImage(ctx, opt); err != nil {
return xerrors.Errorf("image scan error: %w", err)
}
case filesystemArtifact:
if report, err = runner.ScanFilesystem(ctx, opt); err != nil {
return xerrors.Errorf("filesystem scan error: %w", err)
}
case rootfsArtifact:
if report, err = runner.ScanRootfs(ctx, opt); err != nil {
return xerrors.Errorf("rootfs scan error: %w", err)
}
case repositoryArtifact:
if report, err = runner.ScanRepository(ctx, opt); err != nil {
return xerrors.Errorf("repository scan error: %w", err)
}
}
report, err = runner.Filter(ctx, opt, report)
if err != nil {
return xerrors.Errorf("filter error: %w", err)
}
if err = runner.Report(opt, report); err != nil {
return xerrors.Errorf("report error: %w", err)
}
exit(opt, report.Results.Failed())
return nil
}
func InitOption(ctx *cli.Context) (Option, error) {
opt, err := NewOption(ctx) opt, err := NewOption(ctx)
if err != nil { if err != nil {
return Option{}, xerrors.Errorf("option error: %w", err) return Option{}, xerrors.Errorf("option error: %w", err)
@@ -205,7 +391,7 @@ func disabledAnalyzers(opt Option) []analyzer.Type {
return analyzers return analyzers
} }
func initScannerConfig(ctx context.Context, opt Option, cacheClient cache.Cache) (ScannerConfig, types.ScanOptions, error) { func initScannerConfig(opt Option, cacheClient cache.Cache) (ScannerConfig, types.ScanOptions, error) {
target := opt.Target target := opt.Target
if opt.Input != "" { if opt.Input != "" {
target = opt.Input target = opt.Input
@@ -262,7 +448,7 @@ func initScannerConfig(ctx context.Context, opt Option, cacheClient cache.Cache)
func scan(ctx context.Context, opt Option, initializeScanner InitializeScanner, cacheClient cache.Cache) ( func scan(ctx context.Context, opt Option, initializeScanner InitializeScanner, cacheClient cache.Cache) (
types.Report, error) { types.Report, error) {
scannerConfig, scanOptions, err := initScannerConfig(ctx, opt, cacheClient) scannerConfig, scanOptions, err := initScannerConfig(opt, cacheClient)
if err != nil { if err != nil {
return types.Report{}, err return types.Report{}, err
} }
@@ -280,27 +466,6 @@ func scan(ctx context.Context, opt Option, initializeScanner InitializeScanner,
return report, nil return report, nil
} }
func filter(ctx context.Context, opt Option, report types.Report) (types.Report, error) {
resultClient := initializeResultClient()
results := report.Results
for i := range results {
// Fill vulnerability info only in standalone mode
if opt.RemoteAddr == "" {
resultClient.FillVulnerabilityInfo(results[i].Vulnerabilities, results[i].Type)
}
vulns, misconfSummary, misconfs, secrets, err := resultClient.Filter(ctx, results[i].Vulnerabilities, results[i].Misconfigurations, results[i].Secrets,
opt.Severities, opt.IgnoreUnfixed, opt.IncludeNonFailures, opt.IgnoreFile, opt.IgnorePolicy)
if err != nil {
return types.Report{}, xerrors.Errorf("unable to filter vulnerabilities: %w", err)
}
results[i].Vulnerabilities = vulns
results[i].Misconfigurations = misconfs
results[i].MisconfSummary = misconfSummary
results[i].Secrets = secrets
}
return report, nil
}
func exit(c Option, failedResults bool) { func exit(c Option, failedResults bool) {
if c.ExitCode != 0 && failedResults { if c.ExitCode != 0 && failedResults {
os.Exit(c.ExitCode) os.Exit(c.ExitCode)

View File

@@ -2,61 +2,32 @@ package artifact
import ( import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/maps" "golang.org/x/exp/slices"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/aquasecurity/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
) )
type ArtifactType string
const (
containerImageArtifact ArtifactType = "image"
filesystemArtifact ArtifactType = "fs"
repositoryArtifact ArtifactType = "repo"
imageArchiveArtifact ArtifactType = "archive"
)
var artifactTypes = map[ArtifactType]struct {
initializer InitializeScanner
disableAnalyzers []analyzer.Type
}{
containerImageArtifact: {
initializer: imageScanner,
disableAnalyzers: analyzer.TypeLockfiles,
},
filesystemArtifact: {
initializer: filesystemStandaloneScanner,
disableAnalyzers: analyzer.TypeIndividualPkgs,
},
repositoryArtifact: {
initializer: repositoryScanner,
disableAnalyzers: analyzer.TypeIndividualPkgs,
},
imageArchiveArtifact: {
initializer: archiveScanner,
disableAnalyzers: analyzer.TypeLockfiles,
},
}
// SbomRun runs generates sbom for image and package artifacts // SbomRun runs generates sbom for image and package artifacts
func SbomRun(ctx *cli.Context) error { func SbomRun(ctx *cli.Context) error {
opt, err := initOption(ctx) opt, err := InitOption(ctx)
if err != nil { if err != nil {
return xerrors.Errorf("option error: %w", err) return xerrors.Errorf("option error: %w", err)
} }
artifactType := opt.SbomOption.ArtifactType artifactType := ArtifactType(opt.SbomOption.ArtifactType)
s, ok := artifactTypes[ArtifactType(artifactType)] if !slices.Contains(supportedArtifactTypes, artifactType) {
if !ok { return xerrors.Errorf(`"--artifact-type" must be %q`, supportedArtifactTypes)
return xerrors.Errorf(`"--artifact-type" must be %q`, maps.Keys(artifactTypes)) }
// Pass the specified image archive via "--input".
if artifactType == imageArchiveArtifact {
opt.Input = opt.Target
} }
// Scan the relevant dependencies // Scan the relevant dependencies
opt.DisabledAnalyzers = s.disableAnalyzers
opt.ReportOption.VulnType = []string{types.VulnTypeOS, types.VulnTypeLibrary} opt.ReportOption.VulnType = []string{types.VulnTypeOS, types.VulnTypeLibrary}
opt.ReportOption.SecurityChecks = []string{types.SecurityCheckVulnerability} opt.ReportOption.SecurityChecks = []string{types.SecurityCheckVulnerability}
return Run(ctx.Context, opt, s.initializer, initCache) return run(ctx.Context, opt, artifactType)
} }