mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
feat(cache): based on JSON (#398)
* refactor(docker_conf): rename and remove unnecessary options * feat(rpc): define new API * fix(cli): change default timeout * fix(import): fix package names * refactor(vulnerability): remove old mock * refactor(utils): remove un-needed functions * feat(cache): implement cache communicating with a server * refactor(scan): separate scan function as local scanner * test(scanner): add tests for ScanImage * refactor(scan): remove unused options * test(vulnerability): generate mock * refactor(server): split a file * feat(server): implement new RPC server * feat(client): implement new RPC client * fix(cache): use new cache interface * fix(standalone): use new scanner * fix(client): use new scanner * fix(server): pass cache * test(integration): make sure an error is not nil before calling the method * fix(mod): update dependencies * test(integration): ensure the image load finishes * feat(docker): support DOCKER_HOST and DOCKER_CERT_PATH * chore(mod): update dependencies * refactor(rpc): remove old client * feat(server): support old API for backward compatibility * fix(server): check a schema version of JSON cache * fix(rpc): add a version to packages * feat(rpc): add PutImage * test: rename expectations * refactor(cache): rename LayerCache to ImageCache * refactor: rename ImageInfo to ImageReference * fix(applier): pass image_id to ApplyLayer * feat(cache): handle image cache * chore(mod): update dependencies * refactor(server): pass only config * feat(cli): add -removed-pkgs option * refactor(err): wrap errors
This commit is contained in:
2
Makefile
2
Makefile
@@ -47,7 +47,7 @@ build:
|
||||
|
||||
.PHONY: protoc
|
||||
protoc:
|
||||
protoc --proto_path=$(GOSRC):. --twirp_out=. --go_out=. ./rpc/detector/service.proto
|
||||
find ./rpc/ -name "*.proto" -type f -exec protoc --proto_path=$(GOSRC):. --twirp_out=. --go_out=. {} \;
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
|
||||
12
go.mod
12
go.mod
@@ -3,8 +3,7 @@ module github.com/aquasecurity/trivy
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 // indirect
|
||||
github.com/aquasecurity/fanal v0.0.0-20200112144021-9a35ce3bd793
|
||||
github.com/aquasecurity/fanal v0.0.0-20200221125056-947c2a5bb130
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1
|
||||
github.com/caarlos0/env/v6 v6.0.0
|
||||
@@ -13,7 +12,7 @@ require (
|
||||
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f
|
||||
github.com/genuinetools/reg v0.16.0
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d // indirect
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/golang/protobuf v1.3.3
|
||||
github.com/google/go-github/v28 v28.1.1
|
||||
github.com/google/wire v0.3.0
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
|
||||
@@ -21,19 +20,16 @@ require (
|
||||
github.com/knqyf263/go-version v1.1.1
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a
|
||||
github.com/prometheus/procfs v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/twitchtv/twirp v5.10.1+incompatible
|
||||
github.com/urfave/cli v1.20.0
|
||||
github.com/urfave/cli v1.22.1
|
||||
go.uber.org/atomic v1.5.1 // indirect
|
||||
go.uber.org/multierr v1.4.0 // indirect
|
||||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
|
||||
golang.org/x/tools v0.0.0-20191121040551-947d4aa89328 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
|
||||
gopkg.in/yaml.v2 v2.2.4 // indirect
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4
|
||||
)
|
||||
|
||||
replace github.com/genuinetools/reg => github.com/tomoyamachi/reg v0.16.1-0.20190706172545-2a2250fd7c00
|
||||
|
||||
246
go.sum
246
go.sum
@@ -2,16 +2,20 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 h1:SCbEWT58NSt7d2mcFdvxC9uyrdcTfvBbPLThhkDmXzg=
|
||||
github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dYRLLXyJjbkIPeeGyoJ/eKOSI0eU6eTlCBYibgd0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/GoogleCloudPlatform/docker-credential-gcr v1.5.0 h1:wykTgKwhVr2t2qs+xI020s6W5dt614QqCHV+7W9dg64=
|
||||
github.com/GoogleCloudPlatform/docker-credential-gcr v1.5.0/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs=
|
||||
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
|
||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||
github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg=
|
||||
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
@@ -19,18 +23,14 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/aquasecurity/fanal v0.0.0-20190819081512-f04452b627c6/go.mod h1:enEz4FFetw4XAbkffaYgyCVq1556R9Ry+noqT4rq9BE=
|
||||
github.com/aquasecurity/fanal v0.0.0-20200112144021-9a35ce3bd793 h1:wPGD5cu66RvwRkNULAqOAMbNWFjmYSCJ/mqHJ5rYBN0=
|
||||
github.com/aquasecurity/fanal v0.0.0-20200112144021-9a35ce3bd793/go.mod h1:S2D937GMywJzh6KiLQEyt/0yqmfAngUFvuQ9UmkIZSw=
|
||||
github.com/aquasecurity/fanal v0.0.0-20200221125056-947c2a5bb130 h1:OAwolcJ+dj0hDbPh/jSQlOMXxDti0LoOKvgR7e+hzVA=
|
||||
github.com/aquasecurity/fanal v0.0.0-20200221125056-947c2a5bb130/go.mod h1:yPZqe/vMN0QDXBIl3kE9s793zU9NSQuEHGWLlL85bG8=
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
|
||||
github.com/aquasecurity/trivy v0.1.6/go.mod h1:5hobyhxLzDtxruHzPxpND2PUKOssvGUdE9BocpJUwo4=
|
||||
@@ -38,16 +38,14 @@ github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1 h1:IVXoVH8ej
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1/go.mod h1:Uf9bXd50zTHtWTP7+7u5+OFCPtUVrmsS4v0RXd7E5lw=
|
||||
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2 h1:xbdUfr2KE4THsFx9CFWtWpU91lF+YhgP46moV94nYTA=
|
||||
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
|
||||
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 h1:ukTLOeMC0aVxbJWVg6hOsVJ0VPIo8w++PbNsze/pqF8=
|
||||
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
|
||||
github.com/aws/aws-sdk-go v1.19.11 h1:tqaTGER6Byw3QvsjGW0p018U2UOqaJPeJuzoaF7jjoQ=
|
||||
github.com/aws/aws-sdk-go v1.19.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.25.31 h1:14mdh3HsTgRekePPkYcCbAaEXJknc3mN7f4XfsiMMDA=
|
||||
github.com/aws/aws-sdk-go v1.25.31/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91 h1:GMmnK0dvr0Sf0gx3DvTbln0c8DE07B7sPVD9dgHOqo4=
|
||||
github.com/briandowns/spinner v0.0.0-20190319032542-ac46072a5a91/go.mod h1:hw/JEQBIE+c/BLI4aKM8UU8v+ZqrD3h7HC27kKt8JQU=
|
||||
github.com/caarlos0/env/v6 v6.0.0 h1:NZt6FAoB8ieKO5lEwRdwCzYxWFx7ZYF2R7UcoyaWtyc=
|
||||
@@ -58,8 +56,32 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
|
||||
github.com/cheggaaa/pb/v3 v3.0.3 h1:8WApbyUmgMOz7WIxJVNK0IRDcRfAmTxcEdi0TuxjdP4=
|
||||
github.com/cheggaaa/pb/v3 v3.0.3/go.mod h1:Pp35CDuiEpHa/ZLGCtBbM6CBwMstv1bJlG884V+73Yc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/continuity v0.0.0-20180216233310-d8fb8589b0e8/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20180921161001-7f53d412b9eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
|
||||
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
|
||||
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
|
||||
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
|
||||
github.com/containers/image/v5 v5.1.0 h1:5FjAvPJniamuNNIQHkh4PnsL+n+xzs6Aonzaz5dqTEo=
|
||||
github.com/containers/image/v5 v5.1.0/go.mod h1:BKlMD34WxRo1ruGHHEOrPQP0Qci7SWoPwU6fS7arsCU=
|
||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
|
||||
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/ocicrypt v0.0.0-20190930154801-b87a4a69c741 h1:8tQkOcednLJtUcZgK7sPglscXtxvMOnFOa6wd09VWLM=
|
||||
github.com/containers/ocicrypt v0.0.0-20190930154801-b87a4a69c741/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
|
||||
github.com/containers/storage v1.15.3/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
|
||||
github.com/containers/storage v1.15.5 h1:dBZx9yRFHod9c8FVaXlVtRqr2cmlAhpl+9rt87cE7J4=
|
||||
github.com/containers/storage v1.15.5/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
|
||||
github.com/coreos/clair v0.0.0-20180919182544-44ae4bc9590a/go.mod h1:uXhHPWAoRqw0jJc2f8RrPCwRhIo9otQ8OEWUFtpCiwA=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -68,19 +90,27 @@ github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14y
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c h1:QlAVcyoF7QQVN7zV+xYBjgwtRVlRU3WCTCpb2mcqQrM=
|
||||
github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v0.0.0-20170817175659-5f6282db7d65/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v0.0.0-20180920194744-16128bbac47f/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.0.0-20171019062838-86f080cff091/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v0.0.0-20180522102801-da99009bbb11/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f h1:W4fbqg0JUwy6lLesoJaV/rE0fwAmtdtinMa64X1CEh0=
|
||||
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-ce v0.0.0-20180924210327-f53bd8bb8e43 h1:gZ4lWixV821UVbYtr+oz1ZPCHkbtE+ivfmHyZRgyl2Y=
|
||||
github.com/docker/docker-ce v0.0.0-20180924210327-f53bd8bb8e43/go.mod h1:l1FUGRYBvbjnZ8MS6A2xOji4aZFlY/Qmgz7p4oXH7ac=
|
||||
github.com/docker/docker-credential-helpers v0.6.2 h1:CrW9H1VMf3a4GrtyAi7IUJjkJVpwBBpX0+mvkvYJaus=
|
||||
github.com/docker/docker-credential-helpers v0.6.2/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
|
||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/go-connections v0.0.0-20180212134524-7beb39f0b969/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-connections v0.0.0-20180821093606-97c2040d34df/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
||||
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA=
|
||||
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
@@ -93,45 +123,48 @@ github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkg
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/etcd-io/bbolt v1.3.2 h1:RLRQ0TKLX7DlBRXAJHvbmXL17Q3KNnTBtZ9B6Qo+/Y0=
|
||||
github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=
|
||||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e/go.mod h1:2H9hjfbpSMHwY503FclkV/lZTBh2YlOmLLSda12uL8c=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/genuinetools/pkg v0.0.0-20181022210355-2fcf164d37cb/go.mod h1:XTcrCYlXPxnxL2UpnwuRn7tcaTn9HAhxFoFJucootk8=
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
||||
github.com/genuinetools/pkg v0.0.0-20180910213200-1c141f661797/go.mod h1:XTcrCYlXPxnxL2UpnwuRn7tcaTn9HAhxFoFJucootk8=
|
||||
github.com/genuinetools/reg v0.16.0 h1:ZhLZPT+aUGHLfy45Ub5FLWik+3Dij1iwaj8A/GyAZBw=
|
||||
github.com/genuinetools/reg v0.16.0/go.mod h1:12Fe9EIvK3dG/qWhNk5e9O96I8SGmCKLsJ8GsXUbk+Y=
|
||||
github.com/ghodss/yaml v0.0.0-20161207003320-04f313413ffd/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.1.3 h1:cBU46h1lYQk5f2Z+jZbewFKy+1zzE2aUX/ilcPDAm9M=
|
||||
github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/gogo/protobuf v0.0.0-20170815085658-fcdc5011193f/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@@ -148,17 +181,23 @@ github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs167
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||
github.com/gorilla/mux v0.0.0-20170217192616-94e7d24fd285/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU=
|
||||
github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
@@ -167,11 +206,16 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8=
|
||||
github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.9.4 h1:xhvAeUPQ2drNUhKtrGdTGNvV9nNafHMUkRyLkzxJoB4=
|
||||
github.com/klauspost/compress v1.9.4/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
|
||||
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/knqyf263/berkeleydb v0.0.0-20190501065933-fafe01fb9662/go.mod h1:bu1CcN4tUtoRcI/B/RFHhxMNKFHVq/c3SV+UTyduoXg=
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c=
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
|
||||
@@ -182,7 +226,6 @@ github.com/knqyf263/go-version v1.1.1 h1:+MpcBC9b7rk5ihag8Y/FLG8get1H2GjniwKQ+9D
|
||||
github.com/knqyf263/go-version v1.1.1/go.mod h1:0tBvHvOBSf5TqGNcY+/ih9o8qo3R16iZCpB9rP0D3VM=
|
||||
github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc=
|
||||
github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -192,32 +235,32 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed h1:fCWISZq4YN4ulCJx7x0KB15rqxLEe3mtNJL8cSOGKZU=
|
||||
github.com/mattn/go-jsonpointer v0.0.0-20180225143300-37667080efed/go.mod h1:SDJ4hurDYyQ9/7nc+eCYtXqdufgK4Cq9TJlwPklqEYA=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k=
|
||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
|
||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
|
||||
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c/go.mod h1:GhAqVMEWnTcW2dxoD/SO3n2enrgWl3y6Dnx4m59GvcA=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
@@ -225,17 +268,27 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a h1:0LD5FJ
|
||||
github.com/olekukonko/tablewriter v0.0.2-0.20190607075207-195002e6e56a/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2 h1:QhPf3A2AZW3tTGvHPg0TA+CR3oHbVLlXUhlghqISp1I=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
|
||||
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU=
|
||||
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc=
|
||||
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqGe5TgR0g=
|
||||
github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw=
|
||||
github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
|
||||
github.com/parnurzeal/gorequest v0.2.16 h1:T/5x+/4BT+nj+3eSknXmCTnEVGSzFzPGdpqmUVVZXHQ=
|
||||
github.com/parnurzeal/gorequest v0.2.16/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/peterhellberg/link v1.0.0 h1:mUWkiegowUXEcmlb+ybF75Q/8D2Y0BjZtR8cxoKhaQo=
|
||||
github.com/peterhellberg/link v1.0.0/go.mod h1:gtSlOT4jmkY8P47hbTc8PTgiDDWpdPbFYl75keYyBB8=
|
||||
@@ -245,25 +298,26 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
|
||||
github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9 h1:kyf9snWXHvQc+yxE9imhdI8YAm4oKeZISlaAR+x73zs=
|
||||
github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
|
||||
github.com/prometheus/client_golang v0.0.0-20180924113449-f69c853d21c1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
@@ -271,67 +325,86 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/httpfs v0.0.0-20181222201310-74dc9339e414/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
|
||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tomoyamachi/reg v0.16.1-0.20190706172545-2a2250fd7c00 h1:0e4vRd9YqnQBIAIAE39jLKDWffRfJWxloyWwcaMAQho=
|
||||
github.com/tomoyamachi/reg v0.16.1-0.20190706172545-2a2250fd7c00/go.mod h1:RQE7h2jyIxekQZ24/wad0c9RGP+KSq4XzHh7h83ALi8=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
|
||||
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
||||
github.com/twitchtv/twirp v5.10.1+incompatible h1:35js8ID9rYPKkZ0qWnuZw+q+OuCWM1GIibu1F1YImjA=
|
||||
github.com/twitchtv/twirp v5.10.1+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
|
||||
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
|
||||
github.com/vbauerster/mpb/v4 v4.11.1/go.mod h1:vMLa1J/ZKC83G2lB/52XpqT+ZZtFG4aZOdKhmpRL1uM=
|
||||
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
|
||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xeipuuv/gojsonschema v0.0.0-20190816131739-be0936907f66/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
|
||||
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
|
||||
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5 h1:bselrhR0Or1vomJZC8ZIjWtbDmn9OYFLX5Ik9alpJpE=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4=
|
||||
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -342,15 +415,16 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180925072008-f04abc6bdfa7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c h1:SRpq/kuj/xNci/RdvEs+RSvpfxqvLAzTKuKGlzoGdZQ=
|
||||
golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -360,12 +434,12 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180925112736-b09afc3d579e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -374,19 +448,20 @@ golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190506115046-ca7f33d4116e h1:bq5BY1tGuaK8HxuwN6pT6kWgTVLeJ5KwuyBpsl1CZL4=
|
||||
golang.org/x/sys v0.0.0-20190506115046-ca7f33d4116e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -400,16 +475,13 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190503185657-3b6f9c0030f7/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191121040551-947d4aa89328 h1:t3X42h9e6xdbrCD/gPyWqAXr2BEpdJqRd1brThaaxII=
|
||||
golang.org/x/tools v0.0.0-20191121040551-947d4aa89328/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373 h1:PPwnA7z1Pjf7XYaBP9GL1VAMZmcIWyFz7QCMSIIa3Bg=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -418,50 +490,56 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180924164928-221a8d4f7494/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.4.0 h1:KFpaNTUcLHLoP/OkdcRXR+MA5p55MhA41YVb7Wd8EfM=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.4.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.10.0 h1:NWjTJTQnk8UpIGlssuefyDZ6JruEjo5s88vm88uASbw=
|
||||
gopkg.in/src-d/go-git.v4 v4.10.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE=
|
||||
k8s.io/client-go v0.0.0-20170217214107-bcde30fb7eae/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
||||
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
|
||||
k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA=
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
|
||||
@@ -4,6 +4,7 @@ package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -229,7 +230,7 @@ func TestRun_WithDockerEngine(t *testing.T) {
|
||||
name: "sad path, invalid image",
|
||||
invalidImage: true,
|
||||
testfile: "badimage:latest",
|
||||
expectedError: "error in image scan: failed to analyze image: failed to extract files: failed to get the v2 manifest: Get https://registry-1.docker.io/v2/library/badimage/manifests/latest: http: non-successful response (status=401 body=\"{\\\"errors\\\":[{\\\"code\\\":\\\"UNAUTHORIZED\\\",\\\"message\\\":\\\"authentication required\\\",\\\"detail\\\":[{\\\"Type\\\":\\\"repository\\\",\\\"Class\\\":\\\"\\\",\\\"Name\\\":\\\"library/badimage\\\",\\\"Action\\\":\\\"pull\\\"}]}]}\\n\")",
|
||||
expectedError: "unable to initialize a image struct: Error reading manifest latest in docker.io/library/badimage",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -256,8 +257,9 @@ func TestRun_WithDockerEngine(t *testing.T) {
|
||||
})
|
||||
|
||||
// load image into docker engine
|
||||
_, err = cli.ImageLoad(ctx, testfile, true)
|
||||
res, err := cli.ImageLoad(ctx, testfile, true)
|
||||
require.NoError(t, err, tc.name)
|
||||
io.Copy(ioutil.Discard, res.Body)
|
||||
|
||||
// tag our image to something unique
|
||||
err = cli.ImageTag(ctx, tc.imageTag, tc.testfile)
|
||||
@@ -293,7 +295,8 @@ func TestRun_WithDockerEngine(t *testing.T) {
|
||||
err = app.Run(trivyArgs)
|
||||
switch {
|
||||
case tc.expectedError != "":
|
||||
assert.Equal(t, tc.expectedError, err.Error(), tc.name)
|
||||
require.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), tc.expectedError, tc.name)
|
||||
default:
|
||||
assert.NoError(t, err, tc.name)
|
||||
}
|
||||
@@ -311,6 +314,10 @@ func TestRun_WithDockerEngine(t *testing.T) {
|
||||
Force: true,
|
||||
PruneChildren: true,
|
||||
})
|
||||
_, err = cli.ImageRemove(ctx, tc.imageTag, types.ImageRemoveOptions{
|
||||
Force: true,
|
||||
PruneChildren: true,
|
||||
})
|
||||
assert.NoError(t, err, tc.name)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -104,6 +104,12 @@ var (
|
||||
EnvVar: "TRIVY_DEBUG",
|
||||
}
|
||||
|
||||
removedPkgsFlag = cli.BoolFlag{
|
||||
Name: "removed-pkgs",
|
||||
Usage: "detect vulnerabilities of removed packages (only for Alpine)",
|
||||
EnvVar: "TRIVY_REMOVED_PKGS",
|
||||
}
|
||||
|
||||
vulnTypeFlag = cli.StringFlag{
|
||||
Name: "vuln-type",
|
||||
Value: "os,library",
|
||||
@@ -127,7 +133,7 @@ var (
|
||||
|
||||
timeoutFlag = cli.DurationFlag{
|
||||
Name: "timeout",
|
||||
Value: time.Second * 60,
|
||||
Value: time.Second * 120,
|
||||
Usage: "docker timeout",
|
||||
EnvVar: "TRIVY_TIMEOUT",
|
||||
}
|
||||
@@ -192,6 +198,7 @@ OPTIONS:
|
||||
noProgressFlag,
|
||||
ignoreUnfixedFlag,
|
||||
debugFlag,
|
||||
removedPkgsFlag,
|
||||
vulnTypeFlag,
|
||||
cacheDirFlag,
|
||||
ignoreFileFlag,
|
||||
@@ -242,6 +249,7 @@ func NewClientCommand() cli.Command {
|
||||
quietFlag,
|
||||
ignoreUnfixedFlag,
|
||||
debugFlag,
|
||||
removedPkgsFlag,
|
||||
vulnTypeFlag,
|
||||
ignoreFileFlag,
|
||||
cacheDirFlag,
|
||||
|
||||
@@ -30,12 +30,13 @@ type Config struct {
|
||||
Format string
|
||||
Template string
|
||||
|
||||
Timeout time.Duration
|
||||
vulnType string
|
||||
severities string
|
||||
IgnoreFile string
|
||||
IgnoreUnfixed bool
|
||||
ExitCode int
|
||||
Timeout time.Duration
|
||||
ScanRemovedPkgs bool
|
||||
vulnType string
|
||||
severities string
|
||||
IgnoreFile string
|
||||
IgnoreUnfixed bool
|
||||
ExitCode int
|
||||
|
||||
RemoteAddr string
|
||||
token string
|
||||
@@ -73,12 +74,13 @@ func New(c *cli.Context) (Config, error) {
|
||||
Format: c.String("format"),
|
||||
Template: c.String("template"),
|
||||
|
||||
Timeout: c.Duration("timeout"),
|
||||
vulnType: c.String("vuln-type"),
|
||||
severities: c.String("severity"),
|
||||
IgnoreFile: c.String("ignorefile"),
|
||||
IgnoreUnfixed: c.Bool("ignore-unfixed"),
|
||||
ExitCode: c.Int("exit-code"),
|
||||
Timeout: c.Duration("timeout"),
|
||||
ScanRemovedPkgs: c.Bool("removed-pkgs"),
|
||||
vulnType: c.String("vuln-type"),
|
||||
severities: c.String("severity"),
|
||||
IgnoreFile: c.String("ignorefile"),
|
||||
IgnoreUnfixed: c.Bool("ignore-unfixed"),
|
||||
ExitCode: c.Int("exit-code"),
|
||||
|
||||
RemoteAddr: c.String("remote"),
|
||||
token: c.String("token"),
|
||||
|
||||
@@ -3,18 +3,26 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client/library"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
func initializeScanner(cacheClient cache.Cache, ospkgCustomHeaders ospkg.CustomHeaders, libraryCustomHeaders library.CustomHeaders,
|
||||
ospkgURL ospkg.RemoteURL, libURL library.RemoteURL) scanner.Scanner {
|
||||
wire.Build(scanner.ClientSet)
|
||||
return scanner.Scanner{}
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, customHeaders client.CustomHeaders,
|
||||
url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
|
||||
wire.Build(scanner.RemoteDockerSet)
|
||||
return scanner.Scanner{}, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, customHeaders client.CustomHeaders,
|
||||
url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
|
||||
wire.Build(scanner.RemoteArchiveSet)
|
||||
return scanner.Scanner{}, nil
|
||||
}
|
||||
|
||||
func initializeVulnerabilityClient() vulnerability.Client {
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/internal/client/config"
|
||||
"github.com/aquasecurity/trivy/internal/operation"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client/library"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func Run(cliCtx *cli.Context) error {
|
||||
@@ -37,31 +36,40 @@ func run(c config.Config) (err error) {
|
||||
|
||||
// configure cache dir
|
||||
utils.SetCacheDir(c.CacheDir)
|
||||
cacheClient := cache.Initialize(c.CacheDir)
|
||||
cacheOperation := operation.NewCache(cacheClient)
|
||||
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
|
||||
|
||||
if c.ClearCache {
|
||||
return cacheOperation.ClearImages()
|
||||
log.Logger.Warn("A client doesn't have image cache")
|
||||
return nil
|
||||
}
|
||||
|
||||
var scanner scanner.Scanner
|
||||
ctx := context.Background()
|
||||
remoteCache := cache.NewRemoteCache(cache.RemoteURL(c.RemoteAddr), c.CustomHeaders)
|
||||
|
||||
if c.Input != "" {
|
||||
// scan tar file
|
||||
scanner, err = initializeArchiveScanner(ctx, c.Input, remoteCache,
|
||||
client.CustomHeaders(c.CustomHeaders), client.RemoteURL(c.RemoteAddr), c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
||||
}
|
||||
} else {
|
||||
// scan an image in Docker Engine or Docker Registry
|
||||
scanner, err = initializeDockerScanner(ctx, c.ImageName, remoteCache,
|
||||
client.CustomHeaders(c.CustomHeaders), client.RemoteURL(c.RemoteAddr), c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the docker scanner: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
scanOptions := types.ScanOptions{
|
||||
VulnType: c.VulnType,
|
||||
RemoteURL: c.RemoteAddr,
|
||||
VulnType: c.VulnType,
|
||||
ScanRemovedPackages: c.ScanRemovedPkgs,
|
||||
}
|
||||
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
|
||||
|
||||
dockerOption, err := types.GetDockerOption()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get docker option: %w", err)
|
||||
}
|
||||
dockerOption.Timeout = c.Timeout
|
||||
|
||||
scanner := initializeScanner(cacheClient,
|
||||
ospkg.CustomHeaders(c.CustomHeaders), library.CustomHeaders(c.CustomHeaders),
|
||||
ospkg.RemoteURL(c.RemoteAddr), library.RemoteURL(c.RemoteAddr))
|
||||
|
||||
results, err := scanner.ScanImage(c.ImageName, c.Input, scanOptions, dockerOption)
|
||||
results, err := scanner.ScanImage(scanOptions)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in image scan: %w", err)
|
||||
}
|
||||
|
||||
@@ -6,31 +6,54 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/extractor/docker"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client/library"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
library2 "github.com/aquasecurity/trivy/pkg/scanner/library"
|
||||
ospkg2 "github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Injectors from inject.go:
|
||||
|
||||
func initializeScanner(cacheClient cache.Cache, ospkgCustomHeaders ospkg.CustomHeaders, libraryCustomHeaders library.CustomHeaders, ospkgURL ospkg.RemoteURL, libURL library.RemoteURL) scanner.Scanner {
|
||||
osDetector := ospkg.NewProtobufClient(ospkgURL)
|
||||
detector := ospkg.NewDetector(ospkgCustomHeaders, osDetector)
|
||||
ospkgScanner := ospkg2.NewScanner(detector)
|
||||
libDetector := library.NewProtobufClient(libURL)
|
||||
libraryDetector := library.NewDetector(libraryCustomHeaders, libDetector)
|
||||
libraryScanner := library2.NewScanner(libraryDetector)
|
||||
scannerScanner := scanner.NewScanner(cacheClient, ospkgScanner, libraryScanner)
|
||||
return scannerScanner
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
|
||||
scannerScanner := client.NewProtobufClient(url)
|
||||
clientScanner := client.NewScanner(customHeaders, scannerScanner)
|
||||
dockerOption, err := types.GetDockerOption(timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
extractor, err := docker.NewDockerExtractor(ctx, imageName, dockerOption)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scanner2 := scanner.NewScanner(clientScanner, config)
|
||||
return scanner2, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, customHeaders client.CustomHeaders, url client.RemoteURL, timeout time.Duration) (scanner.Scanner, error) {
|
||||
scannerScanner := client.NewProtobufClient(url)
|
||||
clientScanner := client.NewScanner(customHeaders, scannerScanner)
|
||||
dockerOption, err := types.GetDockerOption(timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
extractor, err := docker.NewDockerArchiveExtractor(ctx, filePath, dockerOption)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scanner2 := scanner.NewScanner(clientScanner, config)
|
||||
return scanner2, nil
|
||||
}
|
||||
|
||||
func initializeVulnerabilityClient() vulnerability.Client {
|
||||
config := db.Config{}
|
||||
client := vulnerability.NewClient(config)
|
||||
return client
|
||||
vulnerabilityClient := vulnerability.NewClient(config)
|
||||
return vulnerabilityClient
|
||||
}
|
||||
|
||||
@@ -14,15 +14,16 @@ import (
|
||||
)
|
||||
|
||||
var SuperSet = wire.NewSet(
|
||||
cache.Initialize,
|
||||
cache.NewFSCache,
|
||||
wire.Bind(new(cache.LocalImageCache), new(cache.FSCache)),
|
||||
NewCache,
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
client cache.Cache
|
||||
client cache.LocalImageCache
|
||||
}
|
||||
|
||||
func NewCache(client cache.Cache) Cache {
|
||||
func NewCache(client cache.LocalImageCache) Cache {
|
||||
return Cache{client: client}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -30,8 +31,13 @@ func run(c config.Config) (err error) {
|
||||
utils.SetCacheDir(c.CacheDir)
|
||||
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
|
||||
|
||||
fsCache, err := cache.NewFSCache(utils.CacheDir())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize cache: %w", err)
|
||||
}
|
||||
|
||||
// server doesn't have image cache
|
||||
cacheOperation := operation.NewCache(nil)
|
||||
cacheOperation := operation.NewCache(fsCache)
|
||||
if c.Reset {
|
||||
return cacheOperation.ClearDB()
|
||||
}
|
||||
@@ -49,5 +55,5 @@ func run(c config.Config) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return server.ListenAndServe(c.Listen, c)
|
||||
return server.ListenAndServe(c, fsCache)
|
||||
}
|
||||
|
||||
@@ -33,13 +33,14 @@ type Config struct {
|
||||
Format string
|
||||
Template string
|
||||
|
||||
Timeout time.Duration
|
||||
vulnType string
|
||||
Light bool
|
||||
severities string
|
||||
IgnoreFile string
|
||||
IgnoreUnfixed bool
|
||||
ExitCode int
|
||||
Timeout time.Duration
|
||||
ScanRemovedPkgs bool
|
||||
vulnType string
|
||||
Light bool
|
||||
severities string
|
||||
IgnoreFile string
|
||||
IgnoreUnfixed bool
|
||||
ExitCode int
|
||||
|
||||
// these variables are generated by Init()
|
||||
ImageName string
|
||||
@@ -82,13 +83,14 @@ func New(c *cli.Context) (Config, error) {
|
||||
Format: c.String("format"),
|
||||
Template: c.String("template"),
|
||||
|
||||
Timeout: c.Duration("timeout"),
|
||||
vulnType: c.String("vuln-type"),
|
||||
Light: c.Bool("light"),
|
||||
severities: c.String("severity"),
|
||||
IgnoreFile: c.String("ignorefile"),
|
||||
IgnoreUnfixed: c.Bool("ignore-unfixed"),
|
||||
ExitCode: c.Int("exit-code"),
|
||||
Timeout: c.Duration("timeout"),
|
||||
ScanRemovedPkgs: c.Bool("removed-pkgs"),
|
||||
vulnType: c.String("vuln-type"),
|
||||
Light: c.Bool("light"),
|
||||
severities: c.String("severity"),
|
||||
IgnoreFile: c.String("ignorefile"),
|
||||
IgnoreUnfixed: c.Bool("ignore-unfixed"),
|
||||
ExitCode: c.Int("exit-code"),
|
||||
|
||||
onlyUpdate: c.String("only-update"),
|
||||
refresh: c.Bool("refresh"),
|
||||
|
||||
@@ -3,21 +3,25 @@
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/internal/operation"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
func initializeCacheClient(cacheDir string) (operation.Cache, error) {
|
||||
wire.Build(operation.SuperSet)
|
||||
return operation.Cache{}, nil
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache,
|
||||
timeout time.Duration) (scanner.Scanner, error) {
|
||||
wire.Build(scanner.StandaloneDockerSet)
|
||||
return scanner.Scanner{}, nil
|
||||
}
|
||||
|
||||
func initializeScanner(c cache.Cache) scanner.Scanner {
|
||||
wire.Build(scanner.StandaloneSet)
|
||||
return scanner.Scanner{}
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache,
|
||||
timeout time.Duration) (scanner.Scanner, error) {
|
||||
wire.Build(scanner.StandaloneArchiveSet)
|
||||
return scanner.Scanner{}, nil
|
||||
}
|
||||
|
||||
func initializeVulnerabilityClient() vulnerability.Client {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
l "log"
|
||||
"os"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/internal/standalone/config"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
"github.com/urfave/cli"
|
||||
@@ -38,7 +40,11 @@ func run(c config.Config) (err error) {
|
||||
|
||||
// configure cache dir
|
||||
utils.SetCacheDir(c.CacheDir)
|
||||
cacheClient := cache.Initialize(c.CacheDir)
|
||||
cacheClient, err := cache.NewFSCache(c.CacheDir)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the cache: %w", err)
|
||||
}
|
||||
|
||||
cacheOperation := operation.NewCache(cacheClient)
|
||||
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
|
||||
|
||||
@@ -63,19 +69,30 @@ func run(c config.Config) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var scanner scanner.Scanner
|
||||
ctx := context.Background()
|
||||
|
||||
if c.Input != "" {
|
||||
// scan tar file
|
||||
scanner, err = initializeArchiveScanner(ctx, c.Input, cacheClient, cacheClient, c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the archive scanner: %w", err)
|
||||
}
|
||||
} else {
|
||||
// scan an image in Docker Engine or Docker Registry
|
||||
scanner, err = initializeDockerScanner(ctx, c.ImageName, cacheClient, cacheClient, c.Timeout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to initialize the docker scanner: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
scanOptions := types.ScanOptions{
|
||||
VulnType: c.VulnType,
|
||||
VulnType: c.VulnType,
|
||||
ScanRemovedPackages: c.ScanRemovedPkgs,
|
||||
}
|
||||
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
|
||||
|
||||
dockerOption, err := types.GetDockerOption()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get docker option: %w", err)
|
||||
}
|
||||
dockerOption.Timeout = c.Timeout
|
||||
|
||||
scanner := initializeScanner(cacheClient)
|
||||
results, err := scanner.ScanImage(c.ImageName, c.Input, scanOptions, dockerOption)
|
||||
results, err := scanner.ScanImage(scanOptions)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in image scan: %w", err)
|
||||
}
|
||||
|
||||
@@ -6,33 +6,58 @@
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/extractor/docker"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/internal/operation"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
library2 "github.com/aquasecurity/trivy/pkg/scanner/library"
|
||||
ospkg2 "github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Injectors from inject.go:
|
||||
|
||||
func initializeCacheClient(cacheDir string) (operation.Cache, error) {
|
||||
cacheCache := cache.Initialize(cacheDir)
|
||||
operationCache := operation.NewCache(cacheCache)
|
||||
return operationCache, nil
|
||||
}
|
||||
|
||||
func initializeScanner(c cache.Cache) scanner.Scanner {
|
||||
func initializeDockerScanner(ctx context.Context, imageName string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache, timeout time.Duration) (scanner.Scanner, error) {
|
||||
applier := analyzer.NewApplier(localImageCache)
|
||||
detector := ospkg.Detector{}
|
||||
ospkgScanner := ospkg2.NewScanner(detector)
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
libraryScanner := library2.NewScanner(libraryDetector)
|
||||
scannerScanner := scanner.NewScanner(c, ospkgScanner, libraryScanner)
|
||||
return scannerScanner
|
||||
localScanner := local.NewScanner(applier, detector, libraryDetector)
|
||||
dockerOption, err := types.GetDockerOption(timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
extractor, err := docker.NewDockerExtractor(ctx, imageName, dockerOption)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scannerScanner := scanner.NewScanner(localScanner, config)
|
||||
return scannerScanner, nil
|
||||
}
|
||||
|
||||
func initializeArchiveScanner(ctx context.Context, filePath string, layerCache cache.ImageCache, localImageCache cache.LocalImageCache, timeout time.Duration) (scanner.Scanner, error) {
|
||||
applier := analyzer.NewApplier(localImageCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
localScanner := local.NewScanner(applier, detector, libraryDetector)
|
||||
dockerOption, err := types.GetDockerOption(timeout)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
extractor, err := docker.NewDockerArchiveExtractor(ctx, filePath, dockerOption)
|
||||
if err != nil {
|
||||
return scanner.Scanner{}, err
|
||||
}
|
||||
config := analyzer.New(extractor, layerCache)
|
||||
scannerScanner := scanner.NewScanner(localScanner, config)
|
||||
return scannerScanner, nil
|
||||
}
|
||||
|
||||
func initializeVulnerabilityClient() vulnerability.Client {
|
||||
|
||||
51
pkg/cache/remote.go
vendored
Normal file
51
pkg/cache/remote.go
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
)
|
||||
|
||||
type RemoteCache struct {
|
||||
ctx context.Context // for custom header
|
||||
client rpcCache.Cache
|
||||
}
|
||||
|
||||
type RemoteURL string
|
||||
|
||||
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ImageCache {
|
||||
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
|
||||
c := rpcCache.NewCacheProtobufClient(string(url), &http.Client{})
|
||||
return &RemoteCache{ctx: ctx, client: c}
|
||||
}
|
||||
|
||||
func (c RemoteCache) PutImage(imageID string, imageInfo types.ImageInfo) error {
|
||||
_, err := c.client.PutImage(c.ctx, rpc.ConvertToRpcImageInfo(imageID, imageInfo))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c RemoteCache) PutLayer(layerID, decompressedLayerID string, layerInfo types.LayerInfo) error {
|
||||
_, err := c.client.PutLayer(c.ctx, rpc.ConvertToRpcLayerInfo(layerID, decompressedLayerID, layerInfo))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c RemoteCache) MissingLayers(imageID string, layerIDs []string) (bool, []string, error) {
|
||||
layers, err := c.client.MissingLayers(c.ctx, rpc.ConvertToMissingLayersRequest(imageID, layerIDs))
|
||||
if err != nil {
|
||||
return false, nil, xerrors.Errorf("unable to fetch missing layers: %w", err)
|
||||
}
|
||||
return layers.MissingImage, layers.MissingLayerIds, nil
|
||||
}
|
||||
294
pkg/cache/remote_test.go
vendored
Normal file
294
pkg/cache/remote_test.go
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
package cache_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
google_protobuf "github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/twitchtv/twirp"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
fcache "github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/cache"
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
"github.com/aquasecurity/trivy/rpc/detector"
|
||||
)
|
||||
|
||||
type mockCacheServer struct {
|
||||
cache fcache.Cache
|
||||
}
|
||||
|
||||
func (s *mockCacheServer) PutImage(_ context.Context, in *rpcCache.PutImageRequest) (*google_protobuf.Empty, error) {
|
||||
if strings.Contains(in.ImageId, "invalid") {
|
||||
return &google_protobuf.Empty{}, xerrors.New("invalid image ID")
|
||||
}
|
||||
return &google_protobuf.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *mockCacheServer) PutLayer(_ context.Context, in *rpcCache.PutLayerRequest) (*google_protobuf.Empty, error) {
|
||||
if strings.Contains(in.LayerId, "invalid") {
|
||||
return &google_protobuf.Empty{}, xerrors.New("invalid layer ID")
|
||||
}
|
||||
return &google_protobuf.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *mockCacheServer) MissingLayers(_ context.Context, in *rpcCache.MissingLayersRequest) (*rpcCache.MissingLayersResponse, error) {
|
||||
var layerIDs []string
|
||||
for _, layerID := range in.LayerIds[:len(in.LayerIds)-1] {
|
||||
if strings.Contains(layerID, "invalid") {
|
||||
return nil, xerrors.New("invalid layer ID")
|
||||
}
|
||||
layerIDs = append(layerIDs, layerID)
|
||||
}
|
||||
return &rpcCache.MissingLayersResponse{MissingImage: true, MissingLayerIds: layerIDs}, nil
|
||||
}
|
||||
|
||||
func withToken(base http.Handler, token, tokenHeader string) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if token != "" && token != r.Header.Get(tokenHeader) {
|
||||
detector.WriteError(w, twirp.NewError(twirp.Unauthenticated, "invalid token"))
|
||||
return
|
||||
}
|
||||
base.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRemoteCache_PutImage(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
layerHandler := rpcCache.NewCacheServer(new(mockCacheServer), nil)
|
||||
mux.Handle(rpcCache.CachePathPrefix, withToken(layerHandler, "valid-token", "Trivy-Token"))
|
||||
ts := httptest.NewServer(mux)
|
||||
|
||||
type args struct {
|
||||
imageID string
|
||||
imageInfo types.ImageInfo
|
||||
customHeaders http.Header
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
imageInfo: types.ImageInfo{
|
||||
SchemaVersion: 1,
|
||||
Architecture: "amd64",
|
||||
Created: time.Time{},
|
||||
DockerVersion: "18.06",
|
||||
OS: "linux",
|
||||
HistoryPackages: []types.Package{
|
||||
{
|
||||
Name: "musl",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"valid-token"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad path",
|
||||
args: args{
|
||||
imageID: "sha256:invalid",
|
||||
imageInfo: types.ImageInfo{
|
||||
SchemaVersion: 1,
|
||||
Architecture: "amd64",
|
||||
Created: time.Time{},
|
||||
DockerVersion: "18.06",
|
||||
OS: "linux",
|
||||
HistoryPackages: []types.Package{
|
||||
{
|
||||
Name: "musl",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"valid-token"},
|
||||
},
|
||||
},
|
||||
wantErr: "twirp error internal",
|
||||
},
|
||||
{
|
||||
name: "sad path: invalid token",
|
||||
args: args{
|
||||
imageID: "sha256:invalid",
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"invalid-token"},
|
||||
},
|
||||
},
|
||||
wantErr: "twirp error unauthenticated",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
|
||||
err := c.PutImage(tt.args.imageID, tt.args.imageInfo)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteCache_PutLayer(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
layerHandler := rpcCache.NewCacheServer(new(mockCacheServer), nil)
|
||||
mux.Handle(rpcCache.CachePathPrefix, withToken(layerHandler, "valid-token", "Trivy-Token"))
|
||||
ts := httptest.NewServer(mux)
|
||||
|
||||
type args struct {
|
||||
layerID string
|
||||
decompressedLayerID string
|
||||
layerInfo types.LayerInfo
|
||||
customHeaders http.Header
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
layerID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
decompressedLayerID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"valid-token"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad path",
|
||||
args: args{
|
||||
layerID: "sha256:invalid",
|
||||
decompressedLayerID: "sha256:invalid",
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"valid-token"},
|
||||
},
|
||||
},
|
||||
wantErr: "twirp error internal",
|
||||
},
|
||||
{
|
||||
name: "sad path: invalid token",
|
||||
args: args{
|
||||
layerID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
decompressedLayerID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"invalid-token"},
|
||||
},
|
||||
},
|
||||
wantErr: "twirp error unauthenticated",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
|
||||
err := c.PutLayer(tt.args.layerID, tt.args.decompressedLayerID, tt.args.layerInfo)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteCache_MissingLayers(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
layerHandler := rpcCache.NewCacheServer(new(mockCacheServer), nil)
|
||||
mux.Handle(rpcCache.CachePathPrefix, withToken(layerHandler, "valid-token", "Trivy-Token"))
|
||||
ts := httptest.NewServer(mux)
|
||||
|
||||
type args struct {
|
||||
imageID string
|
||||
layerIDs []string
|
||||
customHeaders http.Header
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantMissingImage bool
|
||||
wantMissingLayerIDs []string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
layerIDs: []string{
|
||||
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"valid-token"},
|
||||
},
|
||||
},
|
||||
wantMissingImage: true,
|
||||
wantMissingLayerIDs: []string{
|
||||
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad path",
|
||||
args: args{
|
||||
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
layerIDs: []string{
|
||||
"sha256:invalid",
|
||||
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"valid-token"},
|
||||
},
|
||||
},
|
||||
wantErr: "twirp error internal",
|
||||
},
|
||||
{
|
||||
name: "sad path with invalid token",
|
||||
args: args{
|
||||
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
layerIDs: []string{
|
||||
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
customHeaders: http.Header{
|
||||
"Trivy-Token": []string{"invalid-token"},
|
||||
},
|
||||
},
|
||||
wantErr: "twirp error unauthenticated",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
|
||||
gotMissingImage, gotMissingLayerIDs, err := c.MissingLayers(tt.args.imageID, tt.args.layerIDs)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.wantMissingImage, gotMissingImage)
|
||||
assert.Equal(t, tt.wantMissingLayerIDs, gotMissingLayerIDs)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/alpine"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
@@ -50,7 +50,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Alpine vulnerabilities...")
|
||||
if strings.Count(osVer, ".") > 1 {
|
||||
osVer = osVer[:strings.LastIndex(osVer, ".")]
|
||||
|
||||
@@ -6,9 +6,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
@@ -23,7 +24,7 @@ func TestMain(m *testing.M) {
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
type args struct {
|
||||
osVer string
|
||||
pkgs []analyzer.Package
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
type getInput struct {
|
||||
osVer string
|
||||
@@ -52,7 +53,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
name: "happy path",
|
||||
args: args{
|
||||
osVer: "3.10.2",
|
||||
pkgs: []analyzer.Package{
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "ansible",
|
||||
Version: "2.6.4",
|
||||
@@ -109,7 +110,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
name: "contain rc",
|
||||
args: args{
|
||||
osVer: "3.9",
|
||||
pkgs: []analyzer.Package{
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "jq",
|
||||
Version: "1.6-r0",
|
||||
@@ -150,7 +151,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
name: "Get returns an error",
|
||||
args: args{
|
||||
osVer: "3.8.1",
|
||||
pkgs: []analyzer.Package{
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "jq",
|
||||
Version: "1.6-r0",
|
||||
|
||||
@@ -3,12 +3,11 @@ package amazon
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/amazon"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
@@ -28,7 +27,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Amazon Linux vulnerabilities...")
|
||||
|
||||
osVer = strings.Fields(osVer)[0]
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
"go.uber.org/zap/zaptest/observer"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
@@ -52,7 +52,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []analyzer.Package{
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "2.1.0",
|
||||
@@ -89,7 +89,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
vuls, err := s.Detect("foo", []analyzer.Package{
|
||||
vuls, err := s.Detect("foo", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
},
|
||||
@@ -115,7 +115,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []analyzer.Package{
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "badsourceversion",
|
||||
@@ -144,7 +144,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []analyzer.Package{
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "3.1.0",
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -52,7 +52,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Debian vulnerabilities...")
|
||||
|
||||
if strings.Count(osVer, ".") > 0 {
|
||||
|
||||
@@ -3,6 +3,11 @@ package ospkg
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/wire"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
fos "github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/alpine"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/amazon"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
|
||||
@@ -12,11 +17,6 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/suse"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/ubuntu"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/google/wire"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
fos "github.com/aquasecurity/fanal/analyzer/os"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
@@ -30,17 +30,17 @@ var (
|
||||
)
|
||||
|
||||
type Operation interface {
|
||||
Detect(string, string, string, time.Time, []analyzer.Package) ([]types.DetectedVulnerability, bool, error)
|
||||
Detect(string, string, string, time.Time, []ftypes.Package) ([]types.DetectedVulnerability, bool, error)
|
||||
}
|
||||
|
||||
type Driver interface {
|
||||
Detect(string, []analyzer.Package) ([]types.DetectedVulnerability, error)
|
||||
Detect(string, []ftypes.Package) ([]types.DetectedVulnerability, error)
|
||||
IsSupportedVersion(string, string) bool
|
||||
}
|
||||
|
||||
type Detector struct{}
|
||||
|
||||
func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
|
||||
func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.Package) ([]types.DetectedVulnerability, bool, error) {
|
||||
driver := newDriver(osFamily, osName)
|
||||
if driver == nil {
|
||||
return nil, false, ErrUnsupportedOS
|
||||
|
||||
@@ -3,7 +3,7 @@ package ospkg
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
@@ -17,7 +17,7 @@ type DetectInput struct {
|
||||
OSFamily string
|
||||
OSName string
|
||||
Created time.Time
|
||||
Pkgs []analyzer.Package
|
||||
Pkgs []ftypes.Package
|
||||
}
|
||||
type DetectOutput struct {
|
||||
Vulns []types.DetectedVulnerability
|
||||
@@ -38,7 +38,7 @@ func NewMockDetector(detectExpectations []DetectExpectation) *MockDetector {
|
||||
return mockDetector
|
||||
}
|
||||
|
||||
func (_m *MockDetector) Detect(a string, b string, c string, d time.Time, e []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
|
||||
func (_m *MockDetector) Detect(a string, b string, c string, d time.Time, e []ftypes.Package) ([]types.DetectedVulnerability, bool, error) {
|
||||
ret := _m.Called(a, b, c, d, e)
|
||||
ret0 := ret.Get(0)
|
||||
if ret0 == nil {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -44,7 +44,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Oracle Linux vulnerabilities...")
|
||||
|
||||
if strings.Count(osVer, ".") > 0 {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -33,7 +33,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Photon Linux vulnerabilities...")
|
||||
log.Logger.Debugf("Photon Linux: os version: %s", osVer)
|
||||
log.Logger.Debugf("Photon Linux: the number of packages: %d", len(pkgs))
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -47,7 +47,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting RHEL/CentOS vulnerabilities...")
|
||||
if strings.Count(osVer, ".") > 0 {
|
||||
osVer = osVer[:strings.Index(osVer, ".")]
|
||||
|
||||
@@ -5,11 +5,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
@@ -23,7 +24,7 @@ func TestMain(m *testing.M) {
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
type args struct {
|
||||
osVer string
|
||||
pkgs []analyzer.Package
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -36,7 +37,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
name: "happy path: src pkg name is different from bin pkg name",
|
||||
args: args{
|
||||
osVer: "7.6",
|
||||
pkgs: []analyzer.Package{
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "vim-minimal",
|
||||
Version: "7.4.160",
|
||||
@@ -107,7 +108,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
name: "happy path: src pkg name is the same as bin pkg name",
|
||||
args: args{
|
||||
osVer: "6.5",
|
||||
pkgs: []analyzer.Package{
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "nss",
|
||||
Version: "3.36.0",
|
||||
@@ -168,7 +169,7 @@ func TestScanner_Detect(t *testing.T) {
|
||||
name: "sad path: Get returns an error",
|
||||
args: args{
|
||||
osVer: "5",
|
||||
pkgs: []analyzer.Package{
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "nss",
|
||||
Version: "3.36.0",
|
||||
|
||||
@@ -3,16 +3,17 @@ package suse
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
fos "github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
susecvrf "github.com/aquasecurity/trivy-db/pkg/vulnsrc/suse-cvrf"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -79,7 +80,7 @@ func NewScanner(t SUSEType) *Scanner {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting SUSE vulnerabilities...")
|
||||
log.Logger.Debugf("SUSE: os version: %s", osVer)
|
||||
log.Logger.Debugf("SUSE: the number of packages: %d", len(pkgs))
|
||||
|
||||
@@ -3,13 +3,12 @@ package ubuntu
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/ubuntu"
|
||||
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/ubuntu"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
@@ -61,7 +60,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Ubuntu vulnerabilities...")
|
||||
log.Logger.Debugf("ubuntu: os version: %s", osVer)
|
||||
log.Logger.Debugf("ubuntu: the number of packages: %d", len(pkgs))
|
||||
|
||||
62
pkg/rpc/client/client.go
Normal file
62
pkg/rpc/client/client.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
"github.com/google/wire"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
r "github.com/aquasecurity/trivy/pkg/rpc"
|
||||
rpc "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
var SuperSet = wire.NewSet(
|
||||
NewProtobufClient,
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
type RemoteURL string
|
||||
|
||||
func NewProtobufClient(remoteURL RemoteURL) rpc.Scanner {
|
||||
return rpc.NewScannerProtobufClient(string(remoteURL), &http.Client{})
|
||||
}
|
||||
|
||||
type CustomHeaders http.Header
|
||||
|
||||
type Scanner struct {
|
||||
customHeaders CustomHeaders
|
||||
client rpc.Scanner
|
||||
}
|
||||
|
||||
func NewScanner(customHeaders CustomHeaders, s rpc.Scanner) Scanner {
|
||||
return Scanner{customHeaders: customHeaders, client: s}
|
||||
}
|
||||
|
||||
func (s Scanner) Scan(target string, imageID digest.Digest, layerIDs []string, options types.ScanOptions) (report.Results, *ftypes.OS, bool, error) {
|
||||
ctx := WithCustomHeaders(context.Background(), http.Header(s.customHeaders))
|
||||
|
||||
var res *rpc.ScanResponse
|
||||
err := r.Retry(func() error {
|
||||
var err error
|
||||
res, err = s.client.Scan(ctx, &rpc.ScanRequest{
|
||||
Target: target,
|
||||
ImageId: string(imageID),
|
||||
LayerIds: layerIDs,
|
||||
Options: &rpc.ScanOptions{
|
||||
VulnType: options.VulnType,
|
||||
},
|
||||
})
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, false, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)
|
||||
}
|
||||
|
||||
return r.ConvertFromRpcResults(res.Results), r.ConvertFromRpcOS(res.Os), res.Eosl, nil
|
||||
}
|
||||
243
pkg/rpc/client/client_test.go
Normal file
243
pkg/rpc/client/client_test.go
Normal file
@@ -0,0 +1,243 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/rpc/common"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/rpc/scanner"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
type mockScanner struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type scanArgs struct {
|
||||
Ctx context.Context
|
||||
CtxAnything bool
|
||||
Request *scanner.ScanRequest
|
||||
RequestAnything bool
|
||||
}
|
||||
|
||||
type scanReturns struct {
|
||||
Res *scanner.ScanResponse
|
||||
Err error
|
||||
}
|
||||
|
||||
type scanExpectation struct {
|
||||
Args scanArgs
|
||||
Returns scanReturns
|
||||
}
|
||||
|
||||
func (_m *mockScanner) ApplyScanExpectation(e scanExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.CtxAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Ctx)
|
||||
}
|
||||
if e.Args.RequestAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Request)
|
||||
}
|
||||
_m.On("Scan", args...).Return(e.Returns.Res, e.Returns.Err)
|
||||
}
|
||||
|
||||
func (_m *mockScanner) ApplyScanExpectations(expectations []scanExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyScanExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Scan provides a mock function with given fields: Ctx, Request
|
||||
func (_m *mockScanner) Scan(Ctx context.Context, Request *scanner.ScanRequest) (*scanner.ScanResponse, error) {
|
||||
ret := _m.Called(Ctx, Request)
|
||||
|
||||
var r0 *scanner.ScanResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *scanner.ScanRequest) *scanner.ScanResponse); ok {
|
||||
r0 = rf(Ctx, Request)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*scanner.ScanResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *scanner.ScanRequest) error); ok {
|
||||
r1 = rf(Ctx, Request)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func TestScanner_Scan(t *testing.T) {
|
||||
type fields struct {
|
||||
customHeaders CustomHeaders
|
||||
}
|
||||
type args struct {
|
||||
target string
|
||||
imageID digest.Digest
|
||||
layerIDs []string
|
||||
options types.ScanOptions
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
scanExpectation scanExpectation
|
||||
wantResults report.Results
|
||||
wantOS *ftypes.OS
|
||||
wantEosl bool
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
customHeaders: CustomHeaders{
|
||||
"Trivy-Token": []string{"foo"},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
target: "alpine:3.11",
|
||||
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{
|
||||
VulnType: []string{"os"},
|
||||
},
|
||||
},
|
||||
scanExpectation: scanExpectation{
|
||||
Args: scanArgs{
|
||||
CtxAnything: true,
|
||||
Request: &scanner.ScanRequest{
|
||||
Target: "alpine:3.11",
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
Options: &scanner.ScanOptions{
|
||||
VulnType: []string{"os"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Returns: scanReturns{
|
||||
Res: &scanner.ScanResponse{
|
||||
Os: &common.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
Eosl: true,
|
||||
Results: []*scanner.Result{
|
||||
{
|
||||
Target: "alpine:3.11",
|
||||
Vulnerabilities: []*common.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2020-0001",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Title: "DoS",
|
||||
Description: "Denial os Service",
|
||||
Severity: common.Severity_CRITICAL,
|
||||
References: []string{"http://exammple.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResults: report.Results{
|
||||
{
|
||||
Target: "alpine:3.11",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-0001",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Title: "DoS",
|
||||
Description: "Denial os Service",
|
||||
Severity: "CRITICAL",
|
||||
References: []string{"http://exammple.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantOS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
wantEosl: true,
|
||||
},
|
||||
{
|
||||
name: "sad path: Scan returns an error",
|
||||
fields: fields{
|
||||
customHeaders: CustomHeaders{
|
||||
"Trivy-Token": []string{"foo"},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
target: "alpine:3.11",
|
||||
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{
|
||||
VulnType: []string{"os"},
|
||||
},
|
||||
},
|
||||
scanExpectation: scanExpectation{
|
||||
Args: scanArgs{
|
||||
CtxAnything: true,
|
||||
Request: &scanner.ScanRequest{
|
||||
Target: "alpine:3.11",
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
Options: &scanner.ScanOptions{
|
||||
VulnType: []string{"os"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Returns: scanReturns{
|
||||
Err: errors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "failed to detect vulnerabilities via RPC",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockClient := new(mockScanner)
|
||||
mockClient.ApplyScanExpectation(tt.scanExpectation)
|
||||
|
||||
s := NewScanner(tt.fields.customHeaders, mockClient)
|
||||
gotResults, gotOS, gotEosl, err := s.Scan(tt.args.target, tt.args.imageID, tt.args.layerIDs, tt.args.options)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
require.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.wantResults, gotResults)
|
||||
assert.Equal(t, tt.wantOS, gotOS)
|
||||
assert.Equal(t, tt.wantEosl, gotEosl)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/google/wire"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
depptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
detector "github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
r "github.com/aquasecurity/trivy/pkg/rpc"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
rpc "github.com/aquasecurity/trivy/rpc/detector"
|
||||
)
|
||||
|
||||
var SuperSet = wire.NewSet(
|
||||
NewProtobufClient,
|
||||
NewDetector,
|
||||
wire.Bind(new(detector.Operation), new(Detector)),
|
||||
)
|
||||
|
||||
type RemoteURL string
|
||||
|
||||
func NewProtobufClient(remoteURL RemoteURL) rpc.LibDetector {
|
||||
return rpc.NewLibDetectorProtobufClient(string(remoteURL), &http.Client{})
|
||||
}
|
||||
|
||||
type CustomHeaders http.Header
|
||||
|
||||
type Detector struct {
|
||||
customHeaders CustomHeaders
|
||||
client rpc.LibDetector
|
||||
}
|
||||
|
||||
func NewDetector(customHeaders CustomHeaders, detector rpc.LibDetector) Detector {
|
||||
return Detector{customHeaders: customHeaders, client: detector}
|
||||
}
|
||||
|
||||
func (d Detector) Detect(imageName, filePath string, created time.Time, libs []depptypes.Library) ([]types.DetectedVulnerability, error) {
|
||||
ctx := client.WithCustomHeaders(context.Background(), http.Header(d.customHeaders))
|
||||
|
||||
var res *rpc.DetectResponse
|
||||
err := r.Retry(func() error {
|
||||
var err error
|
||||
res, err = d.client.Detect(ctx, &rpc.LibDetectRequest{
|
||||
ImageName: imageName,
|
||||
FilePath: filePath,
|
||||
Libraries: r.ConvertToRpcLibraries(libs),
|
||||
Created: func() *timestamp.Timestamp {
|
||||
t, err := ptypes.TimestampProto(created)
|
||||
if err != nil {
|
||||
log.Logger.Warnf("invalid timestamp: %s", err)
|
||||
}
|
||||
return t
|
||||
}(),
|
||||
})
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)
|
||||
}
|
||||
|
||||
return r.ConvertFromRpcVulns(res.Vulnerabilities), nil
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
deptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/rpc/detector"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
type mockDetector struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (_m *mockDetector) Detect(a context.Context, b *detector.LibDetectRequest) (*detector.DetectResponse, error) {
|
||||
ret := _m.Called(a, b)
|
||||
ret0 := ret.Get(0)
|
||||
if ret0 == nil {
|
||||
return nil, ret.Error(1)
|
||||
}
|
||||
res, ok := ret0.(*detector.DetectResponse)
|
||||
if !ok {
|
||||
return nil, ret.Error(1)
|
||||
}
|
||||
return res, ret.Error(1)
|
||||
}
|
||||
|
||||
func TestDetectClient_Detect(t *testing.T) {
|
||||
type detectInput struct {
|
||||
req *detector.LibDetectRequest
|
||||
}
|
||||
type detectOutput struct {
|
||||
res *detector.DetectResponse
|
||||
err error
|
||||
}
|
||||
type detect struct {
|
||||
input detectInput
|
||||
output detectOutput
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
customHeaders CustomHeaders
|
||||
}
|
||||
|
||||
type args struct {
|
||||
imageName string
|
||||
filePath string
|
||||
created time.Time
|
||||
libs []deptypes.Library
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
detect detect
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
customHeaders: CustomHeaders{
|
||||
"Trivy-Token": []string{"token"},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
imageName: "/tmp/alpine.tar",
|
||||
filePath: "app/Pipfile.lock",
|
||||
created: time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
libs: []deptypes.Library{
|
||||
{Name: "django", Version: "3.0.0"},
|
||||
},
|
||||
},
|
||||
detect: detect{
|
||||
input: detectInput{req: &detector.LibDetectRequest{
|
||||
ImageName: "/tmp/alpine.tar",
|
||||
FilePath: "app/Pipfile.lock",
|
||||
Created: func() *timestamp.Timestamp {
|
||||
d := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
t, _ := ptypes.TimestampProto(d)
|
||||
return t
|
||||
}(),
|
||||
Libraries: []*detector.Library{
|
||||
{Name: "django", Version: "3.0.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
res: &detector.DetectResponse{
|
||||
Vulnerabilities: []*detector.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0001",
|
||||
PkgName: "django",
|
||||
InstalledVersion: "3.0.0",
|
||||
FixedVersion: "3.0.1",
|
||||
Title: "RCE",
|
||||
Description: "Remote Code Execution",
|
||||
Severity: detector.Severity_CRITICAL,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-0001",
|
||||
PkgName: "django",
|
||||
InstalledVersion: "3.0.0",
|
||||
FixedVersion: "3.0.1",
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Title: "RCE",
|
||||
Description: "Remote Code Execution",
|
||||
Severity: "CRITICAL",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Detect returns an error",
|
||||
fields: fields{},
|
||||
args: args{
|
||||
imageName: "/tmp/alpine.tar",
|
||||
filePath: "app/Pipfile.lock",
|
||||
created: time.Date(2019, 2, 1, 0, 0, 0, 0, time.UTC),
|
||||
libs: []deptypes.Library{
|
||||
{Name: "django", Version: "3.0.0"},
|
||||
},
|
||||
},
|
||||
detect: detect{
|
||||
input: detectInput{req: &detector.LibDetectRequest{
|
||||
ImageName: "/tmp/alpine.tar",
|
||||
FilePath: "app/Pipfile.lock",
|
||||
Libraries: []*detector.Library{
|
||||
{Name: "django", Version: "3.0.0"},
|
||||
},
|
||||
Created: func() *timestamp.Timestamp {
|
||||
d := time.Date(2019, 2, 1, 0, 0, 0, 0, time.UTC)
|
||||
t, _ := ptypes.TimestampProto(d)
|
||||
return t
|
||||
}(),
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
err: xerrors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "failed to detect vulnerabilities via RPC",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockDetector := new(mockDetector)
|
||||
mockDetector.On("Detect", mock.Anything, tt.detect.input.req).Return(
|
||||
tt.detect.output.res, tt.detect.output.err)
|
||||
|
||||
d := NewDetector(tt.fields.customHeaders, mockDetector)
|
||||
got, err := d.Detect(tt.args.imageName, tt.args.filePath, tt.args.created, tt.args.libs)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
mockDetector.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package ospkg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
|
||||
"github.com/google/wire"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
detector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
r "github.com/aquasecurity/trivy/pkg/rpc"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
rpc "github.com/aquasecurity/trivy/rpc/detector"
|
||||
)
|
||||
|
||||
var SuperSet = wire.NewSet(
|
||||
NewProtobufClient,
|
||||
NewDetector,
|
||||
wire.Bind(new(detector.Operation), new(Detector)),
|
||||
)
|
||||
|
||||
type RemoteURL string
|
||||
|
||||
func NewProtobufClient(remoteURL RemoteURL) rpc.OSDetector {
|
||||
return rpc.NewOSDetectorProtobufClient(string(remoteURL), &http.Client{})
|
||||
}
|
||||
|
||||
type CustomHeaders http.Header
|
||||
|
||||
type Detector struct {
|
||||
customHeaders CustomHeaders
|
||||
client rpc.OSDetector
|
||||
}
|
||||
|
||||
func NewDetector(customHeaders CustomHeaders, detector rpc.OSDetector) Detector {
|
||||
return Detector{customHeaders: customHeaders, client: detector}
|
||||
}
|
||||
|
||||
func (d Detector) Detect(imageName, osFamily, osName string, created time.Time, pkgs []analyzer.Package) ([]types.DetectedVulnerability, bool, error) {
|
||||
ctx := client.WithCustomHeaders(context.Background(), http.Header(d.customHeaders))
|
||||
|
||||
var res *rpc.DetectResponse
|
||||
err := r.Retry(func() error {
|
||||
var err error
|
||||
res, err = d.client.Detect(ctx, &rpc.OSDetectRequest{
|
||||
ImageName: imageName,
|
||||
OsFamily: osFamily,
|
||||
OsName: osName,
|
||||
Created: func() *timestamp.Timestamp {
|
||||
t, err := ptypes.TimestampProto(created)
|
||||
if err != nil {
|
||||
log.Logger.Warnf("invalid timestamp: %s", err)
|
||||
}
|
||||
return t
|
||||
}(),
|
||||
Packages: r.ConvertToRpcPkgs(pkgs),
|
||||
})
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, false, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)
|
||||
}
|
||||
|
||||
return r.ConvertFromRpcVulns(res.Vulnerabilities), res.Eosl, nil
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
package ospkg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/rpc/detector"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type mockDetector struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (_m *mockDetector) Detect(a context.Context, b *detector.OSDetectRequest) (*detector.DetectResponse, error) {
|
||||
ret := _m.Called(a, b)
|
||||
ret0 := ret.Get(0)
|
||||
if ret0 == nil {
|
||||
return nil, ret.Error(1)
|
||||
}
|
||||
res, ok := ret0.(*detector.DetectResponse)
|
||||
if !ok {
|
||||
return nil, ret.Error(1)
|
||||
}
|
||||
return res, ret.Error(1)
|
||||
}
|
||||
|
||||
func TestDetectClient_Detect(t *testing.T) {
|
||||
type detectInput struct {
|
||||
req *detector.OSDetectRequest
|
||||
}
|
||||
type detectOutput struct {
|
||||
res *detector.DetectResponse
|
||||
err error
|
||||
}
|
||||
type detect struct {
|
||||
input detectInput
|
||||
output detectOutput
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
customHeaders CustomHeaders
|
||||
}
|
||||
type args struct {
|
||||
imageName string
|
||||
osFamily string
|
||||
osName string
|
||||
created time.Time
|
||||
pkgs []analyzer.Package
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
detect detect
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
customHeaders: CustomHeaders{
|
||||
"Trivy-Token": []string{"token"},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
imageName: "alpine:3.10.2",
|
||||
osFamily: "alpine",
|
||||
osName: "3.10.2",
|
||||
created: time.Unix(1581498560, 0),
|
||||
pkgs: []analyzer.Package{
|
||||
{
|
||||
Name: "openssl",
|
||||
Version: "1.0.1e",
|
||||
Release: "1",
|
||||
Epoch: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
detect: detect{
|
||||
input: detectInput{
|
||||
req: &detector.OSDetectRequest{
|
||||
OsFamily: "alpine",
|
||||
OsName: "3.10.2",
|
||||
ImageName: "alpine:3.10.2",
|
||||
Created: func() *timestamp.Timestamp {
|
||||
t, _ := ptypes.TimestampProto(time.Unix(1581498560, 0))
|
||||
return t
|
||||
}(),
|
||||
Packages: []*detector.Package{
|
||||
{
|
||||
Name: "openssl",
|
||||
Version: "1.0.1e",
|
||||
Release: "1",
|
||||
Epoch: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
res: &detector.DetectResponse{
|
||||
Vulnerabilities: []*detector.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0001",
|
||||
PkgName: "bash",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Title: "RCE",
|
||||
Description: "Remote Code Execution",
|
||||
Severity: detector.Severity_HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-0001",
|
||||
PkgName: "bash",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Title: "RCE",
|
||||
Description: "Remote Code Execution",
|
||||
Severity: "HIGH",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Detect returns an error",
|
||||
fields: fields{},
|
||||
args: args{
|
||||
imageName: "alpine:3.10.2",
|
||||
osFamily: "alpine",
|
||||
osName: "3.10.2",
|
||||
created: time.Unix(1581498560, 0),
|
||||
pkgs: []analyzer.Package{
|
||||
{
|
||||
Name: "openssl",
|
||||
Version: "1.0.1e",
|
||||
Release: "1",
|
||||
Epoch: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
detect: detect{
|
||||
input: detectInput{
|
||||
req: &detector.OSDetectRequest{
|
||||
ImageName: "alpine:3.10.2",
|
||||
OsFamily: "alpine",
|
||||
OsName: "3.10.2",
|
||||
Created: func() *timestamp.Timestamp {
|
||||
t, _ := ptypes.TimestampProto(time.Unix(1581498560, 0))
|
||||
return t
|
||||
}(),
|
||||
Packages: []*detector.Package{
|
||||
{
|
||||
Name: "openssl",
|
||||
Version: "1.0.1e",
|
||||
Release: "1",
|
||||
Epoch: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
err: xerrors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "failed to detect vulnerabilities via RPC",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockDetector := new(mockDetector)
|
||||
mockDetector.On("Detect", mock.Anything, tt.detect.input.req).Return(
|
||||
tt.detect.output.res, tt.detect.output.err)
|
||||
|
||||
d := NewDetector(tt.fields.customHeaders, mockDetector)
|
||||
got, _, err := d.Detect(tt.args.imageName, tt.args.osFamily, tt.args.osName, tt.args.created, tt.args.pkgs)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
mockDetector.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,23 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
deptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/rpc/detector"
|
||||
"github.com/aquasecurity/trivy/rpc/cache"
|
||||
"github.com/aquasecurity/trivy/rpc/common"
|
||||
"github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
func ConvertToRpcPkgs(pkgs []analyzer.Package) []*detector.Package {
|
||||
var rpcPkgs []*detector.Package
|
||||
func ConvertToRpcPkgs(pkgs []ftypes.Package) []*common.Package {
|
||||
var rpcPkgs []*common.Package
|
||||
for _, pkg := range pkgs {
|
||||
rpcPkgs = append(rpcPkgs, &detector.Package{
|
||||
rpcPkgs = append(rpcPkgs, &common.Package{
|
||||
Name: pkg.Name,
|
||||
Version: pkg.Version,
|
||||
Release: pkg.Release,
|
||||
@@ -27,10 +32,10 @@ func ConvertToRpcPkgs(pkgs []analyzer.Package) []*detector.Package {
|
||||
return rpcPkgs
|
||||
}
|
||||
|
||||
func ConvertFromRpcPkgs(rpcPkgs []*detector.Package) []analyzer.Package {
|
||||
var pkgs []analyzer.Package
|
||||
func ConvertFromRpcPkgs(rpcPkgs []*common.Package) []ftypes.Package {
|
||||
var pkgs []ftypes.Package
|
||||
for _, pkg := range rpcPkgs {
|
||||
pkgs = append(pkgs, analyzer.Package{
|
||||
pkgs = append(pkgs, ftypes.Package{
|
||||
Name: pkg.Name,
|
||||
Version: pkg.Version,
|
||||
Release: pkg.Release,
|
||||
@@ -45,10 +50,10 @@ func ConvertFromRpcPkgs(rpcPkgs []*detector.Package) []analyzer.Package {
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func ConvertFromRpcLibraries(rpcLibs []*detector.Library) []ptypes.Library {
|
||||
var libs []ptypes.Library
|
||||
func ConvertFromRpcLibraries(rpcLibs []*common.Library) []deptypes.Library {
|
||||
var libs []deptypes.Library
|
||||
for _, l := range rpcLibs {
|
||||
libs = append(libs, ptypes.Library{
|
||||
libs = append(libs, deptypes.Library{
|
||||
Name: l.Name,
|
||||
Version: l.Version,
|
||||
})
|
||||
@@ -56,10 +61,10 @@ func ConvertFromRpcLibraries(rpcLibs []*detector.Library) []ptypes.Library {
|
||||
return libs
|
||||
}
|
||||
|
||||
func ConvertToRpcLibraries(libs []ptypes.Library) []*detector.Library {
|
||||
var rpcLibs []*detector.Library
|
||||
func ConvertToRpcLibraries(libs []deptypes.Library) []*common.Library {
|
||||
var rpcLibs []*common.Library
|
||||
for _, l := range libs {
|
||||
rpcLibs = append(rpcLibs, &detector.Library{
|
||||
rpcLibs = append(rpcLibs, &common.Library{
|
||||
Name: l.Name,
|
||||
Version: l.Version,
|
||||
})
|
||||
@@ -67,7 +72,7 @@ func ConvertToRpcLibraries(libs []ptypes.Library) []*detector.Library {
|
||||
return rpcLibs
|
||||
}
|
||||
|
||||
func ConvertFromRpcVulns(rpcVulns []*detector.Vulnerability) []types.DetectedVulnerability {
|
||||
func ConvertFromRpcVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulnerability {
|
||||
var vulns []types.DetectedVulnerability
|
||||
for _, vuln := range rpcVulns {
|
||||
severity := dbTypes.Severity(vuln.Severity)
|
||||
@@ -87,24 +92,205 @@ func ConvertFromRpcVulns(rpcVulns []*detector.Vulnerability) []types.DetectedVul
|
||||
return vulns
|
||||
}
|
||||
|
||||
func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*detector.Vulnerability {
|
||||
var rpcVulns []*detector.Vulnerability
|
||||
func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
|
||||
var rpcVulns []*common.Vulnerability
|
||||
for _, vuln := range vulns {
|
||||
severity, err := dbTypes.NewSeverity(vuln.Severity)
|
||||
if err != nil {
|
||||
log.Logger.Warn(err)
|
||||
}
|
||||
|
||||
rpcVulns = append(rpcVulns, &detector.Vulnerability{
|
||||
rpcVulns = append(rpcVulns, &common.Vulnerability{
|
||||
VulnerabilityId: vuln.VulnerabilityID,
|
||||
PkgName: vuln.PkgName,
|
||||
InstalledVersion: vuln.InstalledVersion,
|
||||
FixedVersion: vuln.FixedVersion,
|
||||
Title: vuln.Title,
|
||||
Description: vuln.Description,
|
||||
Severity: detector.Severity(severity),
|
||||
Severity: common.Severity(severity),
|
||||
References: vuln.References,
|
||||
})
|
||||
}
|
||||
return rpcVulns
|
||||
}
|
||||
|
||||
func ConvertFromRpcResults(rpcResults []*scanner.Result) []report.Result {
|
||||
var results []report.Result
|
||||
for _, result := range rpcResults {
|
||||
var vulns []types.DetectedVulnerability
|
||||
for _, vuln := range result.Vulnerabilities {
|
||||
severity := dbTypes.Severity(vuln.Severity)
|
||||
vulns = append(vulns, types.DetectedVulnerability{
|
||||
VulnerabilityID: vuln.VulnerabilityId,
|
||||
PkgName: vuln.PkgName,
|
||||
InstalledVersion: vuln.InstalledVersion,
|
||||
FixedVersion: vuln.FixedVersion,
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Title: vuln.Title,
|
||||
Description: vuln.Description,
|
||||
Severity: severity.String(),
|
||||
References: vuln.References,
|
||||
},
|
||||
})
|
||||
}
|
||||
results = append(results, report.Result{
|
||||
Target: result.Target,
|
||||
Vulnerabilities: vulns,
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func ConvertFromRpcOS(rpcOS *common.OS) *ftypes.OS {
|
||||
if rpcOS == nil {
|
||||
return nil
|
||||
}
|
||||
return &ftypes.OS{
|
||||
Family: rpcOS.Family,
|
||||
Name: rpcOS.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertFromRpcPackageInfos(rpcPkgInfos []*common.PackageInfo) []ftypes.PackageInfo {
|
||||
var pkgInfos []ftypes.PackageInfo
|
||||
for _, rpcPkgInfo := range rpcPkgInfos {
|
||||
pkgInfos = append(pkgInfos, ftypes.PackageInfo{
|
||||
FilePath: rpcPkgInfo.FilePath,
|
||||
Packages: ConvertFromRpcPkgs(rpcPkgInfo.Packages),
|
||||
})
|
||||
}
|
||||
return pkgInfos
|
||||
}
|
||||
|
||||
func ConvertFromRpcApplications(rpcApps []*common.Application) []ftypes.Application {
|
||||
var apps []ftypes.Application
|
||||
for _, rpcApp := range rpcApps {
|
||||
apps = append(apps, ftypes.Application{
|
||||
Type: rpcApp.Type,
|
||||
FilePath: rpcApp.FilePath,
|
||||
Libraries: ConvertFromRpcLibraries(rpcApp.Libraries),
|
||||
})
|
||||
}
|
||||
return apps
|
||||
}
|
||||
|
||||
func ConvertFromRpcPutImageRequest(req *cache.PutImageRequest) ftypes.ImageInfo {
|
||||
created, _ := ptypes.Timestamp(req.ImageInfo.Created)
|
||||
return ftypes.ImageInfo{
|
||||
SchemaVersion: int(req.ImageInfo.SchemaVersion),
|
||||
Architecture: req.ImageInfo.Architecture,
|
||||
Created: created,
|
||||
DockerVersion: req.ImageInfo.DockerVersion,
|
||||
OS: req.ImageInfo.Os,
|
||||
HistoryPackages: ConvertFromRpcPkgs(req.ImageInfo.HistoryPackages),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertFromRpcPutLayerRequest(req *cache.PutLayerRequest) ftypes.LayerInfo {
|
||||
return ftypes.LayerInfo{
|
||||
SchemaVersion: int(req.LayerInfo.SchemaVersion),
|
||||
OS: ConvertFromRpcOS(req.LayerInfo.Os),
|
||||
PackageInfos: ConvertFromRpcPackageInfos(req.LayerInfo.PackageInfos),
|
||||
Applications: ConvertFromRpcApplications(req.LayerInfo.Applications),
|
||||
OpaqueDirs: req.LayerInfo.OpaqueDirs,
|
||||
WhiteoutFiles: req.LayerInfo.WhiteoutFiles,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcOS(fos *ftypes.OS) *common.OS {
|
||||
if fos == nil {
|
||||
return nil
|
||||
}
|
||||
return &common.OS{
|
||||
Family: fos.Family,
|
||||
Name: fos.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcImageInfo(imageID string, imageInfo ftypes.ImageInfo) *cache.PutImageRequest {
|
||||
t, err := ptypes.TimestampProto(imageInfo.Created)
|
||||
if err != nil {
|
||||
log.Logger.Warnf("invalid timestamp: %s", err)
|
||||
}
|
||||
|
||||
return &cache.PutImageRequest{
|
||||
ImageId: imageID,
|
||||
ImageInfo: &cache.ImageInfo{
|
||||
SchemaVersion: int32(imageInfo.SchemaVersion),
|
||||
Architecture: imageInfo.Architecture,
|
||||
Created: t,
|
||||
DockerVersion: imageInfo.DockerVersion,
|
||||
Os: imageInfo.OS,
|
||||
HistoryPackages: ConvertToRpcPkgs(imageInfo.HistoryPackages),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcLayerInfo(layerID, decompressedLayerID string, layerInfo ftypes.LayerInfo) *cache.PutLayerRequest {
|
||||
var packageInfos []*common.PackageInfo
|
||||
for _, pkgInfo := range layerInfo.PackageInfos {
|
||||
packageInfos = append(packageInfos, &common.PackageInfo{
|
||||
FilePath: pkgInfo.FilePath,
|
||||
Packages: ConvertToRpcPkgs(pkgInfo.Packages),
|
||||
})
|
||||
}
|
||||
|
||||
var applications []*common.Application
|
||||
for _, app := range layerInfo.Applications {
|
||||
var libs []*common.Library
|
||||
for _, lib := range app.Libraries {
|
||||
libs = append(libs, &common.Library{
|
||||
Name: lib.Name,
|
||||
Version: lib.Version,
|
||||
})
|
||||
|
||||
}
|
||||
applications = append(applications, &common.Application{
|
||||
Type: app.Type,
|
||||
FilePath: app.FilePath,
|
||||
Libraries: libs,
|
||||
})
|
||||
}
|
||||
|
||||
return &cache.PutLayerRequest{
|
||||
LayerId: layerID,
|
||||
DecompressedLayerId: decompressedLayerID,
|
||||
LayerInfo: &cache.LayerInfo{
|
||||
SchemaVersion: ftypes.LayerJSONSchemaVersion,
|
||||
Os: ConvertToRpcOS(layerInfo.OS),
|
||||
PackageInfos: packageInfos,
|
||||
Applications: applications,
|
||||
OpaqueDirs: layerInfo.OpaqueDirs,
|
||||
WhiteoutFiles: layerInfo.WhiteoutFiles,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToMissingLayersRequest(imageID string, layerIDs []string) *cache.MissingLayersRequest {
|
||||
return &cache.MissingLayersRequest{
|
||||
ImageId: imageID,
|
||||
LayerIds: layerIDs,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcScanResponse(results report.Results, os *ftypes.OS, eosl bool) *scanner.ScanResponse {
|
||||
rpcOS := &common.OS{}
|
||||
if os != nil {
|
||||
rpcOS.Family = os.Family
|
||||
rpcOS.Name = os.Name
|
||||
}
|
||||
|
||||
var rpcResults []*scanner.Result
|
||||
for _, result := range results {
|
||||
rpcResults = append(rpcResults, &scanner.Result{
|
||||
Target: result.Target,
|
||||
Vulnerabilities: ConvertToRpcVulns(result.Vulnerabilities),
|
||||
})
|
||||
}
|
||||
|
||||
return &scanner.ScanResponse{
|
||||
Os: rpcOS,
|
||||
Eosl: eosl,
|
||||
Results: rpcResults,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,15 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/aquasecurity/trivy/rpc/common"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/rpc/detector"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -22,17 +24,17 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func TestConvertToRpcPkgs(t *testing.T) {
|
||||
type args struct {
|
||||
pkgs []analyzer.Package
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*detector.Package
|
||||
want []*common.Package
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
pkgs: []analyzer.Package{
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "binary",
|
||||
Version: "1.2.3",
|
||||
@@ -46,7 +48,7 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []*detector.Package{
|
||||
want: []*common.Package{
|
||||
{
|
||||
Name: "binary",
|
||||
Version: "1.2.3",
|
||||
@@ -71,16 +73,16 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
||||
|
||||
func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
type args struct {
|
||||
rpcPkgs []*detector.Package
|
||||
rpcPkgs []*common.Package
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []analyzer.Package
|
||||
want []ftypes.Package
|
||||
}{
|
||||
{
|
||||
args: args{
|
||||
rpcPkgs: []*detector.Package{
|
||||
rpcPkgs: []*common.Package{
|
||||
{
|
||||
Name: "binary",
|
||||
Version: "1.2.3",
|
||||
@@ -94,7 +96,7 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []analyzer.Package{
|
||||
want: []ftypes.Package{
|
||||
{
|
||||
Name: "binary",
|
||||
Version: "1.2.3",
|
||||
@@ -119,7 +121,7 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
|
||||
func TestConvertFromRpcLibraries(t *testing.T) {
|
||||
type args struct {
|
||||
rpcLibs []*detector.Library
|
||||
rpcLibs []*common.Library
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -129,7 +131,7 @@ func TestConvertFromRpcLibraries(t *testing.T) {
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
rpcLibs: []*detector.Library{
|
||||
rpcLibs: []*common.Library{
|
||||
{Name: "foo", Version: "1.2.3"},
|
||||
{Name: "bar", Version: "4.5.6"},
|
||||
},
|
||||
@@ -155,7 +157,7 @@ func TestConvertToRpcLibraries(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*detector.Library
|
||||
want []*common.Library
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
@@ -165,7 +167,7 @@ func TestConvertToRpcLibraries(t *testing.T) {
|
||||
{Name: "bar", Version: "4.5.6"},
|
||||
},
|
||||
},
|
||||
want: []*detector.Library{
|
||||
want: []*common.Library{
|
||||
{Name: "foo", Version: "1.2.3"},
|
||||
{Name: "bar", Version: "4.5.6"},
|
||||
},
|
||||
@@ -181,7 +183,7 @@ func TestConvertToRpcLibraries(t *testing.T) {
|
||||
|
||||
func TestConvertFromRpcVulns(t *testing.T) {
|
||||
type args struct {
|
||||
rpcVulns []*detector.Vulnerability
|
||||
rpcVulns []*common.Vulnerability
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -191,7 +193,7 @@ func TestConvertFromRpcVulns(t *testing.T) {
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
rpcVulns: []*detector.Vulnerability{
|
||||
rpcVulns: []*common.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0001",
|
||||
PkgName: "foo",
|
||||
@@ -199,7 +201,7 @@ func TestConvertFromRpcVulns(t *testing.T) {
|
||||
FixedVersion: "1.2.4",
|
||||
Title: "DoS",
|
||||
Description: "Denial of Service",
|
||||
Severity: detector.Severity_CRITICAL,
|
||||
Severity: common.Severity_CRITICAL,
|
||||
References: []string{"http://example.com"},
|
||||
},
|
||||
},
|
||||
@@ -235,7 +237,7 @@ func TestConvertToRpcVulns(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*detector.Vulnerability
|
||||
want []*common.Vulnerability
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
@@ -255,7 +257,7 @@ func TestConvertToRpcVulns(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []*detector.Vulnerability{
|
||||
want: []*common.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0001",
|
||||
PkgName: "foo",
|
||||
@@ -263,7 +265,7 @@ func TestConvertToRpcVulns(t *testing.T) {
|
||||
FixedVersion: "1.2.4",
|
||||
Title: "DoS",
|
||||
Description: "Denial of Service",
|
||||
Severity: detector.Severity_MEDIUM,
|
||||
Severity: common.Severity_MEDIUM,
|
||||
References: []string{"http://example.com"},
|
||||
},
|
||||
},
|
||||
@@ -286,7 +288,7 @@ func TestConvertToRpcVulns(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []*detector.Vulnerability{
|
||||
want: []*common.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0002",
|
||||
PkgName: "bar",
|
||||
@@ -294,7 +296,7 @@ func TestConvertToRpcVulns(t *testing.T) {
|
||||
FixedVersion: "1.2.4",
|
||||
Title: "DoS",
|
||||
Description: "Denial of Service",
|
||||
Severity: detector.Severity_UNKNOWN,
|
||||
Severity: common.Severity_UNKNOWN,
|
||||
References: []string{"http://example.com"},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,12 +3,17 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/server/library"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/server/ospkg"
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
func initializeScanServer(localLayerCache cache.LocalImageCache) *ScanServer {
|
||||
wire.Build(ScanSuperSet)
|
||||
return &ScanServer{}
|
||||
}
|
||||
|
||||
func initializeOspkgServer() *ospkg.Server {
|
||||
wire.Build(ospkg.SuperSet)
|
||||
return &ospkg.Server{}
|
||||
@@ -20,6 +25,6 @@ func initializeLibServer() *library.Server {
|
||||
}
|
||||
|
||||
func initializeDBWorker(quiet bool) dbWorker {
|
||||
wire.Build(SuperSet)
|
||||
wire.Build(DBWorkerSuperSet)
|
||||
return dbWorker{}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ var SuperSet = wire.NewSet(
|
||||
NewServer,
|
||||
)
|
||||
|
||||
// Server is for backward compatibility
|
||||
type Server struct {
|
||||
detector detector.Operation
|
||||
vulnClient vulnerability.Operation
|
||||
@@ -29,6 +30,7 @@ func NewServer(detector detector.Operation, vulnClient vulnerability.Operation)
|
||||
return &Server{detector: detector, vulnClient: vulnClient}
|
||||
}
|
||||
|
||||
// Detect is for backward compatibility
|
||||
func (s *Server) Detect(_ context.Context, req *proto.LibDetectRequest) (res *proto.DetectResponse, err error) {
|
||||
vulns, err := s.detector.Detect("", req.FilePath, time.Time{}, rpc.ConvertFromRpcLibraries(req.Libraries))
|
||||
if err != nil {
|
||||
|
||||
@@ -5,19 +5,17 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"github.com/aquasecurity/trivy/rpc/common"
|
||||
proto "github.com/aquasecurity/trivy/rpc/detector"
|
||||
)
|
||||
|
||||
@@ -32,11 +30,12 @@ func TestServer_Detect(t *testing.T) {
|
||||
req *proto.LibDetectRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
detect library.DetectExpectation
|
||||
wantRes *proto.DetectResponse
|
||||
wantErr string
|
||||
name string
|
||||
args args
|
||||
detectExpectation library.DetectExpectation
|
||||
fillInfoExpectation vulnerability.FillInfoExpectation
|
||||
wantRes *proto.DetectResponse
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
@@ -44,12 +43,12 @@ func TestServer_Detect(t *testing.T) {
|
||||
req: &proto.LibDetectRequest{
|
||||
ImageName: "alpine:3.10",
|
||||
FilePath: "app/Pipfile.lock",
|
||||
Libraries: []*proto.Library{
|
||||
Libraries: []*common.Library{
|
||||
{Name: "django", Version: "3.0.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
detect: library.DetectExpectation{
|
||||
detectExpectation: library.DetectExpectation{
|
||||
Args: library.DetectInput{
|
||||
FilePath: "app/Pipfile.lock",
|
||||
Libs: []ptypes.Library{
|
||||
@@ -73,8 +72,27 @@ func TestServer_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
fillInfoExpectation: vulnerability.FillInfoExpectation{
|
||||
Args: vulnerability.FillInfoArgs{
|
||||
Vulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-0001",
|
||||
PkgName: "test",
|
||||
InstalledVersion: "1",
|
||||
FixedVersion: "2",
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Title: "title",
|
||||
Description: "description",
|
||||
Severity: "MEDIUM",
|
||||
References: []string{"http://example.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Light: false,
|
||||
},
|
||||
},
|
||||
wantRes: &proto.DetectResponse{
|
||||
Vulnerabilities: []*proto.Vulnerability{
|
||||
Vulnerabilities: []*common.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0001",
|
||||
PkgName: "test",
|
||||
@@ -82,7 +100,7 @@ func TestServer_Detect(t *testing.T) {
|
||||
FixedVersion: "2",
|
||||
Title: "title",
|
||||
Description: "description",
|
||||
Severity: proto.Severity_MEDIUM,
|
||||
Severity: common.Severity_MEDIUM,
|
||||
References: []string{"http://example.com"},
|
||||
},
|
||||
},
|
||||
@@ -94,12 +112,12 @@ func TestServer_Detect(t *testing.T) {
|
||||
req: &proto.LibDetectRequest{
|
||||
ImageName: "alpine:3.10",
|
||||
FilePath: "app/Pipfile.lock",
|
||||
Libraries: []*proto.Library{
|
||||
Libraries: []*common.Library{
|
||||
{Name: "django", Version: "3.0.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
detect: library.DetectExpectation{
|
||||
detectExpectation: library.DetectExpectation{
|
||||
Args: library.DetectInput{
|
||||
FilePath: "app/Pipfile.lock",
|
||||
Libs: []ptypes.Library{
|
||||
@@ -115,8 +133,9 @@ func TestServer_Detect(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockDetector := library.NewMockDetector([]library.DetectExpectation{tt.detect})
|
||||
mockVulnClient := vulnerability.NewMockVulnClient()
|
||||
mockDetector := library.NewMockDetector([]library.DetectExpectation{tt.detectExpectation})
|
||||
mockVulnClient := new(vulnerability.MockOperation)
|
||||
mockVulnClient.ApplyFillInfoExpectation(tt.fillInfoExpectation)
|
||||
|
||||
s := NewServer(mockDetector, mockVulnClient)
|
||||
ctx := context.TODO()
|
||||
|
||||
148
pkg/rpc/server/listen.go
Normal file
148
pkg/rpc/server/listen.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/twitchtv/twirp"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/internal/server/config"
|
||||
dbFile "github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
"github.com/aquasecurity/trivy/rpc/detector"
|
||||
rpcDetector "github.com/aquasecurity/trivy/rpc/detector"
|
||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
var DBWorkerSuperSet = wire.NewSet(
|
||||
dbFile.SuperSet,
|
||||
newDBWorker,
|
||||
)
|
||||
|
||||
func ListenAndServe(c config.Config, fsCache cache.FSCache) error {
|
||||
requestWg := &sync.WaitGroup{}
|
||||
dbUpdateWg := &sync.WaitGroup{}
|
||||
|
||||
withWaitGroup := func(base http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Stop processing requests during DB update
|
||||
dbUpdateWg.Wait()
|
||||
|
||||
// Wait for all requests to be processed before DB update
|
||||
requestWg.Add(1)
|
||||
defer requestWg.Done()
|
||||
|
||||
base.ServeHTTP(w, r)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
go func() {
|
||||
worker := initializeDBWorker(true)
|
||||
ctx := context.Background()
|
||||
for {
|
||||
time.Sleep(1 * time.Hour)
|
||||
if err := worker.update(ctx, c.AppVersion, c.CacheDir, dbUpdateWg, requestWg); err != nil {
|
||||
log.Logger.Errorf("%+v\n", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
scanHandler := rpcScanner.NewScannerServer(initializeScanServer(fsCache), nil)
|
||||
mux.Handle(rpcScanner.ScannerPathPrefix, withToken(withWaitGroup(scanHandler), c.Token, c.TokenHeader))
|
||||
|
||||
layerHandler := rpcCache.NewCacheServer(NewCacheServer(fsCache), nil)
|
||||
mux.Handle(rpcCache.CachePathPrefix, withToken(withWaitGroup(layerHandler), c.Token, c.TokenHeader))
|
||||
|
||||
// osHandler is for backward compatibility
|
||||
osHandler := rpcDetector.NewOSDetectorServer(initializeOspkgServer(), nil)
|
||||
mux.Handle(rpcDetector.OSDetectorPathPrefix, withToken(withWaitGroup(osHandler), c.Token, c.TokenHeader))
|
||||
|
||||
// libHandler is for backward compatibility
|
||||
libHandler := rpcDetector.NewLibDetectorServer(initializeLibServer(), nil)
|
||||
mux.Handle(rpcDetector.LibDetectorPathPrefix, withToken(withWaitGroup(libHandler), c.Token, c.TokenHeader))
|
||||
|
||||
log.Logger.Infof("Listening %s...", c.Listen)
|
||||
|
||||
return http.ListenAndServe(c.Listen, mux)
|
||||
}
|
||||
|
||||
func withToken(base http.Handler, token, tokenHeader string) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if token != "" && token != r.Header.Get(tokenHeader) {
|
||||
detector.WriteError(w, twirp.NewError(twirp.Unauthenticated, "invalid token"))
|
||||
return
|
||||
}
|
||||
base.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
type dbWorker struct {
|
||||
dbClient dbFile.Operation
|
||||
}
|
||||
|
||||
func newDBWorker(dbClient dbFile.Operation) dbWorker {
|
||||
return dbWorker{dbClient: dbClient}
|
||||
}
|
||||
|
||||
func (w dbWorker) update(ctx context.Context, appVersion, cacheDir string,
|
||||
dbUpdateWg, requestWg *sync.WaitGroup) error {
|
||||
needsUpdate, err := w.dbClient.NeedsUpdate(ctx, appVersion, false, false)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to check if db needs an update")
|
||||
} else if !needsUpdate {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Logger.Info("Updating DB...")
|
||||
if err = w.hotUpdate(ctx, cacheDir, dbUpdateWg, requestWg); err != nil {
|
||||
return xerrors.Errorf("failed DB hot update")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, requestWg *sync.WaitGroup) error {
|
||||
tmpDir, err := ioutil.TempDir("", "db")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create a temp dir: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if err := w.dbClient.Download(ctx, tmpDir, false); err != nil {
|
||||
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
|
||||
}
|
||||
|
||||
log.Logger.Info("Suspending all requests during DB update")
|
||||
dbUpdateWg.Add(1)
|
||||
defer dbUpdateWg.Done()
|
||||
|
||||
log.Logger.Info("Waiting for all requests to be processed before DB update...")
|
||||
requestWg.Wait()
|
||||
|
||||
if err = db.Close(); err != nil {
|
||||
return xerrors.Errorf("failed to close DB: %w", err)
|
||||
}
|
||||
|
||||
if _, err = utils.CopyFile(db.Path(tmpDir), db.Path(cacheDir)); err != nil {
|
||||
return xerrors.Errorf("failed to copy the database file: %w", err)
|
||||
}
|
||||
|
||||
log.Logger.Info("Reopening DB...")
|
||||
if err = db.Init(cacheDir); err != nil {
|
||||
return xerrors.Errorf("failed to open DB: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
157
pkg/rpc/server/listen_test.go
Normal file
157
pkg/rpc/server/listen_test.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
dbFile "github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
log.InitLogger(false, false)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func Test_dbWorker_update(t *testing.T) {
|
||||
type needsUpdateInput struct {
|
||||
appVersion string
|
||||
skip bool
|
||||
}
|
||||
type needsUpdateOutput struct {
|
||||
needsUpdate bool
|
||||
err error
|
||||
}
|
||||
type needsUpdate struct {
|
||||
input needsUpdateInput
|
||||
output needsUpdateOutput
|
||||
}
|
||||
|
||||
type download struct {
|
||||
call bool
|
||||
err error
|
||||
}
|
||||
|
||||
type args struct {
|
||||
appVersion string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
needsUpdate needsUpdate
|
||||
download download
|
||||
args args
|
||||
want db.Metadata
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{needsUpdate: true},
|
||||
},
|
||||
download: download{
|
||||
call: true,
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
want: db.Metadata{
|
||||
Version: 1,
|
||||
Type: db.TypeFull,
|
||||
NextUpdate: time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not update",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{needsUpdate: false},
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
},
|
||||
{
|
||||
name: "NeedsUpdate returns an error",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{err: xerrors.New("fail")},
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
wantErr: "failed to check if db needs an update",
|
||||
},
|
||||
{
|
||||
name: "Download returns an error",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{needsUpdate: true},
|
||||
},
|
||||
download: download{
|
||||
call: true,
|
||||
err: xerrors.New("fail"),
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
wantErr: "failed DB hot update",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cacheDir, err := ioutil.TempDir("", "server-test")
|
||||
require.NoError(t, err, tt.name)
|
||||
|
||||
require.NoError(t, db.Init(cacheDir), tt.name)
|
||||
|
||||
mockDBClient := new(dbFile.MockClient)
|
||||
mockDBClient.On("NeedsUpdate", mock.Anything,
|
||||
tt.needsUpdate.input.appVersion, false, tt.needsUpdate.input.skip).Return(
|
||||
tt.needsUpdate.output.needsUpdate, tt.needsUpdate.output.err)
|
||||
|
||||
if tt.download.call {
|
||||
mockDBClient.On("Download", mock.Anything, mock.Anything, false).Run(
|
||||
func(args mock.Arguments) {
|
||||
// fake download: copy testdata/new.db to tmpDir/db/trivy.db
|
||||
content, err := ioutil.ReadFile("testdata/new.db")
|
||||
require.NoError(t, err, tt.name)
|
||||
|
||||
tmpDir := args.String(1)
|
||||
dbPath := db.Path(tmpDir)
|
||||
require.NoError(t, os.MkdirAll(filepath.Dir(dbPath), 0777), tt.name)
|
||||
err = ioutil.WriteFile(dbPath, content, 0444)
|
||||
require.NoError(t, err, tt.name)
|
||||
}).Return(tt.download.err)
|
||||
}
|
||||
|
||||
w := newDBWorker(mockDBClient)
|
||||
|
||||
var dbUpdateWg, requestWg sync.WaitGroup
|
||||
err = w.update(context.Background(), tt.args.appVersion, cacheDir,
|
||||
&dbUpdateWg, &requestWg)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
if !tt.download.call {
|
||||
return
|
||||
}
|
||||
|
||||
dbc := db.Config{}
|
||||
got, err := dbc.GetMetadata()
|
||||
assert.NoError(t, err, tt.name)
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
|
||||
mockDBClient.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ var SuperSet = wire.NewSet(
|
||||
NewServer,
|
||||
)
|
||||
|
||||
// Server is for backward compatibility
|
||||
type Server struct {
|
||||
detector detector.Operation
|
||||
vulnClient vulnerability.Operation
|
||||
@@ -29,7 +30,8 @@ func NewServer(detector detector.Operation, vulnClient vulnerability.Operation)
|
||||
return &Server{detector: detector, vulnClient: vulnClient}
|
||||
}
|
||||
|
||||
func (s *Server) Detect(ctx context.Context, req *proto.OSDetectRequest) (res *proto.DetectResponse, err error) {
|
||||
// Detect is for backward compatibility
|
||||
func (s *Server) Detect(_ context.Context, req *proto.OSDetectRequest) (res *proto.DetectResponse, err error) {
|
||||
vulns, eosl, err := s.detector.Detect("", req.OsFamily, req.OsName, time.Time{}, rpc.ConvertFromRpcPkgs(req.Packages))
|
||||
if err != nil {
|
||||
err = xerrors.Errorf("failed to detect vulnerabilities of OS packages: %w", err)
|
||||
|
||||
@@ -9,12 +9,13 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"github.com/aquasecurity/trivy/rpc/common"
|
||||
proto "github.com/aquasecurity/trivy/rpc/detector"
|
||||
)
|
||||
|
||||
@@ -29,11 +30,12 @@ func TestServer_Detect(t *testing.T) {
|
||||
req *proto.OSDetectRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
detect ospkg.DetectExpectation
|
||||
wantRes *proto.DetectResponse
|
||||
wantErr string
|
||||
name string
|
||||
args args
|
||||
detectExpectation ospkg.DetectExpectation
|
||||
fillInfoExpectation vulnerability.FillInfoExpectation
|
||||
wantRes *proto.DetectResponse
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
@@ -41,16 +43,16 @@ func TestServer_Detect(t *testing.T) {
|
||||
req: &proto.OSDetectRequest{
|
||||
OsFamily: "alpine",
|
||||
OsName: "3.10.2",
|
||||
Packages: []*proto.Package{
|
||||
Packages: []*common.Package{
|
||||
{Name: "musl", Version: "1.1.22-r3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
detect: ospkg.DetectExpectation{
|
||||
detectExpectation: ospkg.DetectExpectation{
|
||||
Args: ospkg.DetectInput{
|
||||
OSFamily: "alpine",
|
||||
OSName: "3.10.2",
|
||||
Pkgs: []analyzer.Package{
|
||||
Pkgs: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.1.22-r3"},
|
||||
},
|
||||
},
|
||||
@@ -66,12 +68,25 @@ func TestServer_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
fillInfoExpectation: vulnerability.FillInfoExpectation{
|
||||
Args: vulnerability.FillInfoArgs{
|
||||
Vulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-0001",
|
||||
PkgName: "musl",
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Severity: "HIGH",
|
||||
}},
|
||||
},
|
||||
Light: false,
|
||||
},
|
||||
},
|
||||
wantRes: &proto.DetectResponse{
|
||||
Vulnerabilities: []*proto.Vulnerability{
|
||||
Vulnerabilities: []*common.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0001",
|
||||
PkgName: "musl",
|
||||
Severity: proto.Severity_HIGH,
|
||||
Severity: common.Severity_HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -82,16 +97,16 @@ func TestServer_Detect(t *testing.T) {
|
||||
req: &proto.OSDetectRequest{
|
||||
OsFamily: "alpine",
|
||||
OsName: "3.10.2",
|
||||
Packages: []*proto.Package{
|
||||
Packages: []*common.Package{
|
||||
{Name: "musl", Version: "1.1.22-r3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
detect: ospkg.DetectExpectation{
|
||||
detectExpectation: ospkg.DetectExpectation{
|
||||
Args: ospkg.DetectInput{
|
||||
OSFamily: "alpine",
|
||||
OSName: "3.10.2",
|
||||
Pkgs: []analyzer.Package{
|
||||
Pkgs: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.1.22-r3"},
|
||||
},
|
||||
},
|
||||
@@ -104,8 +119,9 @@ func TestServer_Detect(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockDetector := ospkg.NewMockDetector([]ospkg.DetectExpectation{tt.detect})
|
||||
mockVulnClient := vulnerability.NewMockVulnClient()
|
||||
mockDetector := ospkg.NewMockDetector([]ospkg.DetectExpectation{tt.detectExpectation})
|
||||
mockVulnClient := new(vulnerability.MockOperation)
|
||||
mockVulnClient.ApplyFillInfoExpectation(tt.fillInfoExpectation)
|
||||
|
||||
s := NewServer(mockDetector, mockVulnClient)
|
||||
gotRes, err := s.Detect(context.TODO(), tt.args.req)
|
||||
|
||||
@@ -2,136 +2,94 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
google_protobuf "github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/twitchtv/twirp"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/internal/server/config"
|
||||
dbFile "github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
rpc "github.com/aquasecurity/trivy/rpc/detector"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
var SuperSet = wire.NewSet(
|
||||
dbFile.SuperSet,
|
||||
newDBWorker,
|
||||
var ScanSuperSet = wire.NewSet(
|
||||
local.SuperSet,
|
||||
wire.Bind(new(scanner.Driver), new(local.Scanner)),
|
||||
vulnerability.SuperSet,
|
||||
NewScanServer,
|
||||
)
|
||||
|
||||
func ListenAndServe(addr string, c config.Config) error {
|
||||
requestWg := &sync.WaitGroup{}
|
||||
dbUpdateWg := &sync.WaitGroup{}
|
||||
|
||||
withWaitGroup := func(base http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Stop processing requests during DB update
|
||||
dbUpdateWg.Wait()
|
||||
|
||||
// Wait for all requests to be processed before DB update
|
||||
requestWg.Add(1)
|
||||
defer requestWg.Done()
|
||||
|
||||
base.ServeHTTP(w, r)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
go func() {
|
||||
worker := initializeDBWorker(true)
|
||||
ctx := context.Background()
|
||||
for {
|
||||
time.Sleep(1 * time.Hour)
|
||||
if err := worker.update(ctx, c.AppVersion, c.CacheDir, dbUpdateWg, requestWg); err != nil {
|
||||
log.Logger.Errorf("%+v\n", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
osHandler := rpc.NewOSDetectorServer(initializeOspkgServer(), nil)
|
||||
mux.Handle(rpc.OSDetectorPathPrefix, withToken(withWaitGroup(osHandler), c.Token, c.TokenHeader))
|
||||
|
||||
libHandler := rpc.NewLibDetectorServer(initializeLibServer(), nil)
|
||||
mux.Handle(rpc.LibDetectorPathPrefix, withToken(withWaitGroup(libHandler), c.Token, c.TokenHeader))
|
||||
|
||||
log.Logger.Infof("Listening %s...", addr)
|
||||
|
||||
return http.ListenAndServe(addr, mux)
|
||||
type ScanServer struct {
|
||||
localScanner scanner.Driver
|
||||
vulnClient vulnerability.Operation
|
||||
}
|
||||
|
||||
func withToken(base http.Handler, token, tokenHeader string) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if token != "" && token != r.Header.Get(tokenHeader) {
|
||||
rpc.WriteError(w, twirp.NewError(twirp.Unauthenticated, "invalid token"))
|
||||
return
|
||||
}
|
||||
base.ServeHTTP(w, r)
|
||||
})
|
||||
func NewScanServer(s scanner.Driver, vulnClient vulnerability.Operation) *ScanServer {
|
||||
return &ScanServer{localScanner: s, vulnClient: vulnClient}
|
||||
}
|
||||
|
||||
type dbWorker struct {
|
||||
dbClient dbFile.Operation
|
||||
}
|
||||
|
||||
func newDBWorker(dbClient dbFile.Operation) dbWorker {
|
||||
return dbWorker{dbClient: dbClient}
|
||||
}
|
||||
|
||||
func (w dbWorker) update(ctx context.Context, appVersion, cacheDir string,
|
||||
dbUpdateWg, requestWg *sync.WaitGroup) error {
|
||||
needsUpdate, err := w.dbClient.NeedsUpdate(ctx, appVersion, false, false)
|
||||
func (s *ScanServer) Scan(_ context.Context, in *rpcScanner.ScanRequest) (*rpcScanner.ScanResponse, error) {
|
||||
options := types.ScanOptions{VulnType: in.Options.VulnType}
|
||||
results, os, eosl, err := s.localScanner.Scan(in.Target, digest.Digest(in.ImageId), in.LayerIds, options)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to check if db needs an update")
|
||||
} else if !needsUpdate {
|
||||
return nil
|
||||
return nil, xerrors.Errorf("failed scan, %s: %w", in.Target, err)
|
||||
}
|
||||
|
||||
log.Logger.Info("Updating DB...")
|
||||
if err = w.hotUpdate(ctx, cacheDir, dbUpdateWg, requestWg); err != nil {
|
||||
return xerrors.Errorf("failed DB hot update")
|
||||
for i := range results {
|
||||
s.vulnClient.FillInfo(results[i].Vulnerabilities, false)
|
||||
}
|
||||
return nil
|
||||
return rpc.ConvertToRpcScanResponse(results, os, eosl), nil
|
||||
}
|
||||
|
||||
func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, requestWg *sync.WaitGroup) error {
|
||||
tmpDir, err := ioutil.TempDir("", "db")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create a temp dir: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if err := w.dbClient.Download(ctx, tmpDir, false); err != nil {
|
||||
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
|
||||
}
|
||||
|
||||
log.Logger.Info("Suspending all requests during DB update")
|
||||
dbUpdateWg.Add(1)
|
||||
defer dbUpdateWg.Done()
|
||||
|
||||
log.Logger.Info("Waiting for all requests to be processed before DB update...")
|
||||
requestWg.Wait()
|
||||
|
||||
if err = db.Close(); err != nil {
|
||||
return xerrors.Errorf("failed to close DB: %w", err)
|
||||
}
|
||||
|
||||
if _, err = utils.CopyFile(db.Path(tmpDir), db.Path(cacheDir)); err != nil {
|
||||
return xerrors.Errorf("failed to copy the database file: %w", err)
|
||||
}
|
||||
|
||||
log.Logger.Info("Reopening DB...")
|
||||
if err = db.Init(cacheDir); err != nil {
|
||||
return xerrors.Errorf("failed to open DB: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
type CacheServer struct {
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
func NewCacheServer(c cache.Cache) *CacheServer {
|
||||
return &CacheServer{cache: c}
|
||||
}
|
||||
|
||||
func (s *CacheServer) PutImage(_ context.Context, in *rpcCache.PutImageRequest) (*google_protobuf.Empty, error) {
|
||||
if in.ImageInfo == nil {
|
||||
return nil, xerrors.Errorf("empty image info")
|
||||
}
|
||||
imageInfo := rpc.ConvertFromRpcPutImageRequest(in)
|
||||
if err := s.cache.PutImage(in.ImageId, imageInfo); err != nil {
|
||||
return nil, xerrors.Errorf("unable to store image info in cache: %w", err)
|
||||
}
|
||||
return &google_protobuf.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *CacheServer) PutLayer(_ context.Context, in *rpcCache.PutLayerRequest) (*google_protobuf.Empty, error) {
|
||||
if in.LayerInfo == nil {
|
||||
return nil, xerrors.Errorf("empty layer info")
|
||||
}
|
||||
layerInfo := rpc.ConvertFromRpcPutLayerRequest(in)
|
||||
if err := s.cache.PutLayer(in.LayerId, in.DecompressedLayerId, layerInfo); err != nil {
|
||||
return nil, xerrors.Errorf("unable to store layer info in cache: %w", err)
|
||||
}
|
||||
return &google_protobuf.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *CacheServer) MissingLayers(_ context.Context, in *rpcCache.MissingLayersRequest) (*rpcCache.MissingLayersResponse, error) {
|
||||
var layerIDs []string
|
||||
for _, layerID := range in.LayerIds {
|
||||
l, err := s.cache.GetLayer(layerID)
|
||||
if err != nil || l.SchemaVersion != ftypes.LayerJSONSchemaVersion {
|
||||
layerIDs = append(layerIDs, layerID)
|
||||
}
|
||||
}
|
||||
var missingImage bool
|
||||
img, err := s.cache.GetImage(in.ImageId)
|
||||
if err != nil || img.SchemaVersion != ftypes.ImageJSONSchemaVersion {
|
||||
missingImage = true
|
||||
}
|
||||
return &rpcCache.MissingLayersResponse{MissingImage: missingImage, MissingLayerIds: layerIDs}, nil
|
||||
}
|
||||
|
||||
@@ -2,138 +2,255 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
|
||||
google_protobuf "github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
dbFile "github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
godeptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
"github.com/aquasecurity/trivy/rpc/common"
|
||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
log.InitLogger(false, false)
|
||||
os.Exit(m.Run())
|
||||
type mockCache struct {
|
||||
cache.MockImageCache
|
||||
cache.MockLocalImageCache
|
||||
}
|
||||
|
||||
func Test_dbWorker_update(t *testing.T) {
|
||||
type needsUpdateInput struct {
|
||||
appVersion string
|
||||
skip bool
|
||||
}
|
||||
type needsUpdateOutput struct {
|
||||
needsUpdate bool
|
||||
err error
|
||||
}
|
||||
type needsUpdate struct {
|
||||
input needsUpdateInput
|
||||
output needsUpdateOutput
|
||||
}
|
||||
|
||||
type download struct {
|
||||
call bool
|
||||
err error
|
||||
}
|
||||
|
||||
func TestScanServer_Scan(t *testing.T) {
|
||||
type args struct {
|
||||
appVersion string
|
||||
in *rpcScanner.ScanRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
needsUpdate needsUpdate
|
||||
download download
|
||||
args args
|
||||
want db.Metadata
|
||||
wantErr string
|
||||
name string
|
||||
args args
|
||||
scanExpectation scanner.ScanExpectation
|
||||
fillInfoExpectation vulnerability.FillInfoExpectation
|
||||
want *rpcScanner.ScanResponse
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{needsUpdate: true},
|
||||
args: args{
|
||||
in: &rpcScanner.ScanRequest{
|
||||
Target: "alpine:3.11",
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
Options: &rpcScanner.ScanOptions{},
|
||||
},
|
||||
},
|
||||
download: download{
|
||||
call: true,
|
||||
scanExpectation: scanner.ScanExpectation{
|
||||
Args: scanner.ScanArgs{
|
||||
Target: "alpine:3.11",
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: scanner.ScanReturns{
|
||||
Results: report.Results{
|
||||
{
|
||||
Target: "alpine:3.11 (alpine 3.11)",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-0001",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Vulnerability: dbTypes.Vulnerability{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
OsFound: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
want: db.Metadata{
|
||||
Version: 1,
|
||||
Type: db.TypeFull,
|
||||
NextUpdate: time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
UpdatedAt: time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
fillInfoExpectation: vulnerability.FillInfoExpectation{
|
||||
Args: vulnerability.FillInfoArgs{
|
||||
Vulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-0001",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Vulnerability: dbTypes.Vulnerability{},
|
||||
},
|
||||
},
|
||||
Light: false,
|
||||
},
|
||||
},
|
||||
want: &rpcScanner.ScanResponse{
|
||||
Os: &common.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
Eosl: false,
|
||||
Results: []*rpcScanner.Result{
|
||||
{
|
||||
Target: "alpine:3.11 (alpine 3.11)",
|
||||
Vulnerabilities: []*common.Vulnerability{
|
||||
{
|
||||
VulnerabilityId: "CVE-2019-0001",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not update",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{needsUpdate: false},
|
||||
name: "sad path: Scan returns an error",
|
||||
args: args{
|
||||
in: &rpcScanner.ScanRequest{
|
||||
Target: "alpine:3.11",
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIds: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
Options: &rpcScanner.ScanOptions{},
|
||||
},
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
scanExpectation: scanner.ScanExpectation{
|
||||
Args: scanner.ScanArgs{
|
||||
Target: "alpine:3.11",
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: scanner.ScanReturns{
|
||||
Err: errors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "failed scan, alpine:3.11",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockDriver := new(scanner.MockDriver)
|
||||
mockDriver.ApplyScanExpectation(tt.scanExpectation)
|
||||
|
||||
mockVulnClient := new(vulnerability.MockOperation)
|
||||
mockVulnClient.ApplyFillInfoExpectation(tt.fillInfoExpectation)
|
||||
|
||||
s := NewScanServer(mockDriver, mockVulnClient)
|
||||
got, err := s.Scan(context.Background(), tt.args.in)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheServer_PutImage(t *testing.T) {
|
||||
type args struct {
|
||||
in *rpcCache.PutImageRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
putImage cache.ImageCachePutImageExpectation
|
||||
want *google_protobuf.Empty
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
in: &rpcCache.PutImageRequest{
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
ImageInfo: &rpcCache.ImageInfo{
|
||||
SchemaVersion: 1,
|
||||
Architecture: "amd64",
|
||||
Created: func() *timestamp.Timestamp {
|
||||
d := time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC)
|
||||
t, _ := ptypes.TimestampProto(d)
|
||||
return t
|
||||
}(),
|
||||
DockerVersion: "18.09",
|
||||
Os: "linux",
|
||||
},
|
||||
},
|
||||
},
|
||||
putImage: cache.ImageCachePutImageExpectation{
|
||||
Args: cache.ImageCachePutImageArgs{
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
ImageInfo: ftypes.ImageInfo{
|
||||
SchemaVersion: 1,
|
||||
Architecture: "amd64",
|
||||
Created: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
|
||||
DockerVersion: "18.09",
|
||||
OS: "linux",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &google_protobuf.Empty{},
|
||||
},
|
||||
{
|
||||
name: "NeedsUpdate returns an error",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{err: xerrors.New("fail")},
|
||||
name: "sad path",
|
||||
args: args{
|
||||
in: &rpcCache.PutImageRequest{
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
ImageInfo: &rpcCache.ImageInfo{
|
||||
SchemaVersion: 1,
|
||||
Created: func() *timestamp.Timestamp {
|
||||
d := time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC)
|
||||
t, _ := ptypes.TimestampProto(d)
|
||||
return t
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
wantErr: "failed to check if db needs an update",
|
||||
putImage: cache.ImageCachePutImageExpectation{
|
||||
Args: cache.ImageCachePutImageArgs{
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
ImageInfo: ftypes.ImageInfo{
|
||||
SchemaVersion: 1,
|
||||
Created: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
|
||||
},
|
||||
},
|
||||
Returns: cache.ImageCachePutImageReturns{
|
||||
Err: xerrors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "unable to store image info in cache",
|
||||
},
|
||||
{
|
||||
name: "Download returns an error",
|
||||
needsUpdate: needsUpdate{
|
||||
input: needsUpdateInput{appVersion: "1", skip: false},
|
||||
output: needsUpdateOutput{needsUpdate: true},
|
||||
name: "sad path: empty image info",
|
||||
args: args{
|
||||
in: &rpcCache.PutImageRequest{},
|
||||
},
|
||||
download: download{
|
||||
call: true,
|
||||
err: xerrors.New("fail"),
|
||||
},
|
||||
args: args{appVersion: "1"},
|
||||
wantErr: "failed DB hot update",
|
||||
wantErr: "empty image info",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cacheDir, err := ioutil.TempDir("", "server-test")
|
||||
require.NoError(t, err, tt.name)
|
||||
mockCache := new(mockCache)
|
||||
mockCache.ApplyPutImageExpectation(tt.putImage)
|
||||
|
||||
require.NoError(t, db.Init(cacheDir), tt.name)
|
||||
s := NewCacheServer(mockCache)
|
||||
got, err := s.PutImage(context.Background(), tt.args.in)
|
||||
|
||||
mockDBClient := new(dbFile.MockClient)
|
||||
mockDBClient.On("NeedsUpdate", mock.Anything,
|
||||
tt.needsUpdate.input.appVersion, false, tt.needsUpdate.input.skip).Return(
|
||||
tt.needsUpdate.output.needsUpdate, tt.needsUpdate.output.err)
|
||||
|
||||
if tt.download.call {
|
||||
mockDBClient.On("Download", mock.Anything, mock.Anything, false).Run(
|
||||
func(args mock.Arguments) {
|
||||
// fake download: copy testdata/new.db to tmpDir/db/trivy.db
|
||||
content, err := ioutil.ReadFile("testdata/new.db")
|
||||
require.NoError(t, err, tt.name)
|
||||
|
||||
tmpDir := args.String(1)
|
||||
dbPath := db.Path(tmpDir)
|
||||
require.NoError(t, os.MkdirAll(filepath.Dir(dbPath), 0777), tt.name)
|
||||
err = ioutil.WriteFile(dbPath, content, 0444)
|
||||
require.NoError(t, err, tt.name)
|
||||
}).Return(tt.download.err)
|
||||
}
|
||||
|
||||
w := newDBWorker(mockDBClient)
|
||||
|
||||
var dbUpdateWg, requestWg sync.WaitGroup
|
||||
err = w.update(context.Background(), tt.args.appVersion, cacheDir,
|
||||
&dbUpdateWg, &requestWg)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
@@ -142,16 +259,337 @@ func Test_dbWorker_update(t *testing.T) {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
if !tt.download.call {
|
||||
return
|
||||
}
|
||||
|
||||
dbc := db.Config{}
|
||||
got, err := dbc.GetMetadata()
|
||||
assert.NoError(t, err, tt.name)
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
|
||||
mockDBClient.AssertExpectations(t)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheServer_PutLayer(t *testing.T) {
|
||||
type args struct {
|
||||
in *rpcCache.PutLayerRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
putLayer cache.ImageCachePutLayerExpectation
|
||||
want *google_protobuf.Empty
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
in: &rpcCache.PutLayerRequest{
|
||||
LayerId: "sha256:154ad0735c360b212b167f424d33a62305770a1fcfb6363882f5c436cfbd9812",
|
||||
DecompressedLayerId: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
|
||||
LayerInfo: &rpcCache.LayerInfo{
|
||||
SchemaVersion: 1,
|
||||
Os: &common.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
PackageInfos: []*common.PackageInfo{
|
||||
{
|
||||
FilePath: "lib/apk/db/installed",
|
||||
Packages: []*common.Package{
|
||||
{
|
||||
Name: "binary",
|
||||
Version: "1.2.3",
|
||||
Release: "1",
|
||||
Epoch: 2,
|
||||
Arch: "x86_64",
|
||||
SrcName: "src",
|
||||
SrcVersion: "1.2.3",
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
},
|
||||
{
|
||||
Name: "vim-minimal",
|
||||
Version: "7.4.160",
|
||||
Release: "5.el7",
|
||||
Epoch: 2,
|
||||
Arch: "x86_64",
|
||||
SrcName: "vim",
|
||||
SrcVersion: "7.4.160",
|
||||
SrcRelease: "5.el7",
|
||||
SrcEpoch: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Applications: []*common.Application{
|
||||
{
|
||||
Type: "composer",
|
||||
FilePath: "php-app/composer.lock",
|
||||
Libraries: []*common.Library{
|
||||
{
|
||||
Name: "guzzlehttp/guzzle",
|
||||
Version: "6.2.0",
|
||||
},
|
||||
{
|
||||
Name: "guzzlehttp/promises",
|
||||
Version: "v1.3.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
OpaqueDirs: []string{"etc/"},
|
||||
WhiteoutFiles: []string{"etc/hostname"},
|
||||
},
|
||||
},
|
||||
},
|
||||
putLayer: cache.ImageCachePutLayerExpectation{
|
||||
Args: cache.ImageCachePutLayerArgs{
|
||||
LayerID: "sha256:154ad0735c360b212b167f424d33a62305770a1fcfb6363882f5c436cfbd9812",
|
||||
DecompressedLayerID: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
|
||||
LayerInfo: ftypes.LayerInfo{
|
||||
SchemaVersion: 1,
|
||||
OS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
PackageInfos: []ftypes.PackageInfo{
|
||||
{
|
||||
FilePath: "lib/apk/db/installed",
|
||||
Packages: []ftypes.Package{
|
||||
{
|
||||
Name: "binary",
|
||||
Version: "1.2.3",
|
||||
Release: "1",
|
||||
Epoch: 2,
|
||||
Arch: "x86_64",
|
||||
SrcName: "src",
|
||||
SrcVersion: "1.2.3",
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
},
|
||||
{
|
||||
Name: "vim-minimal",
|
||||
Version: "7.4.160",
|
||||
Release: "5.el7",
|
||||
Epoch: 2,
|
||||
Arch: "x86_64",
|
||||
SrcName: "vim",
|
||||
SrcVersion: "7.4.160",
|
||||
SrcRelease: "5.el7",
|
||||
SrcEpoch: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: "composer",
|
||||
FilePath: "php-app/composer.lock",
|
||||
Libraries: []godeptypes.Library{
|
||||
{
|
||||
Name: "guzzlehttp/guzzle",
|
||||
Version: "6.2.0",
|
||||
},
|
||||
{
|
||||
Name: "guzzlehttp/promises",
|
||||
Version: "v1.3.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
OpaqueDirs: []string{"etc/"},
|
||||
WhiteoutFiles: []string{"etc/hostname"},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &google_protobuf.Empty{},
|
||||
},
|
||||
{
|
||||
name: "sad path",
|
||||
args: args{
|
||||
in: &rpcCache.PutLayerRequest{
|
||||
LayerInfo: &rpcCache.LayerInfo{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
putLayer: cache.ImageCachePutLayerExpectation{
|
||||
Args: cache.ImageCachePutLayerArgs{
|
||||
LayerIDAnything: true,
|
||||
DecompressedLayerIDAnything: true,
|
||||
LayerInfoAnything: true,
|
||||
},
|
||||
Returns: cache.ImageCachePutLayerReturns{
|
||||
Err: xerrors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "unable to store layer info in cache",
|
||||
},
|
||||
{
|
||||
name: "sad path: empty layer info",
|
||||
args: args{
|
||||
in: &rpcCache.PutLayerRequest{},
|
||||
},
|
||||
putLayer: cache.ImageCachePutLayerExpectation{
|
||||
Args: cache.ImageCachePutLayerArgs{
|
||||
LayerIDAnything: true,
|
||||
DecompressedLayerIDAnything: true,
|
||||
LayerInfoAnything: true,
|
||||
},
|
||||
Returns: cache.ImageCachePutLayerReturns{
|
||||
Err: xerrors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "empty layer info",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockCache := new(mockCache)
|
||||
mockCache.ApplyPutLayerExpectation(tt.putLayer)
|
||||
|
||||
s := NewCacheServer(mockCache)
|
||||
got, err := s.PutLayer(context.Background(), tt.args.in)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheServer_MissingLayers(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
in *rpcCache.MissingLayersRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
getLayerExpectations []cache.LocalImageCacheGetLayerExpectation
|
||||
getImageExpectations []cache.LocalImageCacheGetImageExpectation
|
||||
want *rpcCache.MissingLayersResponse
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
in: &rpcCache.MissingLayersRequest{
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIds: []string{
|
||||
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
},
|
||||
},
|
||||
getLayerExpectations: []cache.LocalImageCacheGetLayerExpectation{
|
||||
{
|
||||
Args: cache.LocalImageCacheGetLayerArgs{
|
||||
LayerID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
Returns: cache.LocalImageCacheGetLayerReturns{
|
||||
LayerInfo: ftypes.LayerInfo{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: cache.LocalImageCacheGetLayerArgs{
|
||||
LayerID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
Returns: cache.LocalImageCacheGetLayerReturns{
|
||||
LayerInfo: ftypes.LayerInfo{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
getImageExpectations: []cache.LocalImageCacheGetImageExpectation{
|
||||
{
|
||||
Args: cache.LocalImageCacheGetImageArgs{
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
},
|
||||
Returns: cache.LocalImageCacheGetImageReturns{
|
||||
ImageInfo: ftypes.ImageInfo{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &rpcCache.MissingLayersResponse{
|
||||
MissingImage: false,
|
||||
MissingLayerIds: []string{"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "schema version doesn't match",
|
||||
args: args{
|
||||
in: &rpcCache.MissingLayersRequest{
|
||||
ImageId: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIds: []string{
|
||||
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
},
|
||||
},
|
||||
getLayerExpectations: []cache.LocalImageCacheGetLayerExpectation{
|
||||
{
|
||||
Args: cache.LocalImageCacheGetLayerArgs{
|
||||
LayerID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
Returns: cache.LocalImageCacheGetLayerReturns{
|
||||
LayerInfo: ftypes.LayerInfo{
|
||||
SchemaVersion: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: cache.LocalImageCacheGetLayerArgs{
|
||||
LayerID: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
Returns: cache.LocalImageCacheGetLayerReturns{
|
||||
LayerInfo: ftypes.LayerInfo{
|
||||
SchemaVersion: -1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
getImageExpectations: []cache.LocalImageCacheGetImageExpectation{
|
||||
{
|
||||
Args: cache.LocalImageCacheGetImageArgs{
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
},
|
||||
Returns: cache.LocalImageCacheGetImageReturns{
|
||||
ImageInfo: ftypes.ImageInfo{},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &rpcCache.MissingLayersResponse{
|
||||
MissingImage: true,
|
||||
MissingLayerIds: []string{
|
||||
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
"sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockCache := new(mockCache)
|
||||
mockCache.ApplyGetLayerExpectations(tt.getLayerExpectations)
|
||||
mockCache.ApplyGetImageExpectations(tt.getImageExpectations)
|
||||
|
||||
s := NewCacheServer(mockCache)
|
||||
got, err := s.MissingLayers(tt.args.ctx, tt.args.in)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
mockCache.MockLocalImageCache.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,34 +6,49 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
db2 "github.com/aquasecurity/trivy/pkg/db"
|
||||
library2 "github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
ospkg2 "github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/github"
|
||||
"github.com/aquasecurity/trivy/pkg/indicator"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/server/library"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/server/ospkg"
|
||||
library2 "github.com/aquasecurity/trivy/pkg/rpc/server/library"
|
||||
ospkg2 "github.com/aquasecurity/trivy/pkg/rpc/server/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
// Injectors from inject.go:
|
||||
|
||||
func initializeOspkgServer() *ospkg.Server {
|
||||
detector := ospkg2.Detector{}
|
||||
func initializeScanServer(localLayerCache cache.LocalImageCache) *ScanServer {
|
||||
applier := analyzer.NewApplier(localLayerCache)
|
||||
detector := ospkg.Detector{}
|
||||
driverFactory := library.DriverFactory{}
|
||||
libraryDetector := library.NewDetector(driverFactory)
|
||||
scanner := local.NewScanner(applier, detector, libraryDetector)
|
||||
config := db.Config{}
|
||||
client := vulnerability.NewClient(config)
|
||||
server := ospkg.NewServer(detector, client)
|
||||
scanServer := NewScanServer(scanner, client)
|
||||
return scanServer
|
||||
}
|
||||
|
||||
func initializeOspkgServer() *ospkg2.Server {
|
||||
detector := ospkg.Detector{}
|
||||
config := db.Config{}
|
||||
client := vulnerability.NewClient(config)
|
||||
server := ospkg2.NewServer(detector, client)
|
||||
return server
|
||||
}
|
||||
|
||||
func initializeLibServer() *library.Server {
|
||||
driverFactory := library2.DriverFactory{}
|
||||
detector := library2.NewDetector(driverFactory)
|
||||
func initializeLibServer() *library2.Server {
|
||||
driverFactory := library.DriverFactory{}
|
||||
detector := library.NewDetector(driverFactory)
|
||||
config := db.Config{}
|
||||
client := vulnerability.NewClient(config)
|
||||
server := library.NewServer(detector, client)
|
||||
server := library2.NewServer(detector, client)
|
||||
return server
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
detector "github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/bundler"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/cargo"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/composer"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/npm"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/pipenv"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/poetry"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
|
||||
"github.com/aquasecurity/fanal/extractor"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
detector detector.Operation
|
||||
}
|
||||
|
||||
func NewScanner(detector detector.Operation) Scanner {
|
||||
return Scanner{detector: detector}
|
||||
}
|
||||
|
||||
func (s Scanner) Scan(imageName string, created time.Time, files extractor.FileMap) (map[string][]types.DetectedVulnerability, error) {
|
||||
results, err := analyzer.GetLibraries(files)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to analyze libraries: %w", err)
|
||||
}
|
||||
|
||||
vulnerabilities := map[string][]types.DetectedVulnerability{}
|
||||
for path, libs := range results {
|
||||
vulns, err := s.detector.Detect(imageName, string(path), created, libs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed library scan: %w", err)
|
||||
}
|
||||
|
||||
vulnerabilities[string(path)] = vulns
|
||||
}
|
||||
return vulnerabilities, nil
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
library2 "github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aquasecurity/fanal/extractor"
|
||||
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
func TestScanner_Scan(t *testing.T) {
|
||||
type detectInput struct {
|
||||
imageName string
|
||||
filePath string
|
||||
created time.Time
|
||||
libs []ptypes.Library
|
||||
}
|
||||
type detectOutput struct {
|
||||
vulns []types.DetectedVulnerability
|
||||
err error
|
||||
}
|
||||
type detect struct {
|
||||
input detectInput
|
||||
output detectOutput
|
||||
}
|
||||
type args struct {
|
||||
imageName string
|
||||
created time.Time
|
||||
files extractor.FileMap
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
detect []detect
|
||||
want map[string][]types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
imageName: "alpine:3.10",
|
||||
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
files: extractor.FileMap{
|
||||
"app/Pipfile.lock": []byte(`{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "ad1805ab0e16cf08032c3fe45eeaa29b79e9c196650411977af14e31b12ff0cd"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:665457d4146bbd34ae9d2970fa3b37082d7b225b0671bfd24c337458f229db78",
|
||||
"sha256:bde46d4dbc410678e89bc95ea5d312dd6eb4c37d0fa0e19c9415cad94addf22f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
`),
|
||||
"app/package-lock.json": []byte(`{
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"react": {
|
||||
"version": "16.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz",
|
||||
"integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.13.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`),
|
||||
},
|
||||
},
|
||||
detect: []detect{
|
||||
{
|
||||
input: detectInput{
|
||||
imageName: "alpine:3.10",
|
||||
filePath: "app/Pipfile.lock",
|
||||
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
libs: []ptypes.Library{
|
||||
{Name: "django", Version: "3.0.0"},
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
vulns: []types.DetectedVulnerability{
|
||||
{VulnerabilityID: "CVE-2019-0001"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: detectInput{
|
||||
imageName: "alpine:3.10",
|
||||
filePath: "app/package-lock.json",
|
||||
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
libs: []ptypes.Library{
|
||||
{Name: "react", Version: "16.8.6"},
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
vulns: []types.DetectedVulnerability{
|
||||
{VulnerabilityID: "CVE-2019-0002"},
|
||||
{VulnerabilityID: "CVE-2019-0003"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: map[string][]types.DetectedVulnerability{
|
||||
"app/Pipfile.lock": {{VulnerabilityID: "CVE-2019-0001"}},
|
||||
"app/package-lock.json": {
|
||||
{VulnerabilityID: "CVE-2019-0002"},
|
||||
{VulnerabilityID: "CVE-2019-0003"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "broken lock file",
|
||||
args: args{
|
||||
imageName: "alpine:3.10",
|
||||
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
files: extractor.FileMap{
|
||||
"app/Pipfile.lock": []byte(`{broken}`),
|
||||
},
|
||||
},
|
||||
wantErr: "failed to analyze libraries",
|
||||
},
|
||||
{
|
||||
name: "Detect returns an error",
|
||||
args: args{
|
||||
files: extractor.FileMap{
|
||||
"app/package-lock.json": []byte(`{
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"react": {
|
||||
"version": "16.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz",
|
||||
"integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.13.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`),
|
||||
},
|
||||
},
|
||||
detect: []detect{
|
||||
{
|
||||
input: detectInput{
|
||||
filePath: "app/package-lock.json",
|
||||
libs: []ptypes.Library{
|
||||
{Name: "react", Version: "16.8.6"},
|
||||
},
|
||||
},
|
||||
output: detectOutput{err: xerrors.New("error")},
|
||||
},
|
||||
},
|
||||
wantErr: "failed library scan",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockDetector := new(library2.MockDetector)
|
||||
for _, d := range tt.detect {
|
||||
mockDetector.On("Detect", d.input.imageName, d.input.filePath, d.input.created, d.input.libs).Return(
|
||||
d.output.vulns, d.output.err)
|
||||
}
|
||||
|
||||
s := Scanner{
|
||||
detector: mockDetector,
|
||||
}
|
||||
got, err := s.Scan(tt.args.imageName, tt.args.created, tt.args.files)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
mockDetector.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
71
pkg/scanner/local/mock_applier.go
Normal file
71
pkg/scanner/local/mock_applier.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package local
|
||||
|
||||
import digest "github.com/opencontainers/go-digest"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import types "github.com/aquasecurity/fanal/types"
|
||||
|
||||
// MockApplier is an autogenerated mock type for the Applier type
|
||||
type MockApplier struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type ApplierApplyLayersArgs struct {
|
||||
ImageID digest.Digest
|
||||
ImageIDAnything bool
|
||||
LayerIDs []string
|
||||
LayerIDsAnything bool
|
||||
}
|
||||
|
||||
type ApplierApplyLayersReturns struct {
|
||||
Detail types.ImageDetail
|
||||
Err error
|
||||
}
|
||||
|
||||
type ApplierApplyLayersExpectation struct {
|
||||
Args ApplierApplyLayersArgs
|
||||
Returns ApplierApplyLayersReturns
|
||||
}
|
||||
|
||||
func (_m *MockApplier) ApplyApplyLayersExpectation(e ApplierApplyLayersExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.ImageIDAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.ImageID)
|
||||
}
|
||||
if e.Args.LayerIDsAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.LayerIDs)
|
||||
}
|
||||
_m.On("ApplyLayers", args...).Return(e.Returns.Detail, e.Returns.Err)
|
||||
}
|
||||
|
||||
func (_m *MockApplier) ApplyApplyLayersExpectations(expectations []ApplierApplyLayersExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyApplyLayersExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyLayers provides a mock function with given fields: imageID, layerIDs
|
||||
func (_m *MockApplier) ApplyLayers(imageID digest.Digest, layerIDs []string) (types.ImageDetail, error) {
|
||||
ret := _m.Called(imageID, layerIDs)
|
||||
|
||||
var r0 types.ImageDetail
|
||||
if rf, ok := ret.Get(0).(func(digest.Digest, []string) types.ImageDetail); ok {
|
||||
r0 = rf(imageID, layerIDs)
|
||||
} else {
|
||||
r0 = ret.Get(0).(types.ImageDetail)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(digest.Digest, []string) error); ok {
|
||||
r1 = rf(imageID, layerIDs)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
88
pkg/scanner/local/mock_library_detector.go
Normal file
88
pkg/scanner/local/mock_library_detector.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package local
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import pkgtypes "github.com/aquasecurity/trivy/pkg/types"
|
||||
import time "time"
|
||||
import types "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
|
||||
// MockLibraryDetector is an autogenerated mock type for the LibraryDetector type
|
||||
type MockLibraryDetector struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type LibraryDetectorDetectArgs struct {
|
||||
ImageName string
|
||||
ImageNameAnything bool
|
||||
FilePath string
|
||||
FilePathAnything bool
|
||||
Created time.Time
|
||||
CreatedAnything bool
|
||||
Pkgs []types.Library
|
||||
PkgsAnything bool
|
||||
}
|
||||
|
||||
type LibraryDetectorDetectReturns struct {
|
||||
DetectedVulns []pkgtypes.DetectedVulnerability
|
||||
Err error
|
||||
}
|
||||
|
||||
type LibraryDetectorDetectExpectation struct {
|
||||
Args LibraryDetectorDetectArgs
|
||||
Returns LibraryDetectorDetectReturns
|
||||
}
|
||||
|
||||
func (_m *MockLibraryDetector) ApplyDetectExpectation(e LibraryDetectorDetectExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.ImageNameAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.ImageName)
|
||||
}
|
||||
if e.Args.FilePathAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.FilePath)
|
||||
}
|
||||
if e.Args.CreatedAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Created)
|
||||
}
|
||||
if e.Args.PkgsAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Pkgs)
|
||||
}
|
||||
_m.On("Detect", args...).Return(e.Returns.DetectedVulns, e.Returns.Err)
|
||||
}
|
||||
|
||||
func (_m *MockLibraryDetector) ApplyDetectExpectations(expectations []LibraryDetectorDetectExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyDetectExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect provides a mock function with given fields: imageName, filePath, created, pkgs
|
||||
func (_m *MockLibraryDetector) Detect(imageName string, filePath string, created time.Time, pkgs []types.Library) ([]pkgtypes.DetectedVulnerability, error) {
|
||||
ret := _m.Called(imageName, filePath, created, pkgs)
|
||||
|
||||
var r0 []pkgtypes.DetectedVulnerability
|
||||
if rf, ok := ret.Get(0).(func(string, string, time.Time, []types.Library) []pkgtypes.DetectedVulnerability); ok {
|
||||
r0 = rf(imageName, filePath, created, pkgs)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]pkgtypes.DetectedVulnerability)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string, time.Time, []types.Library) error); ok {
|
||||
r1 = rf(imageName, filePath, created, pkgs)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
103
pkg/scanner/local/mock_ospkg_detector.go
Normal file
103
pkg/scanner/local/mock_ospkg_detector.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package local
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import pkgtypes "github.com/aquasecurity/trivy/pkg/types"
|
||||
import time "time"
|
||||
import types "github.com/aquasecurity/fanal/types"
|
||||
|
||||
// MockOspkgDetector is an autogenerated mock type for the OspkgDetector type
|
||||
type MockOspkgDetector struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type OspkgDetectorDetectArgs struct {
|
||||
ImageName string
|
||||
ImageNameAnything bool
|
||||
OsFamily string
|
||||
OsFamilyAnything bool
|
||||
OsName string
|
||||
OsNameAnything bool
|
||||
Created time.Time
|
||||
CreatedAnything bool
|
||||
Pkgs []types.Package
|
||||
PkgsAnything bool
|
||||
}
|
||||
|
||||
type OspkgDetectorDetectReturns struct {
|
||||
DetectedVulns []pkgtypes.DetectedVulnerability
|
||||
Eosl bool
|
||||
Err error
|
||||
}
|
||||
|
||||
type OspkgDetectorDetectExpectation struct {
|
||||
Args OspkgDetectorDetectArgs
|
||||
Returns OspkgDetectorDetectReturns
|
||||
}
|
||||
|
||||
func (_m *MockOspkgDetector) ApplyDetectExpectation(e OspkgDetectorDetectExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.ImageNameAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.ImageName)
|
||||
}
|
||||
if e.Args.OsFamilyAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.OsFamily)
|
||||
}
|
||||
if e.Args.OsNameAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.OsName)
|
||||
}
|
||||
if e.Args.CreatedAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Created)
|
||||
}
|
||||
if e.Args.PkgsAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Pkgs)
|
||||
}
|
||||
_m.On("Detect", args...).Return(e.Returns.DetectedVulns, e.Returns.Eosl, e.Returns.Err)
|
||||
}
|
||||
|
||||
func (_m *MockOspkgDetector) ApplyDetectExpectations(expectations []OspkgDetectorDetectExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyDetectExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect provides a mock function with given fields: imageName, osFamily, osName, created, pkgs
|
||||
func (_m *MockOspkgDetector) Detect(imageName string, osFamily string, osName string, created time.Time, pkgs []types.Package) ([]pkgtypes.DetectedVulnerability, bool, error) {
|
||||
ret := _m.Called(imageName, osFamily, osName, created, pkgs)
|
||||
|
||||
var r0 []pkgtypes.DetectedVulnerability
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, time.Time, []types.Package) []pkgtypes.DetectedVulnerability); ok {
|
||||
r0 = rf(imageName, osFamily, osName, created, pkgs)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]pkgtypes.DetectedVulnerability)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 bool
|
||||
if rf, ok := ret.Get(1).(func(string, string, string, time.Time, []types.Package) bool); ok {
|
||||
r1 = rf(imageName, osFamily, osName, created, pkgs)
|
||||
} else {
|
||||
r1 = ret.Get(1).(bool)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(string, string, string, time.Time, []types.Package) error); ok {
|
||||
r2 = rf(imageName, osFamily, osName, created, pkgs)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
161
pkg/scanner/local/scan.go
Normal file
161
pkg/scanner/local/scan.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
ptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
|
||||
"github.com/google/wire"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
_ "github.com/aquasecurity/fanal/analyzer/command/apk"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/bundler"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/cargo"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/composer"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/npm"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/pipenv"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/poetry"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/alpine"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/amazonlinux"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/debianbase"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/photon"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/redhatbase"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/suse"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/pkg/apk"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/pkg/dpkg"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/pkg/rpmcmd"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
libDetector "github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
ospkgDetector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
)
|
||||
|
||||
var SuperSet = wire.NewSet(
|
||||
analyzer.NewApplier,
|
||||
wire.Bind(new(Applier), new(analyzer.Applier)),
|
||||
ospkgDetector.SuperSet,
|
||||
wire.Bind(new(OspkgDetector), new(ospkgDetector.Detector)),
|
||||
libDetector.SuperSet,
|
||||
wire.Bind(new(LibraryDetector), new(libDetector.Detector)),
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
type Applier interface {
|
||||
ApplyLayers(imageID digest.Digest, layerIDs []string) (detail ftypes.ImageDetail, err error)
|
||||
}
|
||||
|
||||
type OspkgDetector interface {
|
||||
Detect(imageName, osFamily, osName string, created time.Time, pkgs []ftypes.Package) (detectedVulns []types.DetectedVulnerability, eosl bool, err error)
|
||||
}
|
||||
|
||||
type LibraryDetector interface {
|
||||
Detect(imageName, filePath string, created time.Time, pkgs []ptypes.Library) (detectedVulns []types.DetectedVulnerability, err error)
|
||||
}
|
||||
|
||||
type Scanner struct {
|
||||
applier Applier
|
||||
ospkgDetector OspkgDetector
|
||||
libDetector LibraryDetector
|
||||
}
|
||||
|
||||
func NewScanner(applier Applier, ospkgDetector OspkgDetector, libDetector LibraryDetector) Scanner {
|
||||
return Scanner{applier: applier, ospkgDetector: ospkgDetector, libDetector: libDetector}
|
||||
}
|
||||
|
||||
func (s Scanner) Scan(target string, imageID digest.Digest, layerIDs []string, options types.ScanOptions) (report.Results, *ftypes.OS, bool, error) {
|
||||
imageDetail, err := s.applier.ApplyLayers(imageID, layerIDs)
|
||||
if err != nil {
|
||||
return nil, nil, false, xerrors.Errorf("failed to apply layers: %w", err)
|
||||
}
|
||||
|
||||
var eosl bool
|
||||
var results report.Results
|
||||
|
||||
if utils.StringInSlice("os", options.VulnType) {
|
||||
pkgs := imageDetail.Packages
|
||||
if options.ScanRemovedPackages {
|
||||
pkgs = mergePkgs(pkgs, imageDetail.HistoryPackages)
|
||||
}
|
||||
|
||||
var result *report.Result
|
||||
result, eosl, err = s.scanOSPkg(target, imageDetail.OS.Family, imageDetail.OS.Name, pkgs)
|
||||
if err != nil {
|
||||
return nil, nil, false, xerrors.Errorf("failed to scan OS packages: %w", err)
|
||||
}
|
||||
if result != nil {
|
||||
results = append(results, *result)
|
||||
}
|
||||
}
|
||||
|
||||
if utils.StringInSlice("library", options.VulnType) {
|
||||
libResults, err := s.scanLibrary(imageDetail.Applications)
|
||||
if err != nil {
|
||||
return nil, nil, false, xerrors.Errorf("failed to scan application libraries: %w", err)
|
||||
}
|
||||
results = append(results, libResults...)
|
||||
}
|
||||
|
||||
return results, imageDetail.OS, eosl, nil
|
||||
}
|
||||
|
||||
func (s Scanner) scanOSPkg(target, osFamily, osName string, pkgs []ftypes.Package) (*report.Result, bool, error) {
|
||||
if osFamily == "" {
|
||||
return nil, false, nil
|
||||
}
|
||||
vulns, eosl, err := s.ospkgDetector.Detect("", osFamily, osName, time.Time{}, pkgs)
|
||||
if err == ospkgDetector.ErrUnsupportedOS {
|
||||
return nil, false, nil
|
||||
} else if err != nil {
|
||||
return nil, false, xerrors.Errorf("failed vulnerability detection of OS packages: %w", err)
|
||||
}
|
||||
|
||||
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osName)
|
||||
result := &report.Result{
|
||||
Target: imageDetail,
|
||||
Vulnerabilities: vulns,
|
||||
}
|
||||
return result, eosl, nil
|
||||
}
|
||||
|
||||
func (s Scanner) scanLibrary(apps []ftypes.Application) (report.Results, error) {
|
||||
var results report.Results
|
||||
for _, app := range apps {
|
||||
vulns, err := s.libDetector.Detect("", app.FilePath, time.Time{}, app.Libraries)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed vulnerability detection of libraries: %w", err)
|
||||
}
|
||||
|
||||
results = append(results, report.Result{
|
||||
Target: app.FilePath,
|
||||
Vulnerabilities: vulns,
|
||||
})
|
||||
}
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Target < results[j].Target
|
||||
})
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func mergePkgs(pkgs, pkgsFromCommands []ftypes.Package) []ftypes.Package {
|
||||
// pkg has priority over pkgsFromCommands
|
||||
uniqPkgs := map[string]struct{}{}
|
||||
for _, pkg := range pkgs {
|
||||
uniqPkgs[pkg.Name] = struct{}{}
|
||||
}
|
||||
for _, pkg := range pkgsFromCommands {
|
||||
if _, ok := uniqPkgs[pkg.Name]; ok {
|
||||
continue
|
||||
}
|
||||
pkgs = append(pkgs, pkg)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
518
pkg/scanner/local/scan_test.go
Normal file
518
pkg/scanner/local/scan_test.go
Normal file
@@ -0,0 +1,518 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
ospkgDetector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dtypes "github.com/aquasecurity/go-dep-parser/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
func TestScanner_Scan(t *testing.T) {
|
||||
type args struct {
|
||||
target string
|
||||
layerIDs []string
|
||||
options types.ScanOptions
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
applyLayersExpectation ApplierApplyLayersExpectation
|
||||
ospkgDetectExpectations []OspkgDetectorDetectExpectation
|
||||
libDetectExpectations []LibraryDetectorDetectExpectation
|
||||
wantResults report.Results
|
||||
wantOS *ftypes.OS
|
||||
wantEosl bool
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"os", "library"}},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Detail: ftypes.ImageDetail{
|
||||
OS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
Packages: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.2.3"},
|
||||
},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: "bundler",
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Libraries: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ospkgDetectExpectations: []OspkgDetectorDetectExpectation{
|
||||
{
|
||||
Args: OspkgDetectorDetectArgs{
|
||||
OsFamily: "alpine",
|
||||
OsName: "3.11",
|
||||
Pkgs: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.2.3"},
|
||||
},
|
||||
},
|
||||
Returns: OspkgDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-9999",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
},
|
||||
},
|
||||
Eosl: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
libDetectExpectations: []LibraryDetectorDetectExpectation{
|
||||
{
|
||||
Args: LibraryDetectorDetectArgs{
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Pkgs: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
Returns: LibraryDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResults: report.Results{
|
||||
{
|
||||
Target: "alpine:latest (alpine 3.11)",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-9999",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Target: "/app/Gemfile.lock",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantOS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with empty os",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"os", "library"}},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Detail: ftypes.ImageDetail{
|
||||
OS: &ftypes.OS{},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: "bundler",
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Libraries: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
libDetectExpectations: []LibraryDetectorDetectExpectation{
|
||||
{
|
||||
Args: LibraryDetectorDetectArgs{
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Pkgs: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
Returns: LibraryDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResults: report.Results{
|
||||
{
|
||||
Target: "/app/Gemfile.lock",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantOS: &ftypes.OS{},
|
||||
},
|
||||
{
|
||||
name: "happy path with unknown os",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"os", "library"}},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Detail: ftypes.ImageDetail{
|
||||
OS: &ftypes.OS{
|
||||
Family: "fedora",
|
||||
Name: "27",
|
||||
},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: "bundler",
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Libraries: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ospkgDetectExpectations: []OspkgDetectorDetectExpectation{
|
||||
{
|
||||
Args: OspkgDetectorDetectArgs{
|
||||
OsFamily: "fedora",
|
||||
OsName: "27",
|
||||
},
|
||||
Returns: OspkgDetectorDetectReturns{
|
||||
Err: ospkgDetector.ErrUnsupportedOS,
|
||||
},
|
||||
},
|
||||
},
|
||||
libDetectExpectations: []LibraryDetectorDetectExpectation{
|
||||
{
|
||||
Args: LibraryDetectorDetectArgs{
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Pkgs: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
Returns: LibraryDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResults: report.Results{
|
||||
{
|
||||
Target: "/app/Gemfile.lock",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantOS: &ftypes.OS{
|
||||
Family: "fedora",
|
||||
Name: "27",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with only library detection",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"library"}},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Detail: ftypes.ImageDetail{
|
||||
OS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
Packages: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.2.3"},
|
||||
},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: "bundler",
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Libraries: []dtypes.Library{
|
||||
{Name: "rails", Version: "5.1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "composer",
|
||||
FilePath: "/app/composer-lock.json",
|
||||
Libraries: []dtypes.Library{
|
||||
{Name: "laravel", Version: "6.0.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
libDetectExpectations: []LibraryDetectorDetectExpectation{
|
||||
{
|
||||
Args: LibraryDetectorDetectArgs{
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Pkgs: []dtypes.Library{
|
||||
{Name: "rails", Version: "5.1"},
|
||||
},
|
||||
},
|
||||
Returns: LibraryDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-11111",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "5.1",
|
||||
FixedVersion: "5.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: LibraryDetectorDetectArgs{
|
||||
FilePath: "/app/composer-lock.json",
|
||||
Pkgs: []dtypes.Library{
|
||||
{Name: "laravel", Version: "6.0.0"},
|
||||
},
|
||||
},
|
||||
Returns: LibraryDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-22222",
|
||||
PkgName: "laravel",
|
||||
InstalledVersion: "6.0.0",
|
||||
FixedVersion: "6.1.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResults: report.Results{
|
||||
{
|
||||
Target: "/app/Gemfile.lock",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-11111",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "5.1",
|
||||
FixedVersion: "5.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Target: "/app/composer-lock.json",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-22222",
|
||||
PkgName: "laravel",
|
||||
InstalledVersion: "6.0.0",
|
||||
FixedVersion: "6.1.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantOS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad path: ApplyLayers returns an error",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"os", "library"}},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Err: errors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "failed to apply layers",
|
||||
},
|
||||
{
|
||||
name: "sad path: ospkgDetector.Detect returns an error",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"os", "library"}},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Detail: ftypes.ImageDetail{
|
||||
OS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
Packages: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.2.3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ospkgDetectExpectations: []OspkgDetectorDetectExpectation{
|
||||
{
|
||||
Args: OspkgDetectorDetectArgs{
|
||||
OsFamily: "alpine",
|
||||
OsName: "3.11",
|
||||
Pkgs: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.2.3"},
|
||||
},
|
||||
},
|
||||
Returns: OspkgDetectorDetectReturns{
|
||||
Err: errors.New("error"),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to scan OS packages",
|
||||
},
|
||||
{
|
||||
name: "sad path: libDetector.Detect returns an error",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"library"}},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Detail: ftypes.ImageDetail{
|
||||
OS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
Packages: []ftypes.Package{
|
||||
{Name: "musl", Version: "1.2.3"},
|
||||
},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: "bundler",
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Libraries: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
libDetectExpectations: []LibraryDetectorDetectExpectation{
|
||||
{
|
||||
Args: LibraryDetectorDetectArgs{
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Pkgs: []dtypes.Library{
|
||||
{Name: "rails", Version: "6.0"},
|
||||
},
|
||||
},
|
||||
Returns: LibraryDetectorDetectReturns{
|
||||
Err: errors.New("error"),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to scan application libraries",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
applier := new(MockApplier)
|
||||
applier.ApplyApplyLayersExpectation(tt.applyLayersExpectation)
|
||||
|
||||
ospkgDetector := new(MockOspkgDetector)
|
||||
ospkgDetector.ApplyDetectExpectations(tt.ospkgDetectExpectations)
|
||||
|
||||
libDetector := new(MockLibraryDetector)
|
||||
libDetector.ApplyDetectExpectations(tt.libDetectExpectations)
|
||||
|
||||
s := NewScanner(applier, ospkgDetector, libDetector)
|
||||
gotResults, gotOS, gotEosl, err := s.Scan(tt.args.target, "", tt.args.layerIDs, tt.args.options)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
require.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.wantResults, gotResults)
|
||||
assert.Equal(t, tt.wantOS, gotOS)
|
||||
assert.Equal(t, tt.wantEosl, gotEosl)
|
||||
|
||||
applier.AssertExpectations(t)
|
||||
ospkgDetector.AssertExpectations(t)
|
||||
libDetector.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
64
pkg/scanner/mock_analyzer.go
Normal file
64
pkg/scanner/mock_analyzer.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package scanner
|
||||
|
||||
import context "context"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import types "github.com/aquasecurity/fanal/types"
|
||||
|
||||
// MockAnalyzer is an autogenerated mock type for the Analyzer type
|
||||
type MockAnalyzer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type AnalyzerAnalyzeArgs struct {
|
||||
Ctx context.Context
|
||||
CtxAnything bool
|
||||
}
|
||||
|
||||
type AnalyzerAnalyzeReturns struct {
|
||||
Info types.ImageReference
|
||||
Err error
|
||||
}
|
||||
|
||||
type AnalyzerAnalyzeExpectation struct {
|
||||
Args AnalyzerAnalyzeArgs
|
||||
Returns AnalyzerAnalyzeReturns
|
||||
}
|
||||
|
||||
func (_m *MockAnalyzer) ApplyAnalyzeExpectation(e AnalyzerAnalyzeExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.CtxAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Ctx)
|
||||
}
|
||||
_m.On("Analyze", args...).Return(e.Returns.Info, e.Returns.Err)
|
||||
}
|
||||
|
||||
func (_m *MockAnalyzer) ApplyAnalyzeExpectations(expectations []AnalyzerAnalyzeExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyAnalyzeExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze provides a mock function with given fields: ctx
|
||||
func (_m *MockAnalyzer) Analyze(ctx context.Context) (types.ImageReference, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 types.ImageReference
|
||||
if rf, ok := ret.Get(0).(func(context.Context) types.ImageReference); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
r0 = ret.Get(0).(types.ImageReference)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
107
pkg/scanner/mock_driver.go
Normal file
107
pkg/scanner/mock_driver.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package scanner
|
||||
|
||||
import digest "github.com/opencontainers/go-digest"
|
||||
import fanaltypes "github.com/aquasecurity/fanal/types"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import report "github.com/aquasecurity/trivy/pkg/report"
|
||||
import types "github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
// MockDriver is an autogenerated mock type for the Driver type
|
||||
type MockDriver struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type ScanArgs struct {
|
||||
Target string
|
||||
TargetAnything bool
|
||||
ImageID digest.Digest
|
||||
ImageIDAnything bool
|
||||
LayerIDs []string
|
||||
LayerIDsAnything bool
|
||||
Options types.ScanOptions
|
||||
OptionsAnything bool
|
||||
}
|
||||
|
||||
type ScanReturns struct {
|
||||
Results report.Results
|
||||
OsFound *fanaltypes.OS
|
||||
Eols bool
|
||||
Err error
|
||||
}
|
||||
|
||||
type ScanExpectation struct {
|
||||
Args ScanArgs
|
||||
Returns ScanReturns
|
||||
}
|
||||
|
||||
func (_m *MockDriver) ApplyScanExpectation(e ScanExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.TargetAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Target)
|
||||
}
|
||||
if e.Args.ImageIDAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.ImageID)
|
||||
}
|
||||
if e.Args.LayerIDsAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.LayerIDs)
|
||||
}
|
||||
if e.Args.OptionsAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Options)
|
||||
}
|
||||
_m.On("Scan", args...).Return(e.Returns.Results, e.Returns.OsFound, e.Returns.Eols, e.Returns.Err)
|
||||
}
|
||||
|
||||
func (_m *MockDriver) ApplyScanExpectations(expectations []ScanExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyScanExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Scan provides a mock function with given fields: target, imageID, layerIDs, options
|
||||
func (_m *MockDriver) Scan(target string, imageID digest.Digest, layerIDs []string, options types.ScanOptions) (report.Results, *fanaltypes.OS, bool, error) {
|
||||
ret := _m.Called(target, imageID, layerIDs, options)
|
||||
|
||||
var r0 report.Results
|
||||
if rf, ok := ret.Get(0).(func(string, digest.Digest, []string, types.ScanOptions) report.Results); ok {
|
||||
r0 = rf(target, imageID, layerIDs, options)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(report.Results)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *fanaltypes.OS
|
||||
if rf, ok := ret.Get(1).(func(string, digest.Digest, []string, types.ScanOptions) *fanaltypes.OS); ok {
|
||||
r1 = rf(target, imageID, layerIDs, options)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*fanaltypes.OS)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 bool
|
||||
if rf, ok := ret.Get(2).(func(string, digest.Digest, []string, types.ScanOptions) bool); ok {
|
||||
r2 = rf(target, imageID, layerIDs, options)
|
||||
} else {
|
||||
r2 = ret.Get(2).(bool)
|
||||
}
|
||||
|
||||
var r3 error
|
||||
if rf, ok := ret.Get(3).(func(string, digest.Digest, []string, types.ScanOptions) error); ok {
|
||||
r3 = rf(target, imageID, layerIDs, options)
|
||||
} else {
|
||||
r3 = ret.Error(3)
|
||||
}
|
||||
|
||||
return r0, r1, r2, r3
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package ospkg
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/command/apk"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/alpine"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/amazonlinux"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/debianbase"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/photon"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/redhatbase"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/os/suse"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/pkg/apk"
|
||||
_ "github.com/aquasecurity/fanal/analyzer/pkg/dpkg"
|
||||
"github.com/aquasecurity/fanal/extractor"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
detector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
detector detector.Operation
|
||||
}
|
||||
|
||||
func NewScanner(detector detector.Operation) Scanner {
|
||||
return Scanner{detector: detector}
|
||||
}
|
||||
|
||||
func (s Scanner) Scan(imageName string, created time.Time, files extractor.FileMap) (string, string, []types.DetectedVulnerability, error) {
|
||||
os, err := analyzer.GetOS(files)
|
||||
if err != nil {
|
||||
return "", "", nil, xerrors.Errorf("failed to analyze OS: %w", err)
|
||||
}
|
||||
log.Logger.Debugf("OS family: %s, OS version: %s", os.Family, os.Name)
|
||||
|
||||
pkgs, err := analyzer.GetPackages(files)
|
||||
if err != nil {
|
||||
if xerrors.Is(err, ftypes.ErrNoRpmCmd) {
|
||||
log.Logger.Error("'rpm' command is not installed")
|
||||
}
|
||||
return "", "", nil, xerrors.Errorf("failed to analyze OS packages: %w", err)
|
||||
}
|
||||
log.Logger.Debugf("the number of packages: %d", len(pkgs))
|
||||
|
||||
pkgsFromCommands, err := analyzer.GetPackagesFromCommands(os, files)
|
||||
if err != nil {
|
||||
return "", "", nil, xerrors.Errorf("failed to analyze OS packages: %w", err)
|
||||
}
|
||||
log.Logger.Debugf("the number of packages from commands: %d", len(pkgsFromCommands))
|
||||
|
||||
pkgs = mergePkgs(pkgs, pkgsFromCommands)
|
||||
log.Logger.Debugf("the number of packages: %d", len(pkgs))
|
||||
|
||||
vulns, eosl, err := s.detector.Detect(imageName, os.Family, os.Name, created, pkgs)
|
||||
if err != nil {
|
||||
return "", "", nil, xerrors.Errorf("failed to detect vulnerabilities: %w", err)
|
||||
}
|
||||
if eosl {
|
||||
// TODO: test logger
|
||||
log.Logger.Warnf("This OS version is no longer supported by the distribution: %s %s", os.Family, os.Name)
|
||||
log.Logger.Warnf("The vulnerability detection may be insufficient because security updates are not provided")
|
||||
}
|
||||
|
||||
return os.Family, os.Name, vulns, nil
|
||||
}
|
||||
|
||||
func mergePkgs(pkgs, pkgsFromCommands []analyzer.Package) []analyzer.Package {
|
||||
uniqPkgs := map[string]struct{}{}
|
||||
for _, pkg := range pkgs {
|
||||
uniqPkgs[pkg.Name] = struct{}{}
|
||||
}
|
||||
for _, pkg := range pkgsFromCommands {
|
||||
if _, ok := uniqPkgs[pkg.Name]; ok {
|
||||
continue
|
||||
}
|
||||
pkgs = append(pkgs, pkg)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// +build freebsd netbsd openbsd
|
||||
|
||||
package ospkg
|
||||
|
||||
import (
|
||||
_ "github.com/aquasecurity/fanal/analyzer/pkg/rpmcmd"
|
||||
)
|
||||
@@ -1,228 +0,0 @@
|
||||
package ospkg
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ospkg2 "github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/extractor"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
log.InitLogger(false, true)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func TestScanner_Scan(t *testing.T) {
|
||||
type detectInput struct {
|
||||
imageName string
|
||||
osFamily string
|
||||
osName string
|
||||
buildTime time.Time
|
||||
pkgs []analyzer.Package
|
||||
}
|
||||
type detectOutput struct {
|
||||
vulns []types.DetectedVulnerability
|
||||
eosl bool
|
||||
err error
|
||||
}
|
||||
type detect struct {
|
||||
input detectInput
|
||||
output detectOutput
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
imageName string
|
||||
created time.Time
|
||||
files extractor.FileMap
|
||||
}
|
||||
type want struct {
|
||||
osFamily string
|
||||
osName string
|
||||
vulns []types.DetectedVulnerability
|
||||
err string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
detect detect
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fields: fields{
|
||||
imageName: "alpine:3.10.2",
|
||||
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
files: extractor.FileMap{
|
||||
"/config": []byte(`{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f","container_config":{"Hostname":"c10d36fa368a","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/bin/sh\"]"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2019-05-11T00:07:03.510395965Z","docker_version":"18.06.1-ce","history":[{"created":"2019-05-11T00:07:03.358250803Z","created_by":"/bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6ae03397b99ea77f2e9ee901c5c59e59f76f93adbb4035913 in / "},{"created":"2019-05-11T00:07:03.510395965Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81"]}}`),
|
||||
"etc/alpine-release": []byte("3.10.2"),
|
||||
"lib/apk/db/installed": []byte(`C:Q11Ing8/u1VIdY9czSxaDO9wJg72I=
|
||||
P:musl
|
||||
V:1.1.22-r3
|
||||
A:x86_64
|
||||
S:368204
|
||||
I:598016
|
||||
T:the musl c library (libc) implementation
|
||||
U:http://www.musl-libc.org/
|
||||
L:MIT
|
||||
o:musl
|
||||
m:Timo Teräs <timo.teras@iki.fi>
|
||||
t:1565162130
|
||||
c:0c777cf840e82cdc528651e3f3f8f9dda6b1b028
|
||||
p:so:libc.musl-x86_64.so.1=1
|
||||
F:lib
|
||||
R:libc.musl-x86_64.so.1
|
||||
a:0:0:777
|
||||
Z:Q17yJ3JFNypA4mxhJJr0ou6CzsJVI=
|
||||
R:ld-musl-x86_64.so.1
|
||||
a:0:0:755
|
||||
Z:Q1TTLtUopPeiF9JrA0cgKQZYggG+c=
|
||||
F:usr
|
||||
F:usr/lib
|
||||
`),
|
||||
},
|
||||
},
|
||||
detect: detect{
|
||||
input: detectInput{
|
||||
imageName: "alpine:3.10.2",
|
||||
osFamily: "alpine",
|
||||
osName: "3.10.2",
|
||||
buildTime: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
pkgs: []analyzer.Package{
|
||||
{Name: "musl", Version: "1.1.22-r3"},
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
vulns: []types.DetectedVulnerability{
|
||||
{VulnerabilityID: "CVE-2019-0001", PkgName: "musl"},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
osFamily: "alpine",
|
||||
osName: "3.10.2",
|
||||
vulns: []types.DetectedVulnerability{
|
||||
{VulnerabilityID: "CVE-2019-0001", PkgName: "musl"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad path",
|
||||
fields: fields{
|
||||
files: extractor.FileMap{
|
||||
"etc/alpine-release": []byte("3.10.2"),
|
||||
"invalid": []byte(`invalid`),
|
||||
},
|
||||
},
|
||||
want: want{err: analyzer.ErrPkgAnalysis.Error()},
|
||||
},
|
||||
{
|
||||
name: "Detect returns an error",
|
||||
fields: fields{
|
||||
imageName: "alpine:3.10",
|
||||
created: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
files: extractor.FileMap{
|
||||
"/config": []byte(`{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"c10d36fa368a7ea673683682666758adf35efe98e10989505f4f566b5b18538f","container_config":{"Hostname":"c10d36fa368a","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/bin/sh\"]"],"ArgsEscaped":true,"Image":"sha256:09f2bbe58e774849d74dc1391c2e01731896c745c4aba1ecf69a283bdb4b537a","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2019-05-11T00:07:03.510395965Z","docker_version":"18.06.1-ce","history":[{"created":"2019-05-11T00:07:03.358250803Z","created_by":"/bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6ae03397b99ea77f2e9ee901c5c59e59f76f93adbb4035913 in / "},{"created":"2019-05-11T00:07:03.510395965Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:f1b5933fe4b5f49bbe8258745cf396afe07e625bdab3168e364daf7c956b6b81"]}}`),
|
||||
"etc/alpine-release": []byte("3.10.2"),
|
||||
"lib/apk/db/installed": []byte(`C:Q11Ing8/u1VIdY9czSxaDO9wJg72I=
|
||||
P:musl
|
||||
V:1.1.22-r3
|
||||
A:x86_64
|
||||
`),
|
||||
},
|
||||
},
|
||||
detect: detect{
|
||||
input: detectInput{
|
||||
imageName: "alpine:3.10",
|
||||
osFamily: "alpine",
|
||||
osName: "3.10.2",
|
||||
buildTime: time.Date(2019, 5, 11, 0, 7, 3, 510395965, time.UTC),
|
||||
pkgs: []analyzer.Package{
|
||||
{Name: "musl", Version: "1.1.22-r3"},
|
||||
},
|
||||
},
|
||||
output: detectOutput{
|
||||
err: xerrors.New("error"),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: "failed to detect vulnerabilities",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockDetector := new(ospkg2.MockDetector)
|
||||
mockDetector.On("Detect", tt.detect.input.imageName, tt.detect.input.osFamily, tt.detect.input.osName,
|
||||
tt.detect.input.buildTime, tt.detect.input.pkgs).Return(tt.detect.output.vulns, tt.detect.output.eosl, tt.detect.output.err)
|
||||
|
||||
s := NewScanner(mockDetector)
|
||||
got, got1, got2, err := s.Scan(tt.fields.imageName, tt.fields.created, tt.fields.files)
|
||||
|
||||
if tt.want.err != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
assert.Contains(t, err.Error(), tt.want.err, tt.name)
|
||||
return
|
||||
} else {
|
||||
assert.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want.osFamily, got)
|
||||
assert.Equal(t, tt.want.osName, got1)
|
||||
assert.Equal(t, tt.want.vulns, got2)
|
||||
mockDetector.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_mergePkgs(t *testing.T) {
|
||||
type args struct {
|
||||
pkgs []analyzer.Package
|
||||
pkgsFromCommands []analyzer.Package
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []analyzer.Package
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
pkgs: []analyzer.Package{
|
||||
{Name: "foo", Version: "1.2.3"},
|
||||
{Name: "bar", Version: "3.4.5"},
|
||||
{Name: "baz", Version: "6.7.8"},
|
||||
},
|
||||
pkgsFromCommands: []analyzer.Package{
|
||||
{Name: "bar", Version: "1.1.1"},
|
||||
{Name: "hoge", Version: "9.0.1"},
|
||||
},
|
||||
},
|
||||
want: []analyzer.Package{
|
||||
{Name: "foo", Version: "1.2.3"},
|
||||
{Name: "bar", Version: "3.4.5"},
|
||||
{Name: "baz", Version: "6.7.8"},
|
||||
{Name: "hoge", Version: "9.0.1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := mergePkgs(tt.args.pkgs, tt.args.pkgsFromCommands)
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// +build linux darwin
|
||||
|
||||
package ospkg
|
||||
|
||||
import (
|
||||
_ "github.com/aquasecurity/fanal/analyzer/pkg/rpmcmd"
|
||||
// TODO: Eliminate the dependency on "rpm" command
|
||||
// _ "github.com/aquasecurity/fanal/analyzer/pkg/rpm"
|
||||
)
|
||||
@@ -2,157 +2,103 @@ package scanner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/google/wire"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/fanal/extractor"
|
||||
"github.com/aquasecurity/fanal/extractor/docker"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
libDetector "github.com/aquasecurity/trivy/pkg/detector/library"
|
||||
ospkgDetector "github.com/aquasecurity/trivy/pkg/detector/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
rpcLibDetector "github.com/aquasecurity/trivy/pkg/rpc/client/library"
|
||||
rpcOSDetector "github.com/aquasecurity/trivy/pkg/rpc/client/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/library"
|
||||
libScanner "github.com/aquasecurity/trivy/pkg/scanner/library"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||
ospkgScanner "github.com/aquasecurity/trivy/pkg/scanner/ospkg"
|
||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/local"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
var StandaloneSet = wire.NewSet(
|
||||
ospkgDetector.SuperSet,
|
||||
ospkgScanner.NewScanner,
|
||||
libDetector.SuperSet,
|
||||
libScanner.NewScanner,
|
||||
// StandaloneSuperSet is used in the standalone mode
|
||||
var StandaloneSuperSet = wire.NewSet(
|
||||
analyzer.New,
|
||||
wire.Bind(new(Analyzer), new(analyzer.Config)),
|
||||
local.SuperSet,
|
||||
wire.Bind(new(Driver), new(local.Scanner)),
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
var ClientSet = wire.NewSet(
|
||||
rpcOSDetector.SuperSet,
|
||||
ospkgScanner.NewScanner,
|
||||
rpcLibDetector.SuperSet,
|
||||
libScanner.NewScanner,
|
||||
var StandaloneDockerSet = wire.NewSet(
|
||||
types.GetDockerOption,
|
||||
docker.NewDockerExtractor,
|
||||
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
|
||||
StandaloneSuperSet,
|
||||
)
|
||||
|
||||
var StandaloneArchiveSet = wire.NewSet(
|
||||
types.GetDockerOption,
|
||||
docker.NewDockerArchiveExtractor,
|
||||
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
|
||||
StandaloneSuperSet,
|
||||
)
|
||||
|
||||
// RemoteSuperSet is used in the client mode
|
||||
var RemoteSuperSet = wire.NewSet(
|
||||
analyzer.New,
|
||||
wire.Bind(new(Analyzer), new(analyzer.Config)),
|
||||
client.SuperSet,
|
||||
wire.Bind(new(Driver), new(client.Scanner)),
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
var RemoteDockerSet = wire.NewSet(
|
||||
types.GetDockerOption,
|
||||
docker.NewDockerExtractor,
|
||||
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
|
||||
RemoteSuperSet,
|
||||
)
|
||||
|
||||
var RemoteArchiveSet = wire.NewSet(
|
||||
types.GetDockerOption,
|
||||
docker.NewDockerArchiveExtractor,
|
||||
wire.Bind(new(extractor.Extractor), new(docker.Extractor)),
|
||||
RemoteSuperSet,
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
cacheClient cache.Cache
|
||||
ospkgScanner ospkg.Scanner
|
||||
libScanner library.Scanner
|
||||
driver Driver
|
||||
analyzer Analyzer
|
||||
}
|
||||
|
||||
func NewScanner(cacheClient cache.Cache, ospkgScanner ospkg.Scanner, libScanner library.Scanner) Scanner {
|
||||
return Scanner{cacheClient: cacheClient, ospkgScanner: ospkgScanner, libScanner: libScanner}
|
||||
type Driver interface {
|
||||
Scan(target string, imageID digest.Digest, layerIDs []string, options types.ScanOptions) (results report.Results, osFound *ftypes.OS, eols bool, err error)
|
||||
}
|
||||
|
||||
func (s Scanner) ScanImage(imageName, filePath string, scanOptions types.ScanOptions, dockerOption ftypes.DockerOption) (report.Results, error) {
|
||||
results := report.Results{}
|
||||
type Analyzer interface {
|
||||
Analyze(ctx context.Context) (info ftypes.ImageReference, err error)
|
||||
}
|
||||
|
||||
func NewScanner(driver Driver, ac Analyzer) Scanner {
|
||||
return Scanner{driver: driver, analyzer: ac}
|
||||
}
|
||||
|
||||
func (s Scanner) ScanImage(options types.ScanOptions) (report.Results, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
var target string
|
||||
var files extractor.FileMap
|
||||
var ac analyzer.Config
|
||||
|
||||
ext, err := docker.NewDockerExtractor(dockerOption, s.cacheClient)
|
||||
imageInfo, err := s.analyzer.Analyze(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ac = analyzer.Config{Extractor: ext}
|
||||
|
||||
if imageName != "" {
|
||||
target = imageName
|
||||
files, err = ac.Analyze(ctx, imageName, dockerOption)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to analyze image: %w", err)
|
||||
}
|
||||
} else if filePath != "" {
|
||||
target = filePath
|
||||
rc, err := openStream(filePath)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to open stream: %w", err)
|
||||
}
|
||||
|
||||
files, err = ac.AnalyzeFile(ctx, rc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, xerrors.New("image name or image file must be specified")
|
||||
return nil, xerrors.Errorf("failed analysis: %w", err)
|
||||
}
|
||||
|
||||
created, err := getCreated(files["/config"])
|
||||
log.Logger.Debugf("Image ID: %s", imageInfo.ID)
|
||||
log.Logger.Debugf("Layer IDs: %v", imageInfo.LayerIDs)
|
||||
|
||||
results, osFound, eosl, err := s.driver.Scan(imageInfo.Name, imageInfo.ID, imageInfo.LayerIDs, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, xerrors.Errorf("scan failed: %w", err)
|
||||
}
|
||||
|
||||
if utils.StringInSlice("os", scanOptions.VulnType) {
|
||||
osFamily, osVersion, osVulns, err := s.ospkgScanner.Scan(target, created, files)
|
||||
if err != nil && err != ospkgDetector.ErrUnsupportedOS {
|
||||
return nil, xerrors.Errorf("failed to scan the image: %w", err)
|
||||
}
|
||||
if osFamily != "" {
|
||||
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
|
||||
results = append(results, report.Result{
|
||||
Target: imageDetail,
|
||||
Vulnerabilities: osVulns,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if utils.StringInSlice("library", scanOptions.VulnType) {
|
||||
libVulns, err := s.libScanner.Scan(target, created, files)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to scan libraries: %w", err)
|
||||
}
|
||||
|
||||
var libResults report.Results
|
||||
for path, vulns := range libVulns {
|
||||
libResults = append(libResults, report.Result{
|
||||
Target: path,
|
||||
Vulnerabilities: vulns,
|
||||
})
|
||||
}
|
||||
sort.Slice(libResults, func(i, j int) bool {
|
||||
return libResults[i].Target < libResults[j].Target
|
||||
})
|
||||
results = append(results, libResults...)
|
||||
if eosl {
|
||||
log.Logger.Warnf("This OS version is no longer supported by the distribution: %s %s", osFound.Family, osFound.Name)
|
||||
log.Logger.Warnf("The vulnerability detection may be insufficient because security updates are not provided")
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Created time.Time
|
||||
}
|
||||
|
||||
func getCreated(configBlob []byte) (time.Time, error) {
|
||||
var config config
|
||||
if err := json.Unmarshal(configBlob, &config); err != nil {
|
||||
return time.Time{}, xerrors.Errorf("invalid config JSON: %w", err)
|
||||
}
|
||||
return config.Created, nil
|
||||
}
|
||||
|
||||
func openStream(path string) (*os.File, error) {
|
||||
if path == "-" {
|
||||
if terminal.IsTerminal(0) {
|
||||
flag.Usage()
|
||||
os.Exit(64)
|
||||
} else {
|
||||
return os.Stdin, nil
|
||||
}
|
||||
}
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
161
pkg/scanner/scan_test.go
Normal file
161
pkg/scanner/scan_test.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
log.InitLogger(false, false)
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func TestScanner_ScanImage(t *testing.T) {
|
||||
type args struct {
|
||||
options types.ScanOptions
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
analyzeExpectation AnalyzerAnalyzeExpectation
|
||||
scanExpectation ScanExpectation
|
||||
want report.Results
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
args: args{
|
||||
options: types.ScanOptions{VulnType: []string{"os"}},
|
||||
},
|
||||
analyzeExpectation: AnalyzerAnalyzeExpectation{
|
||||
Args: AnalyzerAnalyzeArgs{
|
||||
CtxAnything: true,
|
||||
},
|
||||
Returns: AnalyzerAnalyzeReturns{
|
||||
Info: ftypes.ImageReference{
|
||||
Name: "alpine:3.11",
|
||||
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
},
|
||||
},
|
||||
scanExpectation: ScanExpectation{
|
||||
Args: ScanArgs{
|
||||
Target: "alpine:3.11",
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
Options: types.ScanOptions{VulnType: []string{"os"}},
|
||||
},
|
||||
Returns: ScanReturns{
|
||||
Results: report.Results{
|
||||
{
|
||||
Target: "alpine:3.11",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-9999",
|
||||
PkgName: "vim",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
OsFound: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.10",
|
||||
},
|
||||
Eols: true,
|
||||
},
|
||||
},
|
||||
want: report.Results{
|
||||
{
|
||||
Target: "alpine:3.11",
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-9999",
|
||||
PkgName: "vim",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad path: AnalyzerAnalyze returns an error",
|
||||
args: args{
|
||||
options: types.ScanOptions{VulnType: []string{"os"}},
|
||||
},
|
||||
analyzeExpectation: AnalyzerAnalyzeExpectation{
|
||||
Args: AnalyzerAnalyzeArgs{
|
||||
CtxAnything: true,
|
||||
},
|
||||
Returns: AnalyzerAnalyzeReturns{
|
||||
Err: errors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "failed analysis",
|
||||
},
|
||||
{
|
||||
name: "sad path: Scan returns an error",
|
||||
args: args{
|
||||
options: types.ScanOptions{VulnType: []string{"os"}},
|
||||
},
|
||||
analyzeExpectation: AnalyzerAnalyzeExpectation{
|
||||
Args: AnalyzerAnalyzeArgs{
|
||||
CtxAnything: true,
|
||||
},
|
||||
Returns: AnalyzerAnalyzeReturns{
|
||||
Info: ftypes.ImageReference{
|
||||
Name: "alpine:3.11",
|
||||
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
},
|
||||
},
|
||||
scanExpectation: ScanExpectation{
|
||||
Args: ScanArgs{
|
||||
Target: "alpine:3.11",
|
||||
ImageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
|
||||
LayerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
Options: types.ScanOptions{VulnType: []string{"os"}},
|
||||
},
|
||||
Returns: ScanReturns{
|
||||
Err: errors.New("error"),
|
||||
},
|
||||
},
|
||||
wantErr: "scan failed",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := new(MockDriver)
|
||||
d.ApplyScanExpectation(tt.scanExpectation)
|
||||
|
||||
analyzer := new(MockAnalyzer)
|
||||
analyzer.ApplyAnalyzeExpectation(tt.analyzeExpectation)
|
||||
|
||||
s := NewScanner(d, analyzer)
|
||||
got, err := s.ScanImage(tt.args.options)
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err, tt.name)
|
||||
require.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err, tt.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
|
||||
"github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/knqyf263/go-version"
|
||||
)
|
||||
@@ -28,11 +27,11 @@ func MatchVersions(currentVersion *version.Version, rangeVersions []string) bool
|
||||
return false
|
||||
}
|
||||
|
||||
func FormatVersion(pkg analyzer.Package) string {
|
||||
func FormatVersion(pkg types.Package) string {
|
||||
return formatVersion(pkg.Epoch, pkg.Version, pkg.Release)
|
||||
}
|
||||
|
||||
func FormatSrcVersion(pkg analyzer.Package) string {
|
||||
func FormatSrcVersion(pkg types.Package) string {
|
||||
return formatVersion(pkg.SrcEpoch, pkg.SrcVersion, pkg.SrcRelease)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/types"
|
||||
"github.com/caarlos0/env/v6"
|
||||
)
|
||||
|
||||
type DockerConfig struct {
|
||||
AuthURL string `env:"TRIVY_AUTH_URL"`
|
||||
UserName string `env:"TRIVY_USERNAME"`
|
||||
Password string `env:"TRIVY_PASSWORD"`
|
||||
Timeout time.Duration `env:"TRIVY_TIMEOUT_SEC" envDefault:"60s"`
|
||||
Insecure bool `env:"TRIVY_INSECURE" envDefault:"true"`
|
||||
NonSSL bool `env:"TRIVY_NON_SSL" envDefault:"false"`
|
||||
}
|
||||
|
||||
func GetDockerOption() (types.DockerOption, error) {
|
||||
cfg := DockerConfig{}
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
return types.DockerOption{}, err
|
||||
}
|
||||
return types.DockerOption{
|
||||
AuthURL: cfg.AuthURL,
|
||||
UserName: cfg.UserName,
|
||||
Password: cfg.Password,
|
||||
Timeout: cfg.Timeout,
|
||||
Insecure: cfg.Insecure,
|
||||
NonSSL: cfg.NonSSL,
|
||||
}, nil
|
||||
}
|
||||
33
pkg/types/docker_conf.go
Normal file
33
pkg/types/docker_conf.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/fanal/types"
|
||||
"github.com/caarlos0/env/v6"
|
||||
)
|
||||
|
||||
type DockerConfig struct {
|
||||
UserName string `env:"TRIVY_USERNAME"`
|
||||
Password string `env:"TRIVY_PASSWORD"`
|
||||
Insecure bool `env:"TRIVY_INSECURE" envDefault:"true"`
|
||||
|
||||
DockerCertPath string `env:"DOCKER_CERT_PATH"`
|
||||
DockerHost string `env:"DOCKER_HOST"`
|
||||
}
|
||||
|
||||
func GetDockerOption(timeout time.Duration) (types.DockerOption, error) {
|
||||
cfg := DockerConfig{}
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
return types.DockerOption{}, err
|
||||
}
|
||||
|
||||
return types.DockerOption{
|
||||
UserName: cfg.UserName,
|
||||
Password: cfg.Password,
|
||||
Timeout: timeout,
|
||||
InsecureSkipTLSVerify: cfg.Insecure,
|
||||
DockerDaemonCertPath: cfg.DockerCertPath,
|
||||
DockerDaemonHost: cfg.DockerHost,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package types
|
||||
|
||||
type ScanOptions struct {
|
||||
VulnType []string
|
||||
|
||||
// for client/server
|
||||
RemoteURL string
|
||||
Token string
|
||||
VulnType []string
|
||||
ScanRemovedPackages bool
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -71,25 +69,6 @@ func FileWalk(root string, targetFiles map[string]struct{}, walkFn func(r io.Rea
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsCommandAvailable(name string) bool {
|
||||
cmd := exec.Command(name, "--help")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Exists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
func StringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
@@ -99,18 +78,6 @@ func StringInSlice(a string, list []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func Exec(command string, args []string) (string, error) {
|
||||
cmd := exec.Command(command, args...)
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
cmd.Stdout = &stdoutBuf
|
||||
cmd.Stderr = &stderrBuf
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Logger.Debug(stderrBuf.String())
|
||||
return "", xerrors.Errorf("failed to exec: %w", err)
|
||||
}
|
||||
return stdoutBuf.String(), nil
|
||||
}
|
||||
|
||||
func FilterTargets(prefixPath string, targets map[string]struct{}) (map[string]struct{}, error) {
|
||||
filtered := map[string]struct{}{}
|
||||
for filename := range targets {
|
||||
|
||||
116
pkg/vulnerability/mock_operation.go
Normal file
116
pkg/vulnerability/mock_operation.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
|
||||
package vulnerability
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import pkgtypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
import types "github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
// MockOperation is an autogenerated mock type for the Operation type
|
||||
type MockOperation struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type FillInfoArgs struct {
|
||||
Vulns []types.DetectedVulnerability
|
||||
VulnsAnything bool
|
||||
Light bool
|
||||
LightAnything bool
|
||||
}
|
||||
|
||||
type FillInfoExpectation struct {
|
||||
Args FillInfoArgs
|
||||
}
|
||||
|
||||
func (_m *MockOperation) ApplyFillInfoExpectation(e FillInfoExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.VulnsAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Vulns)
|
||||
}
|
||||
if e.Args.LightAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Light)
|
||||
}
|
||||
_m.On("FillInfo", args...)
|
||||
}
|
||||
|
||||
func (_m *MockOperation) ApplyFillInfoExpectations(expectations []FillInfoExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyFillInfoExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// FillInfo provides a mock function with given fields: vulns, light
|
||||
func (_m *MockOperation) FillInfo(vulns []types.DetectedVulnerability, light bool) {
|
||||
_m.Called(vulns, light)
|
||||
}
|
||||
|
||||
type FilterArgs struct {
|
||||
Vulns []types.DetectedVulnerability
|
||||
VulnsAnything bool
|
||||
Severities []pkgtypes.Severity
|
||||
SeveritiesAnything bool
|
||||
IgnoreUnfixed bool
|
||||
IgnoreUnfixedAnything bool
|
||||
IgnoreFile string
|
||||
IgnoreFileAnything bool
|
||||
}
|
||||
|
||||
type FilterReturns struct {
|
||||
_a0 []types.DetectedVulnerability
|
||||
}
|
||||
|
||||
type FilterExpectation struct {
|
||||
Args FilterArgs
|
||||
Returns FilterReturns
|
||||
}
|
||||
|
||||
func (_m *MockOperation) ApplyFilterExpectation(e FilterExpectation) {
|
||||
var args []interface{}
|
||||
if e.Args.VulnsAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Vulns)
|
||||
}
|
||||
if e.Args.SeveritiesAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.Severities)
|
||||
}
|
||||
if e.Args.IgnoreUnfixedAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.IgnoreUnfixed)
|
||||
}
|
||||
if e.Args.IgnoreFileAnything {
|
||||
args = append(args, mock.Anything)
|
||||
} else {
|
||||
args = append(args, e.Args.IgnoreFile)
|
||||
}
|
||||
_m.On("Filter", args...).Return(e.Returns._a0)
|
||||
}
|
||||
|
||||
func (_m *MockOperation) ApplyFilterExpectations(expectations []FilterExpectation) {
|
||||
for _, e := range expectations {
|
||||
_m.ApplyFilterExpectation(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter provides a mock function with given fields: vulns, severities, ignoreUnfixed, ignoreFile
|
||||
func (_m *MockOperation) Filter(vulns []types.DetectedVulnerability, severities []pkgtypes.Severity, ignoreUnfixed bool, ignoreFile string) []types.DetectedVulnerability {
|
||||
ret := _m.Called(vulns, severities, ignoreUnfixed, ignoreFile)
|
||||
|
||||
var r0 []types.DetectedVulnerability
|
||||
if rf, ok := ret.Get(0).(func([]types.DetectedVulnerability, []pkgtypes.Severity, bool, string) []types.DetectedVulnerability); ok {
|
||||
r0 = rf(vulns, severities, ignoreUnfixed, ignoreFile)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]types.DetectedVulnerability)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package vulnerability
|
||||
|
||||
import (
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
type MockVulnClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func NewMockVulnClient() *MockVulnClient {
|
||||
mockVulnClient := new(MockVulnClient)
|
||||
mockVulnClient.On("FillInfo", mock.Anything, mock.Anything)
|
||||
return mockVulnClient
|
||||
}
|
||||
|
||||
func (_m *MockVulnClient) FillInfo(a []types.DetectedVulnerability, b bool) {
|
||||
_m.Called(a, b)
|
||||
}
|
||||
|
||||
func (_m *MockVulnClient) Filter(a []types.DetectedVulnerability, b []dbTypes.Severity,
|
||||
c bool, d string) []types.DetectedVulnerability {
|
||||
ret := _m.Called(a, b, c, d)
|
||||
ret0 := ret.Get(0)
|
||||
if ret0 == nil {
|
||||
return nil
|
||||
}
|
||||
vulns, ok := ret0.([]types.DetectedVulnerability)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return vulns
|
||||
}
|
||||
484
rpc/cache/service.pb.go
vendored
Normal file
484
rpc/cache/service.pb.go
vendored
Normal file
@@ -0,0 +1,484 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: rpc/cache/service.proto
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
common "github.com/aquasecurity/trivy/rpc/common"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
_ "github.com/golang/protobuf/ptypes/empty"
|
||||
timestamp "github.com/golang/protobuf/ptypes/timestamp"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type ImageInfo struct {
|
||||
SchemaVersion int32 `protobuf:"varint,1,opt,name=schema_version,json=schemaVersion,proto3" json:"schema_version,omitempty"`
|
||||
Architecture string `protobuf:"bytes,2,opt,name=architecture,proto3" json:"architecture,omitempty"`
|
||||
Created *timestamp.Timestamp `protobuf:"bytes,3,opt,name=created,proto3" json:"created,omitempty"`
|
||||
DockerVersion string `protobuf:"bytes,4,opt,name=docker_version,json=dockerVersion,proto3" json:"docker_version,omitempty"`
|
||||
Os string `protobuf:"bytes,5,opt,name=os,proto3" json:"os,omitempty"`
|
||||
HistoryPackages []*common.Package `protobuf:"bytes,6,rep,name=history_packages,json=historyPackages,proto3" json:"history_packages,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ImageInfo) Reset() { *m = ImageInfo{} }
|
||||
func (m *ImageInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*ImageInfo) ProtoMessage() {}
|
||||
func (*ImageInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_1f1f7d564abadf42, []int{0}
|
||||
}
|
||||
|
||||
func (m *ImageInfo) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ImageInfo.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ImageInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ImageInfo.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ImageInfo) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ImageInfo.Merge(m, src)
|
||||
}
|
||||
func (m *ImageInfo) XXX_Size() int {
|
||||
return xxx_messageInfo_ImageInfo.Size(m)
|
||||
}
|
||||
func (m *ImageInfo) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ImageInfo.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ImageInfo proto.InternalMessageInfo
|
||||
|
||||
func (m *ImageInfo) GetSchemaVersion() int32 {
|
||||
if m != nil {
|
||||
return m.SchemaVersion
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ImageInfo) GetArchitecture() string {
|
||||
if m != nil {
|
||||
return m.Architecture
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ImageInfo) GetCreated() *timestamp.Timestamp {
|
||||
if m != nil {
|
||||
return m.Created
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ImageInfo) GetDockerVersion() string {
|
||||
if m != nil {
|
||||
return m.DockerVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ImageInfo) GetOs() string {
|
||||
if m != nil {
|
||||
return m.Os
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ImageInfo) GetHistoryPackages() []*common.Package {
|
||||
if m != nil {
|
||||
return m.HistoryPackages
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PutImageRequest struct {
|
||||
ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"`
|
||||
ImageInfo *ImageInfo `protobuf:"bytes,2,opt,name=image_info,json=imageInfo,proto3" json:"image_info,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PutImageRequest) Reset() { *m = PutImageRequest{} }
|
||||
func (m *PutImageRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*PutImageRequest) ProtoMessage() {}
|
||||
func (*PutImageRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_1f1f7d564abadf42, []int{1}
|
||||
}
|
||||
|
||||
func (m *PutImageRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PutImageRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *PutImageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_PutImageRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *PutImageRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PutImageRequest.Merge(m, src)
|
||||
}
|
||||
func (m *PutImageRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_PutImageRequest.Size(m)
|
||||
}
|
||||
func (m *PutImageRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PutImageRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PutImageRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *PutImageRequest) GetImageId() string {
|
||||
if m != nil {
|
||||
return m.ImageId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PutImageRequest) GetImageInfo() *ImageInfo {
|
||||
if m != nil {
|
||||
return m.ImageInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type LayerInfo struct {
|
||||
SchemaVersion int32 `protobuf:"varint,1,opt,name=schema_version,json=schemaVersion,proto3" json:"schema_version,omitempty"`
|
||||
Os *common.OS `protobuf:"bytes,2,opt,name=os,proto3" json:"os,omitempty"`
|
||||
PackageInfos []*common.PackageInfo `protobuf:"bytes,3,rep,name=package_infos,json=packageInfos,proto3" json:"package_infos,omitempty"`
|
||||
Applications []*common.Application `protobuf:"bytes,4,rep,name=applications,proto3" json:"applications,omitempty"`
|
||||
OpaqueDirs []string `protobuf:"bytes,5,rep,name=opaque_dirs,json=opaqueDirs,proto3" json:"opaque_dirs,omitempty"`
|
||||
WhiteoutFiles []string `protobuf:"bytes,6,rep,name=whiteout_files,json=whiteoutFiles,proto3" json:"whiteout_files,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *LayerInfo) Reset() { *m = LayerInfo{} }
|
||||
func (m *LayerInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*LayerInfo) ProtoMessage() {}
|
||||
func (*LayerInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_1f1f7d564abadf42, []int{2}
|
||||
}
|
||||
|
||||
func (m *LayerInfo) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_LayerInfo.Unmarshal(m, b)
|
||||
}
|
||||
func (m *LayerInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_LayerInfo.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *LayerInfo) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_LayerInfo.Merge(m, src)
|
||||
}
|
||||
func (m *LayerInfo) XXX_Size() int {
|
||||
return xxx_messageInfo_LayerInfo.Size(m)
|
||||
}
|
||||
func (m *LayerInfo) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_LayerInfo.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_LayerInfo proto.InternalMessageInfo
|
||||
|
||||
func (m *LayerInfo) GetSchemaVersion() int32 {
|
||||
if m != nil {
|
||||
return m.SchemaVersion
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *LayerInfo) GetOs() *common.OS {
|
||||
if m != nil {
|
||||
return m.Os
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LayerInfo) GetPackageInfos() []*common.PackageInfo {
|
||||
if m != nil {
|
||||
return m.PackageInfos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LayerInfo) GetApplications() []*common.Application {
|
||||
if m != nil {
|
||||
return m.Applications
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LayerInfo) GetOpaqueDirs() []string {
|
||||
if m != nil {
|
||||
return m.OpaqueDirs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LayerInfo) GetWhiteoutFiles() []string {
|
||||
if m != nil {
|
||||
return m.WhiteoutFiles
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PutLayerRequest struct {
|
||||
LayerId string `protobuf:"bytes,1,opt,name=layer_id,json=layerId,proto3" json:"layer_id,omitempty"`
|
||||
DecompressedLayerId string `protobuf:"bytes,2,opt,name=decompressed_layer_id,json=decompressedLayerId,proto3" json:"decompressed_layer_id,omitempty"`
|
||||
LayerInfo *LayerInfo `protobuf:"bytes,3,opt,name=layer_info,json=layerInfo,proto3" json:"layer_info,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PutLayerRequest) Reset() { *m = PutLayerRequest{} }
|
||||
func (m *PutLayerRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*PutLayerRequest) ProtoMessage() {}
|
||||
func (*PutLayerRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_1f1f7d564abadf42, []int{3}
|
||||
}
|
||||
|
||||
func (m *PutLayerRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PutLayerRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *PutLayerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_PutLayerRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *PutLayerRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PutLayerRequest.Merge(m, src)
|
||||
}
|
||||
func (m *PutLayerRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_PutLayerRequest.Size(m)
|
||||
}
|
||||
func (m *PutLayerRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PutLayerRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PutLayerRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *PutLayerRequest) GetLayerId() string {
|
||||
if m != nil {
|
||||
return m.LayerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PutLayerRequest) GetDecompressedLayerId() string {
|
||||
if m != nil {
|
||||
return m.DecompressedLayerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PutLayerRequest) GetLayerInfo() *LayerInfo {
|
||||
if m != nil {
|
||||
return m.LayerInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PutResponse struct {
|
||||
Os *common.OS `protobuf:"bytes,1,opt,name=os,proto3" json:"os,omitempty"`
|
||||
Eosl bool `protobuf:"varint,2,opt,name=eosl,proto3" json:"eosl,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PutResponse) Reset() { *m = PutResponse{} }
|
||||
func (m *PutResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*PutResponse) ProtoMessage() {}
|
||||
func (*PutResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_1f1f7d564abadf42, []int{4}
|
||||
}
|
||||
|
||||
func (m *PutResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PutResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *PutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_PutResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *PutResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PutResponse.Merge(m, src)
|
||||
}
|
||||
func (m *PutResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_PutResponse.Size(m)
|
||||
}
|
||||
func (m *PutResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PutResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PutResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *PutResponse) GetOs() *common.OS {
|
||||
if m != nil {
|
||||
return m.Os
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PutResponse) GetEosl() bool {
|
||||
if m != nil {
|
||||
return m.Eosl
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type MissingLayersRequest struct {
|
||||
ImageId string `protobuf:"bytes,1,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"`
|
||||
LayerIds []string `protobuf:"bytes,2,rep,name=layer_ids,json=layerIds,proto3" json:"layer_ids,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *MissingLayersRequest) Reset() { *m = MissingLayersRequest{} }
|
||||
func (m *MissingLayersRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*MissingLayersRequest) ProtoMessage() {}
|
||||
func (*MissingLayersRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_1f1f7d564abadf42, []int{5}
|
||||
}
|
||||
|
||||
func (m *MissingLayersRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_MissingLayersRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *MissingLayersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_MissingLayersRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *MissingLayersRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MissingLayersRequest.Merge(m, src)
|
||||
}
|
||||
func (m *MissingLayersRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_MissingLayersRequest.Size(m)
|
||||
}
|
||||
func (m *MissingLayersRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MissingLayersRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MissingLayersRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *MissingLayersRequest) GetImageId() string {
|
||||
if m != nil {
|
||||
return m.ImageId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *MissingLayersRequest) GetLayerIds() []string {
|
||||
if m != nil {
|
||||
return m.LayerIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type MissingLayersResponse struct {
|
||||
MissingImage bool `protobuf:"varint,1,opt,name=missing_image,json=missingImage,proto3" json:"missing_image,omitempty"`
|
||||
MissingLayerIds []string `protobuf:"bytes,2,rep,name=missing_layer_ids,json=missingLayerIds,proto3" json:"missing_layer_ids,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *MissingLayersResponse) Reset() { *m = MissingLayersResponse{} }
|
||||
func (m *MissingLayersResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*MissingLayersResponse) ProtoMessage() {}
|
||||
func (*MissingLayersResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_1f1f7d564abadf42, []int{6}
|
||||
}
|
||||
|
||||
func (m *MissingLayersResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_MissingLayersResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *MissingLayersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_MissingLayersResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *MissingLayersResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MissingLayersResponse.Merge(m, src)
|
||||
}
|
||||
func (m *MissingLayersResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_MissingLayersResponse.Size(m)
|
||||
}
|
||||
func (m *MissingLayersResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MissingLayersResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MissingLayersResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *MissingLayersResponse) GetMissingImage() bool {
|
||||
if m != nil {
|
||||
return m.MissingImage
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *MissingLayersResponse) GetMissingLayerIds() []string {
|
||||
if m != nil {
|
||||
return m.MissingLayerIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*ImageInfo)(nil), "trivy.cache.v1.ImageInfo")
|
||||
proto.RegisterType((*PutImageRequest)(nil), "trivy.cache.v1.PutImageRequest")
|
||||
proto.RegisterType((*LayerInfo)(nil), "trivy.cache.v1.LayerInfo")
|
||||
proto.RegisterType((*PutLayerRequest)(nil), "trivy.cache.v1.PutLayerRequest")
|
||||
proto.RegisterType((*PutResponse)(nil), "trivy.cache.v1.PutResponse")
|
||||
proto.RegisterType((*MissingLayersRequest)(nil), "trivy.cache.v1.MissingLayersRequest")
|
||||
proto.RegisterType((*MissingLayersResponse)(nil), "trivy.cache.v1.MissingLayersResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("rpc/cache/service.proto", fileDescriptor_1f1f7d564abadf42) }
|
||||
|
||||
var fileDescriptor_1f1f7d564abadf42 = []byte{
|
||||
// 676 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xdd, 0x6e, 0xd3, 0x4a,
|
||||
0x10, 0x56, 0x92, 0xa6, 0x8d, 0x27, 0x49, 0xdb, 0xb3, 0xe7, 0xf4, 0x90, 0xa6, 0x17, 0x8d, 0x0c,
|
||||
0x95, 0x22, 0x2e, 0x6c, 0x11, 0x10, 0xea, 0x0d, 0x08, 0x28, 0x20, 0x45, 0x2a, 0x50, 0x2d, 0x88,
|
||||
0x0b, 0x84, 0x64, 0x6d, 0xd7, 0x9b, 0x64, 0xd5, 0xd8, 0xeb, 0xee, 0xae, 0x83, 0xf2, 0x00, 0xbc,
|
||||
0x04, 0x3c, 0x24, 0xaf, 0x80, 0x3c, 0xb6, 0xd3, 0x24, 0x84, 0xbf, 0x3b, 0xcf, 0x8f, 0xbf, 0x99,
|
||||
0xef, 0xfb, 0xc6, 0x86, 0x5b, 0x3a, 0xe1, 0x3e, 0x67, 0x7c, 0x22, 0x7c, 0x23, 0xf4, 0x4c, 0x72,
|
||||
0xe1, 0x25, 0x5a, 0x59, 0x45, 0x76, 0xad, 0x96, 0xb3, 0xb9, 0x87, 0x25, 0x6f, 0x76, 0xaf, 0x7b,
|
||||
0x3c, 0x56, 0x6a, 0x3c, 0x15, 0x3e, 0x56, 0x2f, 0xd3, 0x91, 0x6f, 0x65, 0x24, 0x8c, 0x65, 0x51,
|
||||
0x92, 0xbf, 0xd0, 0x7d, 0x38, 0x96, 0x76, 0x92, 0x5e, 0x7a, 0x5c, 0x45, 0x3e, 0xbb, 0x4e, 0x99,
|
||||
0x11, 0x3c, 0xd5, 0xd2, 0xce, 0x7d, 0x04, 0xf2, 0x71, 0x8e, 0x8a, 0x22, 0x15, 0xaf, 0x0e, 0xea,
|
||||
0x1e, 0xad, 0x03, 0x8b, 0x28, 0xb1, 0xf3, 0xbc, 0xe8, 0x7e, 0xae, 0x82, 0x33, 0x8c, 0xd8, 0x58,
|
||||
0x0c, 0xe3, 0x91, 0x22, 0x27, 0xb0, 0x6b, 0xf8, 0x44, 0x44, 0x2c, 0x98, 0x09, 0x6d, 0xa4, 0x8a,
|
||||
0x3b, 0x95, 0x5e, 0xa5, 0x5f, 0xa7, 0xed, 0x3c, 0xfb, 0x3e, 0x4f, 0x12, 0x17, 0x5a, 0x4c, 0xf3,
|
||||
0x89, 0xb4, 0x82, 0xdb, 0x54, 0x8b, 0x4e, 0xb5, 0x57, 0xe9, 0x3b, 0x74, 0x25, 0x47, 0x1e, 0xc0,
|
||||
0x0e, 0xd7, 0x82, 0x59, 0x11, 0x76, 0x6a, 0xbd, 0x4a, 0xbf, 0x39, 0xe8, 0x7a, 0xf9, 0x1e, 0x5e,
|
||||
0xb9, 0x87, 0xf7, 0xae, 0x24, 0x48, 0xcb, 0xd6, 0x6c, 0x81, 0x50, 0xf1, 0x2b, 0xa1, 0x17, 0x0b,
|
||||
0x6c, 0x21, 0x76, 0x3b, 0xcf, 0x96, 0x0b, 0xec, 0x42, 0x55, 0x99, 0x4e, 0x1d, 0x4b, 0x55, 0x65,
|
||||
0xc8, 0x13, 0xd8, 0x9f, 0x48, 0x63, 0x95, 0x9e, 0x07, 0x09, 0xe3, 0x57, 0x6c, 0x2c, 0x4c, 0x67,
|
||||
0xbb, 0x57, 0xeb, 0x37, 0x07, 0x07, 0x5e, 0x21, 0x33, 0x2a, 0xe3, 0x5d, 0xe4, 0x55, 0xba, 0x57,
|
||||
0xb4, 0x17, 0xb1, 0x71, 0x47, 0xb0, 0x77, 0x91, 0x5a, 0x54, 0x82, 0x8a, 0xeb, 0x54, 0x18, 0x4b,
|
||||
0x0e, 0xa1, 0x21, 0xb3, 0x38, 0x90, 0x21, 0xca, 0xe0, 0xd0, 0x1d, 0x8c, 0x87, 0x21, 0x39, 0x05,
|
||||
0x28, 0x4a, 0xf1, 0x48, 0x21, 0xfd, 0xe6, 0xe0, 0xd0, 0x5b, 0x35, 0xd4, 0x5b, 0xc8, 0x4a, 0x1d,
|
||||
0x59, 0x3e, 0xba, 0x5f, 0xab, 0xe0, 0x9c, 0xb3, 0xb9, 0xd0, 0x7f, 0xa3, 0x77, 0x0f, 0xe9, 0xe6,
|
||||
0x63, 0xf6, 0x57, 0x09, 0xbd, 0x79, 0x8b, 0x02, 0x3c, 0x86, 0x76, 0x41, 0x1c, 0x57, 0x32, 0x9d,
|
||||
0x1a, 0xb2, 0x3f, 0xdc, 0xc8, 0x1e, 0x77, 0x6a, 0x25, 0x37, 0x81, 0x21, 0x8f, 0xa0, 0xc5, 0x92,
|
||||
0x64, 0x2a, 0x39, 0xb3, 0x52, 0xc5, 0xa6, 0xb3, 0xb5, 0xe9, 0xf5, 0xa7, 0x37, 0x1d, 0x74, 0xa5,
|
||||
0x9d, 0x1c, 0x43, 0x53, 0x25, 0xec, 0x3a, 0x15, 0x41, 0x28, 0x75, 0x66, 0x4c, 0xad, 0xef, 0x50,
|
||||
0xc8, 0x53, 0xcf, 0xa5, 0x36, 0x19, 0xd1, 0x4f, 0xd9, 0x6d, 0xa8, 0xd4, 0x06, 0x23, 0x39, 0x2d,
|
||||
0xec, 0x71, 0x68, 0xbb, 0xcc, 0xbe, 0xcc, 0x92, 0xee, 0x97, 0x0a, 0xda, 0x80, 0x02, 0x2d, 0xd9,
|
||||
0x30, 0xcd, 0xe2, 0x25, 0x1b, 0x30, 0x1e, 0x86, 0x64, 0x00, 0x07, 0xa1, 0xe0, 0x2a, 0x4a, 0xb4,
|
||||
0x30, 0x46, 0x84, 0xc1, 0xa2, 0x2f, 0x3f, 0xc8, 0x7f, 0x97, 0x8b, 0xe7, 0xc5, 0x3b, 0xa7, 0x00,
|
||||
0x45, 0x5b, 0x66, 0x5d, 0x6d, 0xb3, 0x75, 0x0b, 0x87, 0xa8, 0x33, 0x2d, 0x1f, 0xdd, 0x33, 0x68,
|
||||
0x5e, 0xa4, 0x96, 0x0a, 0x93, 0xa8, 0xd8, 0x88, 0xc2, 0x94, 0xca, 0x2f, 0x4c, 0x21, 0xb0, 0x25,
|
||||
0x94, 0x99, 0xe2, 0x36, 0x0d, 0x8a, 0xcf, 0xee, 0x6b, 0xf8, 0xef, 0x95, 0x34, 0x46, 0xc6, 0x63,
|
||||
0x9c, 0x61, 0xfe, 0xe0, 0xd8, 0x8e, 0xc0, 0x29, 0x89, 0x65, 0x47, 0x90, 0xc9, 0xd6, 0x28, 0x14,
|
||||
0x30, 0xee, 0x04, 0x0e, 0xd6, 0xf0, 0x8a, 0xf5, 0x6e, 0x43, 0x3b, 0xca, 0x0b, 0x01, 0x02, 0x21,
|
||||
0x6a, 0x83, 0xb6, 0x8a, 0x24, 0x1e, 0x27, 0xb9, 0x0b, 0xff, 0x94, 0x4d, 0xeb, 0x23, 0xf6, 0xa2,
|
||||
0x25, 0xd8, 0x61, 0x68, 0x06, 0xdf, 0x2a, 0x50, 0x3f, 0xcb, 0x04, 0x22, 0x67, 0xd0, 0x28, 0xbf,
|
||||
0x15, 0x72, 0xbc, 0x2e, 0xdd, 0xda, 0x57, 0xd4, 0xfd, 0xff, 0x87, 0xcf, 0xfe, 0x45, 0xf6, 0xfb,
|
||||
0x29, 0x40, 0x10, 0x7d, 0x23, 0xc8, 0xf2, 0x0d, 0xfc, 0x14, 0xe4, 0x23, 0xb4, 0x57, 0xd8, 0x93,
|
||||
0x3b, 0xeb, 0x48, 0x9b, 0xc4, 0xee, 0x9e, 0xfc, 0xa6, 0x2b, 0x97, 0xf0, 0xd9, 0xce, 0x87, 0x3a,
|
||||
0x76, 0x5c, 0x6e, 0xe3, 0xd8, 0xfb, 0xdf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x84, 0x32, 0x2e,
|
||||
0xcc, 0x05, 0x00, 0x00,
|
||||
}
|
||||
58
rpc/cache/service.proto
vendored
Normal file
58
rpc/cache/service.proto
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package trivy.cache.v1;
|
||||
option go_package = "cache";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "github.com/aquasecurity/trivy/rpc/common/service.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
service Cache {
|
||||
rpc PutImage(PutImageRequest) returns (google.protobuf.Empty);
|
||||
rpc PutLayer(PutLayerRequest) returns (google.protobuf.Empty);
|
||||
rpc MissingLayers(MissingLayersRequest) returns (MissingLayersResponse);
|
||||
}
|
||||
|
||||
message ImageInfo {
|
||||
int32 schema_version = 1;
|
||||
string architecture = 2;
|
||||
google.protobuf.Timestamp created = 3;
|
||||
string docker_version = 4;
|
||||
string os = 5;
|
||||
repeated common.Package history_packages = 6;
|
||||
}
|
||||
|
||||
message PutImageRequest {
|
||||
string image_id = 1;
|
||||
ImageInfo image_info = 2;
|
||||
}
|
||||
|
||||
message LayerInfo {
|
||||
int32 schema_version = 1;
|
||||
common.OS os = 2;
|
||||
repeated common.PackageInfo package_infos = 3;
|
||||
repeated common.Application applications = 4;
|
||||
repeated string opaque_dirs = 5;
|
||||
repeated string whiteout_files = 6;
|
||||
}
|
||||
|
||||
message PutLayerRequest {
|
||||
string layer_id = 1;
|
||||
string decompressed_layer_id = 2;
|
||||
LayerInfo layer_info = 3;
|
||||
}
|
||||
|
||||
message PutResponse {
|
||||
common.OS os = 1;
|
||||
bool eosl = 2;
|
||||
}
|
||||
|
||||
message MissingLayersRequest {
|
||||
string image_id = 1;
|
||||
repeated string layer_ids = 2;
|
||||
}
|
||||
|
||||
message MissingLayersResponse {
|
||||
bool missing_image = 1;
|
||||
repeated string missing_layer_ids = 2;
|
||||
}
|
||||
1258
rpc/cache/service.twirp.go
vendored
Normal file
1258
rpc/cache/service.twirp.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
503
rpc/common/service.pb.go
Normal file
503
rpc/common/service.pb.go
Normal file
@@ -0,0 +1,503 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: rpc/common/service.proto
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type Severity int32
|
||||
|
||||
const (
|
||||
Severity_UNKNOWN Severity = 0
|
||||
Severity_LOW Severity = 1
|
||||
Severity_MEDIUM Severity = 2
|
||||
Severity_HIGH Severity = 3
|
||||
Severity_CRITICAL Severity = 4
|
||||
)
|
||||
|
||||
var Severity_name = map[int32]string{
|
||||
0: "UNKNOWN",
|
||||
1: "LOW",
|
||||
2: "MEDIUM",
|
||||
3: "HIGH",
|
||||
4: "CRITICAL",
|
||||
}
|
||||
|
||||
var Severity_value = map[string]int32{
|
||||
"UNKNOWN": 0,
|
||||
"LOW": 1,
|
||||
"MEDIUM": 2,
|
||||
"HIGH": 3,
|
||||
"CRITICAL": 4,
|
||||
}
|
||||
|
||||
func (x Severity) String() string {
|
||||
return proto.EnumName(Severity_name, int32(x))
|
||||
}
|
||||
|
||||
func (Severity) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6e749acacaaabfff, []int{0}
|
||||
}
|
||||
|
||||
type OS struct {
|
||||
Family string `protobuf:"bytes,1,opt,name=family,proto3" json:"family,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *OS) Reset() { *m = OS{} }
|
||||
func (m *OS) String() string { return proto.CompactTextString(m) }
|
||||
func (*OS) ProtoMessage() {}
|
||||
func (*OS) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6e749acacaaabfff, []int{0}
|
||||
}
|
||||
|
||||
func (m *OS) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_OS.Unmarshal(m, b)
|
||||
}
|
||||
func (m *OS) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_OS.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *OS) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_OS.Merge(m, src)
|
||||
}
|
||||
func (m *OS) XXX_Size() int {
|
||||
return xxx_messageInfo_OS.Size(m)
|
||||
}
|
||||
func (m *OS) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_OS.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_OS proto.InternalMessageInfo
|
||||
|
||||
func (m *OS) GetFamily() string {
|
||||
if m != nil {
|
||||
return m.Family
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *OS) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type PackageInfo struct {
|
||||
FilePath string `protobuf:"bytes,1,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
|
||||
Packages []*Package `protobuf:"bytes,2,rep,name=packages,proto3" json:"packages,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PackageInfo) Reset() { *m = PackageInfo{} }
|
||||
func (m *PackageInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*PackageInfo) ProtoMessage() {}
|
||||
func (*PackageInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6e749acacaaabfff, []int{1}
|
||||
}
|
||||
|
||||
func (m *PackageInfo) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PackageInfo.Unmarshal(m, b)
|
||||
}
|
||||
func (m *PackageInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_PackageInfo.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *PackageInfo) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PackageInfo.Merge(m, src)
|
||||
}
|
||||
func (m *PackageInfo) XXX_Size() int {
|
||||
return xxx_messageInfo_PackageInfo.Size(m)
|
||||
}
|
||||
func (m *PackageInfo) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PackageInfo.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PackageInfo proto.InternalMessageInfo
|
||||
|
||||
func (m *PackageInfo) GetFilePath() string {
|
||||
if m != nil {
|
||||
return m.FilePath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *PackageInfo) GetPackages() []*Package {
|
||||
if m != nil {
|
||||
return m.Packages
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Application struct {
|
||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
|
||||
Libraries []*Library `protobuf:"bytes,3,rep,name=libraries,proto3" json:"libraries,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Application) Reset() { *m = Application{} }
|
||||
func (m *Application) String() string { return proto.CompactTextString(m) }
|
||||
func (*Application) ProtoMessage() {}
|
||||
func (*Application) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6e749acacaaabfff, []int{2}
|
||||
}
|
||||
|
||||
func (m *Application) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Application.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Application) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Application.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Application) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Application.Merge(m, src)
|
||||
}
|
||||
func (m *Application) XXX_Size() int {
|
||||
return xxx_messageInfo_Application.Size(m)
|
||||
}
|
||||
func (m *Application) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Application.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Application proto.InternalMessageInfo
|
||||
|
||||
func (m *Application) GetType() string {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Application) GetFilePath() string {
|
||||
if m != nil {
|
||||
return m.FilePath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Application) GetLibraries() []*Library {
|
||||
if m != nil {
|
||||
return m.Libraries
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
// binary package
|
||||
// e.g. bind-utils
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Release string `protobuf:"bytes,3,opt,name=release,proto3" json:"release,omitempty"`
|
||||
Epoch int32 `protobuf:"varint,4,opt,name=epoch,proto3" json:"epoch,omitempty"`
|
||||
Arch string `protobuf:"bytes,5,opt,name=arch,proto3" json:"arch,omitempty"`
|
||||
// src package containing some binary packages
|
||||
// e.g. bind
|
||||
SrcName string `protobuf:"bytes,6,opt,name=src_name,json=srcName,proto3" json:"src_name,omitempty"`
|
||||
SrcVersion string `protobuf:"bytes,7,opt,name=src_version,json=srcVersion,proto3" json:"src_version,omitempty"`
|
||||
SrcRelease string `protobuf:"bytes,8,opt,name=src_release,json=srcRelease,proto3" json:"src_release,omitempty"`
|
||||
SrcEpoch int32 `protobuf:"varint,9,opt,name=src_epoch,json=srcEpoch,proto3" json:"src_epoch,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Package) Reset() { *m = Package{} }
|
||||
func (m *Package) String() string { return proto.CompactTextString(m) }
|
||||
func (*Package) ProtoMessage() {}
|
||||
func (*Package) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6e749acacaaabfff, []int{3}
|
||||
}
|
||||
|
||||
func (m *Package) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Package.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Package) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Package.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Package) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Package.Merge(m, src)
|
||||
}
|
||||
func (m *Package) XXX_Size() int {
|
||||
return xxx_messageInfo_Package.Size(m)
|
||||
}
|
||||
func (m *Package) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Package.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Package proto.InternalMessageInfo
|
||||
|
||||
func (m *Package) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetVersion() string {
|
||||
if m != nil {
|
||||
return m.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetRelease() string {
|
||||
if m != nil {
|
||||
return m.Release
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetEpoch() int32 {
|
||||
if m != nil {
|
||||
return m.Epoch
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Package) GetArch() string {
|
||||
if m != nil {
|
||||
return m.Arch
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcName() string {
|
||||
if m != nil {
|
||||
return m.SrcName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcVersion() string {
|
||||
if m != nil {
|
||||
return m.SrcVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcRelease() string {
|
||||
if m != nil {
|
||||
return m.SrcRelease
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcEpoch() int32 {
|
||||
if m != nil {
|
||||
return m.SrcEpoch
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Library struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Library) Reset() { *m = Library{} }
|
||||
func (m *Library) String() string { return proto.CompactTextString(m) }
|
||||
func (*Library) ProtoMessage() {}
|
||||
func (*Library) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6e749acacaaabfff, []int{4}
|
||||
}
|
||||
|
||||
func (m *Library) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Library.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Library) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Library.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Library) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Library.Merge(m, src)
|
||||
}
|
||||
func (m *Library) XXX_Size() int {
|
||||
return xxx_messageInfo_Library.Size(m)
|
||||
}
|
||||
func (m *Library) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Library.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Library proto.InternalMessageInfo
|
||||
|
||||
func (m *Library) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Library) GetVersion() string {
|
||||
if m != nil {
|
||||
return m.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Vulnerability struct {
|
||||
VulnerabilityId string `protobuf:"bytes,1,opt,name=vulnerability_id,json=vulnerabilityId,proto3" json:"vulnerability_id,omitempty"`
|
||||
PkgName string `protobuf:"bytes,2,opt,name=pkg_name,json=pkgName,proto3" json:"pkg_name,omitempty"`
|
||||
InstalledVersion string `protobuf:"bytes,3,opt,name=installed_version,json=installedVersion,proto3" json:"installed_version,omitempty"`
|
||||
FixedVersion string `protobuf:"bytes,4,opt,name=fixed_version,json=fixedVersion,proto3" json:"fixed_version,omitempty"`
|
||||
Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"`
|
||||
Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Severity Severity `protobuf:"varint,7,opt,name=severity,proto3,enum=trivy.common.Severity" json:"severity,omitempty"`
|
||||
References []string `protobuf:"bytes,8,rep,name=references,proto3" json:"references,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Vulnerability) Reset() { *m = Vulnerability{} }
|
||||
func (m *Vulnerability) String() string { return proto.CompactTextString(m) }
|
||||
func (*Vulnerability) ProtoMessage() {}
|
||||
func (*Vulnerability) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6e749acacaaabfff, []int{5}
|
||||
}
|
||||
|
||||
func (m *Vulnerability) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Vulnerability.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Vulnerability) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Vulnerability.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Vulnerability) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Vulnerability.Merge(m, src)
|
||||
}
|
||||
func (m *Vulnerability) XXX_Size() int {
|
||||
return xxx_messageInfo_Vulnerability.Size(m)
|
||||
}
|
||||
func (m *Vulnerability) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Vulnerability.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Vulnerability proto.InternalMessageInfo
|
||||
|
||||
func (m *Vulnerability) GetVulnerabilityId() string {
|
||||
if m != nil {
|
||||
return m.VulnerabilityId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetPkgName() string {
|
||||
if m != nil {
|
||||
return m.PkgName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetInstalledVersion() string {
|
||||
if m != nil {
|
||||
return m.InstalledVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetFixedVersion() string {
|
||||
if m != nil {
|
||||
return m.FixedVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetTitle() string {
|
||||
if m != nil {
|
||||
return m.Title
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetDescription() string {
|
||||
if m != nil {
|
||||
return m.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetSeverity() Severity {
|
||||
if m != nil {
|
||||
return m.Severity
|
||||
}
|
||||
return Severity_UNKNOWN
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetReferences() []string {
|
||||
if m != nil {
|
||||
return m.References
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("trivy.common.Severity", Severity_name, Severity_value)
|
||||
proto.RegisterType((*OS)(nil), "trivy.common.OS")
|
||||
proto.RegisterType((*PackageInfo)(nil), "trivy.common.PackageInfo")
|
||||
proto.RegisterType((*Application)(nil), "trivy.common.Application")
|
||||
proto.RegisterType((*Package)(nil), "trivy.common.Package")
|
||||
proto.RegisterType((*Library)(nil), "trivy.common.Library")
|
||||
proto.RegisterType((*Vulnerability)(nil), "trivy.common.Vulnerability")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("rpc/common/service.proto", fileDescriptor_6e749acacaaabfff) }
|
||||
|
||||
var fileDescriptor_6e749acacaaabfff = []byte{
|
||||
// 543 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xd1, 0x6e, 0xd3, 0x30,
|
||||
0x14, 0x25, 0x49, 0xdb, 0xa4, 0x37, 0x1d, 0x04, 0x6b, 0x4c, 0x41, 0x93, 0xa0, 0x0a, 0x2f, 0x05,
|
||||
0xa4, 0x0e, 0xba, 0x07, 0x9e, 0xc7, 0x36, 0xb1, 0x88, 0xae, 0x9d, 0x32, 0xb6, 0x49, 0x48, 0xa8,
|
||||
0x72, 0x5d, 0xb7, 0xb5, 0x9a, 0x26, 0x91, 0x1d, 0x2a, 0xf2, 0x5d, 0x7c, 0x1b, 0xef, 0xc8, 0x8e,
|
||||
0x93, 0xb6, 0x88, 0x97, 0xbd, 0xf9, 0xde, 0x73, 0x7c, 0xcf, 0x39, 0x37, 0x0e, 0xf8, 0x3c, 0x23,
|
||||
0x27, 0x24, 0x5d, 0xaf, 0xd3, 0xe4, 0x44, 0x50, 0xbe, 0x61, 0x84, 0xf6, 0x33, 0x9e, 0xe6, 0x29,
|
||||
0xea, 0xe4, 0x9c, 0x6d, 0x8a, 0x7e, 0x89, 0x05, 0x1f, 0xc0, 0x1c, 0xdf, 0xa2, 0x23, 0x68, 0xcd,
|
||||
0xf1, 0x9a, 0xc5, 0x85, 0x6f, 0x74, 0x8d, 0x5e, 0x3b, 0xd2, 0x15, 0x42, 0xd0, 0x48, 0xf0, 0x9a,
|
||||
0xfa, 0xa6, 0xea, 0xaa, 0x73, 0xf0, 0x03, 0xdc, 0x1b, 0x4c, 0x56, 0x78, 0x41, 0xc3, 0x64, 0x9e,
|
||||
0xa2, 0x63, 0x68, 0xcf, 0x59, 0x4c, 0x27, 0x19, 0xce, 0x97, 0xfa, 0xb6, 0x23, 0x1b, 0x37, 0x38,
|
||||
0x5f, 0xa2, 0x8f, 0xe0, 0x64, 0x25, 0x57, 0xf8, 0x66, 0xd7, 0xea, 0xb9, 0x83, 0x17, 0xfd, 0x5d,
|
||||
0xf9, 0xbe, 0x9e, 0x14, 0xd5, 0xb4, 0x40, 0x80, 0x7b, 0x96, 0x65, 0x31, 0x23, 0x38, 0x67, 0x69,
|
||||
0x22, 0x1d, 0xe4, 0x45, 0x46, 0xf5, 0x64, 0x75, 0xde, 0x97, 0x34, 0xff, 0x91, 0x3c, 0x85, 0x76,
|
||||
0xcc, 0xa6, 0x1c, 0x73, 0x46, 0x85, 0x6f, 0xfd, 0x4f, 0x73, 0xa8, 0xe0, 0x22, 0xda, 0xf2, 0x82,
|
||||
0x3f, 0x06, 0xd8, 0xda, 0x4a, 0x9d, 0xd9, 0xd8, 0x66, 0x46, 0x3e, 0xd8, 0x1b, 0xca, 0x05, 0x4b,
|
||||
0x13, 0xad, 0x57, 0x95, 0x12, 0xe1, 0x34, 0xa6, 0x58, 0x50, 0xdf, 0x2a, 0x11, 0x5d, 0xa2, 0x43,
|
||||
0x68, 0xd2, 0x2c, 0x25, 0x4b, 0xbf, 0xd1, 0x35, 0x7a, 0xcd, 0xa8, 0x2c, 0xe4, 0x74, 0xcc, 0xc9,
|
||||
0xd2, 0x6f, 0x96, 0xd3, 0xe5, 0x19, 0xbd, 0x04, 0x47, 0x70, 0x32, 0x51, 0xaa, 0xad, 0x72, 0x88,
|
||||
0xe0, 0x64, 0x24, 0x85, 0x5f, 0x83, 0x2b, 0xa1, 0x4a, 0xdc, 0x56, 0x28, 0x08, 0x4e, 0xee, 0xb5,
|
||||
0xbe, 0x26, 0x54, 0x1e, 0x9c, 0x9a, 0x10, 0x69, 0x1b, 0xc7, 0xd0, 0x96, 0x84, 0xd2, 0x4a, 0x5b,
|
||||
0x59, 0x91, 0x6a, 0x97, 0xb2, 0x0e, 0x3e, 0x81, 0xad, 0xb7, 0xf1, 0xb8, 0xd8, 0xc1, 0x6f, 0x13,
|
||||
0x0e, 0xee, 0x7f, 0xc6, 0x09, 0xe5, 0x78, 0xca, 0x62, 0x96, 0x17, 0xe8, 0x2d, 0x78, 0x9b, 0xdd,
|
||||
0xc6, 0x84, 0xcd, 0xf4, 0xac, 0x67, 0x7b, 0xfd, 0x70, 0x26, 0xf3, 0x66, 0xab, 0xc5, 0x64, 0xe7,
|
||||
0x65, 0xd9, 0xd9, 0x6a, 0xa1, 0xf2, 0xbe, 0x87, 0xe7, 0x2c, 0x11, 0x39, 0x8e, 0x63, 0x3a, 0xab,
|
||||
0x53, 0x97, 0x8b, 0xf5, 0x6a, 0xa0, 0xca, 0xfe, 0x06, 0x0e, 0xe6, 0xec, 0xd7, 0x0e, 0xb1, 0xa1,
|
||||
0x88, 0x1d, 0xd5, 0xac, 0x48, 0x87, 0xd0, 0xcc, 0x59, 0x1e, 0x53, 0xbd, 0xf1, 0xb2, 0x40, 0x5d,
|
||||
0x70, 0x67, 0x54, 0x10, 0xce, 0x32, 0xf9, 0xca, 0xf4, 0xd6, 0x77, 0x5b, 0x68, 0x00, 0x8e, 0xa0,
|
||||
0x1b, 0xca, 0x59, 0x5e, 0xa8, 0xb5, 0x3f, 0x1d, 0x1c, 0xed, 0x3f, 0xa3, 0x5b, 0x8d, 0x46, 0x35,
|
||||
0x0f, 0xbd, 0x02, 0xe0, 0x74, 0x4e, 0x39, 0x4d, 0x08, 0x15, 0xbe, 0xd3, 0xb5, 0xe4, 0xb7, 0xd8,
|
||||
0x76, 0xde, 0x5d, 0x80, 0x53, 0xdd, 0x42, 0x2e, 0xd8, 0x77, 0xa3, 0xaf, 0xa3, 0xf1, 0xc3, 0xc8,
|
||||
0x7b, 0x82, 0x6c, 0xb0, 0x86, 0xe3, 0x07, 0xcf, 0x40, 0x00, 0xad, 0xeb, 0xcb, 0x8b, 0xf0, 0xee,
|
||||
0xda, 0x33, 0x91, 0x03, 0x8d, 0xab, 0xf0, 0xcb, 0x95, 0x67, 0xa1, 0x0e, 0x38, 0xe7, 0x51, 0xf8,
|
||||
0x2d, 0x3c, 0x3f, 0x1b, 0x7a, 0x8d, 0xcf, 0xce, 0xf7, 0x56, 0x69, 0x61, 0xda, 0x52, 0x7f, 0xf4,
|
||||
0xe9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb5, 0x19, 0x99, 0x46, 0xed, 0x03, 0x00, 0x00,
|
||||
}
|
||||
60
rpc/common/service.proto
Normal file
60
rpc/common/service.proto
Normal file
@@ -0,0 +1,60 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package trivy.common;
|
||||
option go_package = "common";
|
||||
|
||||
message OS {
|
||||
string family = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message PackageInfo {
|
||||
string file_path = 1;
|
||||
repeated Package packages = 2;
|
||||
}
|
||||
|
||||
message Application {
|
||||
string type = 1;
|
||||
string file_path = 2;
|
||||
repeated Library libraries = 3;
|
||||
}
|
||||
|
||||
message Package {
|
||||
// binary package
|
||||
// e.g. bind-utils
|
||||
string name = 1;
|
||||
string version = 2;
|
||||
string release = 3;
|
||||
int32 epoch = 4;
|
||||
string arch = 5;
|
||||
// src package containing some binary packages
|
||||
// e.g. bind
|
||||
string src_name = 6;
|
||||
string src_version = 7;
|
||||
string src_release = 8;
|
||||
int32 src_epoch = 9;
|
||||
}
|
||||
|
||||
message Library {
|
||||
string name = 1;
|
||||
string version = 2;
|
||||
}
|
||||
|
||||
message Vulnerability {
|
||||
string vulnerability_id = 1;
|
||||
string pkg_name = 2;
|
||||
string installed_version = 3;
|
||||
string fixed_version = 4;
|
||||
string title = 5;
|
||||
string description = 6;
|
||||
Severity severity = 7;
|
||||
repeated string references = 8;
|
||||
}
|
||||
|
||||
enum Severity {
|
||||
UNKNOWN = 0;
|
||||
LOW = 1;
|
||||
MEDIUM = 2;
|
||||
HIGH = 3;
|
||||
CRITICAL = 4;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package detector
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
common "github.com/aquasecurity/trivy/rpc/common"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
timestamp "github.com/golang/protobuf/ptypes/timestamp"
|
||||
math "math"
|
||||
@@ -21,44 +22,10 @@ var _ = math.Inf
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type Severity int32
|
||||
|
||||
const (
|
||||
Severity_UNKNOWN Severity = 0
|
||||
Severity_LOW Severity = 1
|
||||
Severity_MEDIUM Severity = 2
|
||||
Severity_HIGH Severity = 3
|
||||
Severity_CRITICAL Severity = 4
|
||||
)
|
||||
|
||||
var Severity_name = map[int32]string{
|
||||
0: "UNKNOWN",
|
||||
1: "LOW",
|
||||
2: "MEDIUM",
|
||||
3: "HIGH",
|
||||
4: "CRITICAL",
|
||||
}
|
||||
|
||||
var Severity_value = map[string]int32{
|
||||
"UNKNOWN": 0,
|
||||
"LOW": 1,
|
||||
"MEDIUM": 2,
|
||||
"HIGH": 3,
|
||||
"CRITICAL": 4,
|
||||
}
|
||||
|
||||
func (x Severity) String() string {
|
||||
return proto.EnumName(Severity_name, int32(x))
|
||||
}
|
||||
|
||||
func (Severity) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_93e16dbd737b8924, []int{0}
|
||||
}
|
||||
|
||||
type OSDetectRequest struct {
|
||||
OsFamily string `protobuf:"bytes,1,opt,name=os_family,json=osFamily,proto3" json:"os_family,omitempty"`
|
||||
OsName string `protobuf:"bytes,2,opt,name=os_name,json=osName,proto3" json:"os_name,omitempty"`
|
||||
Packages []*Package `protobuf:"bytes,3,rep,name=packages,proto3" json:"packages,omitempty"`
|
||||
Packages []*common.Package `protobuf:"bytes,3,rep,name=packages,proto3" json:"packages,omitempty"`
|
||||
ImageName string `protobuf:"bytes,4,opt,name=image_name,json=imageName,proto3" json:"image_name,omitempty"`
|
||||
Created *timestamp.Timestamp `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@@ -105,7 +72,7 @@ func (m *OSDetectRequest) GetOsName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *OSDetectRequest) GetPackages() []*Package {
|
||||
func (m *OSDetectRequest) GetPackages() []*common.Package {
|
||||
if m != nil {
|
||||
return m.Packages
|
||||
}
|
||||
@@ -127,11 +94,11 @@ func (m *OSDetectRequest) GetCreated() *timestamp.Timestamp {
|
||||
}
|
||||
|
||||
type DetectResponse struct {
|
||||
Vulnerabilities []*Vulnerability `protobuf:"bytes,1,rep,name=vulnerabilities,proto3" json:"vulnerabilities,omitempty"`
|
||||
Eosl bool `protobuf:"varint,2,opt,name=eosl,proto3" json:"eosl,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Vulnerabilities []*common.Vulnerability `protobuf:"bytes,1,rep,name=vulnerabilities,proto3" json:"vulnerabilities,omitempty"`
|
||||
Eosl bool `protobuf:"varint,2,opt,name=eosl,proto3" json:"eosl,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *DetectResponse) Reset() { *m = DetectResponse{} }
|
||||
@@ -159,7 +126,7 @@ func (m *DetectResponse) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_DetectResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *DetectResponse) GetVulnerabilities() []*Vulnerability {
|
||||
func (m *DetectResponse) GetVulnerabilities() []*common.Vulnerability {
|
||||
if m != nil {
|
||||
return m.Vulnerabilities
|
||||
}
|
||||
@@ -173,116 +140,9 @@ func (m *DetectResponse) GetEosl() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
// binary package
|
||||
// e.g. bind-utils
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Release string `protobuf:"bytes,3,opt,name=release,proto3" json:"release,omitempty"`
|
||||
Epoch int32 `protobuf:"varint,4,opt,name=epoch,proto3" json:"epoch,omitempty"`
|
||||
Arch string `protobuf:"bytes,5,opt,name=arch,proto3" json:"arch,omitempty"`
|
||||
// src package containing some binary packages
|
||||
// e.g. bind
|
||||
SrcName string `protobuf:"bytes,6,opt,name=src_name,json=srcName,proto3" json:"src_name,omitempty"`
|
||||
SrcVersion string `protobuf:"bytes,7,opt,name=src_version,json=srcVersion,proto3" json:"src_version,omitempty"`
|
||||
SrcRelease string `protobuf:"bytes,8,opt,name=src_release,json=srcRelease,proto3" json:"src_release,omitempty"`
|
||||
SrcEpoch int32 `protobuf:"varint,9,opt,name=src_epoch,json=srcEpoch,proto3" json:"src_epoch,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Package) Reset() { *m = Package{} }
|
||||
func (m *Package) String() string { return proto.CompactTextString(m) }
|
||||
func (*Package) ProtoMessage() {}
|
||||
func (*Package) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_93e16dbd737b8924, []int{2}
|
||||
}
|
||||
|
||||
func (m *Package) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Package.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Package) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Package.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Package) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Package.Merge(m, src)
|
||||
}
|
||||
func (m *Package) XXX_Size() int {
|
||||
return xxx_messageInfo_Package.Size(m)
|
||||
}
|
||||
func (m *Package) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Package.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Package proto.InternalMessageInfo
|
||||
|
||||
func (m *Package) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetVersion() string {
|
||||
if m != nil {
|
||||
return m.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetRelease() string {
|
||||
if m != nil {
|
||||
return m.Release
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetEpoch() int32 {
|
||||
if m != nil {
|
||||
return m.Epoch
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Package) GetArch() string {
|
||||
if m != nil {
|
||||
return m.Arch
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcName() string {
|
||||
if m != nil {
|
||||
return m.SrcName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcVersion() string {
|
||||
if m != nil {
|
||||
return m.SrcVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcRelease() string {
|
||||
if m != nil {
|
||||
return m.SrcRelease
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSrcEpoch() int32 {
|
||||
if m != nil {
|
||||
return m.SrcEpoch
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type LibDetectRequest struct {
|
||||
FilePath string `protobuf:"bytes,1,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
|
||||
Libraries []*Library `protobuf:"bytes,2,rep,name=libraries,proto3" json:"libraries,omitempty"`
|
||||
Libraries []*common.Library `protobuf:"bytes,2,rep,name=libraries,proto3" json:"libraries,omitempty"`
|
||||
ImageName string `protobuf:"bytes,3,opt,name=image_name,json=imageName,proto3" json:"image_name,omitempty"`
|
||||
Created *timestamp.Timestamp `protobuf:"bytes,4,opt,name=created,proto3" json:"created,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@@ -294,7 +154,7 @@ func (m *LibDetectRequest) Reset() { *m = LibDetectRequest{} }
|
||||
func (m *LibDetectRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*LibDetectRequest) ProtoMessage() {}
|
||||
func (*LibDetectRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_93e16dbd737b8924, []int{3}
|
||||
return fileDescriptor_93e16dbd737b8924, []int{2}
|
||||
}
|
||||
|
||||
func (m *LibDetectRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -322,7 +182,7 @@ func (m *LibDetectRequest) GetFilePath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *LibDetectRequest) GetLibraries() []*Library {
|
||||
func (m *LibDetectRequest) GetLibraries() []*common.Library {
|
||||
if m != nil {
|
||||
return m.Libraries
|
||||
}
|
||||
@@ -343,204 +203,41 @@ func (m *LibDetectRequest) GetCreated() *timestamp.Timestamp {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Library struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Library) Reset() { *m = Library{} }
|
||||
func (m *Library) String() string { return proto.CompactTextString(m) }
|
||||
func (*Library) ProtoMessage() {}
|
||||
func (*Library) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_93e16dbd737b8924, []int{4}
|
||||
}
|
||||
|
||||
func (m *Library) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Library.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Library) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Library.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Library) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Library.Merge(m, src)
|
||||
}
|
||||
func (m *Library) XXX_Size() int {
|
||||
return xxx_messageInfo_Library.Size(m)
|
||||
}
|
||||
func (m *Library) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Library.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Library proto.InternalMessageInfo
|
||||
|
||||
func (m *Library) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Library) GetVersion() string {
|
||||
if m != nil {
|
||||
return m.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Vulnerability struct {
|
||||
VulnerabilityId string `protobuf:"bytes,1,opt,name=vulnerability_id,json=vulnerabilityId,proto3" json:"vulnerability_id,omitempty"`
|
||||
PkgName string `protobuf:"bytes,2,opt,name=pkg_name,json=pkgName,proto3" json:"pkg_name,omitempty"`
|
||||
InstalledVersion string `protobuf:"bytes,3,opt,name=installed_version,json=installedVersion,proto3" json:"installed_version,omitempty"`
|
||||
FixedVersion string `protobuf:"bytes,4,opt,name=fixed_version,json=fixedVersion,proto3" json:"fixed_version,omitempty"`
|
||||
Title string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"`
|
||||
Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Severity Severity `protobuf:"varint,7,opt,name=severity,proto3,enum=trivy.detector.Severity" json:"severity,omitempty"`
|
||||
References []string `protobuf:"bytes,8,rep,name=references,proto3" json:"references,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Vulnerability) Reset() { *m = Vulnerability{} }
|
||||
func (m *Vulnerability) String() string { return proto.CompactTextString(m) }
|
||||
func (*Vulnerability) ProtoMessage() {}
|
||||
func (*Vulnerability) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_93e16dbd737b8924, []int{5}
|
||||
}
|
||||
|
||||
func (m *Vulnerability) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Vulnerability.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Vulnerability) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Vulnerability.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Vulnerability) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Vulnerability.Merge(m, src)
|
||||
}
|
||||
func (m *Vulnerability) XXX_Size() int {
|
||||
return xxx_messageInfo_Vulnerability.Size(m)
|
||||
}
|
||||
func (m *Vulnerability) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Vulnerability.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Vulnerability proto.InternalMessageInfo
|
||||
|
||||
func (m *Vulnerability) GetVulnerabilityId() string {
|
||||
if m != nil {
|
||||
return m.VulnerabilityId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetPkgName() string {
|
||||
if m != nil {
|
||||
return m.PkgName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetInstalledVersion() string {
|
||||
if m != nil {
|
||||
return m.InstalledVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetFixedVersion() string {
|
||||
if m != nil {
|
||||
return m.FixedVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetTitle() string {
|
||||
if m != nil {
|
||||
return m.Title
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetDescription() string {
|
||||
if m != nil {
|
||||
return m.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetSeverity() Severity {
|
||||
if m != nil {
|
||||
return m.Severity
|
||||
}
|
||||
return Severity_UNKNOWN
|
||||
}
|
||||
|
||||
func (m *Vulnerability) GetReferences() []string {
|
||||
if m != nil {
|
||||
return m.References
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("trivy.detector.Severity", Severity_name, Severity_value)
|
||||
proto.RegisterType((*OSDetectRequest)(nil), "trivy.detector.OSDetectRequest")
|
||||
proto.RegisterType((*DetectResponse)(nil), "trivy.detector.DetectResponse")
|
||||
proto.RegisterType((*Package)(nil), "trivy.detector.Package")
|
||||
proto.RegisterType((*LibDetectRequest)(nil), "trivy.detector.LibDetectRequest")
|
||||
proto.RegisterType((*Library)(nil), "trivy.detector.Library")
|
||||
proto.RegisterType((*Vulnerability)(nil), "trivy.detector.Vulnerability")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("rpc/detector/service.proto", fileDescriptor_93e16dbd737b8924) }
|
||||
|
||||
var fileDescriptor_93e16dbd737b8924 = []byte{
|
||||
// 693 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0xc5, 0xf9, 0xb2, 0x33, 0xe9, 0x87, 0x59, 0x55, 0xaa, 0x49, 0xd5, 0x36, 0x0a, 0x97, 0x02,
|
||||
0x52, 0x22, 0xa5, 0x45, 0x9c, 0xa1, 0x2d, 0x6d, 0x20, 0x4d, 0x2b, 0xf7, 0x4b, 0x70, 0x89, 0x36,
|
||||
0xce, 0x24, 0x59, 0xd5, 0xc9, 0x9a, 0xdd, 0x6d, 0x44, 0x7e, 0x18, 0x27, 0x7e, 0x05, 0x3f, 0x86,
|
||||
0x3b, 0xf2, 0xae, 0x9d, 0x26, 0xa1, 0x42, 0xf4, 0xb6, 0x33, 0xef, 0xed, 0xec, 0xbc, 0x99, 0x67,
|
||||
0x43, 0x59, 0x44, 0x41, 0xbd, 0x87, 0x0a, 0x03, 0xc5, 0x45, 0x5d, 0xa2, 0x98, 0xb0, 0x00, 0x6b,
|
||||
0x91, 0xe0, 0x8a, 0x93, 0x35, 0x25, 0xd8, 0x64, 0x5a, 0x4b, 0xd1, 0xf2, 0xee, 0x80, 0xf3, 0x41,
|
||||
0x88, 0x75, 0x8d, 0x76, 0xef, 0xfb, 0x75, 0xc5, 0x46, 0x28, 0x15, 0x1d, 0x45, 0xe6, 0x42, 0xf5,
|
||||
0x97, 0x05, 0xeb, 0xe7, 0x97, 0x47, 0x9a, 0xef, 0xe3, 0xb7, 0x7b, 0x94, 0x8a, 0x6c, 0x41, 0x91,
|
||||
0xcb, 0x4e, 0x9f, 0x8e, 0x58, 0x38, 0xf5, 0xac, 0x8a, 0xb5, 0x57, 0xf4, 0x1d, 0x2e, 0x3f, 0xea,
|
||||
0x98, 0x6c, 0x82, 0xcd, 0x65, 0x67, 0x4c, 0x47, 0xe8, 0x65, 0x34, 0x54, 0xe0, 0xb2, 0x4d, 0x47,
|
||||
0x48, 0xf6, 0xc1, 0x89, 0x68, 0x70, 0x47, 0x07, 0x28, 0xbd, 0x6c, 0x25, 0xbb, 0x57, 0x6a, 0x6c,
|
||||
0xd6, 0x16, 0xbb, 0xa9, 0x5d, 0x18, 0xdc, 0x9f, 0x11, 0xc9, 0x36, 0x00, 0x1b, 0xd1, 0x01, 0x9a,
|
||||
0x82, 0x39, 0x5d, 0xb0, 0xa8, 0x33, 0xba, 0xe6, 0x01, 0xd8, 0x81, 0x40, 0xaa, 0xb0, 0xe7, 0xe5,
|
||||
0x2b, 0xd6, 0x5e, 0xa9, 0x51, 0xae, 0x19, 0x41, 0xb5, 0x54, 0x50, 0xed, 0x2a, 0x15, 0xe4, 0xa7,
|
||||
0xd4, 0xea, 0x08, 0xd6, 0x52, 0x41, 0x32, 0xe2, 0x63, 0x89, 0xe4, 0x04, 0xd6, 0x27, 0xf7, 0xe1,
|
||||
0x18, 0x05, 0xed, 0xb2, 0x90, 0x29, 0x86, 0xd2, 0xb3, 0x74, 0x8b, 0xdb, 0xcb, 0x2d, 0xde, 0xcc,
|
||||
0xd1, 0xa6, 0xfe, 0xf2, 0x2d, 0x42, 0x20, 0x87, 0x5c, 0x86, 0x5a, 0xba, 0xe3, 0xeb, 0x73, 0xf5,
|
||||
0xb7, 0x05, 0x76, 0xa2, 0x2c, 0xc6, 0xb5, 0x12, 0x33, 0x35, 0x7d, 0x26, 0x1e, 0xd8, 0x13, 0x14,
|
||||
0x92, 0xf1, 0x71, 0x32, 0xb1, 0x34, 0x8c, 0x11, 0x81, 0x21, 0x52, 0x89, 0x5e, 0xd6, 0x20, 0x49,
|
||||
0x48, 0x36, 0x20, 0x8f, 0x11, 0x0f, 0x86, 0x7a, 0x24, 0x79, 0xdf, 0x04, 0x71, 0x75, 0x2a, 0x82,
|
||||
0xa1, 0x9e, 0x45, 0xd1, 0xd7, 0x67, 0xf2, 0x02, 0x1c, 0x29, 0x02, 0x33, 0xbf, 0x82, 0x29, 0x22,
|
||||
0x45, 0xa0, 0xa7, 0xb7, 0x0b, 0xa5, 0x18, 0x4a, 0x1f, 0xb7, 0x35, 0x0a, 0x52, 0x04, 0x37, 0xc9,
|
||||
0xfb, 0x09, 0x21, 0xed, 0xc1, 0x99, 0x11, 0xfc, 0xa4, 0x8d, 0x2d, 0x28, 0xc6, 0x04, 0xd3, 0x4a,
|
||||
0x51, 0xb7, 0x12, 0xbf, 0x76, 0x1c, 0xc7, 0xd5, 0x9f, 0x16, 0xb8, 0x2d, 0xd6, 0xfd, 0xcb, 0x3b,
|
||||
0x7d, 0x16, 0x62, 0x27, 0xa2, 0x6a, 0x98, 0x7a, 0x27, 0x4e, 0x5c, 0x50, 0x35, 0x24, 0x6f, 0xa1,
|
||||
0x18, 0xb2, 0xae, 0xa0, 0x22, 0x5e, 0x40, 0xe6, 0x71, 0x8f, 0xb4, 0x34, 0x61, 0xea, 0x3f, 0x30,
|
||||
0x97, 0x4c, 0x92, 0xfd, 0x87, 0x49, 0x72, 0xff, 0x6f, 0x92, 0x77, 0x60, 0x27, 0x4f, 0x3d, 0x6d,
|
||||
0x69, 0xd5, 0x1f, 0x19, 0x58, 0x5d, 0x70, 0x09, 0x79, 0x05, 0xee, 0xbc, 0x4f, 0xa6, 0x1d, 0xd6,
|
||||
0x4b, 0x6a, 0x2d, 0xf8, 0x67, 0xda, 0xec, 0xc5, 0xdb, 0x8a, 0xee, 0x06, 0xf3, 0x9f, 0x8f, 0x1d,
|
||||
0xdd, 0x0d, 0xb4, 0x8c, 0x37, 0xf0, 0x9c, 0x8d, 0xa5, 0xa2, 0x61, 0x88, 0xbd, 0xd9, 0xce, 0x8c,
|
||||
0x58, 0x77, 0x06, 0xa4, 0x9b, 0x7b, 0x09, 0xab, 0x7d, 0xf6, 0x7d, 0x8e, 0x68, 0x3e, 0x9d, 0x15,
|
||||
0x9d, 0x4c, 0x49, 0x1b, 0x90, 0x57, 0x4c, 0x85, 0x98, 0xf8, 0xc5, 0x04, 0xa4, 0x02, 0xa5, 0x1e,
|
||||
0xca, 0x40, 0xb0, 0x48, 0xc5, 0x17, 0x8d, 0x67, 0xe6, 0x53, 0xe4, 0x00, 0x1c, 0x89, 0x13, 0x14,
|
||||
0x4c, 0x4d, 0xb5, 0x69, 0xd6, 0x1a, 0xde, 0xf2, 0x96, 0x2e, 0x13, 0xdc, 0x9f, 0x31, 0xc9, 0x0e,
|
||||
0x80, 0xc0, 0x3e, 0x0a, 0x1c, 0x07, 0x28, 0x3d, 0xa7, 0x92, 0x8d, 0xbd, 0xf4, 0x90, 0x79, 0x7d,
|
||||
0x04, 0x4e, 0x7a, 0x8b, 0x94, 0xc0, 0xbe, 0x6e, 0x7f, 0x6e, 0x9f, 0xdf, 0xb6, 0xdd, 0x67, 0xc4,
|
||||
0x86, 0x6c, 0xeb, 0xfc, 0xd6, 0xb5, 0x08, 0x40, 0xe1, 0xec, 0xf8, 0xa8, 0x79, 0x7d, 0xe6, 0x66,
|
||||
0x88, 0x03, 0xb9, 0xd3, 0xe6, 0xc9, 0xa9, 0x9b, 0x25, 0x2b, 0xe0, 0x1c, 0xfa, 0xcd, 0xab, 0xe6,
|
||||
0xe1, 0xfb, 0x96, 0x9b, 0x6b, 0xdc, 0x02, 0xa4, 0xbf, 0x2b, 0x2e, 0x48, 0x13, 0x0a, 0xe6, 0x4c,
|
||||
0x76, 0x97, 0x3b, 0x5c, 0xfa, 0xa9, 0x95, 0x77, 0x96, 0x09, 0x8b, 0xbf, 0x88, 0xc6, 0x17, 0x28,
|
||||
0xcd, 0xcc, 0xcc, 0x05, 0xf9, 0x34, 0xab, 0x5c, 0x79, 0xc4, 0xa1, 0x4f, 0x2a, 0xfd, 0x01, 0xbe,
|
||||
0x3a, 0x29, 0xd4, 0x2d, 0x68, 0x4f, 0xee, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x65, 0x1f, 0xdb,
|
||||
0x8d, 0xc5, 0x05, 0x00, 0x00,
|
||||
// 422 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xd1, 0x8a, 0xd3, 0x40,
|
||||
0x14, 0x86, 0xc9, 0xb6, 0x76, 0xdb, 0x53, 0xd8, 0x95, 0x01, 0x31, 0x64, 0xd1, 0x2d, 0xbd, 0xea,
|
||||
0xd5, 0x04, 0xbb, 0xe2, 0x03, 0x88, 0x0a, 0xca, 0xa2, 0x4b, 0x14, 0x45, 0x6f, 0xca, 0x64, 0xf6,
|
||||
0x34, 0x1d, 0x36, 0xd3, 0x93, 0xce, 0x4c, 0x0a, 0x79, 0x34, 0x9f, 0xc2, 0x57, 0x92, 0x4e, 0x98,
|
||||
0x6a, 0xa2, 0xe8, 0xde, 0x4d, 0xe6, 0xff, 0xcf, 0x7f, 0xce, 0xf9, 0x32, 0x90, 0x98, 0x4a, 0xa6,
|
||||
0xb7, 0xe8, 0x50, 0x3a, 0x32, 0xa9, 0x45, 0xb3, 0x57, 0x12, 0x79, 0x65, 0xc8, 0x11, 0x3b, 0x73,
|
||||
0x46, 0xed, 0x1b, 0x1e, 0xd4, 0xe4, 0xb2, 0x20, 0x2a, 0x4a, 0x4c, 0xbd, 0x9a, 0xd7, 0xeb, 0xd4,
|
||||
0x29, 0x8d, 0xd6, 0x09, 0x5d, 0xb5, 0x05, 0xc9, 0x8b, 0x42, 0xb9, 0x4d, 0x9d, 0x73, 0x49, 0x3a,
|
||||
0x15, 0xbb, 0x5a, 0x58, 0x94, 0xb5, 0x51, 0xae, 0x49, 0x7d, 0x50, 0x7a, 0x68, 0x25, 0x49, 0x6b,
|
||||
0xda, 0x76, 0x1b, 0xcd, 0x7f, 0x44, 0x70, 0xfe, 0xe1, 0xe3, 0x2b, 0xdf, 0x27, 0xc3, 0x5d, 0x8d,
|
||||
0xd6, 0xb1, 0x0b, 0x98, 0x90, 0x5d, 0xad, 0x85, 0x56, 0x65, 0x13, 0x47, 0xb3, 0x68, 0x31, 0xc9,
|
||||
0xc6, 0x64, 0xdf, 0xf8, 0x6f, 0xf6, 0x18, 0x4e, 0xc9, 0xae, 0xb6, 0x42, 0x63, 0x7c, 0xe2, 0xa5,
|
||||
0x11, 0xd9, 0xf7, 0x42, 0x23, 0x7b, 0x06, 0xe3, 0x4a, 0xc8, 0x3b, 0x51, 0xa0, 0x8d, 0x07, 0xb3,
|
||||
0xc1, 0x62, 0xba, 0x7c, 0xc4, 0xdb, 0x2d, 0xda, 0xc6, 0xfc, 0xa6, 0x55, 0xb3, 0xa3, 0x8d, 0x3d,
|
||||
0x01, 0x50, 0x5a, 0x14, 0xd8, 0xc6, 0x0d, 0x7d, 0xdc, 0xc4, 0xdf, 0xf8, 0xc4, 0xe7, 0x70, 0x2a,
|
||||
0x0d, 0x0a, 0x87, 0xb7, 0xf1, 0x83, 0x59, 0xb4, 0x98, 0x2e, 0x13, 0xde, 0x62, 0xe0, 0x01, 0x03,
|
||||
0xff, 0x14, 0x30, 0x64, 0xc1, 0x3a, 0xbf, 0x83, 0xb3, 0xb0, 0x8e, 0xad, 0x68, 0x6b, 0x91, 0xbd,
|
||||
0x86, 0xf3, 0x7d, 0x5d, 0x6e, 0xd1, 0x88, 0x5c, 0x95, 0xca, 0x29, 0xb4, 0x71, 0xe4, 0x07, 0xbc,
|
||||
0xe8, 0x0e, 0xf8, 0xf9, 0x37, 0x53, 0x93, 0xf5, 0x6b, 0x18, 0x83, 0x21, 0x92, 0x2d, 0xfd, 0xda,
|
||||
0xe3, 0xcc, 0x9f, 0xe7, 0xdf, 0x23, 0x78, 0x78, 0xad, 0xf2, 0x3f, 0xf8, 0xad, 0x55, 0x89, 0xab,
|
||||
0x4a, 0xb8, 0x4d, 0xe0, 0x77, 0xb8, 0xb8, 0x11, 0x6e, 0xc3, 0xae, 0x60, 0x52, 0xaa, 0xdc, 0x08,
|
||||
0x73, 0x18, 0xe3, 0xe4, 0x6f, 0x9c, 0xae, 0xbd, 0xdc, 0x64, 0xbf, 0x7c, 0x3d, 0x50, 0x83, 0x7f,
|
||||
0x80, 0x1a, 0xde, 0x1b, 0xd4, 0xf2, 0x0b, 0x40, 0xf8, 0xf3, 0x64, 0xd8, 0x5b, 0x18, 0xb5, 0x67,
|
||||
0x76, 0xc9, 0xbb, 0x8f, 0x8f, 0xf7, 0xde, 0x47, 0xf2, 0xb4, 0x6f, 0xe8, 0xf2, 0x5e, 0x7e, 0x85,
|
||||
0xe9, 0x91, 0x09, 0x19, 0xf6, 0xee, 0x98, 0x3c, 0xeb, 0x17, 0xf6, 0xd1, 0xfd, 0x2f, 0xfa, 0x25,
|
||||
0x7c, 0x1b, 0x07, 0x29, 0x1f, 0xf9, 0xe5, 0xae, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0x60, 0x68,
|
||||
0xcc, 0x2b, 0x48, 0x03, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// for backward compatibility
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
@@ -5,37 +6,23 @@ import "google/protobuf/timestamp.proto";
|
||||
package trivy.detector;
|
||||
option go_package = "detector";
|
||||
|
||||
import "github.com/aquasecurity/trivy/rpc/common/service.proto";
|
||||
|
||||
service OSDetector {
|
||||
rpc Detect(OSDetectRequest) returns (DetectResponse);
|
||||
}
|
||||
|
||||
message OSDetectRequest {
|
||||
string os_family = 1;
|
||||
string os_name = 2;
|
||||
repeated Package packages = 3;
|
||||
string os_family = 1;
|
||||
string os_name = 2;
|
||||
repeated common.Package packages = 3;
|
||||
string image_name = 4;
|
||||
google.protobuf.Timestamp created = 5;
|
||||
}
|
||||
|
||||
message DetectResponse {
|
||||
repeated Vulnerability vulnerabilities = 1;
|
||||
bool eosl = 2;
|
||||
}
|
||||
|
||||
message Package {
|
||||
// binary package
|
||||
// e.g. bind-utils
|
||||
string name = 1;
|
||||
string version = 2;
|
||||
string release = 3;
|
||||
int32 epoch = 4;
|
||||
string arch = 5;
|
||||
// src package containing some binary packages
|
||||
// e.g. bind
|
||||
string src_name = 6;
|
||||
string src_version = 7;
|
||||
string src_release = 8;
|
||||
int32 src_epoch = 9;
|
||||
repeated common.Vulnerability vulnerabilities = 1;
|
||||
bool eosl = 2;
|
||||
}
|
||||
|
||||
service LibDetector {
|
||||
@@ -43,32 +30,8 @@ service LibDetector {
|
||||
}
|
||||
|
||||
message LibDetectRequest {
|
||||
string file_path = 1;
|
||||
repeated Library libraries = 2;
|
||||
string file_path = 1;
|
||||
repeated common.Library libraries = 2;
|
||||
string image_name = 3;
|
||||
google.protobuf.Timestamp created = 4;
|
||||
}
|
||||
|
||||
message Library {
|
||||
string name = 1;
|
||||
string version = 2;
|
||||
}
|
||||
|
||||
message Vulnerability {
|
||||
string vulnerability_id = 1;
|
||||
string pkg_name = 2;
|
||||
string installed_version = 3;
|
||||
string fixed_version = 4;
|
||||
string title = 5;
|
||||
string description = 6;
|
||||
Severity severity = 7;
|
||||
repeated string references = 8;
|
||||
}
|
||||
|
||||
enum Severity {
|
||||
UNKNOWN = 0;
|
||||
LOW = 1;
|
||||
MEDIUM = 2;
|
||||
HIGH = 3;
|
||||
CRITICAL = 4;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Code generated by protoc-gen-twirp v5.9.0, DO NOT EDIT.
|
||||
// Code generated by protoc-gen-twirp v5.10.1, DO NOT EDIT.
|
||||
// source: rpc/detector/service.proto
|
||||
|
||||
/*
|
||||
Package detector is a generated twirp stub package.
|
||||
This code was generated with github.com/twitchtv/twirp/protoc-gen-twirp v5.9.0.
|
||||
This code was generated with github.com/twitchtv/twirp/protoc-gen-twirp v5.10.1.
|
||||
|
||||
It is generated from these files:
|
||||
rpc/detector/service.proto
|
||||
@@ -43,24 +43,30 @@ type OSDetector interface {
|
||||
type oSDetectorProtobufClient struct {
|
||||
client HTTPClient
|
||||
urls [1]string
|
||||
opts twirp.ClientOptions
|
||||
}
|
||||
|
||||
// NewOSDetectorProtobufClient creates a Protobuf client that implements the OSDetector interface.
|
||||
// It communicates using Protobuf and can be configured with a custom HTTPClient.
|
||||
func NewOSDetectorProtobufClient(addr string, client HTTPClient) OSDetector {
|
||||
func NewOSDetectorProtobufClient(addr string, client HTTPClient, opts ...twirp.ClientOption) OSDetector {
|
||||
if c, ok := client.(*http.Client); ok {
|
||||
client = withoutRedirects(c)
|
||||
}
|
||||
|
||||
clientOpts := twirp.ClientOptions{}
|
||||
for _, o := range opts {
|
||||
o(&clientOpts)
|
||||
}
|
||||
|
||||
prefix := urlBase(addr) + OSDetectorPathPrefix
|
||||
urls := [1]string{
|
||||
prefix + "Detect",
|
||||
}
|
||||
if httpClient, ok := client.(*http.Client); ok {
|
||||
return &oSDetectorProtobufClient{
|
||||
client: withoutRedirects(httpClient),
|
||||
urls: urls,
|
||||
}
|
||||
}
|
||||
|
||||
return &oSDetectorProtobufClient{
|
||||
client: client,
|
||||
urls: urls,
|
||||
opts: clientOpts,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +75,18 @@ func (c *oSDetectorProtobufClient) Detect(ctx context.Context, in *OSDetectReque
|
||||
ctx = ctxsetters.WithServiceName(ctx, "OSDetector")
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Detect")
|
||||
out := new(DetectResponse)
|
||||
err := doProtobufRequest(ctx, c.client, c.urls[0], in, out)
|
||||
err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
|
||||
if err != nil {
|
||||
twerr, ok := err.(twirp.Error)
|
||||
if !ok {
|
||||
twerr = twirp.InternalErrorWith(err)
|
||||
}
|
||||
callClientError(ctx, c.opts.Hooks, twerr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callClientResponseReceived(ctx, c.opts.Hooks)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -83,24 +97,30 @@ func (c *oSDetectorProtobufClient) Detect(ctx context.Context, in *OSDetectReque
|
||||
type oSDetectorJSONClient struct {
|
||||
client HTTPClient
|
||||
urls [1]string
|
||||
opts twirp.ClientOptions
|
||||
}
|
||||
|
||||
// NewOSDetectorJSONClient creates a JSON client that implements the OSDetector interface.
|
||||
// It communicates using JSON and can be configured with a custom HTTPClient.
|
||||
func NewOSDetectorJSONClient(addr string, client HTTPClient) OSDetector {
|
||||
func NewOSDetectorJSONClient(addr string, client HTTPClient, opts ...twirp.ClientOption) OSDetector {
|
||||
if c, ok := client.(*http.Client); ok {
|
||||
client = withoutRedirects(c)
|
||||
}
|
||||
|
||||
clientOpts := twirp.ClientOptions{}
|
||||
for _, o := range opts {
|
||||
o(&clientOpts)
|
||||
}
|
||||
|
||||
prefix := urlBase(addr) + OSDetectorPathPrefix
|
||||
urls := [1]string{
|
||||
prefix + "Detect",
|
||||
}
|
||||
if httpClient, ok := client.(*http.Client); ok {
|
||||
return &oSDetectorJSONClient{
|
||||
client: withoutRedirects(httpClient),
|
||||
urls: urls,
|
||||
}
|
||||
}
|
||||
|
||||
return &oSDetectorJSONClient{
|
||||
client: client,
|
||||
urls: urls,
|
||||
opts: clientOpts,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,10 +129,18 @@ func (c *oSDetectorJSONClient) Detect(ctx context.Context, in *OSDetectRequest)
|
||||
ctx = ctxsetters.WithServiceName(ctx, "OSDetector")
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Detect")
|
||||
out := new(DetectResponse)
|
||||
err := doJSONRequest(ctx, c.client, c.urls[0], in, out)
|
||||
err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
|
||||
if err != nil {
|
||||
twerr, ok := err.(twirp.Error)
|
||||
if !ok {
|
||||
twerr = twirp.InternalErrorWith(err)
|
||||
}
|
||||
callClientError(ctx, c.opts.Hooks, twerr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callClientResponseReceived(ctx, c.opts.Hooks)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -309,7 +337,7 @@ func (s *oSDetectorServer) ServiceDescriptor() ([]byte, int) {
|
||||
}
|
||||
|
||||
func (s *oSDetectorServer) ProtocGenTwirpVersion() string {
|
||||
return "v5.9.0"
|
||||
return "v5.10.1"
|
||||
}
|
||||
|
||||
func (s *oSDetectorServer) PathPrefix() string {
|
||||
@@ -331,24 +359,30 @@ type LibDetector interface {
|
||||
type libDetectorProtobufClient struct {
|
||||
client HTTPClient
|
||||
urls [1]string
|
||||
opts twirp.ClientOptions
|
||||
}
|
||||
|
||||
// NewLibDetectorProtobufClient creates a Protobuf client that implements the LibDetector interface.
|
||||
// It communicates using Protobuf and can be configured with a custom HTTPClient.
|
||||
func NewLibDetectorProtobufClient(addr string, client HTTPClient) LibDetector {
|
||||
func NewLibDetectorProtobufClient(addr string, client HTTPClient, opts ...twirp.ClientOption) LibDetector {
|
||||
if c, ok := client.(*http.Client); ok {
|
||||
client = withoutRedirects(c)
|
||||
}
|
||||
|
||||
clientOpts := twirp.ClientOptions{}
|
||||
for _, o := range opts {
|
||||
o(&clientOpts)
|
||||
}
|
||||
|
||||
prefix := urlBase(addr) + LibDetectorPathPrefix
|
||||
urls := [1]string{
|
||||
prefix + "Detect",
|
||||
}
|
||||
if httpClient, ok := client.(*http.Client); ok {
|
||||
return &libDetectorProtobufClient{
|
||||
client: withoutRedirects(httpClient),
|
||||
urls: urls,
|
||||
}
|
||||
}
|
||||
|
||||
return &libDetectorProtobufClient{
|
||||
client: client,
|
||||
urls: urls,
|
||||
opts: clientOpts,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,10 +391,18 @@ func (c *libDetectorProtobufClient) Detect(ctx context.Context, in *LibDetectReq
|
||||
ctx = ctxsetters.WithServiceName(ctx, "LibDetector")
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Detect")
|
||||
out := new(DetectResponse)
|
||||
err := doProtobufRequest(ctx, c.client, c.urls[0], in, out)
|
||||
err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
|
||||
if err != nil {
|
||||
twerr, ok := err.(twirp.Error)
|
||||
if !ok {
|
||||
twerr = twirp.InternalErrorWith(err)
|
||||
}
|
||||
callClientError(ctx, c.opts.Hooks, twerr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callClientResponseReceived(ctx, c.opts.Hooks)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -371,24 +413,30 @@ func (c *libDetectorProtobufClient) Detect(ctx context.Context, in *LibDetectReq
|
||||
type libDetectorJSONClient struct {
|
||||
client HTTPClient
|
||||
urls [1]string
|
||||
opts twirp.ClientOptions
|
||||
}
|
||||
|
||||
// NewLibDetectorJSONClient creates a JSON client that implements the LibDetector interface.
|
||||
// It communicates using JSON and can be configured with a custom HTTPClient.
|
||||
func NewLibDetectorJSONClient(addr string, client HTTPClient) LibDetector {
|
||||
func NewLibDetectorJSONClient(addr string, client HTTPClient, opts ...twirp.ClientOption) LibDetector {
|
||||
if c, ok := client.(*http.Client); ok {
|
||||
client = withoutRedirects(c)
|
||||
}
|
||||
|
||||
clientOpts := twirp.ClientOptions{}
|
||||
for _, o := range opts {
|
||||
o(&clientOpts)
|
||||
}
|
||||
|
||||
prefix := urlBase(addr) + LibDetectorPathPrefix
|
||||
urls := [1]string{
|
||||
prefix + "Detect",
|
||||
}
|
||||
if httpClient, ok := client.(*http.Client); ok {
|
||||
return &libDetectorJSONClient{
|
||||
client: withoutRedirects(httpClient),
|
||||
urls: urls,
|
||||
}
|
||||
}
|
||||
|
||||
return &libDetectorJSONClient{
|
||||
client: client,
|
||||
urls: urls,
|
||||
opts: clientOpts,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,10 +445,18 @@ func (c *libDetectorJSONClient) Detect(ctx context.Context, in *LibDetectRequest
|
||||
ctx = ctxsetters.WithServiceName(ctx, "LibDetector")
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Detect")
|
||||
out := new(DetectResponse)
|
||||
err := doJSONRequest(ctx, c.client, c.urls[0], in, out)
|
||||
err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
|
||||
if err != nil {
|
||||
twerr, ok := err.(twirp.Error)
|
||||
if !ok {
|
||||
twerr = twirp.InternalErrorWith(err)
|
||||
}
|
||||
callClientError(ctx, c.opts.Hooks, twerr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callClientResponseReceived(ctx, c.opts.Hooks)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -597,7 +653,7 @@ func (s *libDetectorServer) ServiceDescriptor() ([]byte, int) {
|
||||
}
|
||||
|
||||
func (s *libDetectorServer) ProtocGenTwirpVersion() string {
|
||||
return "v5.9.0"
|
||||
return "v5.10.1"
|
||||
}
|
||||
|
||||
func (s *libDetectorServer) PathPrefix() string {
|
||||
@@ -738,7 +794,7 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType
|
||||
}
|
||||
req.Header.Set("Accept", contentType)
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
req.Header.Set("Twirp-Version", "v5.9.0")
|
||||
req.Header.Set("Twirp-Version", "v5.10.1")
|
||||
return req, nil
|
||||
}
|
||||
|
||||
@@ -950,7 +1006,7 @@ func withoutRedirects(in *http.Client) *http.Client {
|
||||
}
|
||||
|
||||
// doProtobufRequest makes a Protobuf request to the remote Twirp service.
|
||||
func doProtobufRequest(ctx context.Context, client HTTPClient, url string, in, out proto.Message) (err error) {
|
||||
func doProtobufRequest(ctx context.Context, client HTTPClient, hooks *twirp.ClientHooks, url string, in, out proto.Message) (err error) {
|
||||
reqBodyBytes, err := proto.Marshal(in)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to marshal proto request")
|
||||
@@ -964,6 +1020,12 @@ func doProtobufRequest(ctx context.Context, client HTTPClient, url string, in, o
|
||||
if err != nil {
|
||||
return wrapInternal(err, "could not build request")
|
||||
}
|
||||
ctx, err = callClientRequestPrepared(ctx, hooks, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to do request")
|
||||
@@ -999,7 +1061,7 @@ func doProtobufRequest(ctx context.Context, client HTTPClient, url string, in, o
|
||||
}
|
||||
|
||||
// doJSONRequest makes a JSON request to the remote Twirp service.
|
||||
func doJSONRequest(ctx context.Context, client HTTPClient, url string, in, out proto.Message) (err error) {
|
||||
func doJSONRequest(ctx context.Context, client HTTPClient, hooks *twirp.ClientHooks, url string, in, out proto.Message) (err error) {
|
||||
reqBody := bytes.NewBuffer(nil)
|
||||
marshaler := &jsonpb.Marshaler{OrigName: true}
|
||||
if err = marshaler.Marshal(reqBody, in); err != nil {
|
||||
@@ -1013,6 +1075,12 @@ func doJSONRequest(ctx context.Context, client HTTPClient, url string, in, out p
|
||||
if err != nil {
|
||||
return wrapInternal(err, "could not build request")
|
||||
}
|
||||
ctx, err = callClientRequestPrepared(ctx, hooks, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to do request")
|
||||
@@ -1083,50 +1151,54 @@ func callError(ctx context.Context, h *twirp.ServerHooks, err twirp.Error) conte
|
||||
return h.Error(ctx, err)
|
||||
}
|
||||
|
||||
var twirpFileDescriptor0 = []byte{
|
||||
// 693 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0xc5, 0xf9, 0xb2, 0x33, 0xe9, 0x87, 0x59, 0x55, 0xaa, 0x49, 0xd5, 0x36, 0x0a, 0x97, 0x02,
|
||||
0x52, 0x22, 0xa5, 0x45, 0x9c, 0xa1, 0x2d, 0x6d, 0x20, 0x4d, 0x2b, 0xf7, 0x4b, 0x70, 0x89, 0x36,
|
||||
0xce, 0x24, 0x59, 0xd5, 0xc9, 0x9a, 0xdd, 0x6d, 0x44, 0x7e, 0x18, 0x27, 0x7e, 0x05, 0x3f, 0x86,
|
||||
0x3b, 0xf2, 0xae, 0x9d, 0x26, 0xa1, 0x42, 0xf4, 0xb6, 0x33, 0xef, 0xed, 0xec, 0xbc, 0x99, 0x67,
|
||||
0x43, 0x59, 0x44, 0x41, 0xbd, 0x87, 0x0a, 0x03, 0xc5, 0x45, 0x5d, 0xa2, 0x98, 0xb0, 0x00, 0x6b,
|
||||
0x91, 0xe0, 0x8a, 0x93, 0x35, 0x25, 0xd8, 0x64, 0x5a, 0x4b, 0xd1, 0xf2, 0xee, 0x80, 0xf3, 0x41,
|
||||
0x88, 0x75, 0x8d, 0x76, 0xef, 0xfb, 0x75, 0xc5, 0x46, 0x28, 0x15, 0x1d, 0x45, 0xe6, 0x42, 0xf5,
|
||||
0x97, 0x05, 0xeb, 0xe7, 0x97, 0x47, 0x9a, 0xef, 0xe3, 0xb7, 0x7b, 0x94, 0x8a, 0x6c, 0x41, 0x91,
|
||||
0xcb, 0x4e, 0x9f, 0x8e, 0x58, 0x38, 0xf5, 0xac, 0x8a, 0xb5, 0x57, 0xf4, 0x1d, 0x2e, 0x3f, 0xea,
|
||||
0x98, 0x6c, 0x82, 0xcd, 0x65, 0x67, 0x4c, 0x47, 0xe8, 0x65, 0x34, 0x54, 0xe0, 0xb2, 0x4d, 0x47,
|
||||
0x48, 0xf6, 0xc1, 0x89, 0x68, 0x70, 0x47, 0x07, 0x28, 0xbd, 0x6c, 0x25, 0xbb, 0x57, 0x6a, 0x6c,
|
||||
0xd6, 0x16, 0xbb, 0xa9, 0x5d, 0x18, 0xdc, 0x9f, 0x11, 0xc9, 0x36, 0x00, 0x1b, 0xd1, 0x01, 0x9a,
|
||||
0x82, 0x39, 0x5d, 0xb0, 0xa8, 0x33, 0xba, 0xe6, 0x01, 0xd8, 0x81, 0x40, 0xaa, 0xb0, 0xe7, 0xe5,
|
||||
0x2b, 0xd6, 0x5e, 0xa9, 0x51, 0xae, 0x19, 0x41, 0xb5, 0x54, 0x50, 0xed, 0x2a, 0x15, 0xe4, 0xa7,
|
||||
0xd4, 0xea, 0x08, 0xd6, 0x52, 0x41, 0x32, 0xe2, 0x63, 0x89, 0xe4, 0x04, 0xd6, 0x27, 0xf7, 0xe1,
|
||||
0x18, 0x05, 0xed, 0xb2, 0x90, 0x29, 0x86, 0xd2, 0xb3, 0x74, 0x8b, 0xdb, 0xcb, 0x2d, 0xde, 0xcc,
|
||||
0xd1, 0xa6, 0xfe, 0xf2, 0x2d, 0x42, 0x20, 0x87, 0x5c, 0x86, 0x5a, 0xba, 0xe3, 0xeb, 0x73, 0xf5,
|
||||
0xb7, 0x05, 0x76, 0xa2, 0x2c, 0xc6, 0xb5, 0x12, 0x33, 0x35, 0x7d, 0x26, 0x1e, 0xd8, 0x13, 0x14,
|
||||
0x92, 0xf1, 0x71, 0x32, 0xb1, 0x34, 0x8c, 0x11, 0x81, 0x21, 0x52, 0x89, 0x5e, 0xd6, 0x20, 0x49,
|
||||
0x48, 0x36, 0x20, 0x8f, 0x11, 0x0f, 0x86, 0x7a, 0x24, 0x79, 0xdf, 0x04, 0x71, 0x75, 0x2a, 0x82,
|
||||
0xa1, 0x9e, 0x45, 0xd1, 0xd7, 0x67, 0xf2, 0x02, 0x1c, 0x29, 0x02, 0x33, 0xbf, 0x82, 0x29, 0x22,
|
||||
0x45, 0xa0, 0xa7, 0xb7, 0x0b, 0xa5, 0x18, 0x4a, 0x1f, 0xb7, 0x35, 0x0a, 0x52, 0x04, 0x37, 0xc9,
|
||||
0xfb, 0x09, 0x21, 0xed, 0xc1, 0x99, 0x11, 0xfc, 0xa4, 0x8d, 0x2d, 0x28, 0xc6, 0x04, 0xd3, 0x4a,
|
||||
0x51, 0xb7, 0x12, 0xbf, 0x76, 0x1c, 0xc7, 0xd5, 0x9f, 0x16, 0xb8, 0x2d, 0xd6, 0xfd, 0xcb, 0x3b,
|
||||
0x7d, 0x16, 0x62, 0x27, 0xa2, 0x6a, 0x98, 0x7a, 0x27, 0x4e, 0x5c, 0x50, 0x35, 0x24, 0x6f, 0xa1,
|
||||
0x18, 0xb2, 0xae, 0xa0, 0x22, 0x5e, 0x40, 0xe6, 0x71, 0x8f, 0xb4, 0x34, 0x61, 0xea, 0x3f, 0x30,
|
||||
0x97, 0x4c, 0x92, 0xfd, 0x87, 0x49, 0x72, 0xff, 0x6f, 0x92, 0x77, 0x60, 0x27, 0x4f, 0x3d, 0x6d,
|
||||
0x69, 0xd5, 0x1f, 0x19, 0x58, 0x5d, 0x70, 0x09, 0x79, 0x05, 0xee, 0xbc, 0x4f, 0xa6, 0x1d, 0xd6,
|
||||
0x4b, 0x6a, 0x2d, 0xf8, 0x67, 0xda, 0xec, 0xc5, 0xdb, 0x8a, 0xee, 0x06, 0xf3, 0x9f, 0x8f, 0x1d,
|
||||
0xdd, 0x0d, 0xb4, 0x8c, 0x37, 0xf0, 0x9c, 0x8d, 0xa5, 0xa2, 0x61, 0x88, 0xbd, 0xd9, 0xce, 0x8c,
|
||||
0x58, 0x77, 0x06, 0xa4, 0x9b, 0x7b, 0x09, 0xab, 0x7d, 0xf6, 0x7d, 0x8e, 0x68, 0x3e, 0x9d, 0x15,
|
||||
0x9d, 0x4c, 0x49, 0x1b, 0x90, 0x57, 0x4c, 0x85, 0x98, 0xf8, 0xc5, 0x04, 0xa4, 0x02, 0xa5, 0x1e,
|
||||
0xca, 0x40, 0xb0, 0x48, 0xc5, 0x17, 0x8d, 0x67, 0xe6, 0x53, 0xe4, 0x00, 0x1c, 0x89, 0x13, 0x14,
|
||||
0x4c, 0x4d, 0xb5, 0x69, 0xd6, 0x1a, 0xde, 0xf2, 0x96, 0x2e, 0x13, 0xdc, 0x9f, 0x31, 0xc9, 0x0e,
|
||||
0x80, 0xc0, 0x3e, 0x0a, 0x1c, 0x07, 0x28, 0x3d, 0xa7, 0x92, 0x8d, 0xbd, 0xf4, 0x90, 0x79, 0x7d,
|
||||
0x04, 0x4e, 0x7a, 0x8b, 0x94, 0xc0, 0xbe, 0x6e, 0x7f, 0x6e, 0x9f, 0xdf, 0xb6, 0xdd, 0x67, 0xc4,
|
||||
0x86, 0x6c, 0xeb, 0xfc, 0xd6, 0xb5, 0x08, 0x40, 0xe1, 0xec, 0xf8, 0xa8, 0x79, 0x7d, 0xe6, 0x66,
|
||||
0x88, 0x03, 0xb9, 0xd3, 0xe6, 0xc9, 0xa9, 0x9b, 0x25, 0x2b, 0xe0, 0x1c, 0xfa, 0xcd, 0xab, 0xe6,
|
||||
0xe1, 0xfb, 0x96, 0x9b, 0x6b, 0xdc, 0x02, 0xa4, 0xbf, 0x2b, 0x2e, 0x48, 0x13, 0x0a, 0xe6, 0x4c,
|
||||
0x76, 0x97, 0x3b, 0x5c, 0xfa, 0xa9, 0x95, 0x77, 0x96, 0x09, 0x8b, 0xbf, 0x88, 0xc6, 0x17, 0x28,
|
||||
0xcd, 0xcc, 0xcc, 0x05, 0xf9, 0x34, 0xab, 0x5c, 0x79, 0xc4, 0xa1, 0x4f, 0x2a, 0xfd, 0x01, 0xbe,
|
||||
0x3a, 0x29, 0xd4, 0x2d, 0x68, 0x4f, 0xee, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x65, 0x1f, 0xdb,
|
||||
0x8d, 0xc5, 0x05, 0x00, 0x00,
|
||||
func callClientResponseReceived(ctx context.Context, h *twirp.ClientHooks) {
|
||||
if h == nil || h.ResponseReceived == nil {
|
||||
return
|
||||
}
|
||||
h.ResponseReceived(ctx)
|
||||
}
|
||||
|
||||
func callClientRequestPrepared(ctx context.Context, h *twirp.ClientHooks, req *http.Request) (context.Context, error) {
|
||||
if h == nil || h.RequestPrepared == nil {
|
||||
return ctx, nil
|
||||
}
|
||||
return h.RequestPrepared(ctx, req)
|
||||
}
|
||||
|
||||
func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) {
|
||||
if h == nil || h.Error == nil {
|
||||
return
|
||||
}
|
||||
h.Error(ctx, err)
|
||||
}
|
||||
|
||||
var twirpFileDescriptor0 = []byte{
|
||||
// 422 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xd1, 0x8a, 0xd3, 0x40,
|
||||
0x14, 0x86, 0xc9, 0xb6, 0x76, 0xdb, 0x53, 0xd8, 0x95, 0x01, 0x31, 0x64, 0xd1, 0x2d, 0xbd, 0xea,
|
||||
0xd5, 0x04, 0xbb, 0xe2, 0x03, 0x88, 0x0a, 0xca, 0xa2, 0x4b, 0x14, 0x45, 0x6f, 0xca, 0x64, 0xf6,
|
||||
0x34, 0x1d, 0x36, 0xd3, 0x93, 0xce, 0x4c, 0x0a, 0x79, 0x34, 0x9f, 0xc2, 0x57, 0x92, 0x4e, 0x98,
|
||||
0x6a, 0xa2, 0xe8, 0xde, 0x4d, 0xe6, 0xff, 0xcf, 0x7f, 0xce, 0xf9, 0x32, 0x90, 0x98, 0x4a, 0xa6,
|
||||
0xb7, 0xe8, 0x50, 0x3a, 0x32, 0xa9, 0x45, 0xb3, 0x57, 0x12, 0x79, 0x65, 0xc8, 0x11, 0x3b, 0x73,
|
||||
0x46, 0xed, 0x1b, 0x1e, 0xd4, 0xe4, 0xb2, 0x20, 0x2a, 0x4a, 0x4c, 0xbd, 0x9a, 0xd7, 0xeb, 0xd4,
|
||||
0x29, 0x8d, 0xd6, 0x09, 0x5d, 0xb5, 0x05, 0xc9, 0x8b, 0x42, 0xb9, 0x4d, 0x9d, 0x73, 0x49, 0x3a,
|
||||
0x15, 0xbb, 0x5a, 0x58, 0x94, 0xb5, 0x51, 0xae, 0x49, 0x7d, 0x50, 0x7a, 0x68, 0x25, 0x49, 0x6b,
|
||||
0xda, 0x76, 0x1b, 0xcd, 0x7f, 0x44, 0x70, 0xfe, 0xe1, 0xe3, 0x2b, 0xdf, 0x27, 0xc3, 0x5d, 0x8d,
|
||||
0xd6, 0xb1, 0x0b, 0x98, 0x90, 0x5d, 0xad, 0x85, 0x56, 0x65, 0x13, 0x47, 0xb3, 0x68, 0x31, 0xc9,
|
||||
0xc6, 0x64, 0xdf, 0xf8, 0x6f, 0xf6, 0x18, 0x4e, 0xc9, 0xae, 0xb6, 0x42, 0x63, 0x7c, 0xe2, 0xa5,
|
||||
0x11, 0xd9, 0xf7, 0x42, 0x23, 0x7b, 0x06, 0xe3, 0x4a, 0xc8, 0x3b, 0x51, 0xa0, 0x8d, 0x07, 0xb3,
|
||||
0xc1, 0x62, 0xba, 0x7c, 0xc4, 0xdb, 0x2d, 0xda, 0xc6, 0xfc, 0xa6, 0x55, 0xb3, 0xa3, 0x8d, 0x3d,
|
||||
0x01, 0x50, 0x5a, 0x14, 0xd8, 0xc6, 0x0d, 0x7d, 0xdc, 0xc4, 0xdf, 0xf8, 0xc4, 0xe7, 0x70, 0x2a,
|
||||
0x0d, 0x0a, 0x87, 0xb7, 0xf1, 0x83, 0x59, 0xb4, 0x98, 0x2e, 0x13, 0xde, 0x62, 0xe0, 0x01, 0x03,
|
||||
0xff, 0x14, 0x30, 0x64, 0xc1, 0x3a, 0xbf, 0x83, 0xb3, 0xb0, 0x8e, 0xad, 0x68, 0x6b, 0x91, 0xbd,
|
||||
0x86, 0xf3, 0x7d, 0x5d, 0x6e, 0xd1, 0x88, 0x5c, 0x95, 0xca, 0x29, 0xb4, 0x71, 0xe4, 0x07, 0xbc,
|
||||
0xe8, 0x0e, 0xf8, 0xf9, 0x37, 0x53, 0x93, 0xf5, 0x6b, 0x18, 0x83, 0x21, 0x92, 0x2d, 0xfd, 0xda,
|
||||
0xe3, 0xcc, 0x9f, 0xe7, 0xdf, 0x23, 0x78, 0x78, 0xad, 0xf2, 0x3f, 0xf8, 0xad, 0x55, 0x89, 0xab,
|
||||
0x4a, 0xb8, 0x4d, 0xe0, 0x77, 0xb8, 0xb8, 0x11, 0x6e, 0xc3, 0xae, 0x60, 0x52, 0xaa, 0xdc, 0x08,
|
||||
0x73, 0x18, 0xe3, 0xe4, 0x6f, 0x9c, 0xae, 0xbd, 0xdc, 0x64, 0xbf, 0x7c, 0x3d, 0x50, 0x83, 0x7f,
|
||||
0x80, 0x1a, 0xde, 0x1b, 0xd4, 0xf2, 0x0b, 0x40, 0xf8, 0xf3, 0x64, 0xd8, 0x5b, 0x18, 0xb5, 0x67,
|
||||
0x76, 0xc9, 0xbb, 0x8f, 0x8f, 0xf7, 0xde, 0x47, 0xf2, 0xb4, 0x6f, 0xe8, 0xf2, 0x5e, 0x7e, 0x85,
|
||||
0xe9, 0x91, 0x09, 0x19, 0xf6, 0xee, 0x98, 0x3c, 0xeb, 0x17, 0xf6, 0xd1, 0xfd, 0x2f, 0xfa, 0x25,
|
||||
0x7c, 0x1b, 0x07, 0x29, 0x1f, 0xf9, 0xe5, 0xae, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0x60, 0x68,
|
||||
0xcc, 0x2b, 0x48, 0x03, 0x00, 0x00,
|
||||
}
|
||||
|
||||
263
rpc/scanner/service.pb.go
Normal file
263
rpc/scanner/service.pb.go
Normal file
@@ -0,0 +1,263 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: rpc/scanner/service.proto
|
||||
|
||||
package scanner
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
common "github.com/aquasecurity/trivy/rpc/common"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type ScanRequest struct {
|
||||
Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
|
||||
ImageId string `protobuf:"bytes,2,opt,name=image_id,json=imageId,proto3" json:"image_id,omitempty"`
|
||||
LayerIds []string `protobuf:"bytes,3,rep,name=layer_ids,json=layerIds,proto3" json:"layer_ids,omitempty"`
|
||||
Options *ScanOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ScanRequest) Reset() { *m = ScanRequest{} }
|
||||
func (m *ScanRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ScanRequest) ProtoMessage() {}
|
||||
func (*ScanRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_60d0e837512b18d4, []int{0}
|
||||
}
|
||||
|
||||
func (m *ScanRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ScanRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ScanRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ScanRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ScanRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ScanRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ScanRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_ScanRequest.Size(m)
|
||||
}
|
||||
func (m *ScanRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ScanRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ScanRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ScanRequest) GetTarget() string {
|
||||
if m != nil {
|
||||
return m.Target
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ScanRequest) GetImageId() string {
|
||||
if m != nil {
|
||||
return m.ImageId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ScanRequest) GetLayerIds() []string {
|
||||
if m != nil {
|
||||
return m.LayerIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ScanRequest) GetOptions() *ScanOptions {
|
||||
if m != nil {
|
||||
return m.Options
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ScanOptions struct {
|
||||
VulnType []string `protobuf:"bytes,1,rep,name=vuln_type,json=vulnType,proto3" json:"vuln_type,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ScanOptions) Reset() { *m = ScanOptions{} }
|
||||
func (m *ScanOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*ScanOptions) ProtoMessage() {}
|
||||
func (*ScanOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_60d0e837512b18d4, []int{1}
|
||||
}
|
||||
|
||||
func (m *ScanOptions) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ScanOptions.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ScanOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ScanOptions.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ScanOptions) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ScanOptions.Merge(m, src)
|
||||
}
|
||||
func (m *ScanOptions) XXX_Size() int {
|
||||
return xxx_messageInfo_ScanOptions.Size(m)
|
||||
}
|
||||
func (m *ScanOptions) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ScanOptions.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ScanOptions proto.InternalMessageInfo
|
||||
|
||||
func (m *ScanOptions) GetVulnType() []string {
|
||||
if m != nil {
|
||||
return m.VulnType
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ScanResponse struct {
|
||||
Os *common.OS `protobuf:"bytes,1,opt,name=os,proto3" json:"os,omitempty"`
|
||||
Eosl bool `protobuf:"varint,2,opt,name=eosl,proto3" json:"eosl,omitempty"`
|
||||
Results []*Result `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ScanResponse) Reset() { *m = ScanResponse{} }
|
||||
func (m *ScanResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ScanResponse) ProtoMessage() {}
|
||||
func (*ScanResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_60d0e837512b18d4, []int{2}
|
||||
}
|
||||
|
||||
func (m *ScanResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ScanResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ScanResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ScanResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ScanResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ScanResponse.Merge(m, src)
|
||||
}
|
||||
func (m *ScanResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_ScanResponse.Size(m)
|
||||
}
|
||||
func (m *ScanResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ScanResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ScanResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *ScanResponse) GetOs() *common.OS {
|
||||
if m != nil {
|
||||
return m.Os
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ScanResponse) GetEosl() bool {
|
||||
if m != nil {
|
||||
return m.Eosl
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *ScanResponse) GetResults() []*Result {
|
||||
if m != nil {
|
||||
return m.Results
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Result is the same as github.com/aquasecurity/trivy/pkg/report.Result
|
||||
type Result struct {
|
||||
Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
|
||||
Vulnerabilities []*common.Vulnerability `protobuf:"bytes,2,rep,name=vulnerabilities,proto3" json:"vulnerabilities,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Result) Reset() { *m = Result{} }
|
||||
func (m *Result) String() string { return proto.CompactTextString(m) }
|
||||
func (*Result) ProtoMessage() {}
|
||||
func (*Result) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_60d0e837512b18d4, []int{3}
|
||||
}
|
||||
|
||||
func (m *Result) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Result.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Result) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Result.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Result) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Result.Merge(m, src)
|
||||
}
|
||||
func (m *Result) XXX_Size() int {
|
||||
return xxx_messageInfo_Result.Size(m)
|
||||
}
|
||||
func (m *Result) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Result.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Result proto.InternalMessageInfo
|
||||
|
||||
func (m *Result) GetTarget() string {
|
||||
if m != nil {
|
||||
return m.Target
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Result) GetVulnerabilities() []*common.Vulnerability {
|
||||
if m != nil {
|
||||
return m.Vulnerabilities
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*ScanRequest)(nil), "trivy.scanner.v1.ScanRequest")
|
||||
proto.RegisterType((*ScanOptions)(nil), "trivy.scanner.v1.ScanOptions")
|
||||
proto.RegisterType((*ScanResponse)(nil), "trivy.scanner.v1.ScanResponse")
|
||||
proto.RegisterType((*Result)(nil), "trivy.scanner.v1.Result")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("rpc/scanner/service.proto", fileDescriptor_60d0e837512b18d4) }
|
||||
|
||||
var fileDescriptor_60d0e837512b18d4 = []byte{
|
||||
// 361 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xc1, 0x6b, 0xbb, 0x30,
|
||||
0x18, 0x45, 0x5b, 0x6a, 0x8d, 0x3f, 0xf8, 0x95, 0x1c, 0x86, 0x6d, 0xd9, 0x10, 0x4f, 0x65, 0x07,
|
||||
0x65, 0x0e, 0xb6, 0xfb, 0xa0, 0x87, 0x9e, 0x3a, 0xd2, 0xb1, 0xc3, 0x2e, 0x25, 0xd5, 0x0f, 0x17,
|
||||
0x50, 0x63, 0x93, 0x28, 0xf3, 0x1f, 0xd9, 0xdf, 0x3b, 0x4c, 0x2c, 0xac, 0x1d, 0xbd, 0x25, 0xef,
|
||||
0x3d, 0xbf, 0xf7, 0xde, 0x67, 0xd0, 0x5c, 0xd4, 0x69, 0x2c, 0x53, 0x5a, 0x55, 0x20, 0x62, 0x09,
|
||||
0xa2, 0x65, 0x29, 0x44, 0xb5, 0xe0, 0x8a, 0xe3, 0x99, 0x12, 0xac, 0xed, 0xa2, 0x81, 0x8c, 0xda,
|
||||
0x87, 0xc5, 0x53, 0xce, 0xd4, 0x67, 0x73, 0x88, 0x52, 0x5e, 0xc6, 0xf4, 0xd8, 0x50, 0x09, 0x69,
|
||||
0x23, 0x98, 0xea, 0x62, 0xad, 0x8c, 0xfb, 0x51, 0x29, 0x2f, 0x4b, 0x5e, 0x9d, 0x4f, 0x0a, 0xbf,
|
||||
0x2d, 0xe4, 0xed, 0x52, 0x5a, 0x11, 0x38, 0x36, 0x20, 0x15, 0xbe, 0x41, 0x13, 0x45, 0x45, 0x0e,
|
||||
0xca, 0xb7, 0x02, 0x6b, 0xe5, 0x92, 0xe1, 0x86, 0xe7, 0x68, 0xca, 0x4a, 0x9a, 0xc3, 0x9e, 0x65,
|
||||
0xbe, 0xad, 0x19, 0x47, 0xdf, 0x37, 0x19, 0x5e, 0x22, 0xb7, 0xa0, 0x1d, 0x88, 0x3d, 0xcb, 0xa4,
|
||||
0x3f, 0x0a, 0x46, 0x2b, 0x97, 0x4c, 0x35, 0xb0, 0xc9, 0x24, 0x7e, 0x46, 0x0e, 0xaf, 0x15, 0xe3,
|
||||
0x95, 0xf4, 0xc7, 0x81, 0xb5, 0xf2, 0x92, 0xdb, 0xe8, 0x32, 0x7b, 0xd4, 0xfb, 0x6f, 0x8d, 0x88,
|
||||
0x9c, 0xd4, 0xe1, 0xbd, 0xc9, 0x35, 0xe0, 0xbd, 0x49, 0xdb, 0x14, 0xd5, 0x5e, 0x75, 0x35, 0xf8,
|
||||
0x96, 0x31, 0xe9, 0x81, 0xb7, 0xae, 0x86, 0xf0, 0x0b, 0xfd, 0x33, 0x1d, 0x64, 0xcd, 0x2b, 0x09,
|
||||
0x38, 0x40, 0x36, 0x97, 0xba, 0x80, 0x97, 0xcc, 0x06, 0x3f, 0xd3, 0x3e, 0xda, 0xee, 0x88, 0xcd,
|
||||
0x25, 0xc6, 0x68, 0x0c, 0x5c, 0x16, 0xba, 0xca, 0x94, 0xe8, 0x33, 0x4e, 0x90, 0x23, 0x40, 0x36,
|
||||
0x85, 0x32, 0x2d, 0xbc, 0xc4, 0xff, 0x1b, 0x95, 0x68, 0x01, 0x39, 0x09, 0xc3, 0x1c, 0x4d, 0x0c,
|
||||
0x74, 0x75, 0x71, 0x6b, 0xf4, 0xbf, 0xcf, 0x09, 0x82, 0x1e, 0x58, 0xc1, 0x14, 0x03, 0xe9, 0xdb,
|
||||
0x7a, 0xfa, 0xf2, 0x3c, 0xd8, 0xfb, 0x2f, 0x51, 0x47, 0x2e, 0xbf, 0x49, 0x5e, 0x91, 0xb3, 0x33,
|
||||
0x31, 0xf0, 0x1a, 0x8d, 0xfb, 0x23, 0xbe, 0xb2, 0xc9, 0xe1, 0x4f, 0x2e, 0xee, 0xae, 0xd1, 0x66,
|
||||
0x49, 0x2f, 0xee, 0x87, 0x33, 0x50, 0x87, 0x89, 0x7e, 0x0b, 0x8f, 0x3f, 0x01, 0x00, 0x00, 0xff,
|
||||
0xff, 0x22, 0xf3, 0x23, 0xc0, 0x72, 0x02, 0x00, 0x00,
|
||||
}
|
||||
33
rpc/scanner/service.proto
Normal file
33
rpc/scanner/service.proto
Normal file
@@ -0,0 +1,33 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package trivy.scanner.v1;
|
||||
option go_package = "scanner";
|
||||
|
||||
import "github.com/aquasecurity/trivy/rpc/common/service.proto";
|
||||
|
||||
service Scanner {
|
||||
rpc Scan(ScanRequest) returns (ScanResponse);
|
||||
}
|
||||
|
||||
message ScanRequest {
|
||||
string target = 1; // image name or tar file path
|
||||
string image_id = 2;
|
||||
repeated string layer_ids = 3;
|
||||
ScanOptions options = 4;
|
||||
}
|
||||
|
||||
message ScanOptions {
|
||||
repeated string vuln_type = 1;
|
||||
}
|
||||
|
||||
message ScanResponse {
|
||||
common.OS os = 1;
|
||||
bool eosl = 2;
|
||||
repeated Result results = 3;
|
||||
}
|
||||
|
||||
// Result is the same as github.com/aquasecurity/trivy/pkg/report.Result
|
||||
message Result {
|
||||
string target = 1;
|
||||
repeated common.Vulnerability vulnerabilities = 2;
|
||||
}
|
||||
884
rpc/scanner/service.twirp.go
Normal file
884
rpc/scanner/service.twirp.go
Normal file
@@ -0,0 +1,884 @@
|
||||
// Code generated by protoc-gen-twirp v5.10.1, DO NOT EDIT.
|
||||
// source: rpc/scanner/service.proto
|
||||
|
||||
/*
|
||||
Package scanner is a generated twirp stub package.
|
||||
This code was generated with github.com/twitchtv/twirp/protoc-gen-twirp v5.10.1.
|
||||
|
||||
It is generated from these files:
|
||||
rpc/scanner/service.proto
|
||||
*/
|
||||
package scanner
|
||||
|
||||
import bytes "bytes"
|
||||
import strings "strings"
|
||||
import context "context"
|
||||
import fmt "fmt"
|
||||
import ioutil "io/ioutil"
|
||||
import http "net/http"
|
||||
import strconv "strconv"
|
||||
|
||||
import jsonpb "github.com/golang/protobuf/jsonpb"
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import twirp "github.com/twitchtv/twirp"
|
||||
import ctxsetters "github.com/twitchtv/twirp/ctxsetters"
|
||||
|
||||
// Imports only used by utility functions:
|
||||
import io "io"
|
||||
import json "encoding/json"
|
||||
import url "net/url"
|
||||
|
||||
// =================
|
||||
// Scanner Interface
|
||||
// =================
|
||||
|
||||
type Scanner interface {
|
||||
Scan(context.Context, *ScanRequest) (*ScanResponse, error)
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Scanner Protobuf Client
|
||||
// =======================
|
||||
|
||||
type scannerProtobufClient struct {
|
||||
client HTTPClient
|
||||
urls [1]string
|
||||
opts twirp.ClientOptions
|
||||
}
|
||||
|
||||
// NewScannerProtobufClient creates a Protobuf client that implements the Scanner interface.
|
||||
// It communicates using Protobuf and can be configured with a custom HTTPClient.
|
||||
func NewScannerProtobufClient(addr string, client HTTPClient, opts ...twirp.ClientOption) Scanner {
|
||||
if c, ok := client.(*http.Client); ok {
|
||||
client = withoutRedirects(c)
|
||||
}
|
||||
|
||||
clientOpts := twirp.ClientOptions{}
|
||||
for _, o := range opts {
|
||||
o(&clientOpts)
|
||||
}
|
||||
|
||||
prefix := urlBase(addr) + ScannerPathPrefix
|
||||
urls := [1]string{
|
||||
prefix + "Scan",
|
||||
}
|
||||
|
||||
return &scannerProtobufClient{
|
||||
client: client,
|
||||
urls: urls,
|
||||
opts: clientOpts,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *scannerProtobufClient) Scan(ctx context.Context, in *ScanRequest) (*ScanResponse, error) {
|
||||
ctx = ctxsetters.WithPackageName(ctx, "trivy.scanner.v1")
|
||||
ctx = ctxsetters.WithServiceName(ctx, "Scanner")
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Scan")
|
||||
out := new(ScanResponse)
|
||||
err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
|
||||
if err != nil {
|
||||
twerr, ok := err.(twirp.Error)
|
||||
if !ok {
|
||||
twerr = twirp.InternalErrorWith(err)
|
||||
}
|
||||
callClientError(ctx, c.opts.Hooks, twerr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callClientResponseReceived(ctx, c.opts.Hooks)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ===================
|
||||
// Scanner JSON Client
|
||||
// ===================
|
||||
|
||||
type scannerJSONClient struct {
|
||||
client HTTPClient
|
||||
urls [1]string
|
||||
opts twirp.ClientOptions
|
||||
}
|
||||
|
||||
// NewScannerJSONClient creates a JSON client that implements the Scanner interface.
|
||||
// It communicates using JSON and can be configured with a custom HTTPClient.
|
||||
func NewScannerJSONClient(addr string, client HTTPClient, opts ...twirp.ClientOption) Scanner {
|
||||
if c, ok := client.(*http.Client); ok {
|
||||
client = withoutRedirects(c)
|
||||
}
|
||||
|
||||
clientOpts := twirp.ClientOptions{}
|
||||
for _, o := range opts {
|
||||
o(&clientOpts)
|
||||
}
|
||||
|
||||
prefix := urlBase(addr) + ScannerPathPrefix
|
||||
urls := [1]string{
|
||||
prefix + "Scan",
|
||||
}
|
||||
|
||||
return &scannerJSONClient{
|
||||
client: client,
|
||||
urls: urls,
|
||||
opts: clientOpts,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *scannerJSONClient) Scan(ctx context.Context, in *ScanRequest) (*ScanResponse, error) {
|
||||
ctx = ctxsetters.WithPackageName(ctx, "trivy.scanner.v1")
|
||||
ctx = ctxsetters.WithServiceName(ctx, "Scanner")
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Scan")
|
||||
out := new(ScanResponse)
|
||||
err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out)
|
||||
if err != nil {
|
||||
twerr, ok := err.(twirp.Error)
|
||||
if !ok {
|
||||
twerr = twirp.InternalErrorWith(err)
|
||||
}
|
||||
callClientError(ctx, c.opts.Hooks, twerr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callClientResponseReceived(ctx, c.opts.Hooks)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ======================
|
||||
// Scanner Server Handler
|
||||
// ======================
|
||||
|
||||
type scannerServer struct {
|
||||
Scanner
|
||||
hooks *twirp.ServerHooks
|
||||
}
|
||||
|
||||
func NewScannerServer(svc Scanner, hooks *twirp.ServerHooks) TwirpServer {
|
||||
return &scannerServer{
|
||||
Scanner: svc,
|
||||
hooks: hooks,
|
||||
}
|
||||
}
|
||||
|
||||
// writeError writes an HTTP response with a valid Twirp error format, and triggers hooks.
|
||||
// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err)
|
||||
func (s *scannerServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) {
|
||||
writeError(ctx, resp, err, s.hooks)
|
||||
}
|
||||
|
||||
// ScannerPathPrefix is used for all URL paths on a twirp Scanner server.
|
||||
// Requests are always: POST ScannerPathPrefix/method
|
||||
// It can be used in an HTTP mux to route twirp requests along with non-twirp requests on other routes.
|
||||
const ScannerPathPrefix = "/twirp/trivy.scanner.v1.Scanner/"
|
||||
|
||||
func (s *scannerServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
||||
ctx := req.Context()
|
||||
ctx = ctxsetters.WithPackageName(ctx, "trivy.scanner.v1")
|
||||
ctx = ctxsetters.WithServiceName(ctx, "Scanner")
|
||||
ctx = ctxsetters.WithResponseWriter(ctx, resp)
|
||||
|
||||
var err error
|
||||
ctx, err = callRequestReceived(ctx, s.hooks)
|
||||
if err != nil {
|
||||
s.writeError(ctx, resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Method != "POST" {
|
||||
msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method)
|
||||
err = badRouteError(msg, req.Method, req.URL.Path)
|
||||
s.writeError(ctx, resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
switch req.URL.Path {
|
||||
case "/twirp/trivy.scanner.v1.Scanner/Scan":
|
||||
s.serveScan(ctx, resp, req)
|
||||
return
|
||||
default:
|
||||
msg := fmt.Sprintf("no handler for path %q", req.URL.Path)
|
||||
err = badRouteError(msg, req.Method, req.URL.Path)
|
||||
s.writeError(ctx, resp, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *scannerServer) serveScan(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
||||
header := req.Header.Get("Content-Type")
|
||||
i := strings.Index(header, ";")
|
||||
if i == -1 {
|
||||
i = len(header)
|
||||
}
|
||||
switch strings.TrimSpace(strings.ToLower(header[:i])) {
|
||||
case "application/json":
|
||||
s.serveScanJSON(ctx, resp, req)
|
||||
case "application/protobuf":
|
||||
s.serveScanProtobuf(ctx, resp, req)
|
||||
default:
|
||||
msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type"))
|
||||
twerr := badRouteError(msg, req.Method, req.URL.Path)
|
||||
s.writeError(ctx, resp, twerr)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *scannerServer) serveScanJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
||||
var err error
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Scan")
|
||||
ctx, err = callRequestRouted(ctx, s.hooks)
|
||||
if err != nil {
|
||||
s.writeError(ctx, resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
reqContent := new(ScanRequest)
|
||||
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
||||
if err = unmarshaler.Unmarshal(req.Body, reqContent); err != nil {
|
||||
s.writeError(ctx, resp, malformedRequestError("the json request could not be decoded"))
|
||||
return
|
||||
}
|
||||
|
||||
// Call service method
|
||||
var respContent *ScanResponse
|
||||
func() {
|
||||
defer ensurePanicResponses(ctx, resp, s.hooks)
|
||||
respContent, err = s.Scanner.Scan(ctx, reqContent)
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
s.writeError(ctx, resp, err)
|
||||
return
|
||||
}
|
||||
if respContent == nil {
|
||||
s.writeError(ctx, resp, twirp.InternalError("received a nil *ScanResponse and nil error while calling Scan. nil responses are not supported"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx = callResponsePrepared(ctx, s.hooks)
|
||||
|
||||
var buf bytes.Buffer
|
||||
marshaler := &jsonpb.Marshaler{OrigName: true}
|
||||
if err = marshaler.Marshal(&buf, respContent); err != nil {
|
||||
s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
||||
respBytes := buf.Bytes()
|
||||
resp.Header().Set("Content-Type", "application/json")
|
||||
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
|
||||
if n, err := resp.Write(respBytes); err != nil {
|
||||
msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error())
|
||||
twerr := twirp.NewError(twirp.Unknown, msg)
|
||||
callError(ctx, s.hooks, twerr)
|
||||
}
|
||||
callResponseSent(ctx, s.hooks)
|
||||
}
|
||||
|
||||
func (s *scannerServer) serveScanProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
|
||||
var err error
|
||||
ctx = ctxsetters.WithMethodName(ctx, "Scan")
|
||||
ctx, err = callRequestRouted(ctx, s.hooks)
|
||||
if err != nil {
|
||||
s.writeError(ctx, resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
buf, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
s.writeError(ctx, resp, wrapInternal(err, "failed to read request body"))
|
||||
return
|
||||
}
|
||||
reqContent := new(ScanRequest)
|
||||
if err = proto.Unmarshal(buf, reqContent); err != nil {
|
||||
s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded"))
|
||||
return
|
||||
}
|
||||
|
||||
// Call service method
|
||||
var respContent *ScanResponse
|
||||
func() {
|
||||
defer ensurePanicResponses(ctx, resp, s.hooks)
|
||||
respContent, err = s.Scanner.Scan(ctx, reqContent)
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
s.writeError(ctx, resp, err)
|
||||
return
|
||||
}
|
||||
if respContent == nil {
|
||||
s.writeError(ctx, resp, twirp.InternalError("received a nil *ScanResponse and nil error while calling Scan. nil responses are not supported"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx = callResponsePrepared(ctx, s.hooks)
|
||||
|
||||
respBytes, err := proto.Marshal(respContent)
|
||||
if err != nil {
|
||||
s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK)
|
||||
resp.Header().Set("Content-Type", "application/protobuf")
|
||||
resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes)))
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
if n, err := resp.Write(respBytes); err != nil {
|
||||
msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error())
|
||||
twerr := twirp.NewError(twirp.Unknown, msg)
|
||||
callError(ctx, s.hooks, twerr)
|
||||
}
|
||||
callResponseSent(ctx, s.hooks)
|
||||
}
|
||||
|
||||
func (s *scannerServer) ServiceDescriptor() ([]byte, int) {
|
||||
return twirpFileDescriptor0, 0
|
||||
}
|
||||
|
||||
func (s *scannerServer) ProtocGenTwirpVersion() string {
|
||||
return "v5.10.1"
|
||||
}
|
||||
|
||||
func (s *scannerServer) PathPrefix() string {
|
||||
return ScannerPathPrefix
|
||||
}
|
||||
|
||||
// =====
|
||||
// Utils
|
||||
// =====
|
||||
|
||||
// HTTPClient is the interface used by generated clients to send HTTP requests.
|
||||
// It is fulfilled by *(net/http).Client, which is sufficient for most users.
|
||||
// Users can provide their own implementation for special retry policies.
|
||||
//
|
||||
// HTTPClient implementations should not follow redirects. Redirects are
|
||||
// automatically disabled if *(net/http).Client is passed to client
|
||||
// constructors. See the withoutRedirects function in this file for more
|
||||
// details.
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// TwirpServer is the interface generated server structs will support: they're
|
||||
// HTTP handlers with additional methods for accessing metadata about the
|
||||
// service. Those accessors are a low-level API for building reflection tools.
|
||||
// Most people can think of TwirpServers as just http.Handlers.
|
||||
type TwirpServer interface {
|
||||
http.Handler
|
||||
// ServiceDescriptor returns gzipped bytes describing the .proto file that
|
||||
// this service was generated from. Once unzipped, the bytes can be
|
||||
// unmarshalled as a
|
||||
// github.com/golang/protobuf/protoc-gen-go/descriptor.FileDescriptorProto.
|
||||
//
|
||||
// The returned integer is the index of this particular service within that
|
||||
// FileDescriptorProto's 'Service' slice of ServiceDescriptorProtos. This is a
|
||||
// low-level field, expected to be used for reflection.
|
||||
ServiceDescriptor() ([]byte, int)
|
||||
// ProtocGenTwirpVersion is the semantic version string of the version of
|
||||
// twirp used to generate this file.
|
||||
ProtocGenTwirpVersion() string
|
||||
// PathPrefix returns the HTTP URL path prefix for all methods handled by this
|
||||
// service. This can be used with an HTTP mux to route twirp requests
|
||||
// alongside non-twirp requests on one HTTP listener.
|
||||
PathPrefix() string
|
||||
}
|
||||
|
||||
// WriteError writes an HTTP response with a valid Twirp error format (code, msg, meta).
|
||||
// Useful outside of the Twirp server (e.g. http middleware), but does not trigger hooks.
|
||||
// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err)
|
||||
func WriteError(resp http.ResponseWriter, err error) {
|
||||
writeError(context.Background(), resp, err, nil)
|
||||
}
|
||||
|
||||
// writeError writes Twirp errors in the response and triggers hooks.
|
||||
func writeError(ctx context.Context, resp http.ResponseWriter, err error, hooks *twirp.ServerHooks) {
|
||||
// Non-twirp errors are wrapped as Internal (default)
|
||||
twerr, ok := err.(twirp.Error)
|
||||
if !ok {
|
||||
twerr = twirp.InternalErrorWith(err)
|
||||
}
|
||||
|
||||
statusCode := twirp.ServerHTTPStatusFromErrorCode(twerr.Code())
|
||||
ctx = ctxsetters.WithStatusCode(ctx, statusCode)
|
||||
ctx = callError(ctx, hooks, twerr)
|
||||
|
||||
respBody := marshalErrorToJSON(twerr)
|
||||
|
||||
resp.Header().Set("Content-Type", "application/json") // Error responses are always JSON
|
||||
resp.Header().Set("Content-Length", strconv.Itoa(len(respBody)))
|
||||
resp.WriteHeader(statusCode) // set HTTP status code and send response
|
||||
|
||||
_, writeErr := resp.Write(respBody)
|
||||
if writeErr != nil {
|
||||
// We have three options here. We could log the error, call the Error
|
||||
// hook, or just silently ignore the error.
|
||||
//
|
||||
// Logging is unacceptable because we don't have a user-controlled
|
||||
// logger; writing out to stderr without permission is too rude.
|
||||
//
|
||||
// Calling the Error hook would confuse users: it would mean the Error
|
||||
// hook got called twice for one request, which is likely to lead to
|
||||
// duplicated log messages and metrics, no matter how well we document
|
||||
// the behavior.
|
||||
//
|
||||
// Silently ignoring the error is our least-bad option. It's highly
|
||||
// likely that the connection is broken and the original 'err' says
|
||||
// so anyway.
|
||||
_ = writeErr
|
||||
}
|
||||
|
||||
callResponseSent(ctx, hooks)
|
||||
}
|
||||
|
||||
// urlBase helps ensure that addr specifies a scheme. If it is unparsable
|
||||
// as a URL, it returns addr unchanged.
|
||||
func urlBase(addr string) string {
|
||||
// If the addr specifies a scheme, use it. If not, default to
|
||||
// http. If url.Parse fails on it, return it unchanged.
|
||||
url, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return addr
|
||||
}
|
||||
if url.Scheme == "" {
|
||||
url.Scheme = "http"
|
||||
}
|
||||
return url.String()
|
||||
}
|
||||
|
||||
// getCustomHTTPReqHeaders retrieves a copy of any headers that are set in
|
||||
// a context through the twirp.WithHTTPRequestHeaders function.
|
||||
// If there are no headers set, or if they have the wrong type, nil is returned.
|
||||
func getCustomHTTPReqHeaders(ctx context.Context) http.Header {
|
||||
header, ok := twirp.HTTPRequestHeaders(ctx)
|
||||
if !ok || header == nil {
|
||||
return nil
|
||||
}
|
||||
copied := make(http.Header)
|
||||
for k, vv := range header {
|
||||
if vv == nil {
|
||||
copied[k] = nil
|
||||
continue
|
||||
}
|
||||
copied[k] = make([]string, len(vv))
|
||||
copy(copied[k], vv)
|
||||
}
|
||||
return copied
|
||||
}
|
||||
|
||||
// newRequest makes an http.Request from a client, adding common headers.
|
||||
func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType string) (*http.Request, error) {
|
||||
req, err := http.NewRequest("POST", url, reqBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
if customHeader := getCustomHTTPReqHeaders(ctx); customHeader != nil {
|
||||
req.Header = customHeader
|
||||
}
|
||||
req.Header.Set("Accept", contentType)
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
req.Header.Set("Twirp-Version", "v5.10.1")
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// JSON serialization for errors
|
||||
type twerrJSON struct {
|
||||
Code string `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Meta map[string]string `json:"meta,omitempty"`
|
||||
}
|
||||
|
||||
// marshalErrorToJSON returns JSON from a twirp.Error, that can be used as HTTP error response body.
|
||||
// If serialization fails, it will use a descriptive Internal error instead.
|
||||
func marshalErrorToJSON(twerr twirp.Error) []byte {
|
||||
// make sure that msg is not too large
|
||||
msg := twerr.Msg()
|
||||
if len(msg) > 1e6 {
|
||||
msg = msg[:1e6]
|
||||
}
|
||||
|
||||
tj := twerrJSON{
|
||||
Code: string(twerr.Code()),
|
||||
Msg: msg,
|
||||
Meta: twerr.MetaMap(),
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(&tj)
|
||||
if err != nil {
|
||||
buf = []byte("{\"type\": \"" + twirp.Internal + "\", \"msg\": \"There was an error but it could not be serialized into JSON\"}") // fallback
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
// errorFromResponse builds a twirp.Error from a non-200 HTTP response.
|
||||
// If the response has a valid serialized Twirp error, then it's returned.
|
||||
// If not, the response status code is used to generate a similar twirp
|
||||
// error. See twirpErrorFromIntermediary for more info on intermediary errors.
|
||||
func errorFromResponse(resp *http.Response) twirp.Error {
|
||||
statusCode := resp.StatusCode
|
||||
statusText := http.StatusText(statusCode)
|
||||
|
||||
if isHTTPRedirect(statusCode) {
|
||||
// Unexpected redirect: it must be an error from an intermediary.
|
||||
// Twirp clients don't follow redirects automatically, Twirp only handles
|
||||
// POST requests, redirects should only happen on GET and HEAD requests.
|
||||
location := resp.Header.Get("Location")
|
||||
msg := fmt.Sprintf("unexpected HTTP status code %d %q received, Location=%q", statusCode, statusText, location)
|
||||
return twirpErrorFromIntermediary(statusCode, msg, location)
|
||||
}
|
||||
|
||||
respBodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to read server error response body")
|
||||
}
|
||||
|
||||
var tj twerrJSON
|
||||
dec := json.NewDecoder(bytes.NewReader(respBodyBytes))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&tj); err != nil || tj.Code == "" {
|
||||
// Invalid JSON response; it must be an error from an intermediary.
|
||||
msg := fmt.Sprintf("Error from intermediary with HTTP status code %d %q", statusCode, statusText)
|
||||
return twirpErrorFromIntermediary(statusCode, msg, string(respBodyBytes))
|
||||
}
|
||||
|
||||
errorCode := twirp.ErrorCode(tj.Code)
|
||||
if !twirp.IsValidErrorCode(errorCode) {
|
||||
msg := "invalid type returned from server error response: " + tj.Code
|
||||
return twirp.InternalError(msg)
|
||||
}
|
||||
|
||||
twerr := twirp.NewError(errorCode, tj.Msg)
|
||||
for k, v := range tj.Meta {
|
||||
twerr = twerr.WithMeta(k, v)
|
||||
}
|
||||
return twerr
|
||||
}
|
||||
|
||||
// twirpErrorFromIntermediary maps HTTP errors from non-twirp sources to twirp errors.
|
||||
// The mapping is similar to gRPC: https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md.
|
||||
// Returned twirp Errors have some additional metadata for inspection.
|
||||
func twirpErrorFromIntermediary(status int, msg string, bodyOrLocation string) twirp.Error {
|
||||
var code twirp.ErrorCode
|
||||
if isHTTPRedirect(status) { // 3xx
|
||||
code = twirp.Internal
|
||||
} else {
|
||||
switch status {
|
||||
case 400: // Bad Request
|
||||
code = twirp.Internal
|
||||
case 401: // Unauthorized
|
||||
code = twirp.Unauthenticated
|
||||
case 403: // Forbidden
|
||||
code = twirp.PermissionDenied
|
||||
case 404: // Not Found
|
||||
code = twirp.BadRoute
|
||||
case 429, 502, 503, 504: // Too Many Requests, Bad Gateway, Service Unavailable, Gateway Timeout
|
||||
code = twirp.Unavailable
|
||||
default: // All other codes
|
||||
code = twirp.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
twerr := twirp.NewError(code, msg)
|
||||
twerr = twerr.WithMeta("http_error_from_intermediary", "true") // to easily know if this error was from intermediary
|
||||
twerr = twerr.WithMeta("status_code", strconv.Itoa(status))
|
||||
if isHTTPRedirect(status) {
|
||||
twerr = twerr.WithMeta("location", bodyOrLocation)
|
||||
} else {
|
||||
twerr = twerr.WithMeta("body", bodyOrLocation)
|
||||
}
|
||||
return twerr
|
||||
}
|
||||
|
||||
func isHTTPRedirect(status int) bool {
|
||||
return status >= 300 && status <= 399
|
||||
}
|
||||
|
||||
// wrapInternal wraps an error with a prefix as an Internal error.
|
||||
// The original error cause is accessible by github.com/pkg/errors.Cause.
|
||||
func wrapInternal(err error, prefix string) twirp.Error {
|
||||
return twirp.InternalErrorWith(&wrappedError{prefix: prefix, cause: err})
|
||||
}
|
||||
|
||||
type wrappedError struct {
|
||||
prefix string
|
||||
cause error
|
||||
}
|
||||
|
||||
func (e *wrappedError) Cause() error { return e.cause }
|
||||
func (e *wrappedError) Error() string { return e.prefix + ": " + e.cause.Error() }
|
||||
|
||||
// ensurePanicResponses makes sure that rpc methods causing a panic still result in a Twirp Internal
|
||||
// error response (status 500), and error hooks are properly called with the panic wrapped as an error.
|
||||
// The panic is re-raised so it can be handled normally with middleware.
|
||||
func ensurePanicResponses(ctx context.Context, resp http.ResponseWriter, hooks *twirp.ServerHooks) {
|
||||
if r := recover(); r != nil {
|
||||
// Wrap the panic as an error so it can be passed to error hooks.
|
||||
// The original error is accessible from error hooks, but not visible in the response.
|
||||
err := errFromPanic(r)
|
||||
twerr := &internalWithCause{msg: "Internal service panic", cause: err}
|
||||
// Actually write the error
|
||||
writeError(ctx, resp, twerr, hooks)
|
||||
// If possible, flush the error to the wire.
|
||||
f, ok := resp.(http.Flusher)
|
||||
if ok {
|
||||
f.Flush()
|
||||
}
|
||||
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
|
||||
// errFromPanic returns the typed error if the recovered panic is an error, otherwise formats as error.
|
||||
func errFromPanic(p interface{}) error {
|
||||
if err, ok := p.(error); ok {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("panic: %v", p)
|
||||
}
|
||||
|
||||
// internalWithCause is a Twirp Internal error wrapping an original error cause, accessible
|
||||
// by github.com/pkg/errors.Cause, but the original error message is not exposed on Msg().
|
||||
type internalWithCause struct {
|
||||
msg string
|
||||
cause error
|
||||
}
|
||||
|
||||
func (e *internalWithCause) Cause() error { return e.cause }
|
||||
func (e *internalWithCause) Error() string { return e.msg + ": " + e.cause.Error() }
|
||||
func (e *internalWithCause) Code() twirp.ErrorCode { return twirp.Internal }
|
||||
func (e *internalWithCause) Msg() string { return e.msg }
|
||||
func (e *internalWithCause) Meta(key string) string { return "" }
|
||||
func (e *internalWithCause) MetaMap() map[string]string { return nil }
|
||||
func (e *internalWithCause) WithMeta(key string, val string) twirp.Error { return e }
|
||||
|
||||
// malformedRequestError is used when the twirp server cannot unmarshal a request
|
||||
func malformedRequestError(msg string) twirp.Error {
|
||||
return twirp.NewError(twirp.Malformed, msg)
|
||||
}
|
||||
|
||||
// badRouteError is used when the twirp server cannot route a request
|
||||
func badRouteError(msg string, method, url string) twirp.Error {
|
||||
err := twirp.NewError(twirp.BadRoute, msg)
|
||||
err = err.WithMeta("twirp_invalid_route", method+" "+url)
|
||||
return err
|
||||
}
|
||||
|
||||
// withoutRedirects makes sure that the POST request can not be redirected.
|
||||
// The standard library will, by default, redirect requests (including POSTs) if it gets a 302 or
|
||||
// 303 response, and also 301s in go1.8. It redirects by making a second request, changing the
|
||||
// method to GET and removing the body. This produces very confusing error messages, so instead we
|
||||
// set a redirect policy that always errors. This stops Go from executing the redirect.
|
||||
//
|
||||
// We have to be a little careful in case the user-provided http.Client has its own CheckRedirect
|
||||
// policy - if so, we'll run through that policy first.
|
||||
//
|
||||
// Because this requires modifying the http.Client, we make a new copy of the client and return it.
|
||||
func withoutRedirects(in *http.Client) *http.Client {
|
||||
copy := *in
|
||||
copy.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||
if in.CheckRedirect != nil {
|
||||
// Run the input's redirect if it exists, in case it has side effects, but ignore any error it
|
||||
// returns, since we want to use ErrUseLastResponse.
|
||||
err := in.CheckRedirect(req, via)
|
||||
_ = err // Silly, but this makes sure generated code passes errcheck -blank, which some people use.
|
||||
}
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
return ©
|
||||
}
|
||||
|
||||
// doProtobufRequest makes a Protobuf request to the remote Twirp service.
|
||||
func doProtobufRequest(ctx context.Context, client HTTPClient, hooks *twirp.ClientHooks, url string, in, out proto.Message) (err error) {
|
||||
reqBodyBytes, err := proto.Marshal(in)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to marshal proto request")
|
||||
}
|
||||
reqBody := bytes.NewBuffer(reqBodyBytes)
|
||||
if err = ctx.Err(); err != nil {
|
||||
return wrapInternal(err, "aborted because context was done")
|
||||
}
|
||||
|
||||
req, err := newRequest(ctx, url, reqBody, "application/protobuf")
|
||||
if err != nil {
|
||||
return wrapInternal(err, "could not build request")
|
||||
}
|
||||
ctx, err = callClientRequestPrepared(ctx, hooks, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to do request")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
cerr := resp.Body.Close()
|
||||
if err == nil && cerr != nil {
|
||||
err = wrapInternal(cerr, "failed to close response body")
|
||||
}
|
||||
}()
|
||||
|
||||
if err = ctx.Err(); err != nil {
|
||||
return wrapInternal(err, "aborted because context was done")
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return errorFromResponse(resp)
|
||||
}
|
||||
|
||||
respBodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to read response body")
|
||||
}
|
||||
if err = ctx.Err(); err != nil {
|
||||
return wrapInternal(err, "aborted because context was done")
|
||||
}
|
||||
|
||||
if err = proto.Unmarshal(respBodyBytes, out); err != nil {
|
||||
return wrapInternal(err, "failed to unmarshal proto response")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// doJSONRequest makes a JSON request to the remote Twirp service.
|
||||
func doJSONRequest(ctx context.Context, client HTTPClient, hooks *twirp.ClientHooks, url string, in, out proto.Message) (err error) {
|
||||
reqBody := bytes.NewBuffer(nil)
|
||||
marshaler := &jsonpb.Marshaler{OrigName: true}
|
||||
if err = marshaler.Marshal(reqBody, in); err != nil {
|
||||
return wrapInternal(err, "failed to marshal json request")
|
||||
}
|
||||
if err = ctx.Err(); err != nil {
|
||||
return wrapInternal(err, "aborted because context was done")
|
||||
}
|
||||
|
||||
req, err := newRequest(ctx, url, reqBody, "application/json")
|
||||
if err != nil {
|
||||
return wrapInternal(err, "could not build request")
|
||||
}
|
||||
ctx, err = callClientRequestPrepared(ctx, hooks, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return wrapInternal(err, "failed to do request")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
cerr := resp.Body.Close()
|
||||
if err == nil && cerr != nil {
|
||||
err = wrapInternal(cerr, "failed to close response body")
|
||||
}
|
||||
}()
|
||||
|
||||
if err = ctx.Err(); err != nil {
|
||||
return wrapInternal(err, "aborted because context was done")
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return errorFromResponse(resp)
|
||||
}
|
||||
|
||||
unmarshaler := jsonpb.Unmarshaler{AllowUnknownFields: true}
|
||||
if err = unmarshaler.Unmarshal(resp.Body, out); err != nil {
|
||||
return wrapInternal(err, "failed to unmarshal json response")
|
||||
}
|
||||
if err = ctx.Err(); err != nil {
|
||||
return wrapInternal(err, "aborted because context was done")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Call twirp.ServerHooks.RequestReceived if the hook is available
|
||||
func callRequestReceived(ctx context.Context, h *twirp.ServerHooks) (context.Context, error) {
|
||||
if h == nil || h.RequestReceived == nil {
|
||||
return ctx, nil
|
||||
}
|
||||
return h.RequestReceived(ctx)
|
||||
}
|
||||
|
||||
// Call twirp.ServerHooks.RequestRouted if the hook is available
|
||||
func callRequestRouted(ctx context.Context, h *twirp.ServerHooks) (context.Context, error) {
|
||||
if h == nil || h.RequestRouted == nil {
|
||||
return ctx, nil
|
||||
}
|
||||
return h.RequestRouted(ctx)
|
||||
}
|
||||
|
||||
// Call twirp.ServerHooks.ResponsePrepared if the hook is available
|
||||
func callResponsePrepared(ctx context.Context, h *twirp.ServerHooks) context.Context {
|
||||
if h == nil || h.ResponsePrepared == nil {
|
||||
return ctx
|
||||
}
|
||||
return h.ResponsePrepared(ctx)
|
||||
}
|
||||
|
||||
// Call twirp.ServerHooks.ResponseSent if the hook is available
|
||||
func callResponseSent(ctx context.Context, h *twirp.ServerHooks) {
|
||||
if h == nil || h.ResponseSent == nil {
|
||||
return
|
||||
}
|
||||
h.ResponseSent(ctx)
|
||||
}
|
||||
|
||||
// Call twirp.ServerHooks.Error if the hook is available
|
||||
func callError(ctx context.Context, h *twirp.ServerHooks, err twirp.Error) context.Context {
|
||||
if h == nil || h.Error == nil {
|
||||
return ctx
|
||||
}
|
||||
return h.Error(ctx, err)
|
||||
}
|
||||
|
||||
func callClientResponseReceived(ctx context.Context, h *twirp.ClientHooks) {
|
||||
if h == nil || h.ResponseReceived == nil {
|
||||
return
|
||||
}
|
||||
h.ResponseReceived(ctx)
|
||||
}
|
||||
|
||||
func callClientRequestPrepared(ctx context.Context, h *twirp.ClientHooks, req *http.Request) (context.Context, error) {
|
||||
if h == nil || h.RequestPrepared == nil {
|
||||
return ctx, nil
|
||||
}
|
||||
return h.RequestPrepared(ctx, req)
|
||||
}
|
||||
|
||||
func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) {
|
||||
if h == nil || h.Error == nil {
|
||||
return
|
||||
}
|
||||
h.Error(ctx, err)
|
||||
}
|
||||
|
||||
var twirpFileDescriptor0 = []byte{
|
||||
// 361 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xc1, 0x6b, 0xbb, 0x30,
|
||||
0x18, 0x45, 0x5b, 0x6a, 0x8d, 0x3f, 0xf8, 0x95, 0x1c, 0x86, 0x6d, 0xd9, 0x10, 0x4f, 0x65, 0x07,
|
||||
0x65, 0x0e, 0xb6, 0xfb, 0xa0, 0x87, 0x9e, 0x3a, 0xd2, 0xb1, 0xc3, 0x2e, 0x25, 0xd5, 0x0f, 0x17,
|
||||
0x50, 0x63, 0x93, 0x28, 0xf3, 0x1f, 0xd9, 0xdf, 0x3b, 0x4c, 0x2c, 0xac, 0x1d, 0xbd, 0x25, 0xef,
|
||||
0x3d, 0xbf, 0xf7, 0xde, 0x67, 0xd0, 0x5c, 0xd4, 0x69, 0x2c, 0x53, 0x5a, 0x55, 0x20, 0x62, 0x09,
|
||||
0xa2, 0x65, 0x29, 0x44, 0xb5, 0xe0, 0x8a, 0xe3, 0x99, 0x12, 0xac, 0xed, 0xa2, 0x81, 0x8c, 0xda,
|
||||
0x87, 0xc5, 0x53, 0xce, 0xd4, 0x67, 0x73, 0x88, 0x52, 0x5e, 0xc6, 0xf4, 0xd8, 0x50, 0x09, 0x69,
|
||||
0x23, 0x98, 0xea, 0x62, 0xad, 0x8c, 0xfb, 0x51, 0x29, 0x2f, 0x4b, 0x5e, 0x9d, 0x4f, 0x0a, 0xbf,
|
||||
0x2d, 0xe4, 0xed, 0x52, 0x5a, 0x11, 0x38, 0x36, 0x20, 0x15, 0xbe, 0x41, 0x13, 0x45, 0x45, 0x0e,
|
||||
0xca, 0xb7, 0x02, 0x6b, 0xe5, 0x92, 0xe1, 0x86, 0xe7, 0x68, 0xca, 0x4a, 0x9a, 0xc3, 0x9e, 0x65,
|
||||
0xbe, 0xad, 0x19, 0x47, 0xdf, 0x37, 0x19, 0x5e, 0x22, 0xb7, 0xa0, 0x1d, 0x88, 0x3d, 0xcb, 0xa4,
|
||||
0x3f, 0x0a, 0x46, 0x2b, 0x97, 0x4c, 0x35, 0xb0, 0xc9, 0x24, 0x7e, 0x46, 0x0e, 0xaf, 0x15, 0xe3,
|
||||
0x95, 0xf4, 0xc7, 0x81, 0xb5, 0xf2, 0x92, 0xdb, 0xe8, 0x32, 0x7b, 0xd4, 0xfb, 0x6f, 0x8d, 0x88,
|
||||
0x9c, 0xd4, 0xe1, 0xbd, 0xc9, 0x35, 0xe0, 0xbd, 0x49, 0xdb, 0x14, 0xd5, 0x5e, 0x75, 0x35, 0xf8,
|
||||
0x96, 0x31, 0xe9, 0x81, 0xb7, 0xae, 0x86, 0xf0, 0x0b, 0xfd, 0x33, 0x1d, 0x64, 0xcd, 0x2b, 0x09,
|
||||
0x38, 0x40, 0x36, 0x97, 0xba, 0x80, 0x97, 0xcc, 0x06, 0x3f, 0xd3, 0x3e, 0xda, 0xee, 0x88, 0xcd,
|
||||
0x25, 0xc6, 0x68, 0x0c, 0x5c, 0x16, 0xba, 0xca, 0x94, 0xe8, 0x33, 0x4e, 0x90, 0x23, 0x40, 0x36,
|
||||
0x85, 0x32, 0x2d, 0xbc, 0xc4, 0xff, 0x1b, 0x95, 0x68, 0x01, 0x39, 0x09, 0xc3, 0x1c, 0x4d, 0x0c,
|
||||
0x74, 0x75, 0x71, 0x6b, 0xf4, 0xbf, 0xcf, 0x09, 0x82, 0x1e, 0x58, 0xc1, 0x14, 0x03, 0xe9, 0xdb,
|
||||
0x7a, 0xfa, 0xf2, 0x3c, 0xd8, 0xfb, 0x2f, 0x51, 0x47, 0x2e, 0xbf, 0x49, 0x5e, 0x91, 0xb3, 0x33,
|
||||
0x31, 0xf0, 0x1a, 0x8d, 0xfb, 0x23, 0xbe, 0xb2, 0xc9, 0xe1, 0x4f, 0x2e, 0xee, 0xae, 0xd1, 0x66,
|
||||
0x49, 0x2f, 0xee, 0x87, 0x33, 0x50, 0x87, 0x89, 0x7e, 0x0b, 0x8f, 0x3f, 0x01, 0x00, 0x00, 0xff,
|
||||
0xff, 0x22, 0xf3, 0x23, 0xc0, 0x72, 0x02, 0x00, 0x00,
|
||||
}
|
||||
Reference in New Issue
Block a user