mirror of
https://github.com/anchore/grype
synced 2024-11-10 06:34:13 +00:00
Merge pull request #27 from anchore/curate-db-file
Add curation of db file
This commit is contained in:
commit
89ed62696d
37 changed files with 1316 additions and 179 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,5 +1,7 @@
|
|||
.vscode/
|
||||
.server/
|
||||
*.db
|
||||
!**/test-fixtures/**/*.db
|
||||
*.tar
|
||||
.idea/
|
||||
*.log
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
linter-settings:
|
||||
linters-settings:
|
||||
funlen:
|
||||
lines: 70
|
||||
statements: 50
|
||||
linters:
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
disable-all: true
|
||||
|
|
1
Makefile
1
Makefile
|
@ -46,6 +46,7 @@ coverage:
|
|||
@printf '$(TITLE)Running unit tests + coverage$(RESET)\n'
|
||||
$(TEMPDIR)/bin/go-acc -o $(TEMPDIR)/coverage.txt ./...
|
||||
|
||||
|
||||
# TODO: add benchmarks
|
||||
|
||||
integration:
|
||||
|
|
|
@ -45,7 +45,7 @@ func init() {
|
|||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
log.Errorf("could not start application: %w", err)
|
||||
log.Errorf("could not start application: %+v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/vulnscan/vulnscan/db"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -10,7 +12,11 @@ var dbCheckCmd = &cobra.Command{
|
|||
Use: "check",
|
||||
Short: "check to see if there is a database update available",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
os.Exit(runDbCheckCmd(cmd, args))
|
||||
ret := runDbCheckCmd(cmd, args)
|
||||
if ret != 0 {
|
||||
fmt.Println("Unable to check for vulnerability database updates")
|
||||
}
|
||||
os.Exit(ret)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -18,7 +24,26 @@ func init() {
|
|||
dbCmd.AddCommand(dbCheckCmd)
|
||||
}
|
||||
|
||||
func runDbCheckCmd(cmd *cobra.Command, args []string) int {
|
||||
log.Error("database CHECK command...")
|
||||
func runDbCheckCmd(_ *cobra.Command, _ []string) int {
|
||||
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
|
||||
if err != nil {
|
||||
log.Errorf("could not curate database: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
updateAvailable, _, err := dbCurator.IsUpdateAvailable()
|
||||
if err != nil {
|
||||
// TODO: should this be so fatal? we can certainly continue with a warning...
|
||||
log.Errorf("unable to check for vulnerability database update: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
if !updateAvailable {
|
||||
fmt.Println("No update available")
|
||||
return 0
|
||||
}
|
||||
|
||||
fmt.Println("Update available!")
|
||||
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var dbClearCmd = &cobra.Command{
|
||||
Use: "clear",
|
||||
Short: "delete the vulnerability database",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
os.Exit(runDbClearCmd(cmd, args))
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
dbCmd.AddCommand(dbClearCmd)
|
||||
}
|
||||
|
||||
func runDbClearCmd(cmd *cobra.Command, args []string) int {
|
||||
log.Error("database CLEAR command...")
|
||||
return 0
|
||||
}
|
43
cmd/db_delete.go
Normal file
43
cmd/db_delete.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/vulnscan/vulnscan/db"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var dbDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "delete the vulnerability database",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ret := runDbDeleteCmd(cmd, args)
|
||||
if ret != 0 {
|
||||
fmt.Println("Unable to delete vulnerability database")
|
||||
}
|
||||
os.Exit(ret)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
dbCmd.AddCommand(dbDeleteCmd)
|
||||
}
|
||||
|
||||
func runDbDeleteCmd(_ *cobra.Command, _ []string) int {
|
||||
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
|
||||
if err != nil {
|
||||
log.Errorf("could not curate database: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
err = dbCurator.Delete()
|
||||
if err != nil {
|
||||
log.Errorf("unable to delete vulnerability database: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
fmt.Println("Vulnerability database deleted")
|
||||
|
||||
return 0
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/vulnscan/vulnscan/db"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -10,7 +12,11 @@ var dbUpdateCmd = &cobra.Command{
|
|||
Use: "update",
|
||||
Short: "download the latest vulnerability database",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
os.Exit(runDbUpdateCmd(cmd, args))
|
||||
ret := runDbUpdateCmd(cmd, args)
|
||||
if ret != 0 {
|
||||
fmt.Println("Unable to update vulnerability database")
|
||||
}
|
||||
os.Exit(ret)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -18,7 +24,30 @@ func init() {
|
|||
dbCmd.AddCommand(dbUpdateCmd)
|
||||
}
|
||||
|
||||
func runDbUpdateCmd(cmd *cobra.Command, args []string) int {
|
||||
log.Error("database UPDATE command...")
|
||||
func runDbUpdateCmd(_ *cobra.Command, _ []string) int {
|
||||
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
|
||||
if err != nil {
|
||||
log.Errorf("could not curate database: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
updateAvailable, updateEntry, err := dbCurator.IsUpdateAvailable()
|
||||
if err != nil {
|
||||
// TODO: should this be so fatal? we can certainly continue with a warning...
|
||||
log.Errorf("unable to check for vulnerability database update: %+v", err)
|
||||
return 1
|
||||
}
|
||||
if updateAvailable {
|
||||
err = dbCurator.UpdateTo(updateEntry)
|
||||
if err != nil {
|
||||
log.Errorf("unable to update vulnerability database: %+v", err)
|
||||
return 1
|
||||
}
|
||||
} else {
|
||||
fmt.Println("No vulnerability database update available")
|
||||
return 0
|
||||
}
|
||||
|
||||
fmt.Println("Vulnerability database updated!")
|
||||
return 0
|
||||
}
|
||||
|
|
31
cmd/root.go
31
cmd/root.go
|
@ -9,9 +9,9 @@ import (
|
|||
"github.com/anchore/imgbom/imgbom/scope"
|
||||
"github.com/anchore/stereoscope"
|
||||
"github.com/anchore/vulnscan/internal"
|
||||
"github.com/anchore/vulnscan/internal/db"
|
||||
"github.com/anchore/vulnscan/internal/format"
|
||||
"github.com/anchore/vulnscan/vulnscan"
|
||||
"github.com/anchore/vulnscan/vulnscan/db"
|
||||
"github.com/anchore/vulnscan/vulnscan/presenter"
|
||||
"github.com/anchore/vulnscan/vulnscan/vulnerability"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -83,7 +83,34 @@ func runDefaultCmd(_ *cobra.Command, args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
store := db.GetStore()
|
||||
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
|
||||
if err != nil {
|
||||
log.Errorf("could not curate database: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
if appConfig.Db.UpdateOnStartup {
|
||||
updateAvailable, updateEntry, err := dbCurator.IsUpdateAvailable()
|
||||
if err != nil {
|
||||
// TODO: should this be so fatal? we can certainly continue with a warning...
|
||||
log.Errorf("unable to check for vulnerability database update: %+v", err)
|
||||
return 1
|
||||
}
|
||||
if updateAvailable {
|
||||
err = dbCurator.UpdateTo(updateEntry)
|
||||
if err != nil {
|
||||
log.Errorf("unable to update vulnerability database: %+v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store, err := dbCurator.GetStore()
|
||||
if err != nil {
|
||||
log.Errorf("failed to load vulnerability database: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
provider := vulnerability.NewProviderFromStore(store)
|
||||
|
||||
results := vulnscan.FindAllVulnerabilities(provider, *osObj, catalog)
|
||||
|
|
7
go.mod
7
go.mod
|
@ -4,18 +4,21 @@ go 1.14
|
|||
|
||||
require (
|
||||
github.com/adrg/xdg v0.2.1
|
||||
github.com/anchore/go-testutils v0.0.0-20200520222037-edc2bf1864fe
|
||||
github.com/anchore/imgbom v0.0.0-20200616171024-2cb7dad96784
|
||||
github.com/anchore/stereoscope v0.0.0-20200616152009-189722bdb61b
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200604185950-6a9f5a2c9ddf
|
||||
github.com/go-test/deep v1.0.6
|
||||
github.com/hashicorp/go-getter v1.4.1
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
|
||||
github.com/knqyf263/go-version v1.1.1
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/sergi/go-diff v1.1.0
|
||||
github.com/spf13/afero v1.3.0
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/viper v1.7.0
|
||||
go.uber.org/zap v1.15.0
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
|
||||
gopkg.in/ini.v1 v1.57.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
|
92
go.sum
92
go.sum
|
@ -14,22 +14,27 @@ cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO
|
|||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0 h1:EpMNVUorLiZIELdMZbCYX/ByTFCdoYopYAGxaGVz9ms=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0 h1:a/O/bK/vWrYGOTFtH8di4rBxMZnmkjy+Y5LxpDwo+dA=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0 h1:86K1Gel7BQ9/WmNWn7dTKMvTLFzwtBe5FNqYbi9X35g=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
code.gitea.io/sdk/gitea v0.12.0/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
|
||||
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
|
||||
|
@ -103,40 +108,16 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
|
|||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/anchore/go-feeds-client v0.0.0-20200608121036-d9c3f68622a7 h1:IpwJkSqsmdZHN6CmUYNKKx5J25J3g/6yzwRmpvERqhQ=
|
||||
github.com/anchore/go-feeds-client v0.0.0-20200608121036-d9c3f68622a7/go.mod h1:sugnhPPnoDCFWKzmQxSj444vF3T6UTiCdMLn8YZLyVg=
|
||||
github.com/anchore/go-testutils v0.0.0-20200520222037-edc2bf1864fe h1:YMXe4RA3qy4Ri5fmGQii/Gn+Pxv3oBfiS/LqzeOVuwo=
|
||||
github.com/anchore/go-testutils v0.0.0-20200520222037-edc2bf1864fe/go.mod h1:D3rc2L/q4Hcp9eeX6AIJH4Q+kPjOtJCFhG9za90j+nU=
|
||||
github.com/anchore/imgbom v0.0.0-20200601214218-f0b8aaacdae2 h1:hGKC1CpgK1x8HIUJ1hkZP8kuUXcywWIa7wz3Mi4aFus=
|
||||
github.com/anchore/imgbom v0.0.0-20200601214218-f0b8aaacdae2/go.mod h1:Ttau0/FsMvXMTlPQvSpyQPi0VZQDosjwuHUv1zUwl7k=
|
||||
github.com/anchore/imgbom v0.0.0-20200603004815-b6122a413ba8 h1:k8e5yQI3mnkoxeEI+s7ujBEtjLuicxyOn7IfKsQsotY=
|
||||
github.com/anchore/imgbom v0.0.0-20200603004815-b6122a413ba8/go.mod h1:Ttau0/FsMvXMTlPQvSpyQPi0VZQDosjwuHUv1zUwl7k=
|
||||
github.com/anchore/imgbom v0.0.0-20200604184352-e88669c536ce h1:t/2K7VPuKX7DrYnPeclLNrH0gsRbW8ZBig7o50pqq50=
|
||||
github.com/anchore/imgbom v0.0.0-20200604184352-e88669c536ce/go.mod h1:oVcJ4sEuqz/7XTPaJYIZRc4NYVl3zPP96g7RtWG31SE=
|
||||
github.com/anchore/imgbom v0.0.0-20200605135927-64a9125895b5 h1:0ylgLfUfao/4DiuhuYLV9vX9fs2N+VfmgWZ0d8HqsxA=
|
||||
github.com/anchore/imgbom v0.0.0-20200605135927-64a9125895b5/go.mod h1:c4LPvBC2SvyzgOdpbjUM6Ys4n10aX6gSOGQUYzfryWw=
|
||||
github.com/anchore/imgbom v0.0.0-20200616171024-2cb7dad96784 h1:s9zoF5uqN8rvp6TBtFgwIoBsP6gwhqaCw43XfELh3C4=
|
||||
github.com/anchore/imgbom v0.0.0-20200616171024-2cb7dad96784/go.mod h1:QCQcQ4EfM+ejNaFu3Ep24YwR5t72PcwAbfSBqXWJeB4=
|
||||
github.com/anchore/stereoscope v0.0.0-20200520221116-025e07f1c93e h1:QBwtrM0MXi0z+GcHk3RoSyzaQ+CLgas0bC/uOd1P+PQ=
|
||||
github.com/anchore/stereoscope v0.0.0-20200520221116-025e07f1c93e/go.mod h1:bkyLl5VITnrmgErv4S1vDfVz/TGAZ5il6161IQo7w2g=
|
||||
github.com/anchore/stereoscope v0.0.0-20200523232006-be5f3c18958f h1:aPJQyXi8Y7PhnzhUszZfS/23TA5o29UCc3XGreflaqo=
|
||||
github.com/anchore/stereoscope v0.0.0-20200523232006-be5f3c18958f/go.mod h1:bkyLl5VITnrmgErv4S1vDfVz/TGAZ5il6161IQo7w2g=
|
||||
github.com/anchore/stereoscope v0.0.0-20200602123205-6c2ce3c0b2d5 h1:eViCIr4O1e4M93nbbMZdrRW0JjqDjPYdtMXEOC3jQQQ=
|
||||
github.com/anchore/stereoscope v0.0.0-20200602123205-6c2ce3c0b2d5/go.mod h1:OeCrFeSu8+p02qC7u9/u8wBOh50VQa8eHJjXVuANvLo=
|
||||
github.com/anchore/stereoscope v0.0.0-20200604133300-7e63b350b6d6 h1:Fu779yw004jyFH1UkQD8lTf0GmGRfrOQIK5QiqmIwU8=
|
||||
github.com/anchore/stereoscope v0.0.0-20200604133300-7e63b350b6d6/go.mod h1:eQ2/Al6XDA7RFk3FVfpjyGRErITRjNciUPIWixHc7kQ=
|
||||
github.com/anchore/stereoscope v0.0.0-20200616152009-189722bdb61b h1:LmFKsQi4oj2VJjch7JhQNzJg1A56FjwHqWZz1ZZKgIw=
|
||||
github.com/anchore/stereoscope v0.0.0-20200616152009-189722bdb61b/go.mod h1:eQ2/Al6XDA7RFk3FVfpjyGRErITRjNciUPIWixHc7kQ=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200528193934-4a3f5d48b4c8 h1:pSGrFVpRZe2P9Ov+6GQSz0vh1yrUEmkMTEpjn+HT2Sw=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200528193934-4a3f5d48b4c8/go.mod h1:VX8yNH+ERoyXQ0Qsd+Ct8FxRvMSyOPcno/zwq/pjg0s=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200603183000-b64fbcd7044b h1:cFBPQpPv/Nk8G1bVsMU8xxwqXLXCe3GdyGn9AEsVuNE=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200603183000-b64fbcd7044b/go.mod h1:OVROq5+BT+g+ES+heRewy7NU2f147o2QyMortckSXek=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200604185950-6a9f5a2c9ddf h1:U1KgI8Lk6acUjjmtBLWOCoL9U7AV8tFmHnqAtFikJ7E=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200604185950-6a9f5a2c9ddf/go.mod h1:OVROq5+BT+g+ES+heRewy7NU2f147o2QyMortckSXek=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200608121247-dc89e4e50bb5 h1:V3vDhg/YdBCaL2AqukuRMwSD/MdKdrg81dEHJ+YsfrQ=
|
||||
github.com/anchore/vulnscan-db v0.0.0-20200608121247-dc89e4e50bb5/go.mod h1:HNoSeIuRTZC30XBlOIFSOEVMMuj7vkijUZR/nl6L2Uc=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ=
|
||||
github.com/apex/log v1.3.0/go.mod h1:jd8Vpsr46WAe3EZSQ/IUMs2qQD/GOycT5rPWCO1yGcs=
|
||||
github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
|
||||
|
@ -148,17 +129,21 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
|
|||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
|
||||
github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.31.6 h1:nKjQbpXhdImctBh1e0iLg9iQW/X297LPPuY/9f92R2k=
|
||||
github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
||||
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/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
|
@ -173,6 +158,7 @@ github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oD
|
|||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
@ -224,7 +210,6 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU
|
|||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
|
||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible h1:G2hY8RD7jB9QaSmcb8mYEIg8QbEvVAB7se8+lXHZHfg=
|
||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
|
||||
|
@ -311,6 +296,7 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
|
|||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
|
@ -362,10 +348,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-containerregistry v0.0.0-20200430153450-5cbd060f5c92/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA=
|
||||
github.com/google/go-containerregistry v0.0.0-20200521151920-a873a21aff23 h1:42qjTtGOVRefA89EPBmd2Vm+m9x/WrZiCq9n022khSE=
|
||||
github.com/google/go-containerregistry v0.0.0-20200521151920-a873a21aff23/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA=
|
||||
github.com/google/go-containerregistry v0.0.0-20200601195303-96cf69f03a3c h1:skQHUoy/S0WT+HFlN4MuDQCHsc6vTgKTMaKA3QKGABI=
|
||||
github.com/google/go-containerregistry v0.0.0-20200601195303-96cf69f03a3c/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM=
|
||||
github.com/google/go-containerregistry v0.1.0 h1:hL5mVw7cTX3SBr64Arpv+cJH93L+Z9Q6WjckImYLB3g=
|
||||
github.com/google/go-containerregistry v0.1.0/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM=
|
||||
github.com/google/go-containerregistry v0.1.1 h1:AG8FSAfXglim2l5qSrqp5VK2Xl03PiBf25NiTGGamws=
|
||||
|
@ -377,6 +359,7 @@ github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwG
|
|||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible h1:xmapqc1AyLoB+ddYT6r04bD9lIjlOqGaREovi0SzFaE=
|
||||
github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
|
@ -392,13 +375,14 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
|
||||
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
|
||||
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
|
||||
github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
||||
|
@ -425,7 +409,11 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt
|
|||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA=
|
||||
github.com/hashicorp/go-getter v1.4.1/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
|
@ -435,10 +423,13 @@ github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+
|
|||
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
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/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
|
@ -466,6 +457,7 @@ github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod
|
|||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
|
||||
|
@ -478,12 +470,11 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
|||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/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/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
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=
|
||||
|
@ -495,12 +486,11 @@ github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4
|
|||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
|
||||
github.com/knqyf263/go-version v1.1.1 h1:+MpcBC9b7rk5ihag8Y/FLG8get1H2GjniwKQ+9DxI2o=
|
||||
github.com/knqyf263/go-version v1.1.1/go.mod h1:0tBvHvOBSf5TqGNcY+/ih9o8qo3R16iZCpB9rP0D3VM=
|
||||
github.com/knqyf263/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||
github.com/knqyf263/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
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/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
|
@ -516,6 +506,7 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.5.2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
|
@ -537,15 +528,14 @@ github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/
|
|||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
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.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
|
||||
|
@ -561,6 +551,7 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
|||
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-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
|
@ -624,6 +615,7 @@ github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV
|
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
@ -668,6 +660,7 @@ github.com/securego/gosec v0.0.0-20200103095621-79fbf3af8d83/go.mod h1:vvbZ2Ae7A
|
|||
github.com/securego/gosec v0.0.0-20200401082031-e946c8c39989/go.mod h1:i9l/TNj+yDFh9SZXUTvspXTjbFXgZGP/UvhU1S65A4A=
|
||||
github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
|
@ -676,7 +669,6 @@ github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOms
|
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||
|
@ -698,6 +690,8 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.3.0 h1:Ysnmjh1Di8EaWaBv40CYR4IdaIsBc5996Gh1oZzCBKk=
|
||||
github.com/spf13/afero v1.3.0/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
|
@ -752,7 +746,9 @@ github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaoz
|
|||
github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
|
||||
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
||||
|
@ -765,12 +761,6 @@ github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOV
|
|||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c=
|
||||
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||
github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d h1:KOxOL6qpmqwoPloNwi+CEgc1ayjHNOFNrvoOmeDOjDg=
|
||||
github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d/go.mod h1:JPirS5jde/CF5qIjcK4WX+eQmKXdPc6vcZkJ/P0hfPw=
|
||||
github.com/wagoodman/go-progress v0.0.0-20200526224006-dd1404d54b0b h1:UDJoympq2F2QqhIu0wF6PtI+Apq1sW3TobBoZOrUTa8=
|
||||
github.com/wagoodman/go-progress v0.0.0-20200526224006-dd1404d54b0b/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA=
|
||||
github.com/wagoodman/jotframe v0.0.0-20200414171733-a67b24625ea8 h1:mHqUlTt7fcYbRw0fR6WTgk+XkWb7u6394PQsXzRcifo=
|
||||
github.com/wagoodman/jotframe v0.0.0-20200414171733-a67b24625ea8/go.mod h1:DzXZ1wfRedNhC3KQTick8Gf3CEPMFHsP5k4R/ldjKtw=
|
||||
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
|
||||
github.com/xanzy/go-gitlab v0.32.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
|
@ -787,6 +777,7 @@ go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
|||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
|
@ -806,12 +797,12 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -924,7 +915,6 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -964,8 +954,6 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34 h1:u6CI7A++8r4SItZHYe2cWeAEndN4p1p+3Oum/Ft2EzM=
|
||||
golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38=
|
||||
|
@ -1076,6 +1064,7 @@ google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
|
|||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA=
|
||||
google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -1116,14 +1105,8 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaR
|
|||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece h1:1YM0uhfumvoDu9sx8+RyWwTI63zoCQvI23IYFRlvte0=
|
||||
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200602104108-2bb8d6132df6 h1:fsxmG3uIxSjgTNy6zSkdHSyElfRV0Tq+yzS+Ukjthx0=
|
||||
google.golang.org/genproto v0.0.0-20200602104108-2bb8d6132df6/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200603110839-e855014d5736 h1:+IE3xTD+6Eb7QWG5JFp+dQr/XjKpjmrNkh4pdjTdHEs=
|
||||
google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb h1:ek2py5bOqzR7MR/6obzk0rXUgYCLmjyLnaO9ssT+l6w=
|
||||
google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200605102947-12044bf5ea91 h1:ES+5k7Xz+sYByd2L7mvcanaIuY0Iz3L3O6OhN+cRdu8=
|
||||
google.golang.org/genproto v0.0.0-20200605102947-12044bf5ea91/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 h1:1N7l1PuXZwEK7OhHdmKQROOM75PnUjABGwvVRbLBgFk=
|
||||
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
@ -1159,6 +1142,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.27/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/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/adrg/xdg"
|
||||
"github.com/anchore/imgbom/imgbom/scope"
|
||||
"github.com/anchore/vulnscan/internal"
|
||||
"github.com/anchore/vulnscan/vulnscan/db"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
@ -25,6 +26,7 @@ type Application struct {
|
|||
Quiet bool `mapstructure:"quiet"`
|
||||
Log Logging `mapstructure:"log"`
|
||||
CliOptions CliOnlyOptions
|
||||
Db Database `mapstructure:"db"`
|
||||
}
|
||||
|
||||
type Logging struct {
|
||||
|
@ -34,10 +36,28 @@ type Logging struct {
|
|||
FileLocation string `mapstructure:"file"`
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
Dir string `mapstructure:"cache-dir"`
|
||||
UpdateURL string `mapstructure:"update-url"`
|
||||
UpdateOnStartup bool `mapstructure:"update-on-startup"`
|
||||
}
|
||||
|
||||
func (d Database) ToCuratorConfig() db.Config {
|
||||
return db.Config{
|
||||
DbDir: d.Dir,
|
||||
ListingURL: d.UpdateURL,
|
||||
}
|
||||
}
|
||||
|
||||
func setNonCliDefaultValues(v *viper.Viper) {
|
||||
v.SetDefault("log.level", "")
|
||||
v.SetDefault("log.file", "")
|
||||
v.SetDefault("log.structured", false)
|
||||
// e.g. ~/.cache/appname/db
|
||||
v.SetDefault("db.cache-dir", path.Join(xdg.CacheHome, internal.ApplicationName, "db"))
|
||||
// TODO: change me to the production URL at release
|
||||
v.SetDefault("db.update-url", "http://localhost:5000/listing.json")
|
||||
v.SetDefault("db.update-on-startup", true)
|
||||
}
|
||||
|
||||
func LoadConfigFromFile(v *viper.Viper, cliOpts *CliOnlyOptions) (*Application, error) {
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"github.com/anchore/vulnscan-db/pkg/db"
|
||||
"github.com/anchore/vulnscan-db/pkg/sqlite"
|
||||
)
|
||||
|
||||
func GetStore() db.VulnStore {
|
||||
// TODO: add connection options and info
|
||||
// TODO: we are ignoreing cleanup/close function (not good)
|
||||
store, _, err := sqlite.NewStore(nil)
|
||||
if err != nil {
|
||||
// TODO: replace me
|
||||
panic(err)
|
||||
}
|
||||
return store
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"github.com/anchore/vulnscan-db/pkg/db"
|
||||
)
|
||||
|
||||
type MockDb struct {
|
||||
data map[string]map[string][]db.Vulnerability
|
||||
}
|
||||
|
||||
func NewMockDb() *MockDb {
|
||||
d := MockDb{
|
||||
data: make(map[string]map[string][]db.Vulnerability),
|
||||
}
|
||||
d.populate()
|
||||
return &d
|
||||
}
|
||||
|
||||
func (d *MockDb) populate() {
|
||||
d.data["debian:8"] = map[string][]db.Vulnerability{
|
||||
"neutron": {
|
||||
{
|
||||
Name: "neutron",
|
||||
NamespaceName: "debian:8",
|
||||
Version: "2014.1.3-6",
|
||||
VulnerabilityID: "CVE-2014-fake",
|
||||
VersionFormat: "dpkg",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (d *MockDb) Add(v *db.Vulnerability) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *MockDb) Get(namespace, name string) ([]db.Vulnerability, error) {
|
||||
return d.data[namespace][name], nil
|
||||
}
|
69
internal/file/copy.go
Normal file
69
internal/file/copy.go
Normal file
|
@ -0,0 +1,69 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func CopyDir(fs afero.Fs, src string, dst string) error {
|
||||
var err error
|
||||
var fds []os.FileInfo
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if srcinfo, err = fs.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = fs.MkdirAll(dst, srcinfo.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fds, err = ioutil.ReadDir(src); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fd := range fds {
|
||||
srcPath := path.Join(src, fd.Name())
|
||||
dstPath := path.Join(dst, fd.Name())
|
||||
|
||||
if fd.IsDir() {
|
||||
if err = CopyDir(fs, srcPath, dstPath); err != nil {
|
||||
return fmt.Errorf("could not copy dir (%s -> %s): %w", srcPath, dstPath, err)
|
||||
}
|
||||
} else {
|
||||
if err = CopyFile(fs, srcPath, dstPath); err != nil {
|
||||
return fmt.Errorf("could not copy file (%s -> %s): %w", srcPath, dstPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CopyFile(fs afero.Fs, src, dst string) error {
|
||||
var err error
|
||||
var srcFd afero.File
|
||||
var dstFd afero.File
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if srcFd, err = fs.Open(src); err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFd.Close()
|
||||
|
||||
if dstFd, err = fs.Create(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFd.Close()
|
||||
|
||||
if _, err = io.Copy(dstFd, srcFd); err != nil {
|
||||
return err
|
||||
}
|
||||
if srcinfo, err = fs.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
return fs.Chmod(dst, srcinfo.Mode())
|
||||
}
|
15
internal/file/exists.go
Normal file
15
internal/file/exists.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func Exists(fs afero.Fs, path string) bool {
|
||||
info, err := fs.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
22
internal/file/getter.go
Normal file
22
internal/file/getter.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package file
|
||||
|
||||
import "github.com/hashicorp/go-getter"
|
||||
|
||||
type Getter interface {
|
||||
// GetFile downloads the give URL into the given path. The URL must reference a single file.
|
||||
GetFile(dst, src string) error
|
||||
|
||||
// Get downloads the given URL into the given directory. The directory must already exist.
|
||||
GetToDir(dst, src string) error
|
||||
}
|
||||
|
||||
type HashiGoGetter struct {
|
||||
}
|
||||
|
||||
func (g HashiGoGetter) GetFile(dst, src string) error {
|
||||
return getter.GetFile(dst, src)
|
||||
}
|
||||
|
||||
func (g HashiGoGetter) GetToDir(dst, src string) error {
|
||||
return getter.Get(dst, src)
|
||||
}
|
45
internal/file/hasher.go
Normal file
45
internal/file/hasher.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func ValidateByHash(fs afero.Fs, path, hashStr string) (bool, error) {
|
||||
var hasher hash.Hash
|
||||
switch {
|
||||
case strings.HasPrefix(hashStr, "sha256:"):
|
||||
hasher = sha256.New()
|
||||
default:
|
||||
return false, fmt.Errorf("hasher not supported or specified (given: %s)", hashStr)
|
||||
}
|
||||
|
||||
hashNoPrefix := strings.Split(hashStr, ":")[1]
|
||||
|
||||
actualHash, err := HashFile(fs, path, hasher)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return actualHash == hashNoPrefix, nil
|
||||
}
|
||||
|
||||
func HashFile(fs afero.Fs, path string, hasher hash.Hash) (string, error) {
|
||||
f, err := fs.Open(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to open file '%s': %w", path, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
return "", fmt.Errorf("failed to hash file '%s': %w", path, err)
|
||||
}
|
||||
|
||||
return hex.EncodeToString(hasher.Sum(nil)), nil
|
||||
}
|
|
@ -1,20 +1,20 @@
|
|||
package internal
|
||||
|
||||
type Set map[string]struct{}
|
||||
type StringSet map[string]struct{}
|
||||
|
||||
func NewStringSet() Set {
|
||||
return make(Set)
|
||||
func NewStringSet() StringSet {
|
||||
return make(StringSet)
|
||||
}
|
||||
|
||||
func (s Set) Add(i string) {
|
||||
func (s StringSet) Add(i string) {
|
||||
s[i] = struct{}{}
|
||||
}
|
||||
|
||||
func (s Set) Remove(i string) {
|
||||
func (s StringSet) Remove(i string) {
|
||||
delete(s, i)
|
||||
}
|
||||
|
||||
func (s Set) Contains(i string) bool {
|
||||
func (s StringSet) Contains(i string) bool {
|
||||
_, ok := s[i]
|
||||
return ok
|
||||
}
|
||||
|
|
208
vulnscan/db/curator.go
Normal file
208
vulnscan/db/curator.go
Normal file
|
@ -0,0 +1,208 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/anchore/vulnscan-db/pkg/db"
|
||||
"github.com/anchore/vulnscan-db/pkg/sqlite"
|
||||
"github.com/anchore/vulnscan/internal/file"
|
||||
"github.com/anchore/vulnscan/internal/log"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
const (
|
||||
supportedVersion = ">=1.0.0, <2.0.0"
|
||||
dbFileName = "vulnerability.db"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
DbDir string
|
||||
ListingURL string
|
||||
}
|
||||
|
||||
type Curator struct {
|
||||
fs afero.Fs
|
||||
config Config
|
||||
client file.Getter
|
||||
versionConstraint version.Constraints
|
||||
}
|
||||
|
||||
func NewCurator(cfg Config) (Curator, error) {
|
||||
constraint, err := version.NewConstraint(supportedVersion)
|
||||
if err != nil {
|
||||
return Curator{}, fmt.Errorf("unable to set DB curator version constraint (%s): %w", supportedVersion, err)
|
||||
}
|
||||
|
||||
return Curator{
|
||||
config: cfg,
|
||||
fs: afero.NewOsFs(),
|
||||
versionConstraint: constraint,
|
||||
client: &file.HashiGoGetter{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Curator) GetStore() (db.VulnStore, error) {
|
||||
// ensure the DB is ok
|
||||
err := c.Validate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("vulnerability database is corrupt (run db update to correct): %+v", err)
|
||||
}
|
||||
|
||||
// provide an abstraction for the underlying store
|
||||
connectOptions := sqlite.Options{
|
||||
FilePath: path.Join(c.config.DbDir, dbFileName),
|
||||
}
|
||||
store, _, err := sqlite.NewStore(&connectOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get vulnerability store: %w", err)
|
||||
}
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func (c *Curator) Delete() error {
|
||||
return c.fs.RemoveAll(c.config.DbDir)
|
||||
}
|
||||
|
||||
func (c *Curator) IsUpdateAvailable() (bool, *ListingEntry, error) {
|
||||
log.Debugf("checking for available database updates")
|
||||
|
||||
listing, err := newListingFromURL(c.fs, c.client, c.config.ListingURL)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("failed to get listing file: %w", err)
|
||||
}
|
||||
|
||||
updateEntry := listing.bestUpdate(c.versionConstraint)
|
||||
if updateEntry == nil {
|
||||
return false, nil, fmt.Errorf("no db candidates with correct version available (maybe there is an application update available?)")
|
||||
}
|
||||
log.Debugf("found database update candidate: %s", updateEntry)
|
||||
|
||||
// compare created data to current db date
|
||||
current, err := newMetadataFromDir(c.fs, c.config.DbDir)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("current metadata corrupt: %w", err)
|
||||
}
|
||||
|
||||
if current.isSupercededBy(updateEntry) {
|
||||
log.Debugf("database update available: %s", updateEntry)
|
||||
return true, updateEntry, nil
|
||||
}
|
||||
log.Debugf("no database update available")
|
||||
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
// Validate checks the current database to ensure file integrity and if it can be used by this version of the application.
|
||||
func (c *Curator) Validate() error {
|
||||
return c.validate(c.config.DbDir)
|
||||
}
|
||||
|
||||
// TODO: implement me
|
||||
// func (c *Curator) ImportFrom(manualDbPath string) error {
|
||||
// // TODO: ...
|
||||
|
||||
// // cp file to tempdir
|
||||
|
||||
// // validate tempdir
|
||||
|
||||
// // activate
|
||||
// return nil
|
||||
// }
|
||||
|
||||
func (c *Curator) UpdateTo(listing *ListingEntry) error {
|
||||
// note: the temp directory is persisted upon download/validation/activation failure to allow for investigation
|
||||
tempDir, err := c.download(listing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.validate(tempDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.activate(tempDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.fs.RemoveAll(tempDir)
|
||||
}
|
||||
|
||||
func (c *Curator) download(listing *ListingEntry) (string, error) {
|
||||
// get a temp dir
|
||||
tempDir, err := ioutil.TempDir("", "vulnscan-scratch")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to create db temp dir: %w", err)
|
||||
}
|
||||
|
||||
// download the db to the temp dir
|
||||
url := listing.URL
|
||||
|
||||
// from go-getter, adding a checksum as a query string will validate the payload after download
|
||||
// note: the checksum query parameter is not sent to the server
|
||||
query := url.Query()
|
||||
query.Add("checksum", listing.Checksum)
|
||||
url.RawQuery = query.Encode()
|
||||
|
||||
// go-getter will automatically extract all files within the archive to the temp dir
|
||||
err = c.client.GetToDir(tempDir, listing.URL.String())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to download db: %w", err)
|
||||
}
|
||||
|
||||
return tempDir, nil
|
||||
}
|
||||
|
||||
func (c *Curator) validate(dbDirPath string) error {
|
||||
// check that the disk checksum still matches the db payload
|
||||
metadata, err := newMetadataFromDir(c.fs, dbDirPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse database metadata (%s): %w", dbDirPath, err)
|
||||
}
|
||||
if metadata == nil {
|
||||
return fmt.Errorf("database metadata not found: %s", dbDirPath)
|
||||
}
|
||||
|
||||
dbPath := path.Join(dbDirPath, dbFileName)
|
||||
valid, err := file.ValidateByHash(c.fs, dbPath, metadata.Checksum)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !valid {
|
||||
return fmt.Errorf("bad db checksum (%s)", dbDirPath)
|
||||
}
|
||||
|
||||
if !c.versionConstraint.Check(metadata.Version) {
|
||||
return fmt.Errorf("unsupported database version: version=%s constraint=%s", metadata.Version.String(), c.versionConstraint.String())
|
||||
}
|
||||
|
||||
// TODO: add version checks here to ensure this version of the application can use this database version (relative to what the DB says, not JUST the metadata!)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// activate swaps over the downloaded db to the application directory
|
||||
func (c *Curator) activate(aDbDirPath string) error {
|
||||
_, err := c.fs.Stat(c.config.DbDir)
|
||||
if !os.IsNotExist(err) {
|
||||
// remove any previous databases
|
||||
err = c.Delete()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to purge existing database: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ensure there is an application db directory
|
||||
err = c.fs.MkdirAll(c.config.DbDir, 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create db directory: %w", err)
|
||||
}
|
||||
|
||||
// activate the new db cache
|
||||
return file.CopyDir(c.fs, aDbDirPath, c.config.DbDir)
|
||||
}
|
182
vulnscan/db/curator_test.go
Normal file
182
vulnscan/db/curator_test.go
Normal file
|
@ -0,0 +1,182 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/vulnscan/internal"
|
||||
"github.com/anchore/vulnscan/internal/file"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
type testGetter struct {
|
||||
file map[string]string
|
||||
dir map[string]string
|
||||
calls internal.StringSet
|
||||
fs afero.Fs
|
||||
}
|
||||
|
||||
func newTestGetter(fs afero.Fs, f, d map[string]string) *testGetter {
|
||||
return &testGetter{
|
||||
file: f,
|
||||
dir: d,
|
||||
calls: internal.NewStringSet(),
|
||||
fs: fs,
|
||||
}
|
||||
}
|
||||
|
||||
// GetFile downloads the give URL into the given path. The URL must reference a single file.
|
||||
func (g *testGetter) GetFile(dst, src string) error {
|
||||
g.calls.Add(src)
|
||||
if _, ok := g.file[src]; !ok {
|
||||
return fmt.Errorf("blerg, no file!")
|
||||
}
|
||||
return afero.WriteFile(g.fs, dst, []byte(g.file[src]), 0755)
|
||||
}
|
||||
|
||||
// Get downloads the given URL into the given directory. The directory must already exist.
|
||||
func (g *testGetter) GetToDir(dst, src string) error {
|
||||
g.calls.Add(src)
|
||||
if _, ok := g.dir[src]; !ok {
|
||||
return fmt.Errorf("blerg, no file!")
|
||||
}
|
||||
return afero.WriteFile(g.fs, dst, []byte(g.dir[src]), 0755)
|
||||
}
|
||||
|
||||
func newTestCurator(fs afero.Fs, getter file.Getter, dbDir, metadataUrl string) (Curator, error) {
|
||||
c, err := NewCurator(Config{
|
||||
DbDir: dbDir,
|
||||
ListingURL: metadataUrl,
|
||||
})
|
||||
|
||||
c.client = getter
|
||||
c.fs = fs
|
||||
return c, err
|
||||
}
|
||||
|
||||
func TestCuratorDownload(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
entry *ListingEntry
|
||||
expectedURL string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "download populates returned tempdir",
|
||||
entry: &ListingEntry{
|
||||
Built: time.Date(2020, 06, 13, 17, 13, 13, 0, time.UTC),
|
||||
URL: mustUrl(url.Parse("http://a-url/payload.tar.gz")),
|
||||
Checksum: "sha256:deadbeefcafe",
|
||||
},
|
||||
expectedURL: "http://a-url/payload.tar.gz?checksum=sha256%3Adeadbeefcafe",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
metadataUrl := "http://metadata.io"
|
||||
contents := "CONTENTS!!!"
|
||||
files := map[string]string{}
|
||||
dirs := map[string]string{
|
||||
test.expectedURL: contents,
|
||||
}
|
||||
fs := afero.NewMemMapFs()
|
||||
getter := newTestGetter(fs, files, dirs)
|
||||
cur, err := newTestCurator(fs, getter, "/tmp/dbdir", metadataUrl)
|
||||
if err != nil {
|
||||
t.Fatalf("failed making curator: %+v", err)
|
||||
}
|
||||
|
||||
path, err := cur.download(test.entry)
|
||||
|
||||
if !getter.calls.Contains(test.expectedURL) {
|
||||
t.Fatalf("never made the appropriate fetch call: %+v", getter.calls)
|
||||
}
|
||||
|
||||
f, err := fs.Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("no db file: %+v", err)
|
||||
}
|
||||
|
||||
actual, err := afero.ReadAll(f)
|
||||
if err != nil {
|
||||
t.Fatalf("bad db file read: %+v", err)
|
||||
}
|
||||
|
||||
if string(actual) != contents {
|
||||
t.Fatalf("bad contents: %+v", string(actual))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCuratorValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
constraint string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "good checksum & good constraint",
|
||||
fixture: "test-fixtures/curator-validate/good-checksum",
|
||||
constraint: ">=1.0.0, <2.0.0",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "good checksum & bad constraint",
|
||||
fixture: "test-fixtures/curator-validate/good-checksum",
|
||||
constraint: ">=0.0.0, <1.0.0",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "bad checksum & good constraint",
|
||||
fixture: "test-fixtures/curator-validate/bad-checksum",
|
||||
constraint: ">=1.0.0, <2.0.0",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "bad checksum & bad constraint",
|
||||
fixture: "test-fixtures/curator-validate/bad-checksum",
|
||||
constraint: ">=0.0.0, <1.0.0",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "allow equal version",
|
||||
fixture: "test-fixtures/curator-validate/good-checksum",
|
||||
constraint: ">=1.1.0",
|
||||
err: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
metadataUrl := "http://metadata.io"
|
||||
|
||||
fs := afero.NewOsFs()
|
||||
getter := newTestGetter(fs, nil, nil)
|
||||
cur, err := newTestCurator(fs, getter, "/tmp/dbdir", metadataUrl)
|
||||
if err != nil {
|
||||
t.Fatalf("failed making curator: %+v", err)
|
||||
}
|
||||
|
||||
constraint, err := version.NewConstraint(test.constraint)
|
||||
if err != nil {
|
||||
t.Errorf("unable to set DB curator version constraint (%s): %w", test.constraint, err)
|
||||
}
|
||||
cur.versionConstraint = constraint
|
||||
|
||||
err = cur.validate(test.fixture)
|
||||
|
||||
if err == nil && test.err {
|
||||
t.Errorf("expected an error but got none")
|
||||
} else if err != nil && !test.err {
|
||||
t.Errorf("expected no error, got: %+v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
82
vulnscan/db/listing.go
Normal file
82
vulnscan/db/listing.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/vulnscan/internal/file"
|
||||
"github.com/anchore/vulnscan/internal/log"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
// TODO: move all of this to vulnscan-db
|
||||
|
||||
type Listing struct {
|
||||
Latest ListingEntry `json:"latest"`
|
||||
Available []ListingEntry `json:"available"`
|
||||
}
|
||||
|
||||
func newListingFromPath(fs afero.Fs, path string) (Listing, error) {
|
||||
f, err := fs.Open(path)
|
||||
if err != nil {
|
||||
return Listing{}, fmt.Errorf("unable to open DB listing path: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var l Listing
|
||||
err = json.NewDecoder(f).Decode(&l)
|
||||
if err != nil {
|
||||
return Listing{}, fmt.Errorf("unable to parse DB listing: %w", err)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func newListingFromURL(fs afero.Fs, getter file.Getter, listingURL string) (Listing, error) {
|
||||
tempFile, err := afero.TempFile(fs, "", "vulnscan-listing")
|
||||
if err != nil {
|
||||
return Listing{}, fmt.Errorf("unable to create listing temp file: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
err := fs.RemoveAll(tempFile.Name())
|
||||
if err != nil {
|
||||
log.Errorf("failed to remove file (%s): %w", tempFile.Name(), err)
|
||||
}
|
||||
}()
|
||||
|
||||
// download the listing file
|
||||
err = getter.GetFile(tempFile.Name(), listingURL)
|
||||
if err != nil {
|
||||
return Listing{}, fmt.Errorf("unable to download listing: %w", err)
|
||||
}
|
||||
|
||||
// parse the listing file
|
||||
listing, err := newListingFromPath(fs, tempFile.Name())
|
||||
if err != nil {
|
||||
return Listing{}, err
|
||||
}
|
||||
return listing, nil
|
||||
}
|
||||
|
||||
func (l *Listing) bestUpdate(constraint version.Constraints) *ListingEntry {
|
||||
// extract the latest available db
|
||||
candidates := []ListingEntry{l.Latest}
|
||||
candidates = append(candidates, l.Available...)
|
||||
|
||||
// TODO: sort candidates by version and built date
|
||||
|
||||
for _, candidate := range candidates {
|
||||
log.Debugf("found update: %s", candidate)
|
||||
}
|
||||
|
||||
var updateEntry *ListingEntry
|
||||
for _, candidate := range candidates {
|
||||
if constraint.Check(candidate.Version) {
|
||||
copy := candidate
|
||||
updateEntry = ©
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return updateEntry
|
||||
}
|
67
vulnscan/db/listing_entry.go
Normal file
67
vulnscan/db/listing_entry.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
// TODO: move all of this to vulnscan-db
|
||||
|
||||
type ListingEntry struct {
|
||||
Built time.Time // RFC 3339
|
||||
Version *version.Version
|
||||
URL *url.URL
|
||||
Checksum string
|
||||
}
|
||||
|
||||
type ListingEntryJSON struct {
|
||||
Built string `json:"built"`
|
||||
Version string `json:"version"`
|
||||
URL string `json:"url"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
|
||||
func (l ListingEntryJSON) ToListingEntry() (ListingEntry, error) {
|
||||
build, err := time.Parse(time.RFC3339, l.Built)
|
||||
if err != nil {
|
||||
return ListingEntry{}, fmt.Errorf("cannot convert built time (%s): %+v", l.Built, err)
|
||||
}
|
||||
|
||||
ver, err := version.NewVersion(l.Version)
|
||||
if err != nil {
|
||||
return ListingEntry{}, fmt.Errorf("cannot parse version (%s): %+v", l.Version, err)
|
||||
}
|
||||
|
||||
u, err := url.Parse(l.URL)
|
||||
if err != nil {
|
||||
return ListingEntry{}, fmt.Errorf("cannot parse url (%s): %+v", l.URL, err)
|
||||
}
|
||||
|
||||
return ListingEntry{
|
||||
Built: build.UTC(),
|
||||
Version: ver,
|
||||
URL: u,
|
||||
Checksum: l.Checksum,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *ListingEntry) UnmarshalJSON(data []byte) error {
|
||||
var lej ListingEntryJSON
|
||||
if err := json.Unmarshal(data, &lej); err != nil {
|
||||
return err
|
||||
}
|
||||
le, err := lej.ToListingEntry()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*l = le
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l ListingEntry) String() string {
|
||||
return fmt.Sprintf("Listing(url=%s)", l.URL)
|
||||
}
|
115
vulnscan/db/listing_test.go
Normal file
115
vulnscan/db/listing_test.go
Normal file
|
@ -0,0 +1,115 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-test/deep"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func mustUrl(u *url.URL, err error) *url.URL {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func mustConst(u version.Constraints, err error) version.Constraints {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func TestNewListingFromPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
fixture string
|
||||
expected Listing
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
fixture: "test-fixtures/listing.json",
|
||||
expected: Listing{
|
||||
Latest: ListingEntry{
|
||||
Built: time.Date(2020, 06, 13, 17, 13, 13, 0, time.UTC),
|
||||
URL: mustUrl(url.Parse("http://localhost:5000/vulnerability-db-v1.1.0+2020-6-13.tar.gz")),
|
||||
Version: version.Must(version.NewVersion("1.1.0")),
|
||||
Checksum: "sha256:dcd6a285c839a7c65939e20c251202912f64826be68609dfc6e48df7f853ddc8",
|
||||
},
|
||||
Available: []ListingEntry{
|
||||
{
|
||||
Built: time.Date(2020, 06, 12, 16, 12, 12, 0, time.UTC),
|
||||
URL: mustUrl(url.Parse("http://localhost:5000/vulnerability-db-v0.2.0+2020-6-12.tar.gz")),
|
||||
Version: version.Must(version.NewVersion("0.2.0")),
|
||||
Checksum: "sha256:e20c251202948df7f853ddc812f64826bdcd6a285c839a7c65939e68609dfc6e",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.fixture, func(t *testing.T) {
|
||||
listing, err := newListingFromPath(afero.NewOsFs(), test.fixture)
|
||||
if err != nil && !test.err {
|
||||
t.Fatalf("failed to get metadata: %+v", err)
|
||||
} else if err == nil && test.err {
|
||||
t.Fatalf("expected errer but got none")
|
||||
}
|
||||
|
||||
for _, diff := range deep.Equal(listing, test.expected) {
|
||||
t.Errorf("listing difference: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListingBestUpdate(t *testing.T) {
|
||||
tests := []struct {
|
||||
fixture string
|
||||
constraint version.Constraints
|
||||
expected *ListingEntry
|
||||
}{
|
||||
{
|
||||
fixture: "test-fixtures/listing.json",
|
||||
constraint: mustConst(version.NewConstraint("> 1.0.0, < 2.0.0")),
|
||||
expected: &ListingEntry{
|
||||
Built: time.Date(2020, 06, 13, 17, 13, 13, 0, time.UTC),
|
||||
URL: mustUrl(url.Parse("http://localhost:5000/vulnerability-db-v1.1.0+2020-6-13.tar.gz")),
|
||||
Version: version.Must(version.NewVersion("1.1.0")),
|
||||
Checksum: "sha256:dcd6a285c839a7c65939e20c251202912f64826be68609dfc6e48df7f853ddc8",
|
||||
},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/listing.json",
|
||||
constraint: mustConst(version.NewConstraint("> 0.0.0, < 1.0.0")),
|
||||
expected: &ListingEntry{
|
||||
Built: time.Date(2020, 06, 12, 16, 12, 12, 0, time.UTC),
|
||||
URL: mustUrl(url.Parse("http://localhost:5000/vulnerability-db-v0.2.0+2020-6-12.tar.gz")),
|
||||
Version: version.Must(version.NewVersion("0.2.0")),
|
||||
Checksum: "sha256:e20c251202948df7f853ddc812f64826bdcd6a285c839a7c65939e68609dfc6e",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.constraint.String(), func(t *testing.T) {
|
||||
listing, err := newListingFromPath(afero.NewOsFs(), test.fixture)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get metadata: %+v", err)
|
||||
}
|
||||
|
||||
actual := listing.bestUpdate(test.constraint)
|
||||
if actual == nil && test.expected != nil || actual != nil && test.expected == nil {
|
||||
t.Fatalf("mismatched best candidate expectations")
|
||||
}
|
||||
|
||||
for _, diff := range deep.Equal(actual, test.expected) {
|
||||
t.Errorf("listing entry difference: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
110
vulnscan/db/metadata.go
Normal file
110
vulnscan/db/metadata.go
Normal file
|
@ -0,0 +1,110 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/vulnscan/internal/file"
|
||||
"github.com/anchore/vulnscan/internal/log"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
const metadataFileName = "metadata.json"
|
||||
|
||||
type Metadata struct {
|
||||
Built time.Time
|
||||
Version *version.Version
|
||||
Checksum string
|
||||
}
|
||||
|
||||
type MetadataJSON struct {
|
||||
Built string `json:"built"` // RFC 3339
|
||||
Version string `json:"version"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
|
||||
func (m MetadataJSON) ToMetadata() (Metadata, error) {
|
||||
build, err := time.Parse(time.RFC3339, m.Built)
|
||||
if err != nil {
|
||||
return Metadata{}, fmt.Errorf("cannot convert built time (%s): %+v", m.Built, err)
|
||||
}
|
||||
|
||||
ver, err := version.NewVersion(m.Version)
|
||||
if err != nil {
|
||||
return Metadata{}, fmt.Errorf("cannot parse version (%s): %+v", m.Version, err)
|
||||
}
|
||||
|
||||
metadata := Metadata{
|
||||
Built: build.UTC(),
|
||||
Version: ver,
|
||||
Checksum: m.Checksum,
|
||||
}
|
||||
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
func metadataPath(dir string) string {
|
||||
return path.Join(dir, metadataFileName)
|
||||
}
|
||||
|
||||
func newMetadataFromDir(fs afero.Fs, dir string) (*Metadata, error) {
|
||||
metadataFilePath := metadataPath(dir)
|
||||
if !file.Exists(fs, metadataFilePath) {
|
||||
return nil, nil
|
||||
}
|
||||
f, err := fs.Open(metadataFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open DB metadata path (%s): %w", metadataFilePath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var m Metadata
|
||||
err = json.NewDecoder(f).Decode(&m)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse DB metadata (%s): %w", metadataFilePath, err)
|
||||
}
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (m *Metadata) UnmarshalJSON(data []byte) error {
|
||||
var mj MetadataJSON
|
||||
if err := json.Unmarshal(data, &mj); err != nil {
|
||||
return err
|
||||
}
|
||||
me, err := mj.ToMetadata()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = me
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metadata) isSupercededBy(entry *ListingEntry) bool {
|
||||
if m == nil {
|
||||
log.Debugf("cannot find existing metadata, using update...")
|
||||
// any valid update beats no database, use it!
|
||||
return true
|
||||
}
|
||||
|
||||
if entry.Version.GreaterThan(m.Version) {
|
||||
log.Debugf("update is a newer version than the current database, using update...")
|
||||
// the listing is newer than the existing db, use it!
|
||||
return true
|
||||
}
|
||||
|
||||
if entry.Built.After(m.Built) {
|
||||
log.Debugf("existing database (%s) is older than candidate update (%s), using update...", m.Built.String(), entry.Built.String())
|
||||
// the listing is newer than the existing db, use it!
|
||||
return true
|
||||
}
|
||||
|
||||
log.Debugf("existing database is already up to date")
|
||||
return false
|
||||
}
|
||||
|
||||
func (m Metadata) String() string {
|
||||
return fmt.Sprintf("Metadata(built=%s version=%s checksum=%s)", m.Built, m.Version, m.Checksum)
|
||||
}
|
107
vulnscan/db/metadata_test.go
Normal file
107
vulnscan/db/metadata_test.go
Normal file
|
@ -0,0 +1,107 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-test/deep"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func TestMetadataParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
fixture string
|
||||
expected Metadata
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
fixture: "test-fixtures/metadata-gocase",
|
||||
expected: Metadata{
|
||||
Built: time.Date(2020, 06, 15, 14, 02, 36, 0, time.UTC),
|
||||
Version: version.Must(version.NewVersion("0.2.0")),
|
||||
Checksum: "sha256:dcd6a285c839a7c65939e20c251202912f64826be68609dfc6e48df7f853ddc8",
|
||||
},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/metadata-edt-timezone",
|
||||
expected: Metadata{
|
||||
Built: time.Date(2020, 06, 15, 18, 02, 36, 0, time.UTC),
|
||||
Version: version.Must(version.NewVersion("0.2.0")),
|
||||
Checksum: "sha256:dcd6a285c839a7c65939e20c251202912f64826be68609dfc6e48df7f853ddc8",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.fixture, func(t *testing.T) {
|
||||
metadata, err := newMetadataFromDir(afero.NewOsFs(), test.fixture)
|
||||
if err != nil && !test.err {
|
||||
t.Fatalf("failed to get metadata: %+v", err)
|
||||
} else if err == nil && test.err {
|
||||
t.Fatalf("expected errer but got none")
|
||||
}
|
||||
|
||||
if metadata == nil {
|
||||
t.Fatalf("metadata not found: %+v", test.fixture)
|
||||
}
|
||||
|
||||
for _, diff := range deep.Equal(*metadata, test.expected) {
|
||||
t.Errorf("metadata difference: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetadataIsSupercededBy(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
current *Metadata
|
||||
update *ListingEntry
|
||||
expectedToSupercede bool
|
||||
}{
|
||||
{
|
||||
name: "prefer updated versions over later dates",
|
||||
expectedToSupercede: true,
|
||||
current: &Metadata{
|
||||
Built: time.Date(2020, 06, 15, 14, 02, 36, 0, time.UTC),
|
||||
Version: version.Must(version.NewVersion("0.2.0")),
|
||||
},
|
||||
update: &ListingEntry{
|
||||
Built: time.Date(2020, 06, 13, 17, 13, 13, 0, time.UTC),
|
||||
Version: version.Must(version.NewVersion("0.3.0")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prefer later dates when version is the same",
|
||||
expectedToSupercede: false,
|
||||
current: &Metadata{
|
||||
Built: time.Date(2020, 06, 15, 14, 02, 36, 0, time.UTC),
|
||||
Version: version.Must(version.NewVersion("1.1.0")),
|
||||
},
|
||||
update: &ListingEntry{
|
||||
Built: time.Date(2020, 06, 13, 17, 13, 13, 0, time.UTC),
|
||||
Version: version.Must(version.NewVersion("1.1.0")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prefer something over nothing",
|
||||
expectedToSupercede: true,
|
||||
current: nil,
|
||||
update: &ListingEntry{
|
||||
Built: time.Date(2020, 06, 13, 17, 13, 13, 0, time.UTC),
|
||||
Version: version.Must(version.NewVersion("1.1.0")),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := test.current.isSupercededBy(test.update)
|
||||
|
||||
if test.expectedToSupercede != actual {
|
||||
t.Errorf("failed supercede assertion: got %+v", actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"built": "2020-06-15T14:02:36Z",
|
||||
"version": "1.1.0",
|
||||
"checksum": "sha256:deadbeefcafe"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
I can haz cve?
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"built": "2020-06-15T14:02:36Z",
|
||||
"version": "1.1.0",
|
||||
"checksum": "sha256:3baf9c50c94e7f1e65bafac2e6a6d559fb177461dd25bf8fca7e6e9e9c266cb4"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
I can haz cve?
|
16
vulnscan/db/test-fixtures/listing.json
Normal file
16
vulnscan/db/test-fixtures/listing.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"latest": {
|
||||
"built": "2020-06-13T13:13:13-04:00",
|
||||
"version": "1.1.0",
|
||||
"url": "http://localhost:5000/vulnerability-db-v1.1.0+2020-6-13.tar.gz",
|
||||
"checksum": "sha256:dcd6a285c839a7c65939e20c251202912f64826be68609dfc6e48df7f853ddc8"
|
||||
},
|
||||
"available": [
|
||||
{
|
||||
"built": "2020-06-12T12:12:12-04:00",
|
||||
"version": "0.2.0",
|
||||
"url": "http://localhost:5000/vulnerability-db-v0.2.0+2020-6-12.tar.gz",
|
||||
"checksum": "sha256:e20c251202948df7f853ddc812f64826bdcd6a285c839a7c65939e68609dfc6e"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"built": "2020-06-15T14:02:36-04:00",
|
||||
"updated": "2020-06-15T14:02:36-04:00",
|
||||
"last-check": "2020-06-15T14:02:36-04:00",
|
||||
"version": "0.2.0",
|
||||
"checksum": "sha256:dcd6a285c839a7c65939e20c251202912f64826be68609dfc6e48df7f853ddc8"
|
||||
}
|
5
vulnscan/db/test-fixtures/metadata-gocase/metadata.json
Normal file
5
vulnscan/db/test-fixtures/metadata-gocase/metadata.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"built": "2020-06-15T14:02:36Z",
|
||||
"version": "0.2.0",
|
||||
"checksum": "sha256:dcd6a285c839a7c65939e20c251202912f64826be68609dfc6e48df7f853ddc8"
|
||||
}
|
|
@ -42,15 +42,12 @@ func (pres *Presenter) Present(output io.Writer, catalog *pkg.Catalog, results r
|
|||
Package: Package{Name: pkg.Name, Version: pkg.Version}},
|
||||
)
|
||||
|
||||
//for _, match := range matches {
|
||||
doc = append(
|
||||
doc,
|
||||
ResultObj{
|
||||
Cve: match.Vulnerability.ID,
|
||||
Package: Package{Name: pkg.Name, Version: pkg.Version}},
|
||||
)
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(&doc)
|
||||
|
|
|
@ -15,34 +15,35 @@ import (
|
|||
|
||||
var update = flag.Bool("update", false, "update the *.golden files for json presenters")
|
||||
|
||||
var pkg1 = pkg.Package{
|
||||
Name: "package-1",
|
||||
Version: "1.0.1",
|
||||
Type: pkg.DebPkg,
|
||||
}
|
||||
|
||||
var pkg2 = pkg.Package{
|
||||
Name: "package-2",
|
||||
Version: "2.0.1",
|
||||
Type: pkg.DebPkg,
|
||||
}
|
||||
|
||||
var match1 = match.Match{
|
||||
Type: match.ExactDirectMatch,
|
||||
Vulnerability: vulnerability.Vulnerability{ID: "CVE-1999-0001"},
|
||||
// XXX: matches also have a `pkg *pkg.Pkg` field
|
||||
}
|
||||
|
||||
var match2 = match.Match{
|
||||
Type: match.ExactIndirectMatch,
|
||||
Vulnerability: vulnerability.Vulnerability{ID: "CVE-1999-0002"},
|
||||
}
|
||||
|
||||
func TestJsonPresenter(t *testing.T) {
|
||||
|
||||
pres := NewPresenter()
|
||||
var buffer bytes.Buffer
|
||||
|
||||
var pkg1 = pkg.Package{
|
||||
Name: "package-1",
|
||||
Version: "1.0.1",
|
||||
Type: pkg.DebPkg,
|
||||
}
|
||||
|
||||
var pkg2 = pkg.Package{
|
||||
Name: "package-2",
|
||||
Version: "2.0.1",
|
||||
Type: pkg.DebPkg,
|
||||
}
|
||||
|
||||
var match1 = match.Match{
|
||||
Type: match.ExactDirectMatch,
|
||||
Vulnerability: vulnerability.Vulnerability{ID: "CVE-1999-0001"},
|
||||
Package: &pkg1,
|
||||
}
|
||||
|
||||
var match2 = match.Match{
|
||||
Type: match.ExactIndirectMatch,
|
||||
Vulnerability: vulnerability.Vulnerability{ID: "CVE-1999-0002"},
|
||||
Package: &pkg1,
|
||||
}
|
||||
|
||||
results := result.NewResult()
|
||||
|
||||
results.Add(&pkg1, match1, match2)
|
||||
|
|
|
@ -1 +1 @@
|
|||
[{"cve":"CVE-1999-0001","package":{"name":"package-1","version":"1.0.1"}},{"cve":"CVE-1999-0002","package":{"name":"package-1","version":"1.0.1"}}]
|
||||
[{"cve":"CVE-1999-0001","package":{"name":"package-1","version":"1.0.1"}},{"cve":"CVE-1999-0001","package":{"name":"package-1","version":"1.0.1"}},{"cve":"CVE-1999-0002","package":{"name":"package-1","version":"1.0.1"}},{"cve":"CVE-1999-0002","package":{"name":"package-1","version":"1.0.1"}}]
|
|
@ -19,6 +19,26 @@ func TestDistroNamespace_AllDistros(t *testing.T) {
|
|||
version: "8",
|
||||
expected: "debian:8",
|
||||
},
|
||||
{
|
||||
dist: distro.Busybox,
|
||||
version: "3.1.1",
|
||||
expected: "busybox:3.1.1",
|
||||
},
|
||||
{
|
||||
dist: distro.CentOS,
|
||||
version: "7",
|
||||
expected: "centos:7",
|
||||
},
|
||||
{
|
||||
dist: distro.Ubuntu,
|
||||
version: "18.04",
|
||||
expected: "ubuntu:18.04",
|
||||
},
|
||||
{
|
||||
dist: distro.RedHat,
|
||||
version: "6",
|
||||
expected: "redhat:6",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
Loading…
Reference in a new issue