Compare commits

...

43 Commits

Author SHA1 Message Date
Kota Kanbe
8e18451e3f Merge branch 'master' of github.com:future-architect/vuls 2021-01-28 08:24:23 +09:00
Kota Kanbe
3dbdd01f97 fix(report): wordrpess scanning skipped when package is emtpy (#1150) 2021-01-28 08:24:03 +09:00
sadayuki-matsuno
a89079c005 fix(saas) change saas upload s3 key (#1116) 2021-01-28 08:20:13 +09:00
sadayuki-matsuno
a8c0926b4f fix(saas) change saas upload s3 key (#1116) 2021-01-27 14:43:09 +09:00
Kota Kanbe
dd2959a31b fix(eol): add eol for alpine 3.13 (#1149) 2021-01-27 12:52:07 +09:00
Kota Kanbe
51099f42c3 fix(tui): runtime panic when tui with docker-base-setup (#1148)
* fix(tui): runtime panic when tui with docker-base-setup

* pass test case
2021-01-26 09:40:26 +09:00
Kota Kanbe
63f170cc7a fix(report): set severity in Red Hat OVAL to both CVSS v3 and v2 #1146 (#1147) 2021-01-26 07:58:59 +09:00
Kota Kanbe
3c1489e588 feat(report): range notion calc by severity when no-cvss-score (#1145) 2021-01-25 13:22:55 +09:00
Kota Kanbe
e4f1e03f62 feat(github): display GitHub Security Advisory details (#1143) 2021-01-24 09:15:04 +09:00
Kota Kanbe
83d48ec990 Create codeql-analysis.yml 2021-01-24 09:06:13 +09:00
Kota Kanbe
b20d2b2684 fix(scan): skip wordpress scan for preudo servers (#1142) 2021-01-21 07:11:55 +09:00
Kota Kanbe
2b918c70ae fix(scan): config dump nocolor in debug mode. (#1141) 2021-01-21 06:38:37 +09:00
Kota Kanbe
1100c133ba feat(config): Default values for WordPress scanning to be set in config.toml (#1140)
* chore: update go mod

* fix(wordpress): set default if defined in config.toml
2021-01-21 06:22:25 +09:00
Kota Kanbe
88899f0e89 refactor: around CheckHTTPHealth (#1139) 2021-01-20 07:41:29 +09:00
Kota Kanbe
59dc0059bc fix(model): omit changelog from json if empty (#1137) 2021-01-19 09:01:35 +09:00
Kota Kanbe
986fb304c0 fix(scan): add --nogpgcheck to dnf mod list to avoid Error: Cache-only enabled but no cache for *** (#1136) 2021-01-19 08:05:20 +09:00
Kota Kanbe
d6435d2885 fix(xml): remove -format-xml #1068 (#1134) 2021-01-18 04:38:00 +09:00
shopper
affb456499 fix(email.go):Fix runtime error(invalid memory address) (#1133) 2021-01-18 04:08:14 +09:00
Kota Kanbe
705ed0a0ac fix(discover): change config.toml template (#1132) 2021-01-16 07:58:46 +09:00
Kota Kanbe
dfffe5b508 fix(config): err occurs when host not set in local-scan-mode (#1129)
If host is not set in local scan mode, an error occurs.
2021-01-14 09:22:04 +09:00
Shigechika AIKAWA
fca102edba fix dnf prompt and ssh user (#1126) 2021-01-14 08:22:06 +09:00
Kota Kanbe
554b6345a2 chore: go mod update (#1127) 2021-01-14 08:12:47 +09:00
Kota Kanbe
aa954dc84c fix(scan): kindness msg when no-cache err on dnf mod list (#1128) 2021-01-14 08:12:35 +09:00
Kota Kanbe
b5506a1368 chore: go mod update (#1125) 2021-01-13 11:56:35 +09:00
Kota Kanbe
0b55f94828 Improve implementation around config (#1122)
* refactor config

* fix saas config

* feat(config): scanmodule for each server in config.toml

* feat(config): enable to specify containersOnly in config.toml

* add new keys of config.toml to discover.go

* fix summary output, logging
2021-01-13 08:46:27 +09:00
Kota Kanbe
a67052f48c fix(scan): err detecting EOL for alpine Linux (#1124) 2021-01-12 20:10:22 +09:00
Kota Kanbe
6eff6a9329 feat(report): display EOL information to scan summary (#1120)
* feat(report): display EOL information to scan summary

* detect Amazon linux EOL
2021-01-09 07:58:55 +09:00
Kota Kanbe
69d32d4511 feat(report): add a err code to wpscan.com API error (#1119) 2021-01-07 14:57:49 +09:00
Kota Kanbe
d7a613b710 chore: go mod update (#1118) 2021-01-07 08:02:29 +09:00
sadayuki-matsuno
669c019287 fix(cvecontent) Fixed not to split empty string (#1117) 2021-01-06 15:52:55 +09:00
Shigechika AIKAWA
fcc4901a10 fix(scan): Failed to parse CentOS Stream (#1098) 2021-01-06 14:57:19 +09:00
Kota Kanbe
4359503484 fix(redhat): possibility of false positives on RHEL (#1115) 2021-01-06 13:33:08 +09:00
Kota Kanbe
b13f93a2d3 feat(scan): support dnf modules (#1114)
* feat(scan): support dnf modules

* change dnf module list --installed to --enabled

* chore: refactor

* feat(report): detect logic for dnf modularity label

* fix func name

* chore: update go mods
2021-01-06 11:36:41 +09:00
Kota Kanbe
8405e0fad6 refactor(gost): Duplicate code into function (#1110)
* refactor(gost): Duplicate code into function

* fix
2020-12-30 08:33:30 +09:00
Kota Kanbe
aceb3f1826 fix(scan): add an error case for rpm -qa (#1109) 2020-12-30 08:05:14 +09:00
Kota Kanbe
a206675f3e fix(wordpress): remove cache because not permitted. (#1107) 2020-12-29 07:25:58 +09:00
Kota Kanbe
f4253d74ae fix(wordpress): wpscan.com unmarshal error (#1106)
* refactor(report): remove Integration.apply

* add an err check

* fix(wordpress): wpscan.com unmarshal error

* fix warnings
2020-12-29 07:11:04 +09:00
Kota Kanbe
aaea15e516 refactor(report): remove Integration.apply (#1105)
* refactor(report): remove Integration.apply

* add an err check
2020-12-29 06:59:48 +09:00
Kota Kanbe
83d1f80959 chore(report): remove stride and hipchat support (#1104) 2020-12-26 08:52:45 +09:00
Kota Kanbe
a33cff8f13 fix(reprot): use SQLite3 in current dir if not specified (#1103) 2020-12-26 08:24:17 +09:00
Kota Kanbe
8679759f60 chore: fix typo (#1102) 2020-12-26 08:23:02 +09:00
Kota Kanbe
53deaee3d7 refactor(config): remove DependencyCheckXMLPath in config.toml (#1100) 2020-12-25 06:38:00 +09:00
Kota Kanbe
5a14a58fe4 refactor(nvdxml): Remove codes related to NVD xml(deprecated) (#1099) 2020-12-25 06:16:14 +09:00
86 changed files with 3132 additions and 2975 deletions

67
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '32 20 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -92,7 +92,7 @@ Vuls is a tool created to solve the problems listed above. It has the following
- [RustSec Advisory Database](https://github.com/RustSec/advisory-db)
- WordPress
- [WPVulnDB](https://wpvulndb.com/api)
- [wpscan](https://wpscan.com/api)
### Scan mode
@@ -177,6 +177,10 @@ For more information such as Installation, Tutorial, Usage, visit [vuls.io](http
kotakanbe ([@kotakanbe](https://twitter.com/kotakanbe)) created vuls and [these fine people](https://github.com/future-architect/vuls/graphs/contributors) have contributed.
## Contribute
see [vulsdoc](https://vuls.io/docs/en/how-to-contribute.html)
----
## Stargazers over time

32
config/chatworkconf.go Normal file
View File

@@ -0,0 +1,32 @@
package config
import (
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// ChatWorkConf is ChatWork config
type ChatWorkConf struct {
APIToken string `json:"-"`
Room string `json:"-"`
}
// Validate validates configuration
func (c *ChatWorkConf) Validate() (errs []error) {
if !Conf.ToChatWork {
return
}
if len(c.Room) == 0 {
errs = append(errs, xerrors.New("chatWorkConf.room must not be empty"))
}
if len(c.APIToken) == 0 {
errs = append(errs, xerrors.New("chatWorkConf.ApiToken must not be empty"))
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}

File diff suppressed because it is too large Load Diff

73
config/exploitconf.go Normal file
View File

@@ -0,0 +1,73 @@
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// ExploitConf is exploit config
type ExploitConf struct {
// DB type for exploit dictionary (sqlite3, mysql, postgres or redis)
Type string
// http://exploit-dictionary.com:1324 or DB connection string
URL string `json:"-"`
// /path/to/exploit.sqlite3
SQLite3Path string `json:"-"`
}
func (cnf *ExploitConf) setDefault() {
if cnf.Type == "" {
cnf.Type = "sqlite3"
}
if cnf.URL == "" && cnf.SQLite3Path == "" {
wd, _ := os.Getwd()
cnf.SQLite3Path = filepath.Join(wd, "go-exploitdb.sqlite3")
}
}
const exploitDBType = "EXPLOITDB_TYPE"
const exploitDBURL = "EXPLOITDB_URL"
const exploitDBPATH = "EXPLOITDB_SQLITE3_PATH"
// Init set options with the following priority.
// 1. Environment variable
// 2. config.toml
func (cnf *ExploitConf) Init() {
if os.Getenv(exploitDBType) != "" {
cnf.Type = os.Getenv(exploitDBType)
}
if os.Getenv(exploitDBURL) != "" {
cnf.URL = os.Getenv(exploitDBURL)
}
if os.Getenv(exploitDBPATH) != "" {
cnf.SQLite3Path = os.Getenv(exploitDBPATH)
}
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *ExploitConf) IsFetchViaHTTP() bool {
return Conf.Exploit.Type == "http"
}
// CheckHTTPHealth do health check
func (cnf *ExploitConf) CheckHTTPHealth() error {
if !cnf.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.URL)
resp, _, errs := gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to exploit server. url: %s, errs: %s", url, errs)
}
return nil
}

73
config/gocvedictconf.go Normal file
View File

@@ -0,0 +1,73 @@
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// GoCveDictConf is go-cve-dictionary config
type GoCveDictConf struct {
// DB type of CVE dictionary (sqlite3, mysql, postgres or redis)
Type string
// http://cve-dictionary.com:1323 or DB connection string
URL string `json:"-"`
// /path/to/cve.sqlite3
SQLite3Path string `json:"-"`
}
func (cnf *GoCveDictConf) setDefault() {
if cnf.Type == "" {
cnf.Type = "sqlite3"
}
if cnf.URL == "" && cnf.SQLite3Path == "" {
wd, _ := os.Getwd()
cnf.SQLite3Path = filepath.Join(wd, "cve.sqlite3")
}
}
const cveDBType = "CVEDB_TYPE"
const cveDBURL = "CVEDB_URL"
const cveDBPATH = "CVEDB_SQLITE3_PATH"
// Init set options with the following priority.
// 1. Environment variable
// 2. config.toml
func (cnf *GoCveDictConf) Init() {
if os.Getenv(cveDBType) != "" {
cnf.Type = os.Getenv(cveDBType)
}
if os.Getenv(cveDBURL) != "" {
cnf.URL = os.Getenv(cveDBURL)
}
if os.Getenv(cveDBPATH) != "" {
cnf.SQLite3Path = os.Getenv(cveDBPATH)
}
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *GoCveDictConf) IsFetchViaHTTP() bool {
return Conf.CveDict.Type == "http"
}
// CheckHTTPHealth checks http server status
func (cnf *GoCveDictConf) CheckHTTPHealth() error {
if !cnf.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.URL)
resp, _, errs := gorequest.New().SetDebug(Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to request to CVE server. url: %s, errs: %s",
url, errs)
}
return nil
}

73
config/gostconf.go Normal file
View File

@@ -0,0 +1,73 @@
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// GostConf is gost config
type GostConf struct {
// DB type for gost dictionary (sqlite3, mysql, postgres or redis)
Type string
// http://gost-dictionary.com:1324 or DB connection string
URL string `json:"-"`
// /path/to/gost.sqlite3
SQLite3Path string `json:"-"`
}
func (cnf *GostConf) setDefault() {
if cnf.Type == "" {
cnf.Type = "sqlite3"
}
if cnf.URL == "" && cnf.SQLite3Path == "" {
wd, _ := os.Getwd()
cnf.SQLite3Path = filepath.Join(wd, "gost.sqlite3")
}
}
const gostDBType = "GOSTDB_TYPE"
const gostDBURL = "GOSTDB_URL"
const gostDBPATH = "GOSTDB_SQLITE3_PATH"
// Init set options with the following priority.
// 1. Environment variable
// 2. config.toml
func (cnf *GostConf) Init() {
if os.Getenv(gostDBType) != "" {
cnf.Type = os.Getenv(gostDBType)
}
if os.Getenv(gostDBURL) != "" {
cnf.URL = os.Getenv(gostDBURL)
}
if os.Getenv(gostDBPATH) != "" {
cnf.SQLite3Path = os.Getenv(gostDBPATH)
}
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *GostConf) IsFetchViaHTTP() bool {
return Conf.Gost.Type == "http"
}
// CheckHTTPHealth do health check
func (cnf *GostConf) CheckHTTPHealth() error {
if !cnf.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.URL)
resp, _, errs := gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to gost server. url: %s, errs: %s", url, errs)
}
return nil
}

75
config/govaldictconf.go Normal file
View File

@@ -0,0 +1,75 @@
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// GovalDictConf is goval-dictionary config
type GovalDictConf struct {
// DB type of OVAL dictionary (sqlite3, mysql, postgres or redis)
Type string
// http://goval-dictionary.com:1324 or DB connection string
URL string `json:"-"`
// /path/to/oval.sqlite3
SQLite3Path string `json:"-"`
}
func (cnf *GovalDictConf) setDefault() {
if cnf.Type == "" {
cnf.Type = "sqlite3"
}
if cnf.URL == "" && cnf.SQLite3Path == "" {
wd, _ := os.Getwd()
cnf.SQLite3Path = filepath.Join(wd, "oval.sqlite3")
}
}
const govalType = "OVALDB_TYPE"
const govalURL = "OVALDB_URL"
const govalPATH = "OVALDB_SQLITE3_PATH"
// Init set options with the following priority.
// 1. Environment variable
// 2. config.toml
func (cnf *GovalDictConf) Init() {
if os.Getenv(govalType) != "" {
cnf.Type = os.Getenv(govalType)
}
if os.Getenv(govalURL) != "" {
cnf.URL = os.Getenv(govalURL)
}
if os.Getenv(govalPATH) != "" {
cnf.SQLite3Path = os.Getenv(govalPATH)
}
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *GovalDictConf) IsFetchViaHTTP() bool {
return Conf.OvalDict.Type == "http"
}
// CheckHTTPHealth do health check
func (cnf *GovalDictConf) CheckHTTPHealth() error {
if !cnf.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.URL)
resp, _, errs := gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to request to OVAL server. url: %s, errs: %s",
url, errs)
}
return nil
}

38
config/httpconf.go Normal file
View File

@@ -0,0 +1,38 @@
package config
import (
"os"
"github.com/asaskevich/govalidator"
)
// HTTPConf is HTTP config
type HTTPConf struct {
URL string `valid:"url" json:"-"`
}
// Validate validates configuration
func (c *HTTPConf) Validate() (errs []error) {
if !Conf.ToHTTP {
return nil
}
if _, err := govalidator.ValidateStruct(c); err != nil {
errs = append(errs, err)
}
return errs
}
const httpKey = "VULS_HTTP_URL"
// Init set options with the following priority.
// 1. Environment variable
// 2. config.toml
func (c *HTTPConf) Init(toml HTTPConf) {
if os.Getenv(httpKey) != "" {
c.URL = os.Getenv(httpKey)
}
if toml.URL != "" {
c.URL = toml.URL
}
}

73
config/metasploitconf.go Normal file
View File

@@ -0,0 +1,73 @@
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// MetasploitConf is metasploit config
type MetasploitConf struct {
// DB type for metasploit dictionary (sqlite3, mysql, postgres or redis)
Type string
// http://metasploit-dictionary.com:1324 or DB connection string
URL string `json:"-"`
// /path/to/metasploit.sqlite3
SQLite3Path string `json:"-"`
}
func (cnf *MetasploitConf) setDefault() {
if cnf.Type == "" {
cnf.Type = "sqlite3"
}
if cnf.URL == "" && cnf.SQLite3Path == "" {
wd, _ := os.Getwd()
cnf.SQLite3Path = filepath.Join(wd, "go-msfdb.sqlite3")
}
}
const metasploitDBType = "METASPLOITDB_TYPE"
const metasploitDBURL = "METASPLOITDB_URL"
const metasploitDBPATH = "METASPLOITDB_SQLITE3_PATH"
// Init set options with the following priority.
// 1. Environment variable
// 2. config.toml
func (cnf *MetasploitConf) Init() {
if os.Getenv(metasploitDBType) != "" {
cnf.Type = os.Getenv(metasploitDBType)
}
if os.Getenv(metasploitDBURL) != "" {
cnf.URL = os.Getenv(metasploitDBURL)
}
if os.Getenv(metasploitDBPATH) != "" {
cnf.SQLite3Path = os.Getenv(metasploitDBPATH)
}
cnf.setDefault()
}
// IsFetchViaHTTP returns wether fetch via http
func (cnf *MetasploitConf) IsFetchViaHTTP() bool {
return Conf.Metasploit.Type == "http"
}
// CheckHTTPHealth do health check
func (cnf *MetasploitConf) CheckHTTPHealth() error {
if !cnf.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.URL)
resp, _, errs := gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to metasploit server. url: %s, errs: %s", url, errs)
}
return nil
}

249
config/os.go Normal file
View File

@@ -0,0 +1,249 @@
package config
import (
"fmt"
"strings"
"time"
)
const (
// RedHat is
RedHat = "redhat"
// Debian is
Debian = "debian"
// Ubuntu is
Ubuntu = "ubuntu"
// CentOS is
CentOS = "centos"
// Fedora is
// Fedora = "fedora"
// Amazon is
Amazon = "amazon"
// Oracle is
Oracle = "oracle"
// FreeBSD is
FreeBSD = "freebsd"
// Raspbian is
Raspbian = "raspbian"
// Windows is
Windows = "windows"
// OpenSUSE is
OpenSUSE = "opensuse"
// OpenSUSELeap is
OpenSUSELeap = "opensuse.leap"
// SUSEEnterpriseServer is
SUSEEnterpriseServer = "suse.linux.enterprise.server"
// SUSEEnterpriseDesktop is
SUSEEnterpriseDesktop = "suse.linux.enterprise.desktop"
// SUSEOpenstackCloud is
SUSEOpenstackCloud = "suse.openstack.cloud"
// Alpine is
Alpine = "alpine"
// ServerTypePseudo is used for ServerInfo.Type, r.Family
ServerTypePseudo = "pseudo"
)
// EOL has End-of-Life information
type EOL struct {
StandardSupportUntil time.Time
ExtendedSupportUntil time.Time
Ended bool
}
// IsStandardSupportEnded checks now is under standard support
func (e EOL) IsStandardSupportEnded(now time.Time) bool {
return e.Ended ||
!e.ExtendedSupportUntil.IsZero() && e.StandardSupportUntil.IsZero() ||
!e.StandardSupportUntil.IsZero() && now.After(e.StandardSupportUntil)
}
// IsExtendedSuppportEnded checks now is under extended support
func (e EOL) IsExtendedSuppportEnded(now time.Time) bool {
if e.Ended {
return true
}
if e.StandardSupportUntil.IsZero() && e.ExtendedSupportUntil.IsZero() {
return false
}
return !e.ExtendedSupportUntil.IsZero() && now.After(e.ExtendedSupportUntil) ||
e.ExtendedSupportUntil.IsZero() && now.After(e.StandardSupportUntil)
}
// GetEOL return EOL information for the OS-release passed by args
// https://github.com/aquasecurity/trivy/blob/master/pkg/detector/ospkg/redhat/redhat.go#L20
func GetEOL(family, release string) (eol EOL, found bool) {
switch family {
case Amazon:
rel := "2"
if isAmazonLinux1(release) {
rel = "1"
}
eol, found = map[string]EOL{
"1": {StandardSupportUntil: time.Date(2023, 6, 30, 23, 59, 59, 0, time.UTC)},
"2": {},
}[rel]
case RedHat:
// https://access.redhat.com/support/policy/updates/errata
eol, found = map[string]EOL{
"3": {Ended: true},
"4": {Ended: true},
"5": {Ended: true},
"6": {
StandardSupportUntil: time.Date(2020, 11, 30, 23, 59, 59, 0, time.UTC),
ExtendedSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC),
},
"7": {
StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC),
},
"8": {
StandardSupportUntil: time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC),
},
}[major(release)]
case CentOS:
// https://en.wikipedia.org/wiki/CentOS#End-of-support_schedule
// TODO Stream
eol, found = map[string]EOL{
"3": {Ended: true},
"4": {Ended: true},
"5": {Ended: true},
"6": {Ended: true},
"7": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
"8": {StandardSupportUntil: time.Date(2021, 12, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case Oracle:
eol, found = map[string]EOL{
// Source:
// https://www.oracle.com/a/ocom/docs/elsp-lifetime-069338.pdf
// https://community.oracle.com/docs/DOC-917964
"3": {Ended: true},
"4": {Ended: true},
"5": {Ended: true},
"6": {
StandardSupportUntil: time.Date(2021, 3, 1, 23, 59, 59, 0, time.UTC),
ExtendedSupportUntil: time.Date(2024, 3, 1, 23, 59, 59, 0, time.UTC),
},
"7": {
StandardSupportUntil: time.Date(2024, 7, 1, 23, 59, 59, 0, time.UTC),
},
"8": {
StandardSupportUntil: time.Date(2029, 7, 1, 23, 59, 59, 0, time.UTC),
},
}[major(release)]
case Debian:
eol, found = map[string]EOL{
// https://wiki.debian.org/LTS
"6": {Ended: true},
"7": {Ended: true},
"8": {Ended: true},
"9": {StandardSupportUntil: time.Date(2022, 6, 30, 23, 59, 59, 0, time.UTC)},
"10": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case Raspbian:
// Not found
eol, found = map[string]EOL{}[major(release)]
case Ubuntu:
// https://wiki.ubuntu.com/Releases
eol, found = map[string]EOL{
"14.10": {Ended: true},
"14.04": {
ExtendedSupportUntil: time.Date(2022, 4, 1, 23, 59, 59, 0, time.UTC),
},
"15.04": {Ended: true},
"16.10": {Ended: true},
"17.04": {Ended: true},
"17.10": {Ended: true},
"16.04": {
StandardSupportUntil: time.Date(2021, 4, 1, 23, 59, 59, 0, time.UTC),
ExtendedSupportUntil: time.Date(2024, 4, 1, 23, 59, 59, 0, time.UTC),
},
"18.04": {
StandardSupportUntil: time.Date(2023, 4, 1, 23, 59, 59, 0, time.UTC),
ExtendedSupportUntil: time.Date(2028, 4, 1, 23, 59, 59, 0, time.UTC),
},
"18.10": {Ended: true},
"19.04": {Ended: true},
"19.10": {Ended: true},
"20.04": {
StandardSupportUntil: time.Date(2025, 4, 1, 23, 59, 59, 0, time.UTC),
},
"21.04": {
StandardSupportUntil: time.Date(2022, 1, 1, 23, 59, 59, 0, time.UTC),
},
"21.10": {
StandardSupportUntil: time.Date(2022, 7, 1, 23, 59, 59, 0, time.UTC),
},
}[release]
case SUSEEnterpriseServer:
//TODO
case Alpine:
// https://github.com/aquasecurity/trivy/blob/master/pkg/detector/ospkg/alpine/alpine.go#L19
// https://wiki.alpinelinux.org/wiki/Alpine_Linux:Releases
eol, found = map[string]EOL{
"2.0": {Ended: true},
"2.1": {Ended: true},
"2.2": {Ended: true},
"2.3": {Ended: true},
"2.4": {Ended: true},
"2.5": {Ended: true},
"2.6": {Ended: true},
"2.7": {Ended: true},
"3.0": {Ended: true},
"3.1": {Ended: true},
"3.2": {Ended: true},
"3.3": {Ended: true},
"3.4": {Ended: true},
"3.5": {Ended: true},
"3.6": {Ended: true},
"3.7": {Ended: true},
"3.8": {Ended: true},
"3.9": {Ended: true},
"3.10": {StandardSupportUntil: time.Date(2021, 5, 1, 23, 59, 59, 0, time.UTC)},
"3.11": {StandardSupportUntil: time.Date(2021, 11, 1, 23, 59, 59, 0, time.UTC)},
"3.12": {StandardSupportUntil: time.Date(2022, 5, 1, 23, 59, 59, 0, time.UTC)},
"3.13": {StandardSupportUntil: time.Date(2022, 11, 1, 23, 59, 59, 0, time.UTC)},
}[majorDotMinor(release)]
case FreeBSD:
// https://www.freebsd.org/security/
eol, found = map[string]EOL{
"7": {Ended: true},
"8": {Ended: true},
"9": {Ended: true},
"10": {Ended: true},
"11": {StandardSupportUntil: time.Date(2021, 9, 30, 23, 59, 59, 0, time.UTC)},
"12": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
}[major(release)]
}
return
}
func major(osVer string) (majorVersion string) {
return strings.Split(osVer, ".")[0]
}
func majorDotMinor(osVer string) (majorDotMinor string) {
ss := strings.SplitN(osVer, ".", 3)
if len(ss) == 1 {
return osVer
}
return fmt.Sprintf("%s.%s", ss[0], ss[1])
}
func isAmazonLinux1(osRelease string) bool {
return len(strings.Fields(osRelease)) == 1
}

373
config/os_test.go Normal file
View File

@@ -0,0 +1,373 @@
package config
import (
"testing"
"time"
)
func TestEOL_IsStandardSupportEnded(t *testing.T) {
type fields struct {
family string
release string
}
tests := []struct {
name string
fields fields
now time.Time
found bool
stdEnded bool
extEnded bool
}{
// Amazon Linux
{
name: "amazon linux 1 supported",
fields: fields{family: Amazon, release: "2018.03"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "amazon linux 1 eol on 2023-6-30",
fields: fields{family: Amazon, release: "2018.03"},
now: time.Date(2023, 7, 1, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
{
name: "amazon linux 2 supported",
fields: fields{family: Amazon, release: "2 (Karoo)"},
now: time.Date(2023, 7, 1, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
//RHEL
{
name: "RHEL7 supported",
fields: fields{family: RedHat, release: "7"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "RHEL8 supported",
fields: fields{family: RedHat, release: "8"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "RHEL6 eol",
fields: fields{family: RedHat, release: "6"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: false,
found: true,
},
{
name: "RHEL9 not found",
fields: fields{family: RedHat, release: "9"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//CentOS
{
name: "CentOS 7 supported",
fields: fields{family: CentOS, release: "7"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "CentOS 8 supported",
fields: fields{family: CentOS, release: "8"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "CentOS 6 eol",
fields: fields{family: CentOS, release: "6"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
{
name: "CentOS 9 not found",
fields: fields{family: CentOS, release: "9"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//Oracle
{
name: "Oracle Linux 7 supported",
fields: fields{family: Oracle, release: "7"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Oracle Linux 8 supported",
fields: fields{family: Oracle, release: "8"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Oracle Linux 6 eol",
fields: fields{family: Oracle, release: "6"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Oracle Linux 9 not found",
fields: fields{family: Oracle, release: "9"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//Ubuntu
{
name: "Ubuntu 18.04 supported",
fields: fields{family: Ubuntu, release: "18.04"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Ubuntu 18.04 ext supported",
fields: fields{family: Ubuntu, release: "18.04"},
now: time.Date(2025, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: false,
found: true,
},
{
name: "Ubuntu 16.04 supported",
fields: fields{family: Ubuntu, release: "18.04"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Ubuntu 14.04 eol",
fields: fields{family: Ubuntu, release: "14.04"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: false,
found: true,
},
{
name: "Ubuntu 14.10 eol",
fields: fields{family: Ubuntu, release: "14.10"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
{
name: "Ubuntu 12.10 not found",
fields: fields{family: Ubuntu, release: "12.10"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
found: false,
stdEnded: false,
extEnded: false,
},
{
name: "Ubuntu 21.04 supported",
fields: fields{family: Ubuntu, release: "21.04"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
found: true,
stdEnded: false,
extEnded: false,
},
//Debian
{
name: "Debian 9 supported",
fields: fields{family: Debian, release: "9"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Debian 10 supported",
fields: fields{family: Debian, release: "10"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Debian 8 supported",
fields: fields{family: Debian, release: "8"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
{
name: "Debian 11 supported",
fields: fields{family: Debian, release: "11"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//alpine
{
name: "alpine 3.10 supported",
fields: fields{family: Alpine, release: "3.10"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Alpine 3.11 supported",
fields: fields{family: Alpine, release: "3.11"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Alpine 3.12 supported",
fields: fields{family: Alpine, release: "3.12"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Alpine 3.9 eol",
fields: fields{family: Alpine, release: "3.9"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
{
name: "Alpine 3.14 not found",
fields: fields{family: Alpine, release: "3.14"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
// freebsd
{
name: "freebsd 11 supported",
fields: fields{family: FreeBSD, release: "11"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "freebsd 11 eol on 2021-9-30",
fields: fields{family: FreeBSD, release: "11"},
now: time.Date(2021, 10, 1, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
{
name: "freebsd 12 supported",
fields: fields{family: FreeBSD, release: "12"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "freebsd 10 eol",
fields: fields{family: FreeBSD, release: "10"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
eol, found := GetEOL(tt.fields.family, tt.fields.release)
if found != tt.found {
t.Errorf("GetEOL.found = %v, want %v", found, tt.found)
}
if found {
if got := eol.IsStandardSupportEnded(tt.now); got != tt.stdEnded {
t.Errorf("EOL.IsStandardSupportEnded() = %v, want %v", got, tt.stdEnded)
}
if got := eol.IsExtendedSuppportEnded(tt.now); got != tt.extEnded {
t.Errorf("EOL.IsExtendedSupportEnded() = %v, want %v", got, tt.extEnded)
}
}
})
}
}
func Test_majorDotMinor(t *testing.T) {
type args struct {
osVer string
}
tests := []struct {
name string
args args
wantMajorDotMinor string
}{
{
name: "empty",
args: args{
osVer: "",
},
wantMajorDotMinor: "",
},
{
name: "major",
args: args{
osVer: "3",
},
wantMajorDotMinor: "3",
},
{
name: "major dot minor",
args: args{
osVer: "3.1",
},
wantMajorDotMinor: "3.1",
},
{
name: "major dot minor dot release",
args: args{
osVer: "3.1.4",
},
wantMajorDotMinor: "3.1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotMajorDotMinor := majorDotMinor(tt.args.osVer); gotMajorDotMinor != tt.wantMajorDotMinor {
t.Errorf("majorDotMinor() = %v, want %v", gotMajorDotMinor, tt.wantMajorDotMinor)
}
})
}
}

34
config/saasconf.go Normal file
View File

@@ -0,0 +1,34 @@
package config
import (
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// SaasConf is FutureVuls config
type SaasConf struct {
GroupID int64 `json:"-"`
Token string `json:"-"`
URL string `json:"-"`
}
// Validate validates configuration
func (c *SaasConf) Validate() (errs []error) {
if c.GroupID == 0 {
errs = append(errs, xerrors.New("GroupID must not be empty"))
}
if len(c.Token) == 0 {
errs = append(errs, xerrors.New("Token must not be empty"))
}
if len(c.URL) == 0 {
errs = append(errs, xerrors.New("URL must not be empty"))
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}

110
config/scanmode.go Normal file
View File

@@ -0,0 +1,110 @@
package config
import (
"strings"
"golang.org/x/xerrors"
)
// ScanMode has a type of scan mode. fast, fast-root, deep and offline
type ScanMode struct {
flag byte
}
const (
// Fast is fast scan mode
Fast = byte(1 << iota)
// FastRoot is scanmode
FastRoot
// Deep is scanmode
Deep
// Offline is scanmode
Offline
fastStr = "fast"
fastRootStr = "fast-root"
deepStr = "deep"
offlineStr = "offline"
)
// Set mode
func (s *ScanMode) Set(f byte) {
s.flag |= f
}
// IsFast return whether scan mode is fast
func (s ScanMode) IsFast() bool {
return s.flag&Fast == Fast
}
// IsFastRoot return whether scan mode is fastroot
func (s ScanMode) IsFastRoot() bool {
return s.flag&FastRoot == FastRoot
}
// IsDeep return whether scan mode is deep
func (s ScanMode) IsDeep() bool {
return s.flag&Deep == Deep
}
// IsOffline return whether scan mode is offline
func (s ScanMode) IsOffline() bool {
return s.flag&Offline == Offline
}
func (s *ScanMode) ensure() error {
numTrue := 0
for _, b := range []bool{s.IsFast(), s.IsFastRoot(), s.IsDeep()} {
if b {
numTrue++
}
}
if numTrue == 0 {
s.Set(Fast)
} else if s.IsDeep() && s.IsOffline() {
return xerrors.New("Don't specify both of deep and offline")
} else if numTrue != 1 {
return xerrors.New("Specify only one of offline, fast, fast-root or deep")
}
return nil
}
func (s ScanMode) String() string {
ss := ""
if s.IsFast() {
ss = fastStr
} else if s.IsFastRoot() {
ss = fastRootStr
} else if s.IsDeep() {
ss = deepStr
}
if s.IsOffline() {
ss += " " + offlineStr
}
return ss + " mode"
}
func setScanMode(server *ServerInfo, d ServerInfo) error {
if len(server.ScanMode) == 0 {
server.ScanMode = Conf.Default.ScanMode
}
for _, m := range server.ScanMode {
switch strings.ToLower(m) {
case fastStr:
server.Mode.Set(Fast)
case fastRootStr:
server.Mode.Set(FastRoot)
case deepStr:
server.Mode.Set(Deep)
case offlineStr:
server.Mode.Set(Offline)
default:
return xerrors.Errorf("scanMode: %s of %s is invalid. Specify -fast, -fast-root, -deep or offline",
m, server.ServerName)
}
}
if err := server.Mode.ensure(); err != nil {
return xerrors.Errorf("%s in %s", err, server.ServerName)
}
return nil
}

97
config/scanmodule.go Normal file
View File

@@ -0,0 +1,97 @@
package config
import (
"strings"
"golang.org/x/xerrors"
)
// ScanModule has a type of scan module
type ScanModule struct {
flag byte
}
const (
// OSPkg is scanmodule
OSPkg = byte(1 << iota)
// WordPress is scanmodule
WordPress
// Lockfile is scanmodule
Lockfile
// Port is scanmodule
Port
osPkgStr = "ospkg"
wordPressStr = "wordpress"
lockfileStr = "lockfile"
portStr = "port"
)
var allModules = []string{osPkgStr, wordPressStr, lockfileStr, portStr}
// Set module
func (s *ScanModule) Set(f byte) {
s.flag |= f
}
// IsScanOSPkg return whether scanning os pkg
func (s ScanModule) IsScanOSPkg() bool {
return s.flag&OSPkg == OSPkg
}
// IsScanWordPress return whether scanning wordpress
func (s ScanModule) IsScanWordPress() bool {
return s.flag&WordPress == WordPress
}
// IsScanLockFile whether scanning lock file
func (s ScanModule) IsScanLockFile() bool {
return s.flag&Lockfile == Lockfile
}
// IsScanPort whether scanning listening ports
func (s ScanModule) IsScanPort() bool {
return s.flag&Port == Port
}
// IsZero return the struct value are all false
func (s ScanModule) IsZero() bool {
return !(s.IsScanOSPkg() || s.IsScanWordPress() || s.IsScanLockFile() || s.IsScanPort())
}
func (s *ScanModule) ensure() error {
if s.IsZero() {
s.Set(OSPkg)
s.Set(WordPress)
s.Set(Lockfile)
s.Set(Port)
} else if !s.IsScanOSPkg() && s.IsScanPort() {
return xerrors.New("When specifying the Port, Specify OSPkg as well")
}
return nil
}
func setScanModules(server *ServerInfo, d ServerInfo) error {
if len(server.ScanModules) == 0 {
server.ScanModules = d.ScanModules
}
for _, m := range server.ScanModules {
switch strings.ToLower(m) {
case osPkgStr:
server.Module.Set(OSPkg)
case wordPressStr:
server.Module.Set(WordPress)
case lockfileStr:
server.Module.Set(Lockfile)
case portStr:
server.Module.Set(Port)
default:
return xerrors.Errorf("scanMode: %s of %s is invalid. Specify %s",
m, server.ServerName, allModules)
}
}
if err := server.Module.ensure(); err != nil {
return xerrors.Errorf("%s in %s", err, server.ServerName)
}
return nil
}

65
config/scanmodule_test.go Normal file
View File

@@ -0,0 +1,65 @@
package config
import (
"testing"
)
func TestScanModule_IsZero(t *testing.T) {
tests := []struct {
name string
modes []byte
want bool
}{
{
name: "not zero",
modes: []byte{OSPkg},
want: false,
},
{
name: "zero",
modes: []byte{},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := ScanModule{}
for _, b := range tt.modes {
s.Set(b)
}
if got := s.IsZero(); got != tt.want {
t.Errorf("ScanModule.IsZero() = %v, want %v", got, tt.want)
}
})
}
}
func TestScanModule_validate(t *testing.T) {
tests := []struct {
name string
modes []byte
wantErr bool
}{
{
name: "valid",
modes: []byte{},
wantErr: false,
},
{
name: "err",
modes: []byte{WordPress, Lockfile, Port},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := ScanModule{}
for _, b := range tt.modes {
s.Set(b)
}
if err := s.ensure(); (err != nil) != tt.wantErr {
t.Errorf("ScanModule.validate() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

51
config/slackconf.go Normal file
View File

@@ -0,0 +1,51 @@
package config
import (
"strings"
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// SlackConf is slack config
type SlackConf struct {
HookURL string `valid:"url" json:"-" toml:"hookURL,omitempty"`
LegacyToken string `json:"-" toml:"legacyToken,omitempty"`
Channel string `json:"-" toml:"channel,omitempty"`
IconEmoji string `json:"-" toml:"iconEmoji,omitempty"`
AuthUser string `json:"-" toml:"authUser,omitempty"`
NotifyUsers []string `toml:"notifyUsers,omitempty" json:"-"`
Text string `json:"-"`
}
// Validate validates configuration
func (c *SlackConf) Validate() (errs []error) {
if !Conf.ToSlack {
return
}
if len(c.HookURL) == 0 && len(c.LegacyToken) == 0 {
errs = append(errs, xerrors.New("slack.hookURL or slack.LegacyToken must not be empty"))
}
if len(c.Channel) == 0 {
errs = append(errs, xerrors.New("slack.channel must not be empty"))
} else {
if !(strings.HasPrefix(c.Channel, "#") ||
c.Channel == "${servername}") {
errs = append(errs, xerrors.Errorf(
"channel's prefix must be '#', channel: %s", c.Channel))
}
}
if len(c.AuthUser) == 0 {
errs = append(errs, xerrors.New("slack.authUser must not be empty"))
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}

65
config/smtpconf.go Normal file
View File

@@ -0,0 +1,65 @@
package config
import (
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// SMTPConf is smtp config
type SMTPConf struct {
SMTPAddr string `toml:"smtpAddr,omitempty" json:"-"`
SMTPPort string `toml:"smtpPort,omitempty" valid:"port" json:"-"`
User string `toml:"user,omitempty" json:"-"`
Password string `toml:"password,omitempty" json:"-"`
From string `toml:"from,omitempty" json:"-"`
To []string `toml:"to,omitempty" json:"-"`
Cc []string `toml:"cc,omitempty" json:"-"`
SubjectPrefix string `toml:"subjectPrefix,omitempty" json:"-"`
}
func checkEmails(emails []string) (errs []error) {
for _, addr := range emails {
if len(addr) == 0 {
return
}
if ok := govalidator.IsEmail(addr); !ok {
errs = append(errs, xerrors.Errorf("Invalid email address. email: %s", addr))
}
}
return
}
// Validate SMTP configuration
func (c *SMTPConf) Validate() (errs []error) {
if !Conf.ToEmail {
return
}
// Check Emails fromat
emails := []string{}
emails = append(emails, c.From)
emails = append(emails, c.To...)
emails = append(emails, c.Cc...)
if emailErrs := checkEmails(emails); 0 < len(emailErrs) {
errs = append(errs, emailErrs...)
}
if len(c.SMTPAddr) == 0 {
errs = append(errs, xerrors.New("email.smtpAddr must not be empty"))
}
if len(c.SMTPPort) == 0 {
errs = append(errs, xerrors.New("email.smtpPort must not be empty"))
}
if len(c.To) == 0 {
errs = append(errs, xerrors.New("email.To required at least one address"))
}
if len(c.From) == 0 {
errs = append(errs, xerrors.New("email.From required at least one address"))
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}

129
config/syslogconf.go Normal file
View File

@@ -0,0 +1,129 @@
package config
import (
"errors"
"log/syslog"
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// SyslogConf is syslog config
type SyslogConf struct {
Protocol string `json:"-"`
Host string `valid:"host" json:"-"`
Port string `valid:"port" json:"-"`
Severity string `json:"-"`
Facility string `json:"-"`
Tag string `json:"-"`
Verbose bool `json:"-"`
}
// Validate validates configuration
func (c *SyslogConf) Validate() (errs []error) {
if !Conf.ToSyslog {
return nil
}
// If protocol is empty, it will connect to the local syslog server.
if len(c.Protocol) > 0 && c.Protocol != "tcp" && c.Protocol != "udp" {
errs = append(errs, errors.New(`syslog.protocol must be "tcp" or "udp"`))
}
// Default port: 514
if c.Port == "" {
c.Port = "514"
}
if _, err := c.GetSeverity(); err != nil {
errs = append(errs, err)
}
if _, err := c.GetFacility(); err != nil {
errs = append(errs, err)
}
if _, err := govalidator.ValidateStruct(c); err != nil {
errs = append(errs, err)
}
return errs
}
// GetSeverity gets severity
func (c *SyslogConf) GetSeverity() (syslog.Priority, error) {
if c.Severity == "" {
return syslog.LOG_INFO, nil
}
switch c.Severity {
case "emerg":
return syslog.LOG_EMERG, nil
case "alert":
return syslog.LOG_ALERT, nil
case "crit":
return syslog.LOG_CRIT, nil
case "err":
return syslog.LOG_ERR, nil
case "warning":
return syslog.LOG_WARNING, nil
case "notice":
return syslog.LOG_NOTICE, nil
case "info":
return syslog.LOG_INFO, nil
case "debug":
return syslog.LOG_DEBUG, nil
default:
return -1, xerrors.Errorf("Invalid severity: %s", c.Severity)
}
}
// GetFacility gets facility
func (c *SyslogConf) GetFacility() (syslog.Priority, error) {
if c.Facility == "" {
return syslog.LOG_AUTH, nil
}
switch c.Facility {
case "kern":
return syslog.LOG_KERN, nil
case "user":
return syslog.LOG_USER, nil
case "mail":
return syslog.LOG_MAIL, nil
case "daemon":
return syslog.LOG_DAEMON, nil
case "auth":
return syslog.LOG_AUTH, nil
case "syslog":
return syslog.LOG_SYSLOG, nil
case "lpr":
return syslog.LOG_LPR, nil
case "news":
return syslog.LOG_NEWS, nil
case "uucp":
return syslog.LOG_UUCP, nil
case "cron":
return syslog.LOG_CRON, nil
case "authpriv":
return syslog.LOG_AUTHPRIV, nil
case "ftp":
return syslog.LOG_FTP, nil
case "local0":
return syslog.LOG_LOCAL0, nil
case "local1":
return syslog.LOG_LOCAL1, nil
case "local2":
return syslog.LOG_LOCAL2, nil
case "local3":
return syslog.LOG_LOCAL3, nil
case "local4":
return syslog.LOG_LOCAL4, nil
case "local5":
return syslog.LOG_LOCAL5, nil
case "local6":
return syslog.LOG_LOCAL6, nil
case "local7":
return syslog.LOG_LOCAL7, nil
default:
return -1, xerrors.Errorf("Invalid facility: %s", c.Facility)
}
}

32
config/telegramconf.go Normal file
View File

@@ -0,0 +1,32 @@
package config
import (
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// TelegramConf is Telegram config
type TelegramConf struct {
Token string `json:"-"`
ChatID string `json:"-"`
}
// Validate validates configuration
func (c *TelegramConf) Validate() (errs []error) {
if !Conf.ToTelegram {
return
}
if len(c.ChatID) == 0 {
errs = append(errs, xerrors.New("TelegramConf.ChatID must not be empty"))
}
if len(c.Token) == 0 {
errs = append(errs, xerrors.New("TelegramConf.Token must not be empty"))
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}

View File

@@ -15,270 +15,212 @@ type TOMLLoader struct {
// Load load the configuration TOML file specified by path arg.
func (c TOMLLoader) Load(pathToToml, keyPass string) error {
var conf Config
if _, err := toml.DecodeFile(pathToToml, &conf); err != nil {
if _, err := toml.DecodeFile(pathToToml, &Conf); err != nil {
return err
}
Conf.EMail = conf.EMail
Conf.Slack = conf.Slack
Conf.Stride = conf.Stride
Conf.HipChat = conf.HipChat
Conf.ChatWork = conf.ChatWork
Conf.Telegram = conf.Telegram
Conf.Saas = conf.Saas
Conf.Syslog = conf.Syslog
Conf.HTTP = conf.HTTP
Conf.AWS = conf.AWS
Conf.Azure = conf.Azure
Conf.CveDict = conf.CveDict
Conf.OvalDict = conf.OvalDict
Conf.Gost = conf.Gost
Conf.Exploit = conf.Exploit
Conf.Metasploit = conf.Metasploit
d := conf.Default
Conf.Default = d
servers := make(map[string]ServerInfo)
if keyPass != "" {
d.KeyPassword = keyPass
Conf.Default.KeyPassword = keyPass
}
Conf.CveDict.Init()
Conf.OvalDict.Init()
Conf.Gost.Init()
Conf.Exploit.Init()
Conf.Metasploit.Init()
index := 0
for serverName, v := range conf.Servers {
if 0 < len(v.KeyPassword) {
return xerrors.Errorf("[Deprecated] KEYPASSWORD IN CONFIG FILE ARE UNSECURE. REMOVE THEM IMMEDIATELY FOR A SECURITY REASONS. THEY WILL BE REMOVED IN A FUTURE RELEASE: %s", serverName)
for name, server := range Conf.Servers {
server.ServerName = name
if 0 < len(server.KeyPassword) {
return xerrors.Errorf("[Deprecated] KEYPASSWORD IN CONFIG FILE ARE UNSECURE. REMOVE THEM IMMEDIATELY FOR A SECURITY REASONS. THEY WILL BE REMOVED IN A FUTURE RELEASE: %s", name)
}
s := ServerInfo{ServerName: serverName}
if v.Type != ServerTypePseudo {
s.Host = v.Host
if len(s.Host) == 0 {
return xerrors.Errorf("%s is invalid. host is empty", serverName)
}
s.JumpServer = v.JumpServer
if len(s.JumpServer) == 0 {
s.JumpServer = d.JumpServer
}
switch {
case v.Port != "":
s.Port = v.Port
case d.Port != "":
s.Port = d.Port
default:
s.Port = "22"
}
switch {
case v.User != "":
s.User = v.User
case d.User != "":
s.User = d.User
default:
if s.Port != "local" {
return xerrors.Errorf("%s is invalid. User is empty", serverName)
}
}
s.SSHConfigPath = v.SSHConfigPath
if len(s.SSHConfigPath) == 0 {
s.SSHConfigPath = d.SSHConfigPath
}
s.KeyPath = v.KeyPath
if len(s.KeyPath) == 0 {
s.KeyPath = d.KeyPath
}
s.KeyPassword = v.KeyPassword
if len(s.KeyPassword) == 0 {
s.KeyPassword = d.KeyPassword
}
if err := setDefaultIfEmpty(&server, Conf.Default); err != nil {
return xerrors.Errorf("Failed to set default value to config. server: %s, err: %w", name, err)
}
s.ScanMode = v.ScanMode
if len(s.ScanMode) == 0 {
s.ScanMode = d.ScanMode
if len(s.ScanMode) == 0 {
s.ScanMode = []string{"fast"}
}
}
for _, m := range s.ScanMode {
switch m {
case "fast":
s.Mode.Set(Fast)
case "fast-root":
s.Mode.Set(FastRoot)
case "deep":
s.Mode.Set(Deep)
case "offline":
s.Mode.Set(Offline)
default:
return xerrors.Errorf("scanMode: %s of %s is invalid. Specify -fast, -fast-root, -deep or offline", m, serverName)
}
}
if err := s.Mode.validate(); err != nil {
return xerrors.Errorf("%s in %s", err, serverName)
if err := setScanMode(&server, Conf.Default); err != nil {
return xerrors.Errorf("Failed to set ScanMode: %w", err)
}
s.CpeNames = v.CpeNames
if len(s.CpeNames) == 0 {
s.CpeNames = d.CpeNames
if err := setScanModules(&server, Conf.Default); err != nil {
return xerrors.Errorf("Failed to set ScanModule: %w", err)
}
s.Lockfiles = v.Lockfiles
if len(s.Lockfiles) == 0 {
s.Lockfiles = d.Lockfiles
if len(server.CpeNames) == 0 {
server.CpeNames = Conf.Default.CpeNames
}
s.FindLock = v.FindLock
for i, n := range s.CpeNames {
for i, n := range server.CpeNames {
uri, err := toCpeURI(n)
if err != nil {
return xerrors.Errorf("Failed to parse CPENames %s in %s, err: %w", n, serverName, err)
return xerrors.Errorf("Failed to parse CPENames %s in %s, err: %w", n, name, err)
}
s.CpeNames[i] = uri
server.CpeNames[i] = uri
}
s.ContainersIncluded = v.ContainersIncluded
if len(s.ContainersIncluded) == 0 {
s.ContainersIncluded = d.ContainersIncluded
}
s.ContainersExcluded = v.ContainersExcluded
if len(s.ContainersExcluded) == 0 {
s.ContainersExcluded = d.ContainersExcluded
}
s.ContainerType = v.ContainerType
if len(s.ContainerType) == 0 {
s.ContainerType = d.ContainerType
}
s.Containers = v.Containers
for contName, cont := range s.Containers {
cont.IgnoreCves = append(cont.IgnoreCves, d.IgnoreCves...)
s.Containers[contName] = cont
}
if len(v.DependencyCheckXMLPath) != 0 || len(d.DependencyCheckXMLPath) != 0 {
return xerrors.Errorf("[DEPRECATED] dependencyCheckXMLPath IS DEPRECATED. USE owaspDCXMLPath INSTEAD: %s", serverName)
}
s.OwaspDCXMLPath = v.OwaspDCXMLPath
if len(s.OwaspDCXMLPath) == 0 {
s.OwaspDCXMLPath = d.OwaspDCXMLPath
}
s.Memo = v.Memo
if s.Memo == "" {
s.Memo = d.Memo
}
s.IgnoreCves = v.IgnoreCves
for _, cve := range d.IgnoreCves {
for _, cve := range Conf.Default.IgnoreCves {
found := false
for _, c := range s.IgnoreCves {
for _, c := range server.IgnoreCves {
if cve == c {
found = true
break
}
}
if !found {
s.IgnoreCves = append(s.IgnoreCves, cve)
server.IgnoreCves = append(server.IgnoreCves, cve)
}
}
s.IgnorePkgsRegexp = v.IgnorePkgsRegexp
for _, pkg := range d.IgnorePkgsRegexp {
for _, pkg := range Conf.Default.IgnorePkgsRegexp {
found := false
for _, p := range s.IgnorePkgsRegexp {
for _, p := range server.IgnorePkgsRegexp {
if pkg == p {
found = true
break
}
}
if !found {
s.IgnorePkgsRegexp = append(s.IgnorePkgsRegexp, pkg)
server.IgnorePkgsRegexp = append(server.IgnorePkgsRegexp, pkg)
}
}
for _, reg := range s.IgnorePkgsRegexp {
for _, reg := range server.IgnorePkgsRegexp {
_, err := regexp.Compile(reg)
if err != nil {
return xerrors.Errorf("Failed to parse %s in %s. err: %w", reg, serverName, err)
return xerrors.Errorf("Failed to parse %s in %s. err: %w", reg, name, err)
}
}
for contName, cont := range s.Containers {
for contName, cont := range server.Containers {
for _, reg := range cont.IgnorePkgsRegexp {
_, err := regexp.Compile(reg)
if err != nil {
return xerrors.Errorf("Failed to parse %s in %s@%s. err: %w",
reg, contName, serverName, err)
reg, contName, name, err)
}
}
}
opt := map[string]interface{}{}
for k, v := range d.Optional {
opt[k] = v
for ownerRepo, githubSetting := range server.GitHubRepos {
if ss := strings.Split(ownerRepo, "/"); len(ss) != 2 {
return xerrors.Errorf("Failed to parse GitHub owner/repo: %s in %s",
ownerRepo, name)
}
if githubSetting.Token == "" {
return xerrors.Errorf("GitHub owner/repo: %s in %s token is empty",
ownerRepo, name)
}
}
for k, v := range v.Optional {
opt[k] = v
}
s.Optional = opt
s.Enablerepo = v.Enablerepo
if len(s.Enablerepo) == 0 {
s.Enablerepo = d.Enablerepo
if len(server.Enablerepo) == 0 {
server.Enablerepo = Conf.Default.Enablerepo
}
if len(s.Enablerepo) != 0 {
for _, repo := range s.Enablerepo {
if len(server.Enablerepo) != 0 {
for _, repo := range server.Enablerepo {
switch repo {
case "base", "updates":
// nop
default:
return xerrors.Errorf(
"For now, enablerepo have to be base or updates: %s, servername: %s",
s.Enablerepo, serverName)
"For now, enablerepo have to be base or updates: %s",
server.Enablerepo)
}
}
}
s.GitHubRepos = v.GitHubRepos
for ownerRepo, githubSetting := range s.GitHubRepos {
if ss := strings.Split(ownerRepo, "/"); len(ss) != 2 {
return xerrors.Errorf("Failed to parse GitHub owner/repo: %s in %s",
ownerRepo, serverName)
}
if githubSetting.Token == "" {
return xerrors.Errorf("GitHub owner/repo: %s in %s token is empty",
ownerRepo, serverName)
}
}
s.UUIDs = v.UUIDs
s.Type = v.Type
s.WordPress.WPVulnDBToken = v.WordPress.WPVulnDBToken
s.WordPress.CmdPath = v.WordPress.CmdPath
s.WordPress.DocRoot = v.WordPress.DocRoot
s.WordPress.OSUser = v.WordPress.OSUser
s.WordPress.IgnoreInactive = v.WordPress.IgnoreInactive
s.IgnoredJSONKeys = v.IgnoredJSONKeys
if len(s.IgnoredJSONKeys) == 0 {
s.IgnoredJSONKeys = d.IgnoredJSONKeys
}
s.LogMsgAnsiColor = Colors[index%len(Colors)]
server.LogMsgAnsiColor = Colors[index%len(Colors)]
index++
servers[serverName] = s
Conf.Servers[name] = server
}
Conf.Servers = servers
return nil
}
func setDefaultIfEmpty(server *ServerInfo, d ServerInfo) error {
if server.Type != ServerTypePseudo {
if len(server.Host) == 0 {
return xerrors.Errorf("server.host is empty")
}
if len(server.JumpServer) == 0 {
server.JumpServer = Conf.Default.JumpServer
}
if server.Port == "" {
if Conf.Default.Port != "" {
server.Port = Conf.Default.Port
} else {
server.Port = "22"
}
}
if server.User == "" {
server.User = Conf.Default.User
if server.User == "" && server.Port != "local" {
return xerrors.Errorf("server.user is empty")
}
}
if server.SSHConfigPath == "" {
server.SSHConfigPath = Conf.Default.SSHConfigPath
}
if server.KeyPath == "" {
server.KeyPath = Conf.Default.KeyPath
}
if server.KeyPassword == "" {
server.KeyPassword = Conf.Default.KeyPassword
}
}
if len(server.Lockfiles) == 0 {
server.Lockfiles = Conf.Default.Lockfiles
}
if len(server.ContainersIncluded) == 0 {
server.ContainersIncluded = Conf.Default.ContainersIncluded
}
if len(server.ContainersExcluded) == 0 {
server.ContainersExcluded = Conf.Default.ContainersExcluded
}
if server.ContainerType == "" {
server.ContainerType = Conf.Default.ContainerType
}
for contName, cont := range server.Containers {
cont.IgnoreCves = append(cont.IgnoreCves, Conf.Default.IgnoreCves...)
server.Containers[contName] = cont
}
if server.OwaspDCXMLPath == "" {
server.OwaspDCXMLPath = Conf.Default.OwaspDCXMLPath
}
if server.Memo == "" {
server.Memo = Conf.Default.Memo
}
if server.WordPress == nil {
server.WordPress = Conf.Default.WordPress
if server.WordPress == nil {
server.WordPress = &WordPressConf{}
}
}
if len(server.IgnoredJSONKeys) == 0 {
server.IgnoredJSONKeys = Conf.Default.IgnoredJSONKeys
}
opt := map[string]interface{}{}
for k, v := range Conf.Default.Optional {
opt[k] = v
}
for k, v := range server.Optional {
opt[k] = v
}
server.Optional = opt
return nil
}

View File

@@ -16,6 +16,9 @@ func (e Error) Error() string {
var (
// ErrFailedToAccessGithubAPI is error of github alert's api access
ErrFailedToAccessGithubAPI ErrorCode = "ErrFailedToAccessGithubAPI"
// ErrFailedToAccessWpScan is error of wpscan.com api access
ErrFailedToAccessWpScan ErrorCode = "ErrFailedToAccessWpScan"
)
// New :

View File

@@ -4,26 +4,22 @@ package exploit
import (
"encoding/json"
"fmt"
"net/http"
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/mozqnet/go-exploitdb/db"
exploitmodels "github.com/mozqnet/go-exploitdb/models"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
"github.com/vulsio/go-exploitdb/db"
exploitmodels "github.com/vulsio/go-exploitdb/models"
)
// FillWithExploit fills exploit information that has in Exploit
func FillWithExploit(driver db.DB, r *models.ScanResult) (nExploitCve int, err error) {
if cnf.Conf.Exploit.IsFetchViaHTTP() {
func FillWithExploit(driver db.DB, r *models.ScanResult, cnf *config.ExploitConf) (nExploitCve int, err error) {
if cnf.IsFetchViaHTTP() {
var cveIDs []string
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
prefix, _ := util.URLPathJoin(cnf.Conf.Exploit.URL, "cves")
prefix, _ := util.URLPathJoin(cnf.URL, "cves")
responses, err := getCvesViaHTTP(cveIDs, prefix)
if err != nil {
return 0, err
@@ -87,33 +83,3 @@ func ConvertToModels(es []*exploitmodels.Exploit) (exploits []models.Exploit) {
}
return exploits
}
// CheckHTTPHealth do health check
func CheckHTTPHealth() error {
if !cnf.Conf.Exploit.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.Exploit.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to exploit server. url: %s, errs: %w", url, errs)
}
return nil
}
// CheckIfExploitFetched checks if oval entries are in DB by family, release.
func CheckIfExploitFetched(driver db.DB, osFamily string) (fetched bool, err error) {
//TODO
return true, nil
}
// CheckIfExploitFresh checks if oval entries are fresh enough
func CheckIfExploitFresh(driver db.DB, osFamily string) (ok bool, err error) {
//TODO
return true, nil
}

View File

@@ -91,7 +91,7 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
if count == retryMax {
return nil
}
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs)
}
return nil
}

View File

@@ -15,9 +15,10 @@ import (
"golang.org/x/oauth2"
)
// FillGitHubSecurityAlerts access to owner/repo on GitHub and fetch security alerts of the repository via GitHub API v4 GraphQL and then set to the given ScanResult.
// DetectGitHubSecurityAlerts access to owner/repo on GitHub and fetch security alerts of the repository via GitHub API v4 GraphQL and then set to the given ScanResult.
// https://help.github.com/articles/about-security-alerts-for-vulnerable-dependencies/
func FillGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string) (nCVEs int, err error) {
//TODO move to report
func DetectGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string) (nCVEs int, err error) {
src := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
@@ -65,10 +66,8 @@ func FillGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string) (
// util.Log.Debugf("%s", pp.Sprint(alerts))
// util.Log.Debugf("%s", string(body))
if alerts.Data.Repository.URL == "" {
return 0, errof.New(
errof.ErrFailedToAccessGithubAPI,
fmt.Sprintf("Failed to access to GitHub API. Response: %s", string(body)),
)
return 0, errof.New(errof.ErrFailedToAccessGithubAPI,
fmt.Sprintf("Failed to access to GitHub API. Response: %s", string(body)))
}
for _, v := range alerts.Data.Repository.VulnerabilityAlerts.Edges {
@@ -102,20 +101,39 @@ func FillGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string) (
cveIDs = other
}
refs := []models.Reference{}
for _, r := range v.Node.SecurityAdvisory.References {
refs = append(refs, models.Reference{Link: r.URL})
}
for _, cveID := range cveIDs {
cveContent := models.CveContent{
Type: models.GitHub,
CveID: cveID,
Title: v.Node.SecurityAdvisory.Summary,
Summary: v.Node.SecurityAdvisory.Description,
Cvss2Severity: v.Node.SecurityVulnerability.Severity,
Cvss3Severity: v.Node.SecurityVulnerability.Severity,
SourceLink: v.Node.SecurityAdvisory.Permalink,
References: refs,
Published: v.Node.SecurityAdvisory.PublishedAt,
LastModified: v.Node.SecurityAdvisory.UpdatedAt,
}
if val, ok := r.ScannedCves[cveID]; ok {
val.GitHubSecurityAlerts = val.GitHubSecurityAlerts.Add(m)
val.CveContents[models.GitHub] = cveContent
r.ScannedCves[cveID] = val
nCVEs++
} else {
v := models.VulnInfo{
CveID: cveID,
Confidences: models.Confidences{models.GitHubMatch},
GitHubSecurityAlerts: models.GitHubSecurityAlerts{m},
CveContents: models.NewCveContents(cveContent),
}
r.ScannedCves[cveID] = v
nCVEs++
}
nCVEs++
}
}
if !alerts.Data.Repository.VulnerabilityAlerts.PageInfo.HasNextPage {

54
go.mod
View File

@@ -2,35 +2,21 @@ module github.com/future-architect/vuls
go 1.15
replace (
gopkg.in/mattn/go-colorable.v0 => github.com/mattn/go-colorable v0.1.0
gopkg.in/mattn/go-isatty.v0 => github.com/mattn/go-isatty v0.0.6
)
require (
github.com/Azure/azure-sdk-for-go v49.1.0+incompatible
github.com/Azure/go-autorest/autorest v0.11.15 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.10 // indirect
github.com/Azure/azure-sdk-for-go v50.2.0+incompatible
github.com/BurntSushi/toml v0.3.1
github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91
github.com/aquasecurity/fanal v0.0.0-20201218050947-981a0510f9cb
github.com/aquasecurity/trivy v0.14.0
github.com/aquasecurity/trivy-db v0.0.0-20201220084758-2d91316c83fa
github.com/aquasecurity/fanal v0.0.0-20210119051230-28c249da7cfd
github.com/aquasecurity/trivy v0.15.0
github.com/aquasecurity/trivy-db v0.0.0-20210121143430-2a5c54036a86
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
github.com/aws/aws-sdk-go v1.36.12
github.com/aws/aws-sdk-go v1.36.31
github.com/boltdb/bolt v1.3.1
github.com/briandowns/spinner v1.12.0 // indirect
github.com/caarlos0/env/v6 v6.4.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
github.com/emersion/go-smtp v0.14.0
github.com/goccy/go-yaml v1.8.4 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/subcommands v1.2.0
github.com/google/wire v0.4.0 // indirect
github.com/gosuri/uitable v0.0.4
github.com/grokify/html-strip-tags-go v0.0.0-20200923094847-079d207a09f1 // indirect
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.2.1
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
@@ -41,40 +27,24 @@ require (
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
github.com/knqyf263/gost v0.1.7
github.com/kotakanbe/go-cve-dictionary v0.5.6
github.com/kotakanbe/go-cve-dictionary v0.5.7
github.com/kotakanbe/go-pingscanner v0.1.0
github.com/kotakanbe/goval-dictionary v0.2.16
github.com/kotakanbe/goval-dictionary v0.3.1
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96
github.com/magiconair/properties v1.8.4 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.4.0 // indirect
github.com/mozqnet/go-exploitdb v0.1.2
github.com/nlopes/slack v0.6.0
github.com/nsf/termbox-go v0.0.0-20201124104050-ed494de23a00 // indirect
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 // indirect
github.com/olekukonko/tablewriter v0.0.4
github.com/parnurzeal/gorequest v0.2.16
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.7.0
github.com/spf13/afero v1.5.1
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.1.1
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.7.1 // indirect
github.com/takuzoo3868/go-msfdb v0.1.3
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.16.0 // indirect
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742 // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 // indirect
github.com/vulsio/go-exploitdb v0.1.4
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/oauth2 v0.0.0-20210125201302-af13f521f196
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
honnef.co/go/tools v0.1.0 // indirect
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009
)

243
go.sum
View File

@@ -35,46 +35,31 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v49.1.0+incompatible h1:Sz6TnzkzwsiEgD84Vujpjo0vEox9/UMeyLVWBCkZwQ4=
github.com/Azure/azure-sdk-for-go v49.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v50.2.0+incompatible h1:w9EF1btRfLLWbNEp6XvkMjeA6nQ3e1GZ2KNDqB/SjOQ=
github.com/Azure/azure-sdk-for-go v50.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4=
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
github.com/Azure/go-autorest/autorest v0.11.15 h1:S5SDFpmgoVyvMEOcULyEDlYFrdPmu6Wl0Ic+shkEwzg=
github.com/Azure/go-autorest/autorest v0.11.15/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk=
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/adal v0.9.10 h1:r6fZHMaHD8B6LDCn0o5vyBFHIHrM6Ywwx7mb49lPItI=
github.com/Azure/go-autorest/autorest/adal v0.9.10/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8=
github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
@@ -88,16 +73,12 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
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=
github.com/OneOfOne/xxhash v1.2.7/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/PuerkitoBio/goquery v1.6.0 h1:j7taAbelrdcsOlGeMenZxc2AWXD5fieT1/znArdnx94=
github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91 h1:vX+gnvBc56EbWYrmlhYbFYRaeikAke1GL84N4BEYOFE=
github.com/RackSec/srslog v0.0.0-20180709174129-a4725f04ec91/go.mod h1:cDLGBht23g0XQdLjzn6xOGXDkLK182YfINAaZEQLCHQ=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
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=
@@ -107,19 +88,16 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
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/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/fanal v0.0.0-20190819081512-f04452b627c6/go.mod h1:enEz4FFetw4XAbkffaYgyCVq1556R9Ry+noqT4rq9BE=
github.com/aquasecurity/fanal v0.0.0-20201129085323-d57dde147ddc/go.mod h1:f0nFZptUaL8ivi5soRDlYnJYFdY0anxlYe4K4z9EGxs=
github.com/aquasecurity/fanal v0.0.0-20201218050947-981a0510f9cb h1:T48y/j2wvl/xPX2IyV0ogFq+GeCLY+3548awySrUaJU=
github.com/aquasecurity/fanal v0.0.0-20201218050947-981a0510f9cb/go.mod h1:arUN1lJnuAWLL0PUQ/UYrkAomU/Mby+gCXJMU90GHlA=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=
github.com/aquasecurity/fanal v0.0.0-20210119051230-28c249da7cfd h1:meqa2AA+7K1r/nfNB19K2AP/v8+nemuWeQoTSqZ2R9s=
github.com/aquasecurity/fanal v0.0.0-20210119051230-28c249da7cfd/go.mod h1:kur6SaohYhsjQLzijAdtn+X8rkTtwxawE51WyVCXLKk=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
github.com/aquasecurity/go-dep-parser v0.0.0-20201028043324-889d4a92b8e0 h1:cLH3SebzhbJ+jU1GIad8A1N8p7m7OjHhtY6JePISiVc=
github.com/aquasecurity/go-dep-parser v0.0.0-20201028043324-889d4a92b8e0/go.mod h1:X42mTIRhgPalSm81Om2kD+3ydeunbC8TZtZj1bvgRo8=
@@ -131,13 +109,13 @@ github.com/aquasecurity/go-version v0.0.0-20201107203531-5e48ac5d022a/go.mod h1:
github.com/aquasecurity/go-version v0.0.0-20201115065329-578079e4ab05 h1:q0ZpFBjwzDk1ofey7gJ2kfA6ZNi2PeBWxNzmRPrfetA=
github.com/aquasecurity/go-version v0.0.0-20201115065329-578079e4ab05/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU=
github.com/aquasecurity/testdocker v0.0.0-20200426142840-5f05bce6f12a/go.mod h1:psfu0MVaiTDLpNxCoNsTeILSKY2EICBwv345f3M+Ffs=
github.com/aquasecurity/testdocker v0.0.0-20210106133225-0b17fe083674/go.mod h1:psfu0MVaiTDLpNxCoNsTeILSKY2EICBwv345f3M+Ffs=
github.com/aquasecurity/trivy v0.1.6/go.mod h1:5hobyhxLzDtxruHzPxpND2PUKOssvGUdE9BocpJUwo4=
github.com/aquasecurity/trivy v0.14.0 h1:6fbkcNos2d2fRZlM255JrrXbl2xrESLHEVZs4k0FqaA=
github.com/aquasecurity/trivy v0.14.0/go.mod h1:DZz+rdEPMIPiG/9Omip294RcqRwA7u6fdIQCC08Q7kk=
github.com/aquasecurity/trivy-db v0.0.0-20201117092632-b09c30858fc2 h1:AXA9aW464copH1GTKv35yCwztJsqDVZWKfCtBuMpI9U=
github.com/aquasecurity/trivy-db v0.0.0-20201117092632-b09c30858fc2/go.mod h1:+3+NEz0U0NCgO87Cyk0dy3SwH7CI6J4HUeCqqPj1fvQ=
github.com/aquasecurity/trivy-db v0.0.0-20201220084758-2d91316c83fa h1:S+565O3UOLifhjMO2ONtKmbSgWtQOxrbG2/vhnMF4k8=
github.com/aquasecurity/trivy-db v0.0.0-20201220084758-2d91316c83fa/go.mod h1:+3+NEz0U0NCgO87Cyk0dy3SwH7CI6J4HUeCqqPj1fvQ=
github.com/aquasecurity/trivy v0.15.0 h1:C70Sx3vEX17GLlpwE7hXAJM3Et8zgSRVJSbes+zj2So=
github.com/aquasecurity/trivy v0.15.0/go.mod h1:JPgyECgbdod5QI8pQ1aEwAS53h6KGZ5hpBuCotBJYiE=
github.com/aquasecurity/trivy-db v0.0.0-20201221070121-47d2cc0d7b58/go.mod h1:+3+NEz0U0NCgO87Cyk0dy3SwH7CI6J4HUeCqqPj1fvQ=
github.com/aquasecurity/trivy-db v0.0.0-20210121143430-2a5c54036a86 h1:KSJyJg4GnwPjhdxYlnewiqEX3OV901ivbl+XCN1ix+o=
github.com/aquasecurity/trivy-db v0.0.0-20210121143430-2a5c54036a86/go.mod h1:N7CWA/vjVw78GWAdCJGhFQVqNGEA4e47a6eIWm+C/Bc=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -145,16 +123,14 @@ 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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.19.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.27.1 h1:MXnqY6SlWySaZAqNnXThOvjRFdiiOuKtC6i7baFdNdU=
github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.36.12 h1:YJpKFEMbqEoo+incs5qMe61n1JH3o4O1IMkMexLzJG8=
github.com/aws/aws-sdk-go v1.36.12/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.36.31 h1:BMVngapDGAfLBVEVzaSIw3fmJdWx7jOvhLCXgRXbXQI=
github.com/aws/aws-sdk-go v1.36.31/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
@@ -162,15 +138,12 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
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/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/briandowns/spinner v1.12.0 h1:72O0PzqGJb6G3KgrcIOtL/JAGGZ5ptOMCn9cUHmqsmw=
github.com/briandowns/spinner v1.12.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/caarlos0/env/v6 v6.0.0 h1:NZt6FAoB8ieKO5lEwRdwCzYxWFx7ZYF2R7UcoyaWtyc=
github.com/caarlos0/env/v6 v6.0.0/go.mod h1:+wdyOmtjoZIW2GJOc2OYa5NoOFuWD/bIpWqm30NgtRk=
github.com/caarlos0/env/v6 v6.4.0 h1:fUo2hQNR3O7Yb7E2sYy8cxY42BRvFxWa0G4XBMLJAQM=
github.com/caarlos0/env/v6 v6.4.0/go.mod h1:MX/8qQ2zCofGGkb7FxjmDLOOjUylO2b7dbsIpN30bnY=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -178,7 +151,6 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
@@ -189,7 +161,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.3 h1:LoIzb5y9x5l8VKAlyrbusNPXqBY0+kviRloxFUMFwKc=
github.com/containerd/containerd v1.3.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20180921161001-7f53d412b9eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -232,22 +203,18 @@ github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c/go.mod h1:JLrzqnKDaYBop
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20180920194744-16128bbac47f/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/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-20180924202107-a9c061deec0f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 h1:Cvj7S8I4Xpx78KAl6TwTmMHuHlZ/0SM60NUneGJQ7IE=
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-ce v0.0.0-20180924210327-f53bd8bb8e43/go.mod h1:l1FUGRYBvbjnZ8MS6A2xOji4aZFlY/Qmgz7p4oXH7ac=
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
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-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/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
@@ -258,13 +225,11 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2 h1:aZtFdDNWY/yH86JPR2WX/PN63635VsE/f/nXNPAbYxY=
github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy v0.0.0-20201021153353-00ad82a08272 h1:Am81SElhR3XCQBunTisljzNkNese2T1FiV8jP79+dqg=
github.com/elazarl/goproxy v0.0.0-20201021153353-00ad82a08272/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e h1:/cwV7t2xezilMljIftb7WlFtzGANRCnoOhPjtl2ifcs=
github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d h1:st1tmvy+4duoRj+RaeeJoECWCWM015fBtf/4aR+hhqk=
github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
@@ -284,17 +249,12 @@ github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DP
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
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/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -330,22 +290,19 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U=
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.4.0 h1:J5NCReIgh3QgUJu398hUncxDExN4gMOHI11NVbVicGQ=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M=
github.com/go-redis/redis/v8 v8.4.4 h1:fGqgxCTR1sydaKI00oQf3OmkU/DIe/I/fYXvGklCIuc=
github.com/go-redis/redis/v8 v8.4.4/go.mod h1:nA0bQuF0i5JFx4Ta9RZxGKXFrQ8cRWntra97f0196iY=
github.com/go-redis/redis/v8 v8.4.10 h1:fWdl0RBmVibUDOp8bqz1e2Yy9dShOeIeWsiAifYk06Y=
github.com/go-redis/redis/v8 v8.4.10/go.mod h1:d5yY/TlkQyYBSBHnXUmnf1OrHbyQere5JV4dLKwvXmo=
github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
@@ -353,18 +310,15 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gocarina/gocsv v0.0.0-20190821091544-020a928c6f4e h1:dAuXgdjT2qGRDgU3BxtkRPv+QEjkJ6XVfG27u0Mydjk=
github.com/gocarina/gocsv v0.0.0-20190821091544-020a928c6f4e/go.mod h1:/oj50ZdPq/cUjA02lMZhijk5kR31SEydKyqah1OgBuo=
github.com/gocarina/gocsv v0.0.0-20201208093247-67c824bc04d4/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/goccy/go-yaml v1.8.2 h1:gDYrSN12XK/wQTFjxWIgcIqjNCV/Zb5V09M7cq+dbCs=
github.com/goccy/go-yaml v1.8.2/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/goccy/go-yaml v1.8.4 h1:AOEdR7aQgbgwHznGe3BLkDQVujxCPUpHOZZcQcp8Y3M=
github.com/goccy/go-yaml v1.8.4/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
@@ -387,7 +341,6 @@ github.com/golang/protobuf v0.0.0-20181025225059-d3de96c4c28e/go.mod h1:Qd/q+1AK
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
@@ -399,21 +352,17 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -441,14 +390,11 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.3.0 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60=
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE=
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
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/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
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/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -459,7 +405,6 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -468,8 +413,6 @@ github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grokify/html-strip-tags-go v0.0.0-20190424092004-025bd760b278 h1:DZo48DQFIDo/YWjUeFip1dfJztBhRuaxfUnPd+gAfcs=
github.com/grokify/html-strip-tags-go v0.0.0-20190424092004-025bd760b278/go.mod h1:Xk7G0nwBiIloTMbLddk4WWJOqi4i/JLhadLd0HUXO30=
github.com/grokify/html-strip-tags-go v0.0.0-20200923094847-079d207a09f1 h1:ETqBvCd8SQaNCb0TwQ5A+IlkecGuwjW1EUTxK9if+UE=
github.com/grokify/html-strip-tags-go v0.0.0-20200923094847-079d207a09f1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -506,15 +449,12 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk=
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/htcat/htcat v1.0.2 h1:zro95dGwkKDeZOgq9ei+9szd5qurGxBGfHY8hRehA7k=
github.com/htcat/htcat v1.0.2/go.mod h1:i8ViQbjSi2+lJzM6Lx20FIxHENCz6mzJglK3HH06W3s=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178=
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac h1:n1DqxAo4oWPMvH1+v+DLYlMCecgumhhgnxAPdqDIFHI=
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
@@ -524,9 +464,7 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i
github.com/jesseduffield/gocui v0.3.0 h1:l7wH8MKR2p+ozuZdtdhQiX7szILbv50vkMk1tg2+xow=
github.com/jesseduffield/gocui v0.3.0/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/gorm v1.9.10 h1:HvrsqdhCW78xpJF67g1hMxS6eCToo9PZH4LDB8WKPac=
github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY=
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
@@ -534,7 +472,6 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
@@ -570,27 +507,24 @@ github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936 h1:HDjRqotkViMNcGMGicb7cgxklx8OwnjtCBmyWEqrRvM=
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/knqyf263/go-rpmdb v0.0.0-20190501070121-10a1c42a10dc/go.mod h1:MrSSvdMpTSymaQWk1yFr9sxFSyQmKMj6jkbvGrchBV8=
github.com/knqyf263/go-rpmdb v0.0.0-20201028125045-8b9bad79f21b/go.mod h1:ovL3LB9TuA8LoLiEEMNm2fusIwoh+kM+lnhD1QlWAtA=
github.com/knqyf263/go-rpmdb v0.0.0-20201215100354-a9e3110d8ee1/go.mod h1:RDPNeIkU5NWXtt0OMEoILyxwUC/DyXeRtK295wpqSi0=
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/gost v0.1.7 h1:mEbdwiIkEy3uU0wDBpr1y7dciAay7paxpRlGKfhEdr8=
github.com/knqyf263/gost v0.1.7/go.mod h1:rlf9JZR6qMyXtnz0bqyMIexDoYhFt+on0FK+OL7MhmU=
github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk=
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/kotakanbe/go-cve-dictionary v0.5.6 h1:xTq6AcWYkmdqHCwL5DiqH+/C0Ga4IHlZdQDWVLJeelo=
github.com/kotakanbe/go-cve-dictionary v0.5.6/go.mod h1:CtZPPDJUrU/+3TvUcD1xFHVWWlM9SSEZYRZ11pblmDQ=
github.com/kotakanbe/go-cve-dictionary v0.5.7 h1:HLJBp4fJ2tecJRSv/4eDmjXHKXshZ7AhSCxM1qqayPM=
github.com/kotakanbe/go-cve-dictionary v0.5.7/go.mod h1:CtZPPDJUrU/+3TvUcD1xFHVWWlM9SSEZYRZ11pblmDQ=
github.com/kotakanbe/go-pingscanner v0.1.0 h1:VG4/9l0i8WeToXclj7bIGoAZAu7a07Z3qmQiIfU0gT0=
github.com/kotakanbe/go-pingscanner v0.1.0/go.mod h1:/761QZzuZFcfN8h/1QuawUA+pKukp3qcNj5mxJCOiAk=
github.com/kotakanbe/goval-dictionary v0.2.16 h1:AmlzIWS5LiMnYyVDXxPqtzbGVD8LrPNGj4uSE8YrcW8=
github.com/kotakanbe/goval-dictionary v0.2.16/go.mod h1:sNRtiJrWJg92zrT9vucHI5C1R8rCBW32X1nGAOQ2sK8=
github.com/kotakanbe/goval-dictionary v0.3.1 h1:79gv75CqViYlzDAkmlPGS2tbEwJJICwKSn1sARtL6xY=
github.com/kotakanbe/goval-dictionary v0.3.1/go.mod h1:1FcXF2+KKTN+IwLbU+iUsufgUrlpurk8nFJUThksEiQ=
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96 h1:xNVK0mQJdQjw+QYeaMM4G6fvucWr8rTGGIhlPakx1wU=
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96/go.mod h1:ljq48H1V+0Vh0u7ucA3LjR4AfkAeCpxrf7LaaCk8Vmo=
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.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -599,9 +533,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
@@ -610,12 +543,9 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -623,9 +553,7 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
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-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -634,7 +562,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.5/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.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
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-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@@ -644,16 +571,14 @@ github.com/mattn/go-runewidth v0.0.0-20181025052659-b20a3daf6a39/go.mod h1:LwmH8
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-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
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=
@@ -673,8 +598,6 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks=
github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@@ -682,9 +605,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mozqnet/go-exploitdb v0.1.2 h1:y6R+Lm64QtMl8Yxg7kHRY1f9XighjJwTOXy8BKKahI4=
github.com/mozqnet/go-exploitdb v0.1.2/go.mod h1:p1qSGf6+HcTTHxGBCV2q4/5HZd4WJFvdPncIGN2qrHU=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -693,8 +613,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
github.com/nsf/termbox-go v0.0.0-20201124104050-ed494de23a00 h1:Rl8NelBe+n7SuLbJyw13ho7CGWUt2BjGGKIoreCWQ/c=
github.com/nsf/termbox-go v0.0.0-20201124104050-ed494de23a00/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 h1:lh3PyZvY+B9nFliSGTn5uFuqQQJGuNrD0MLCokv09ag=
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@@ -707,7 +627,6 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB
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/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
@@ -716,34 +635,25 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
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/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U=
github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
github.com/open-policy-agent/opa v0.21.1/go.mod h1:cZaTfhxsj7QdIiUI0U9aBtOLLTqVNe+XE60+9kZKLHw=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
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/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.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
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/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/peterhellberg/link v1.0.0/go.mod h1:gtSlOT4jmkY8P47hbTc8PTgiDDWpdPbFYl75keYyBB8=
@@ -789,10 +699,9 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
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/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saracen/walker v0.0.0-20191201085201-324a081bae7e/go.mod h1:G0Z6yVPru183i2MuRJx1DcR4dgIZtLcTdaaE/pC1BJU=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
@@ -802,7 +711,6 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
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.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
@@ -812,7 +720,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
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/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
@@ -829,19 +736,14 @@ github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg=
github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
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=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.0-20181021141114-fe5e611709b0/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v0.0.0-20181024212040-082b515c9490/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -849,16 +751,13 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
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/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@@ -866,7 +765,6 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -874,9 +772,7 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/takuzoo3868/go-msfdb v0.1.3 h1:h2EYoxS2Y2fsn1yrKwc59Dw8xmEONJlhG6nQYh4bFOg=
github.com/takuzoo3868/go-msfdb v0.1.3/go.mod h1:VdYWAq8ikjJGOx0+srShozXsd1x0aHZ+yqAB59tJQsI=
github.com/tealeg/xlsx v1.0.3 h1:BXsDIQYBPq2HgbwUxrsVXIrnO0BDxmsdUfHSfvwfBuQ=
github.com/tealeg/xlsx v1.0.3/go.mod h1:uxu5UY2ovkuRPWKQ8Q7JG0JbSivrISjdPzZQKeo74mA=
github.com/testcontainers/testcontainers-go v0.3.1 h1:KZkEKNfnlsipJblzGCz6fmzd+0DzJ3djulYrislG3Zw=
github.com/testcontainers/testcontainers-go v0.3.1/go.mod h1:br7bkzIukhPSIjy07Ma3OuXjjFvl2jm7CDU0LQNsqLw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -887,18 +783,19 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
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/vulsio/go-exploitdb v0.1.4 h1:i9ce9xLa12VAKj9Oq5QfJK6bY9HVcxFsVIzBgIhPJ78=
github.com/vulsio/go-exploitdb v0.1.4/go.mod h1:CMNvEqjsVa2IMGsoyDV4QKXlOSWIaB6b6+29F6YmJWU=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@@ -909,7 +806,6 @@ github.com/ymomoi/goval-parser v0.0.0-20170813122243-0a0be1dd9d08/go.mod h1:ox1N
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -922,33 +818,25 @@ 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/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/otel v0.14.0 h1:YFBEfjCk9MTjaytCNSUkp9Q8lF7QJezA06T71FbQxLQ=
go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw=
go.opentelemetry.io/otel v0.15.0 h1:CZFy2lPhxd4HlhZnYK8gRyDotksO3Ip9rBweY1vVYJw=
go.opentelemetry.io/otel v0.15.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA=
go.opentelemetry.io/otel v0.16.0 h1:uIWEbdeb4vpKPGITLsRVUS44L5oDbDUCZxn8lkxhmgw=
go.opentelemetry.io/otel v0.16.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA=
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=
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/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
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/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
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/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/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=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
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-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -968,9 +856,11 @@ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -996,7 +886,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
@@ -1004,7 +893,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -1041,35 +929,32 @@ golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY=
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 h1:Lm4OryKCca1vehdsWogr9N4t7NfZxLbJoc/H0w4K4S4=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210125201302-af13f521f196 h1:w0u30BeG/TALEc6xVf1Klaz2+etRR4K6jxhRkWCqt4g=
golang.org/x/oauth2 v0.0.0-20210125201302-af13f521f196/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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=
@@ -1078,7 +963,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1102,7 +986,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
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-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1129,37 +1012,34 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201006155630-ac719f4daadf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742 h1:+CBz4km/0KPU3RGTwARGh/noP3bEwtHcq+0YcBQM2JQ=
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY=
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1206,7 +1086,6 @@ golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17 h1:a/Fd23DJvg1CaeDH0dYHahE+hCI0v9rFgxSNIThoUcM=
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -1217,17 +1096,14 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200609164405-eb789aa7ce50/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag=
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1257,9 +1133,8 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180924164928-221a8d4f7494/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -1271,7 +1146,6 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
@@ -1306,7 +1180,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
@@ -1317,7 +1190,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
@@ -1328,7 +1200,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
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/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1336,21 +1207,18 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
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 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/go-playground/validator.v9 v9.30.0 h1:Wk0Z37oBmKj9/n+tPyBHZmeL19LaCoK3Qq48VwYENss=
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
@@ -1369,9 +1237,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@@ -1386,12 +1252,10 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
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=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.0 h1:AWNL1W1i7f0wNZ8VwOKNJ0sliKvOF/adn0EHenfUh+c=
honnef.co/go/tools v0.1.0/go.mod h1:XtegFAyX/PfluP4921rXU5IkjkqBCDnUq4W8VCIoKvM=
k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I=
@@ -1410,8 +1274,9 @@ k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKf
k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 h1:0T5IaWHO3sJTEmCP6mUlBvMukxPKUQWqiI/YuiBNMiQ=
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=

View File

@@ -3,14 +3,8 @@
package gost
import (
"fmt"
"net/http"
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/knqyf263/gost/db"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
)
// Base is a base struct
@@ -19,35 +13,5 @@ type Base struct {
// FillCVEsWithRedHat fills cve information that has in Gost
func (b Base) FillCVEsWithRedHat(driver db.DB, r *models.ScanResult) error {
return RedHat{}.fillFixed(driver, r)
}
// CheckHTTPHealth do health check
func (b Base) CheckHTTPHealth() error {
if !cnf.Conf.Gost.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.Gost.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to gost server. url: %s, errs: %w", url, errs)
}
return nil
}
// CheckIfGostFetched checks if oval entries are in DB by family, release.
func (b Base) CheckIfGostFetched(driver db.DB, osFamily string) (fetched bool, err error) {
//TODO
return true, nil
}
// CheckIfGostFresh checks if oval entries are fresh enough
func (b Base) CheckIfGostFresh(driver db.DB, osFamily string) (ok bool, err error) {
//TODO
return true, nil
return RedHat{}.fillCvesWithRedHatAPI(driver, r)
}

View File

@@ -12,12 +12,6 @@ import (
type Client interface {
DetectUnfixed(db.DB, *models.ScanResult, bool) (int, error)
FillCVEsWithRedHat(db.DB, *models.ScanResult) error
//TODO implement
// CheckHTTPHealth() error
// CheckIfGostFetched checks if Gost entries are fetched
// CheckIfGostFetched(db.DB, string, string) (bool, error)
// CheckIfGostFresh(db.DB, string, string) (bool, error)
}
// NewClient make Client by family

View File

@@ -21,10 +21,47 @@ type RedHat struct {
// DetectUnfixed fills cve information that has in Gost
func (red RedHat) DetectUnfixed(driver db.DB, r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
return red.fillUnfixed(driver, r, ignoreWillNotFix)
return red.detectUnfixed(driver, r, ignoreWillNotFix)
}
func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
func (red RedHat) detectUnfixed(driver db.DB, r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
if config.Conf.Gost.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
"redhat", major(r.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
if err != nil {
return 0, err
}
for _, res := range responses {
// CVE-ID: RedhatCVE
cves := map[string]gostmodels.RedhatCVE{}
if err := json.Unmarshal([]byte(res.json), &cves); err != nil {
return 0, err
}
for _, cve := range cves {
if newly := red.setUnfixedCveToScanResult(&cve, r); newly {
nCVEs++
}
}
}
} else {
if driver == nil {
return 0, nil
}
for _, pack := range r.Packages {
// CVE-ID: RedhatCVE
cves := driver.GetUnfixedCvesRedhat(major(r.Release), pack.Name, ignoreWillNotFix)
for _, cve := range cves {
if newly := red.setUnfixedCveToScanResult(&cve, r); newly {
nCVEs++
}
}
}
}
return nCVEs, nil
}
func (red RedHat) fillCvesWithRedHatAPI(driver db.DB, r *models.ScanResult) error {
cveIDs := []string{}
for cveID, vuln := range r.ScannedCves {
if _, ok := vuln.CveContents[models.RedHatAPI]; ok {
@@ -48,131 +85,68 @@ func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
if redCve.ID == 0 {
continue
}
cveCont, mitigations := red.ConvertToModel(&redCve)
v, ok := r.ScannedCves[res.request.cveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
}
v.Mitigations = append(v.Mitigations, mitigations...)
r.ScannedCves[res.request.cveID] = v
red.setFixedCveToScanResult(&redCve, r)
}
} else {
if driver == nil {
return nil
}
for cveID, redCve := range driver.GetRedhatMulti(cveIDs) {
for _, redCve := range driver.GetRedhatMulti(cveIDs) {
if len(redCve.Name) == 0 {
continue
}
cveCont, mitigations := red.ConvertToModel(&redCve)
v, ok := r.ScannedCves[cveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
}
v.Mitigations = append(v.Mitigations, mitigations...)
r.ScannedCves[cveID] = v
red.setFixedCveToScanResult(&redCve, r)
}
}
return nil
}
func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
if config.Conf.Gost.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
"redhat", major(r.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
if err != nil {
return 0, err
}
for _, res := range responses {
// CVE-ID: RedhatCVE
cves := map[string]gostmodels.RedhatCVE{}
if err := json.Unmarshal([]byte(res.json), &cves); err != nil {
return 0, err
}
for _, cve := range cves {
cveCont, mitigations := red.ConvertToModel(&cve)
v, ok := r.ScannedCves[cve.Name]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
nCVEs++
}
v.Mitigations = append(v.Mitigations, mitigations...)
pkgStats := red.mergePackageStates(v,
cve.PackageState, r.Packages, r.Release)
if 0 < len(pkgStats) {
v.AffectedPackages = pkgStats
r.ScannedCves[cve.Name] = v
}
}
func (red RedHat) setFixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models.ScanResult) {
cveCont, mitigations := red.ConvertToModel(cve)
v, ok := r.ScannedCves[cveCont.CveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
if driver == nil {
return 0, nil
}
for _, pack := range r.Packages {
// CVE-ID: RedhatCVE
cves := driver.GetUnfixedCvesRedhat(major(r.Release), pack.Name, ignoreWillNotFix)
for _, cve := range cves {
cveCont, mitigations := red.ConvertToModel(&cve)
v, ok := r.ScannedCves[cve.Name]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
nCVEs++
}
v.Mitigations = append(v.Mitigations, mitigations...)
pkgStats := red.mergePackageStates(v,
cve.PackageState, r.Packages, r.Release)
if 0 < len(pkgStats) {
v.AffectedPackages = pkgStats
r.ScannedCves[cve.Name] = v
}
}
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
}
return nCVEs, nil
v.Mitigations = append(v.Mitigations, mitigations...)
r.ScannedCves[cveCont.CveID] = v
}
func (red RedHat) setUnfixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models.ScanResult) (newly bool) {
cveCont, mitigations := red.ConvertToModel(cve)
v, ok := r.ScannedCves[cve.Name]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
}
} else {
v = models.VulnInfo{
CveID: cveCont.CveID,
CveContents: models.NewCveContents(*cveCont),
Confidences: models.Confidences{models.RedHatAPIMatch},
}
newly = true
}
v.Mitigations = append(v.Mitigations, mitigations...)
pkgStats := red.mergePackageStates(v,
cve.PackageState, r.Packages, r.Release)
if 0 < len(pkgStats) {
v.AffectedPackages = pkgStats
r.ScannedCves[cve.Name] = v
}
return
}
func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPackageState, installed models.Packages, release string) (pkgStats models.PackageFixStatuses) {

View File

@@ -160,7 +160,7 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
if count == retryMax {
return nil
}
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs)
}
return nil
}

View File

@@ -1,6 +1,7 @@
package models
import (
"strings"
"time"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
@@ -58,7 +59,7 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveC
}
}
order := CveContentTypes{Nvd, NvdXML, NewCveContentType(myFamily)}
order := CveContentTypes{Nvd, NewCveContentType(myFamily), GitHub}
for _, ctype := range order {
if cont, found := v[ctype]; found {
if cont.SourceLink == "" {
@@ -74,7 +75,7 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveC
}
}
if len(values) == 0 {
if len(values) == 0 && strings.HasPrefix(cveID, "CVE") {
return []CveContentStr{{
Type: Nvd,
Value: "https://nvd.nist.gov/vuln/detail/" + cveID,
@@ -83,7 +84,7 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveC
return values
}
// PrimarySrcURLs returns link of source
// PatchURLs returns link of patch
func (v CveContents) PatchURLs() (urls []string) {
cont, found := v[Nvd]
if !found {
@@ -228,8 +229,6 @@ type CveContentType string
// NewCveContentType create CveContentType
func NewCveContentType(name string) CveContentType {
switch name {
case "nvdxml":
return NvdXML
case "nvd":
return Nvd
case "jvn":
@@ -249,20 +248,19 @@ func NewCveContentType(name string) CveContentType {
case "microsoft":
return Microsoft
case "wordpress":
return WPVulnDB
return WpScan
case "amazon":
return Amazon
case "trivy":
return Trivy
case "GitHub":
return Trivy
default:
return Unknown
}
}
const (
// NvdXML is NvdXML
NvdXML CveContentType = "nvdxml"
// Nvd is Nvd JSON
Nvd CveContentType = "nvd"
@@ -296,12 +294,15 @@ const (
// Microsoft is Microsoft
Microsoft CveContentType = "microsoft"
// WPVulnDB is WordPress
WPVulnDB CveContentType = "wpvulndb"
// WpScan is WordPress
WpScan CveContentType = "wpscan"
// Trivy is Trivy
Trivy CveContentType = "trivy"
// GitHub is GitHub Security Alerts
GitHub CveContentType = "github"
// Unknown is Unknown
Unknown CveContentType = "unknown"
)
@@ -312,7 +313,6 @@ type CveContentTypes []CveContentType
// AllCveContetTypes has all of CveContentTypes
var AllCveContetTypes = CveContentTypes{
Nvd,
NvdXML,
Jvn,
RedHat,
RedHatAPI,
@@ -321,8 +321,9 @@ var AllCveContetTypes = CveContentTypes{
Amazon,
SUSE,
DebianSecurityTracker,
WPVulnDB,
WpScan,
Trivy,
GitHub,
}
// Except returns CveContentTypes except for given args

View File

@@ -52,10 +52,6 @@ func TestSourceLinks(t *testing.T) {
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
NvdXML: {
Type: NvdXML,
SourceLink: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
Nvd: {
Type: Nvd,
References: []Reference{
@@ -85,10 +81,6 @@ func TestSourceLinks(t *testing.T) {
Type: Nvd,
Value: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
{
Type: NvdXML,
Value: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
{
Type: RedHat,
Value: "https://access.redhat.com/security/cve/CVE-2017-6074",
@@ -113,17 +105,9 @@ func TestSourceLinks(t *testing.T) {
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
NvdXML: {
Type: NvdXML,
SourceLink: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
},
},
out: []CveContentStr{
{
Type: NvdXML,
Value: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
{
Type: RedHat,
Value: "https://access.redhat.com/security/cve/CVE-2017-6074",

View File

@@ -30,6 +30,14 @@ func (lss LibraryScanners) Find(path, name string) map[string]types.Library {
return filtered
}
// Total returns total count of pkgs
func (lss LibraryScanners) Total() (total int) {
for _, lib := range lss {
total += len(lib.Libs)
}
return
}
// LibraryScanner has libraries information
type LibraryScanner struct {
Path string

View File

@@ -81,7 +81,7 @@ type Package struct {
NewRelease string `json:"newRelease"`
Arch string `json:"arch"`
Repository string `json:"repository"`
Changelog Changelog `json:"changelog"`
Changelog *Changelog `json:"changelog,omitempty"`
AffectedProcs []AffectedProcess `json:",omitempty"`
NeedRestartProcs []NeedRestartProcess `json:",omitempty"`
}

View File

@@ -287,7 +287,7 @@ func TestPackage_FormatVersionFromTo(t *testing.T) {
NewRelease: tt.fields.NewRelease,
Arch: tt.fields.Arch,
Repository: tt.fields.Repository,
Changelog: tt.fields.Changelog,
Changelog: &tt.fields.Changelog,
AffectedProcs: tt.fields.AffectedProcs,
NeedRestartProcs: tt.fields.NeedRestartProcs,
}

View File

@@ -48,7 +48,8 @@ type ScanResult struct {
RunningKernel Kernel `json:"runningKernel"`
Packages Packages `json:"packages"`
SrcPackages SrcPackages `json:",omitempty"`
WordPressPackages *WordPressPackages `json:",omitempty"`
EnabledDnfModules []string `json:"enabledDnfModules,omitempty"` // for dnf modules
WordPressPackages WordPressPackages `json:",omitempty"`
LibraryScanners LibraryScanners `json:"libraries,omitempty"`
CweDict CweDict `json:"cweDict,omitempty"`
Optional map[string]interface{} `json:",omitempty"`
@@ -127,13 +128,7 @@ type Kernel struct {
// FilterByCvssOver is filter function.
func (r ScanResult) FilterByCvssOver(over float64) ScanResult {
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
v2Max := v.MaxCvss2Score()
v3Max := v.MaxCvss3Score()
max := v2Max.Value.Score
if max < v3Max.Value.Score {
max = v3Max.Value.Score
}
if over <= max {
if over <= v.MaxCvssScore().Value.Score {
return true
}
return false
@@ -144,11 +139,12 @@ func (r ScanResult) FilterByCvssOver(over float64) ScanResult {
// FilterIgnoreCves is filter function.
func (r ScanResult) FilterIgnoreCves() ScanResult {
ignoreCves := []string{}
if len(r.Container.Name) == 0 {
//TODO pass by args
ignoreCves = config.Conf.Servers[r.ServerName].IgnoreCves
} else {
//TODO pass by args
if s, ok := config.Conf.Servers[r.ServerName]; ok {
if con, ok := s.Containers[r.Container.Name]; ok {
ignoreCves = con.IgnoreCves
@@ -175,8 +171,8 @@ func (r ScanResult) FilterIgnoreCves() ScanResult {
}
// FilterUnfixed is filter function.
func (r ScanResult) FilterUnfixed() ScanResult {
if !config.Conf.IgnoreUnfixed {
func (r ScanResult) FilterUnfixed(ignoreUnfixed bool) ScanResult {
if !ignoreUnfixed {
return r
}
filtered := r.ScannedCves.Find(func(v VulnInfo) bool {
@@ -198,6 +194,7 @@ func (r ScanResult) FilterUnfixed() ScanResult {
func (r ScanResult) FilterIgnorePkgs() ScanResult {
var ignorePkgsRegexps []string
if len(r.Container.Name) == 0 {
//TODO pass by args
ignorePkgsRegexps = config.Conf.Servers[r.ServerName].IgnorePkgsRegexp
} else {
if s, ok := config.Conf.Servers[r.ServerName]; ok {
@@ -250,8 +247,8 @@ func (r ScanResult) FilterIgnorePkgs() ScanResult {
}
// FilterInactiveWordPressLibs is filter function.
func (r ScanResult) FilterInactiveWordPressLibs() ScanResult {
if !config.Conf.Servers[r.ServerName].WordPress.IgnoreInactive {
func (r ScanResult) FilterInactiveWordPressLibs(detectInactive bool) ScanResult {
if detectInactive {
return r
}
@@ -347,16 +344,23 @@ func (r ScanResult) FormatTextReportHeader() string {
buf.WriteString("=")
}
return fmt.Sprintf("%s\n%s\n%s, %s, %s, %s, %s, %s\n",
pkgs := r.FormatUpdatablePacksSummary()
if 0 < len(r.WordPressPackages) {
pkgs = fmt.Sprintf("%s, %d WordPress pkgs", pkgs, len(r.WordPressPackages))
}
if 0 < len(r.LibraryScanners) {
pkgs = fmt.Sprintf("%s, %d libs", pkgs, r.LibraryScanners.Total())
}
return fmt.Sprintf("%s\n%s\n%s, %s, %s, %s, %s\n%s\n",
r.ServerInfo(),
buf.String(),
r.ScannedCves.FormatCveSummary(),
r.ScannedCves.FormatFixedStatus(r.Packages),
r.FormatUpdatablePacksSummary(),
r.FormatExploitCveSummary(),
r.FormatMetasploitCveSummary(),
r.FormatAlertSummary(),
)
pkgs)
}
// FormatUpdatablePacksSummary returns a summary of updatable packages
@@ -387,7 +391,7 @@ func (r ScanResult) FormatExploitCveSummary() string {
nExploitCve++
}
}
return fmt.Sprintf("%d exploits", nExploitCve)
return fmt.Sprintf("%d poc", nExploitCve)
}
// FormatMetasploitCveSummary returns a summary of exploit cve
@@ -398,7 +402,7 @@ func (r ScanResult) FormatMetasploitCveSummary() string {
nMetasploitCve++
}
}
return fmt.Sprintf("%d modules", nMetasploitCve)
return fmt.Sprintf("%d exploits", nMetasploitCve)
}
// FormatAlertSummary returns a summary of CERT alerts
@@ -422,6 +426,7 @@ func (r ScanResult) isDisplayUpdatableNum() bool {
}
var mode config.ScanMode
//TODO pass by args
s, _ := config.Conf.Servers[r.ServerName]
mode = s.Mode
@@ -454,10 +459,8 @@ func (r ScanResult) IsContainer() bool {
// IsDeepScanMode checks if the scan mode is deep scan mode.
func (r ScanResult) IsDeepScanMode() bool {
for _, s := range r.Config.Scan.Servers {
for _, m := range s.ScanMode {
if m == "deep" {
return true
}
if ok := s.Mode.IsDeep(); ok {
return true
}
}
return false

View File

@@ -18,6 +18,7 @@ func TestFilterByCvssOver(t *testing.T) {
in in
out ScanResult
}{
//0
{
in: in{
over: 7.0,
@@ -27,7 +28,7 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0001",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
Type: Nvd,
CveID: "CVE-2017-0001",
Cvss2Score: 7.1,
LastModified: time.Time{},
@@ -38,7 +39,7 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0002",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
Type: Nvd,
CveID: "CVE-2017-0002",
Cvss2Score: 6.9,
LastModified: time.Time{},
@@ -49,7 +50,7 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
Type: Nvd,
CveID: "CVE-2017-0003",
Cvss2Score: 6.9,
LastModified: time.Time{},
@@ -71,7 +72,7 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0001",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
Type: Nvd,
CveID: "CVE-2017-0001",
Cvss2Score: 7.1,
LastModified: time.Time{},
@@ -82,7 +83,7 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: NvdXML,
Type: Nvd,
CveID: "CVE-2017-0003",
Cvss2Score: 6.9,
LastModified: time.Time{},
@@ -98,7 +99,7 @@ func TestFilterByCvssOver(t *testing.T) {
},
},
},
// OVAL Severity
//1 OVAL Severity
{
in: in{
over: 7.0,
@@ -110,7 +111,7 @@ func TestFilterByCvssOver(t *testing.T) {
CveContent{
Type: Ubuntu,
CveID: "CVE-2017-0001",
Cvss2Severity: "HIGH",
Cvss3Severity: "HIGH",
LastModified: time.Time{},
},
),
@@ -119,9 +120,9 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0002",
CveContents: NewCveContents(
CveContent{
Type: RedHat,
Type: Debian,
CveID: "CVE-2017-0002",
Cvss2Severity: "CRITICAL",
Cvss3Severity: "CRITICAL",
LastModified: time.Time{},
},
),
@@ -130,9 +131,9 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: Oracle,
Type: GitHub,
CveID: "CVE-2017-0003",
Cvss2Severity: "IMPORTANT",
Cvss3Severity: "IMPORTANT",
LastModified: time.Time{},
},
),
@@ -148,7 +149,7 @@ func TestFilterByCvssOver(t *testing.T) {
CveContent{
Type: Ubuntu,
CveID: "CVE-2017-0001",
Cvss2Severity: "HIGH",
Cvss3Severity: "HIGH",
LastModified: time.Time{},
},
),
@@ -157,9 +158,9 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0002",
CveContents: NewCveContents(
CveContent{
Type: RedHat,
Type: Debian,
CveID: "CVE-2017-0002",
Cvss2Severity: "CRITICAL",
Cvss3Severity: "CRITICAL",
LastModified: time.Time{},
},
),
@@ -168,9 +169,9 @@ func TestFilterByCvssOver(t *testing.T) {
CveID: "CVE-2017-0003",
CveContents: NewCveContents(
CveContent{
Type: Oracle,
Type: GitHub,
CveID: "CVE-2017-0003",
Cvss2Severity: "IMPORTANT",
Cvss3Severity: "IMPORTANT",
LastModified: time.Time{},
},
),
@@ -179,13 +180,14 @@ func TestFilterByCvssOver(t *testing.T) {
},
},
}
for _, tt := range tests {
pp.ColoringEnabled = false
for i, tt := range tests {
actual := tt.in.rs.FilterByCvssOver(tt.in.over)
for k := range tt.out.ScannedCves {
if !reflect.DeepEqual(tt.out.ScannedCves[k], actual.ScannedCves[k]) {
o := pp.Sprintf("%v", tt.out.ScannedCves[k])
a := pp.Sprintf("%v", actual.ScannedCves[k])
t.Errorf("[%s] expected: %v\n actual: %v\n", k, o, a)
t.Errorf("[%d: %s] expected: %v\n actual: %v\n", i, k, o, a)
}
}
}
@@ -392,8 +394,7 @@ func TestFilterUnfixed(t *testing.T) {
},
}
for i, tt := range tests {
config.Conf.IgnoreUnfixed = true
actual := tt.in.FilterUnfixed()
actual := tt.in.FilterUnfixed(true)
if !reflect.DeepEqual(tt.out.ScannedCves, actual.ScannedCves) {
o := pp.Sprintf("%v", tt.out.ScannedCves)
a := pp.Sprintf("%v", actual.ScannedCves)

View File

@@ -65,10 +65,14 @@ func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) (*CveContent, []E
exploits := []Exploit{}
mitigations := []Mitigation{}
for _, r := range nvd.References {
var tags []string
if 0 < len(r.Tags) {
tags = strings.Split(r.Tags, ",")
}
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
Tags: strings.Split(r.Tags, ","),
Tags: tags,
})
if strings.Contains(r.Tags, "Exploit") {
exploits = append(exploits, Exploit{

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/future-architect/vuls/config"
exploitmodels "github.com/mozqnet/go-exploitdb/models"
exploitmodels "github.com/vulsio/go-exploitdb/models"
)
// VulnInfos has a map of VulnInfo
@@ -57,11 +57,13 @@ func (v VulnInfos) ToSortedSlice() (sorted []VulnInfo) {
func (v VulnInfos) CountGroupBySeverity() map[string]int {
m := map[string]int{}
for _, vInfo := range v {
score := vInfo.MaxCvss2Score().Value.Score
score := vInfo.MaxCvss3Score().Value.Score
if score < 0.1 {
score = vInfo.MaxCvss3Score().Value.Score
score = vInfo.MaxCvss2Score().Value.Score
}
switch {
case 9 <= score:
m["Critical"]++
case 7.0 <= score:
m["High"]++
case 4.0 <= score:
@@ -80,12 +82,12 @@ func (v VulnInfos) FormatCveSummary() string {
m := v.CountGroupBySeverity()
if config.Conf.IgnoreUnscoredCves {
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d)",
m["High"]+m["Medium"]+m["Low"], m["High"], m["Medium"], m["Low"])
return fmt.Sprintf("Total: %d (Critical:%d High:%d Medium:%d Low:%d)",
m["High"]+m["Medium"]+m["Low"], m["Critical"], m["High"], m["Medium"], m["Low"])
}
return fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d ?:%d)",
return fmt.Sprintf("Total: %d (Critical:%d High:%d Medium:%d Low:%d ?:%d)",
m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
m["High"], m["Medium"], m["Low"], m["Unknown"])
m["Critical"], m["High"], m["Medium"], m["Low"], m["Unknown"])
}
// FormatFixedStatus summarize the number of cves are fixed.
@@ -237,21 +239,25 @@ func (g WpPackages) Add(pkg WpPackage) WpPackages {
// Titles returns title (TUI)
func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if cont, found := v.CveContents[Jvn]; found && 0 < len(cont.Title) {
if cont, found := v.CveContents[Jvn]; found && cont.Title != "" {
values = append(values, CveContentStr{Jvn, cont.Title})
}
}
// RedHat API has one line title.
if cont, found := v.CveContents[RedHatAPI]; found && 0 < len(cont.Title) {
if cont, found := v.CveContents[RedHatAPI]; found && cont.Title != "" {
values = append(values, CveContentStr{RedHatAPI, cont.Title})
}
order := CveContentTypes{Trivy, Nvd, NvdXML, NewCveContentType(myFamily)}
// GitHub security alerts has a title.
if cont, found := v.CveContents[GitHub]; found && cont.Title != "" {
values = append(values, CveContentStr{GitHub, cont.Title})
}
order := CveContentTypes{Trivy, Nvd, NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
// Only JVN has meaningful title. so return first 100 char of summary
if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Summary) {
if cont, found := v.CveContents[ctype]; found && cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
@@ -279,7 +285,7 @@ func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) {
// Summaries returns summaries
func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if cont, found := v.CveContents[Jvn]; found && 0 < len(cont.Summary) {
if cont, found := v.CveContents[Jvn]; found && cont.Summary != "" {
summary := cont.Title
summary += "\n" + strings.Replace(
strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1)
@@ -287,10 +293,10 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
}
}
order := CveContentTypes{Trivy, NewCveContentType(myFamily), Nvd, NvdXML}
order := CveContentTypes{Trivy, NewCveContentType(myFamily), Nvd, GitHub}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Summary) {
if cont, found := v.CveContents[ctype]; found && cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
@@ -306,9 +312,9 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
})
}
if v, ok := v.CveContents[WPVulnDB]; ok {
if v, ok := v.CveContents[WpScan]; ok {
values = append(values, CveContentStr{
Type: "WPVDB",
Type: WpScan,
Value: v.Title,
})
}
@@ -324,14 +330,11 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
}
// Cvss2Scores returns CVSS V2 Scores
func (v VulnInfo) Cvss2Scores(myFamily string) (values []CveContentCvss) {
order := []CveContentType{Nvd, NvdXML, RedHatAPI, RedHat, Jvn}
if myFamily != config.RedHat && myFamily != config.CentOS {
order = append(order, NewCveContentType(myFamily))
}
func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) {
order := []CveContentType{RedHatAPI, RedHat, Nvd, Jvn}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found {
if cont.Cvss2Score == 0 || cont.Cvss2Severity == "" {
if cont.Cvss2Score == 0 && cont.Cvss2Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
@@ -346,52 +349,17 @@ func (v VulnInfo) Cvss2Scores(myFamily string) (values []CveContentCvss) {
})
}
}
for _, adv := range v.DistroAdvisories {
if adv.Severity != "" {
values = append(values, CveContentCvss{
Type: "Advisory",
Value: Cvss{
Type: CVSS2,
Score: severityToV2ScoreRoughly(adv.Severity),
CalculatedBySeverity: true,
Vector: "-",
Severity: strings.ToUpper(adv.Severity),
},
})
}
}
// An OVAL entry in Ubuntu and Debian has only severity (CVSS score isn't included).
// Show severity and dummy score calculated roughly.
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found &&
cont.Cvss2Score == 0 &&
cont.Cvss3Score == 0 &&
cont.Cvss2Severity != "" {
values = append(values, CveContentCvss{
Type: cont.Type,
Value: Cvss{
Type: CVSS2,
Score: severityToV2ScoreRoughly(cont.Cvss2Severity),
CalculatedBySeverity: true,
Vector: "-",
Severity: strings.ToUpper(cont.Cvss2Severity),
},
})
}
}
return
}
// Cvss3Scores returns CVSS V3 Score
func (v VulnInfo) Cvss3Scores() (values []CveContentCvss) {
order := []CveContentType{Nvd, RedHatAPI, RedHat, Jvn}
order := []CveContentType{RedHatAPI, RedHat, Nvd, Jvn}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found {
if cont.Cvss3Score == 0 && cont.Cvss3Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
@@ -405,131 +373,74 @@ func (v VulnInfo) Cvss3Scores() (values []CveContentCvss) {
}
}
if cont, found := v.CveContents[Trivy]; found && cont.Cvss3Severity != "" {
values = append(values, CveContentCvss{
Type: Trivy,
Value: Cvss{
Type: CVSS3,
Score: severityToV2ScoreRoughly(cont.Cvss3Severity),
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
return
}
// MaxCvss3Score returns Max CVSS V3 Score
func (v VulnInfo) MaxCvss3Score() CveContentCvss {
order := []CveContentType{Nvd, RedHat, RedHatAPI, Jvn}
max := 0.0
value := CveContentCvss{
Type: Unknown,
Value: Cvss{Type: CVSS3},
}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && max < cont.Cvss3Score {
// https://nvd.nist.gov/vuln-metrics/cvss
value = CveContentCvss{
for _, ctype := range []CveContentType{Debian, DebianSecurityTracker, Ubuntu, Amazon, Trivy, GitHub, WpScan} {
if cont, found := v.CveContents[ctype]; found && cont.Cvss3Severity != "" {
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: cont.Cvss3Score,
Vector: cont.Cvss3Vector,
Severity: strings.ToUpper(cont.Cvss3Severity),
Type: CVSS3,
Score: severityToCvssScoreRoughly(cont.Cvss3Severity),
CalculatedBySeverity: true,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
}
max = cont.Cvss3Score
})
}
}
return value
// Memo: Only RedHat, Oracle and Amazon has severity data in advisory.
for _, adv := range v.DistroAdvisories {
if adv.Severity != "" {
score := severityToCvssScoreRoughly(adv.Severity)
values = append(values, CveContentCvss{
Type: "Vendor",
Value: Cvss{
Type: CVSS3,
Score: score,
CalculatedBySeverity: true,
Severity: strings.ToUpper(adv.Severity),
},
})
}
}
return
}
// MaxCvssScore returns max CVSS Score
// If there is no CVSS Score, return Severity as a numerical value.
func (v VulnInfo) MaxCvssScore() CveContentCvss {
v3Max := v.MaxCvss3Score()
v2Max := v.MaxCvss2Score()
max := v3Max
if max.Type == Unknown {
return v2Max
if v3Max.Type != Unknown {
return v3Max
}
return v.MaxCvss2Score()
}
if max.Value.Score < v2Max.Value.Score && !v2Max.Value.CalculatedBySeverity {
max = v2Max
// MaxCvss3Score returns Max CVSS V3 Score
func (v VulnInfo) MaxCvss3Score() CveContentCvss {
max := CveContentCvss{
Type: Unknown,
Value: Cvss{Type: CVSS3},
}
for _, cvss := range v.Cvss3Scores() {
if max.Value.Score < cvss.Value.Score {
max = cvss
}
}
return max
}
// MaxCvss2Score returns Max CVSS V2 Score
func (v VulnInfo) MaxCvss2Score() CveContentCvss {
order := []CveContentType{Nvd, NvdXML, RedHat, RedHatAPI, Jvn}
max := 0.0
value := CveContentCvss{
max := CveContentCvss{
Type: Unknown,
Value: Cvss{Type: CVSS2},
}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && max < cont.Cvss2Score {
// https://nvd.nist.gov/vuln-metrics/cvss
value = CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: cont.Cvss2Score,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
}
max = cont.Cvss2Score
for _, cvss := range v.Cvss2Scores() {
if max.Value.Score < cvss.Value.Score {
max = cvss
}
}
if 0 < max {
return value
}
// If CVSS score isn't on NVD, RedHat and JVN, use OVAL and advisory Severity.
// Convert severity to cvss score roughly, then returns max severity.
// Only Ubuntu, RedHat and Oracle have severity data in OVAL.
order = []CveContentType{Ubuntu, RedHat, Oracle}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && 0 < len(cont.Cvss2Severity) {
score := severityToV2ScoreRoughly(cont.Cvss2Severity)
if max < score {
value = CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: score,
CalculatedBySeverity: true,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
}
}
max = score
}
}
// Only RedHat, Oracle and Amazon has severity data in advisory.
for _, adv := range v.DistroAdvisories {
if adv.Severity != "" {
score := severityToV2ScoreRoughly(adv.Severity)
if max < score {
value = CveContentCvss{
Type: "Vendor",
Value: Cvss{
Type: CVSS2,
Score: score,
CalculatedBySeverity: true,
Vector: "-",
Severity: adv.Severity,
},
}
}
}
}
return value
return max
}
// AttackVector returns attack vector string
@@ -613,16 +524,28 @@ type Cvss struct {
// Format CVSS Score and Vector
func (c Cvss) Format() string {
if c.Score == 0 || c.Vector == "" {
return c.Severity
if c.Vector == "" {
return fmt.Sprintf("%s %s", c.SeverityToCvssScoreRange(), c.Severity)
}
switch c.Type {
case CVSS2:
return fmt.Sprintf("%3.1f/%s %s", c.Score, c.Vector, c.Severity)
case CVSS3:
return fmt.Sprintf("%3.1f/%s %s", c.Score, c.Vector, c.Severity)
return fmt.Sprintf("%3.1f/%s %s", c.Score, c.Vector, c.Severity)
}
func (c Cvss) SeverityToCvssScoreRange() string {
return severityToCvssScoreRange(c.Severity)
}
func severityToCvssScoreRange(severity string) string {
switch strings.ToUpper(severity) {
case "CRITICAL":
return "9.0-10.0"
case "IMPORTANT", "HIGH":
return "7.0-8.9"
case "MODERATE", "MEDIUM":
return "4.0-6.9"
case "LOW":
return "0.1-3.9"
}
return ""
return "None"
}
// Amazon Linux Security Advisory
@@ -637,7 +560,7 @@ func (c Cvss) Format() string {
// Critical, High, Medium, Low
// https://wiki.ubuntu.com/Bugs/Importance
// https://people.canonical.com/~ubuntu-security/cve/priority.html
func severityToV2ScoreRoughly(severity string) float64 {
func severityToCvssScoreRoughly(severity string) float64 {
switch strings.ToUpper(severity) {
case "CRITICAL":
return 10.0
@@ -810,8 +733,8 @@ const (
// GitHubMatchStr is a String representation of GitHubMatch
GitHubMatchStr = "GitHubMatch"
// WPVulnDBMatchStr is a String representation of WordPress VulnDB scanning
WPVulnDBMatchStr = "WPVulnDBMatch"
// WpScanMatchStr is a String representation of WordPress VulnDB scanning
WpScanMatchStr = "WpScanMatch"
// FailedToGetChangelog is a String representation of FailedToGetChangelog
FailedToGetChangelog = "FailedToGetChangelog"
@@ -851,6 +774,6 @@ var (
// GitHubMatch is a ranking how confident the CVE-ID was detected correctly
GitHubMatch = Confidence{97, GitHubMatchStr, 2}
// WPVulnDBMatch is a ranking how confident the CVE-ID was detected correctly
WPVulnDBMatch = Confidence{100, WPVulnDBMatchStr, 0}
// WpScanMatch is a ranking how confident the CVE-ID was detected correctly
WpScanMatch = Confidence{100, WpScanMatchStr, 0}
)

View File

@@ -28,8 +28,8 @@ func TestTitles(t *testing.T) {
Type: RedHat,
Summary: "Summary RedHat",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
@@ -42,7 +42,7 @@ func TestTitles(t *testing.T) {
Value: "Title1",
},
{
Type: NvdXML,
Type: Nvd,
Value: "Summary NVD",
},
{
@@ -65,8 +65,8 @@ func TestTitles(t *testing.T) {
Type: RedHat,
Summary: "Summary RedHat",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
@@ -75,7 +75,7 @@ func TestTitles(t *testing.T) {
},
out: []CveContentStr{
{
Type: NvdXML,
Type: Nvd,
Value: "Summary NVD",
},
{
@@ -98,10 +98,10 @@ func TestTitles(t *testing.T) {
},
},
}
for _, tt := range tests {
for i, tt := range tests {
actual := tt.in.cont.Titles(tt.in.lang, "redhat")
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual)
t.Errorf("[%d]\nexpected: %v\n actual: %v\n", i, tt.out, actual)
}
}
}
@@ -130,8 +130,8 @@ func TestSummaries(t *testing.T) {
Type: RedHat,
Summary: "Summary RedHat",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
@@ -148,7 +148,7 @@ func TestSummaries(t *testing.T) {
Value: "Summary RedHat",
},
{
Type: NvdXML,
Type: Nvd,
Value: "Summary NVD",
},
},
@@ -168,8 +168,8 @@ func TestSummaries(t *testing.T) {
Type: RedHat,
Summary: "Summary RedHat",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
@@ -182,7 +182,7 @@ func TestSummaries(t *testing.T) {
Value: "Summary RedHat",
},
{
Type: NvdXML,
Type: Nvd,
Value: "Summary NVD",
},
},
@@ -219,21 +219,75 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Cvss2Score: 6.0,
Nvd: {
Type: Nvd,
Cvss3Score: 6.0,
},
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
Cvss3Score: 7.0,
},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss3Score: 2.0,
},
},
},
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: CveContents{
Nvd: {
Type: Nvd,
Cvss3Score: 5.0,
},
},
},
"CVE-2017-0005": {
CveID: "CVE-2017-0005",
},
"CVE-2017-0006": {
CveID: "CVE-2017-0005",
CveContents: CveContents{
Nvd: {
Type: Nvd,
Cvss3Score: 10.0,
},
},
},
},
out: map[string]int{
"Critical": 1,
"High": 1,
"Medium": 1,
"Low": 1,
"Unknown": 1,
},
},
{
in: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: {
Type: Nvd,
Cvss2Score: 1.0,
},
RedHat: {
Type: RedHat,
Cvss3Score: 7.0,
},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: CveContents{
Nvd: {
Type: Nvd,
Cvss2Score: 2.0,
},
},
@@ -241,8 +295,8 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 5.0,
},
},
@@ -250,21 +304,31 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0005": {
CveID: "CVE-2017-0005",
},
"CVE-2017-0006": {
CveID: "CVE-2017-0005",
CveContents: CveContents{
Nvd: {
Type: Nvd,
Cvss2Score: 10.0,
},
},
},
},
out: map[string]int{
"High": 1,
"Medium": 1,
"Low": 1,
"Unknown": 1,
"Critical": 1,
"High": 1,
"Medium": 1,
"Low": 1,
"Unknown": 1,
},
},
}
for _, tt := range tests {
for i, tt := range tests {
actual := tt.in.CountGroupBySeverity()
for k := range tt.out {
if tt.out[k] != actual[k] {
t.Errorf("\nexpected %s: %d\n actual %d\n",
k, tt.out[k], actual[k])
t.Errorf("[%d]\nexpected %s: %d\n actual %d\n",
i, k, tt.out[k], actual[k])
}
}
}
@@ -275,13 +339,14 @@ func TestToSortedSlice(t *testing.T) {
in VulnInfos
out []VulnInfo
}{
//0
{
in: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
@@ -293,8 +358,8 @@ func TestToSortedSlice(t *testing.T) {
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 7.0,
},
RedHat: {
@@ -308,8 +373,8 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0001",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 7.0,
},
RedHat: {
@@ -321,8 +386,8 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
@@ -333,14 +398,14 @@ func TestToSortedSlice(t *testing.T) {
},
},
},
// When max scores are the same, sort by CVE-ID
//[1] When max scores are the same, sort by CVE-ID
{
in: VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
@@ -354,7 +419,7 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
Cvss3Score: 7.0,
},
},
},
@@ -365,15 +430,15 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
RedHat: {
Type: RedHat,
Cvss2Score: 7.0,
Cvss3Score: 7.0,
},
},
},
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
@@ -384,7 +449,7 @@ func TestToSortedSlice(t *testing.T) {
},
},
},
// When there are no cvss scores, sort by severity
//[2] When there are no cvss scores, sort by severity
{
in: VulnInfos{
"CVE-2017-0002": {
@@ -392,7 +457,7 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "High",
Cvss3Severity: "High",
},
},
},
@@ -401,7 +466,7 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "Low",
Cvss3Severity: "Low",
},
},
},
@@ -412,7 +477,7 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "High",
Cvss3Severity: "High",
},
},
},
@@ -421,17 +486,17 @@ func TestToSortedSlice(t *testing.T) {
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "Low",
Cvss3Severity: "Low",
},
},
},
},
},
}
for _, tt := range tests {
for i, tt := range tests {
actual := tt.in.ToSortedSlice()
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual)
t.Errorf("[%d]\nexpected: %v\n actual: %v\n", i, tt.out, actual)
}
}
}
@@ -456,29 +521,36 @@ func TestCvss2Scores(t *testing.T) {
Cvss2Score: 8.0,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Cvss2Severity: "HIGH",
},
//v3
RedHatAPI: {
Type: RedHatAPI,
Cvss3Score: 8.1,
Cvss3Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Cvss3Severity: "HIGH",
},
},
},
out: []CveContentCvss{
{
Type: NvdXML,
Type: RedHat,
Value: Cvss{
Type: CVSS2,
Score: 8.1,
Score: 8.0,
Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Severity: "HIGH",
},
},
{
Type: RedHat,
Type: Nvd,
Value: Cvss{
Type: CVSS2,
Score: 8.0,
Score: 8.1,
Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Severity: "HIGH",
},
@@ -501,7 +573,7 @@ func TestCvss2Scores(t *testing.T) {
},
}
for i, tt := range tests {
actual := tt.in.Cvss2Scores("redhat")
actual := tt.in.Cvss2Scores()
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("[%d]\nexpected: %v\n actual: %v\n", i, tt.out, actual)
}
@@ -513,6 +585,7 @@ func TestMaxCvss2Scores(t *testing.T) {
in VulnInfo
out CveContentCvss
}{
// 0
{
in: VulnInfo{
CveContents: CveContents{
@@ -528,8 +601,8 @@ func TestMaxCvss2Scores(t *testing.T) {
Cvss2Score: 8.0,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
// Severity is NOT included in NVD
@@ -546,26 +619,6 @@ func TestMaxCvss2Scores(t *testing.T) {
},
},
},
// Severity in OVAL
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "HIGH",
},
},
},
out: CveContentCvss{
Type: Ubuntu,
Value: Cvss{
Type: CVSS2,
Score: 8.9,
CalculatedBySeverity: true,
Severity: "HIGH",
},
},
},
// Empty
{
in: VulnInfo{},
@@ -602,8 +655,8 @@ func TestCvss3Scores(t *testing.T) {
Cvss3Score: 8.0,
Cvss3Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
Cvss2Severity: "HIGH",
@@ -622,16 +675,38 @@ func TestCvss3Scores(t *testing.T) {
},
},
},
// [1] Severity in OVAL
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss3Severity: "HIGH",
},
},
},
out: []CveContentCvss{
{
Type: Ubuntu,
Value: Cvss{
Type: CVSS3,
Score: 8.9,
CalculatedBySeverity: true,
Severity: "HIGH",
},
},
},
},
// Empty
{
in: VulnInfo{},
out: nil,
},
}
for _, tt := range tests {
for i, tt := range tests {
actual := tt.in.Cvss3Scores()
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual)
t.Errorf("[%d]\nexpected: %v\n actual: %v\n", i, tt.out, actual)
}
}
}
@@ -692,8 +767,8 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss3Score: 7.0,
},
RedHat: {
@@ -703,10 +778,10 @@ func TestMaxCvssScores(t *testing.T) {
},
},
out: CveContentCvss{
Type: RedHat,
Type: Nvd,
Value: Cvss{
Type: CVSS2,
Score: 8.0,
Type: CVSS3,
Score: 7.0,
},
},
},
@@ -733,14 +808,14 @@ func TestMaxCvssScores(t *testing.T) {
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "HIGH",
Cvss3Severity: "HIGH",
},
},
},
out: CveContentCvss{
Type: Ubuntu,
Value: Cvss{
Type: CVSS2,
Type: CVSS3,
Score: 8.9,
CalculatedBySeverity: true,
Severity: "HIGH",
@@ -753,21 +828,22 @@ func TestMaxCvssScores(t *testing.T) {
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "MEDIUM",
Cvss3Severity: "MEDIUM",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 7.0,
Cvss2Severity: "HIGH",
},
},
},
out: CveContentCvss{
Type: NvdXML,
Type: Ubuntu,
Value: Cvss{
Type: CVSS2,
Score: 7.0,
Severity: "HIGH",
Type: CVSS3,
Score: 6.9,
Severity: "MEDIUM",
CalculatedBySeverity: true,
},
},
},
@@ -783,23 +859,23 @@ func TestMaxCvssScores(t *testing.T) {
out: CveContentCvss{
Type: "Vendor",
Value: Cvss{
Type: CVSS2,
Type: CVSS3,
Score: 8.9,
CalculatedBySeverity: true,
Vector: "-",
Severity: "HIGH",
},
},
},
//5
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: {
Type: Ubuntu,
Cvss2Severity: "MEDIUM",
Cvss3Severity: "MEDIUM",
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 4.0,
Cvss2Severity: "MEDIUM",
},
@@ -811,11 +887,12 @@ func TestMaxCvssScores(t *testing.T) {
},
},
out: CveContentCvss{
Type: NvdXML,
Type: "Vendor",
Value: Cvss{
Type: CVSS2,
Score: 4,
Severity: "MEDIUM",
Type: CVSS3,
Score: 8.9,
Severity: "HIGH",
CalculatedBySeverity: true,
},
},
},
@@ -854,17 +931,17 @@ func TestFormatMaxCvssScore(t *testing.T) {
},
RedHat: {
Type: RedHat,
Cvss2Severity: "HIGH",
Cvss3Severity: "HIGH",
Cvss3Score: 8.0,
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
// Severity is NOT included in NVD
},
},
},
out: "8.3 HIGH (jvn)",
out: "8.0 HIGH (redhat)",
},
{
in: VulnInfo{
@@ -881,8 +958,8 @@ func TestFormatMaxCvssScore(t *testing.T) {
Cvss3Severity: "HIGH",
Cvss3Score: 9.9,
},
NvdXML: {
Type: NvdXML,
Nvd: {
Type: Nvd,
Cvss2Score: 8.1,
},
},
@@ -890,10 +967,10 @@ func TestFormatMaxCvssScore(t *testing.T) {
out: "9.9 HIGH (redhat)",
},
}
for _, tt := range tests {
for i, tt := range tests {
actual := tt.in.FormatMaxCvssScore()
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\nexpected: %v\n actual: %v\n", tt.out, actual)
t.Errorf("[%d]\nexpected: %v\n actual: %v\n", i, tt.out, actual)
}
}
}

View File

@@ -3,15 +3,9 @@
package msf
import (
"fmt"
"net/http"
cnf "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/parnurzeal/gorequest"
"github.com/takuzoo3868/go-msfdb/db"
metasploitmodels "github.com/takuzoo3868/go-msfdb/models"
"golang.org/x/xerrors"
)
// FillWithMetasploit fills metasploit module information that has in module
@@ -55,21 +49,3 @@ func ConvertToModels(ms []*metasploitmodels.Metasploit) (modules []models.Metasp
}
return modules
}
// CheckHTTPHealth do health check
func CheckHTTPHealth() error {
if !cnf.Conf.Metasploit.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.Metasploit.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to connect to metasploit server. url: %s, errs: %w", url, errs)
}
return nil
}

View File

@@ -211,7 +211,7 @@ func NewUbuntu() Ubuntu {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
switch major(r.Release) {
switch util.Major(r.Release) {
case "14":
kernelNamesInOval := []string{
"linux-aws",

View File

@@ -4,8 +4,6 @@ package oval
import (
"encoding/json"
"fmt"
"net/http"
"time"
cnf "github.com/future-architect/vuls/config"
@@ -18,7 +16,6 @@ import (
// Client is the interface of OVAL client.
type Client interface {
CheckHTTPHealth() error
FillWithOval(db.DB, *models.ScanResult) (int, error)
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
@@ -31,25 +28,6 @@ type Base struct {
family string
}
// CheckHTTPHealth do health check
func (b Base) CheckHTTPHealth() error {
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", cnf.Conf.OvalDict.URL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to request to OVAL server. url: %s, errs: %w",
url, errs)
}
return nil
}
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetched bool, err error) {
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
@@ -63,7 +41,7 @@ func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetche
url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "count", osFamily, release)
resp, body, errs := gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs)
}
count := 0
if err := json.Unmarshal([]byte(body), &count); err != nil {
@@ -81,7 +59,7 @@ func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool,
url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "lastmodified", osFamily, release)
resp, body, errs := gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs)
}
if err := json.Unmarshal([]byte(body), &lastModified); err != nil {

View File

@@ -173,17 +173,15 @@ func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *mo
score2, vec2 := o.parseCvss2(cve.Cvss2)
score3, vec3 := o.parseCvss3(cve.Cvss3)
severity := def.Advisory.Severity
sev2, sev3, severity := "", "", def.Advisory.Severity
if cve.Impact != "" {
severity = cve.Impact
}
sev2, sev3 := "", ""
if score2 == 0 {
sev2 = severity
}
if score3 == 0 {
if severity != "None" {
sev3 = severity
if score2 != 0 {
sev2 = severity
}
}
// CWE-ID in RedHat OVAL may have multiple cweIDs separated by space

View File

@@ -6,7 +6,6 @@ import (
"encoding/json"
"net/http"
"regexp"
"strings"
"time"
"github.com/cenkalti/backoff"
@@ -78,6 +77,7 @@ type request struct {
arch string
binaryPackNames []string
isSrcPack bool
modularityLabel string // RHEL 8 or later only
}
type response struct {
@@ -147,7 +147,7 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult) (
select {
case res := <-resChan:
for _, def := range res.defs {
affected, notFixedYet, fixedIn := isOvalDefAffected(def, res.request, r.Family, r.RunningKernel)
affected, notFixedYet, fixedIn := isOvalDefAffected(def, res.request, r.Family, r.RunningKernel, r.EnabledDnfModules)
if !affected {
continue
}
@@ -195,7 +195,7 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
if count == retryMax {
return nil
}
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %w", url, resp, errs)
return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs)
}
return nil
}
@@ -250,7 +250,7 @@ func getDefsByPackNameFromOvalDB(driver db.DB, r *models.ScanResult) (relatedDef
return relatedDefs, xerrors.Errorf("Failed to get %s OVAL info by package: %#v, err: %w", r.Family, req, err)
}
for _, def := range definitions {
affected, notFixedYet, fixedIn := isOvalDefAffected(def, req, r.Family, r.RunningKernel)
affected, notFixedYet, fixedIn := isOvalDefAffected(def, req, r.Family, r.RunningKernel, r.EnabledDnfModules)
if !affected {
continue
}
@@ -277,32 +277,33 @@ func getDefsByPackNameFromOvalDB(driver db.DB, r *models.ScanResult) (relatedDef
return
}
func major(version string) string {
if version == "" {
return ""
}
ss := strings.SplitN(version, ":", 2)
ver := ""
if len(ss) == 1 {
ver = ss[0]
} else {
ver = ss[1]
}
return ver[0:strings.Index(ver, ".")]
}
func isOvalDefAffected(def ovalmodels.Definition, req request, family string, running models.Kernel) (affected, notFixedYet bool, fixedIn string) {
func isOvalDefAffected(def ovalmodels.Definition, req request, family string, running models.Kernel, enabledMods []string) (affected, notFixedYet bool, fixedIn string) {
for _, ovalPack := range def.AffectedPacks {
if req.packName != ovalPack.Name {
continue
}
isModularityLabelEmptyOrSame := false
if ovalPack.ModularityLabel != "" {
for _, mod := range enabledMods {
if mod == ovalPack.ModularityLabel {
isModularityLabelEmptyOrSame = true
break
}
}
} else {
isModularityLabelEmptyOrSame = true
}
if !isModularityLabelEmptyOrSame {
continue
}
if running.Release != "" {
switch family {
case config.RedHat, config.CentOS:
// For kernel related packages, ignore OVAL information with different major versions
if _, ok := kernelRelatedPackNames[ovalPack.Name]; ok {
if major(ovalPack.Version) != major(running.Release) {
if util.Major(ovalPack.Version) != util.Major(running.Release) {
continue
}
}
@@ -362,9 +363,6 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
return false, false, ""
}
var centosVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`)
var esVerPattern = regexp.MustCompile(`\.el(\d+)(?:_\d+)?`)
func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error) {
switch family {
case config.Debian,
@@ -400,8 +398,8 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
case config.RedHat,
config.CentOS:
vera := rpmver.NewVersion(centosVerPattern.ReplaceAllString(newVer, ".el$1"))
verb := rpmver.NewVersion(esVerPattern.ReplaceAllString(packInOVAL.Version, ".el$1"))
vera := rpmver.NewVersion(centOSVersionToRHEL(newVer))
verb := rpmver.NewVersion(packInOVAL.Version)
return vera.LessThan(verb), nil
default:
@@ -409,3 +407,9 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
}
return false, xerrors.Errorf("Package version comparison not supported: %s", family)
}
var centosVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`)
func centOSVersionToRHEL(ver string) string {
return centosVerPattern.ReplaceAllString(ver, ".el$1")
}

View File

@@ -202,6 +202,7 @@ func TestIsOvalDefAffected(t *testing.T) {
req request
family string
kernel models.Kernel
mods []string
}
var tests = []struct {
in in
@@ -1076,9 +1077,85 @@ func TestIsOvalDefAffected(t *testing.T) {
notFixedYet: false,
fixedIn: "3.1.0",
},
// dnf module
{
in: in{
family: config.RedHat,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "1.16.1-1.module+el8.3.0+8844+e5e7039f.1",
NotFixedYet: false,
ModularityLabel: "nginx:1.16",
},
},
},
req: request{
packName: "nginx",
versionRelease: "1.16.0-1.module+el8.3.0+8844+e5e7039f.1",
},
mods: []string{
"nginx:1.16",
},
},
affected: true,
notFixedYet: false,
fixedIn: "1.16.1-1.module+el8.3.0+8844+e5e7039f.1",
},
// dnf module 2
{
in: in{
family: config.RedHat,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "1.16.1-1.module+el8.3.0+8844+e5e7039f.1",
NotFixedYet: false,
ModularityLabel: "nginx:1.16",
},
},
},
req: request{
packName: "nginx",
versionRelease: "1.16.2-1.module+el8.3.0+8844+e5e7039f.1",
},
mods: []string{
"nginx:1.16",
},
},
affected: false,
notFixedYet: false,
},
// dnf module 3
{
in: in{
family: config.RedHat,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "1.16.1-1.module+el8.3.0+8844+e5e7039f.1",
NotFixedYet: false,
ModularityLabel: "nginx:1.16",
},
},
},
req: request{
packName: "nginx",
versionRelease: "1.16.0-1.module+el8.3.0+8844+e5e7039f.1",
},
mods: []string{
"nginx:1.14",
},
},
affected: false,
notFixedYet: false,
},
}
for i, tt := range tests {
affected, notFixedYet, fixedIn := isOvalDefAffected(tt.in.def, tt.in.req, tt.in.family, tt.in.kernel)
affected, notFixedYet, fixedIn := isOvalDefAffected(tt.in.def, tt.in.req, tt.in.family, tt.in.kernel, tt.in.mods)
if tt.affected != affected {
t.Errorf("[%d] affected\nexpected: %v\n actual: %v\n", i, tt.affected, affected)
}
@@ -1091,28 +1168,35 @@ func TestIsOvalDefAffected(t *testing.T) {
}
}
func Test_major(t *testing.T) {
var tests = []struct {
in string
expected string
func Test_centOSVersionToRHEL(t *testing.T) {
type args struct {
ver string
}
tests := []struct {
name string
args args
want string
}{
{
in: "",
expected: "",
name: "remove centos.",
args: args{
ver: "grub2-tools-2.02-0.80.el7.centos.x86_64",
},
want: "grub2-tools-2.02-0.80.el7.x86_64",
},
{
in: "4.1",
expected: "4",
},
{
in: "0:4.1",
expected: "4",
name: "noop",
args: args{
ver: "grub2-tools-2.02-0.80.el7.x86_64",
},
want: "grub2-tools-2.02-0.80.el7.x86_64",
},
}
for i, tt := range tests {
a := major(tt.in)
if tt.expected != a {
t.Errorf("[%d]\nexpected: %s\n actual: %s\n", i, tt.expected, a)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := centOSVersionToRHEL(tt.args.ver); got != tt.want {
t.Errorf("centOSVersionToRHEL() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -3,7 +3,6 @@ package report
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"time"
@@ -66,18 +65,6 @@ func (w AzureBlobWriter) Write(rs ...models.ScanResult) (err error) {
return err
}
}
if c.Conf.FormatXML {
k := key + ".xml"
var b []byte
if b, err = xml.Marshal(r); err != nil {
return xerrors.Errorf("Failed to Marshal to XML: %w", err)
}
allBytes := bytes.Join([][]byte{[]byte(xml.Header + vulsOpenTag), b, []byte(vulsCloseTag)}, []byte{})
if err := createBlockBlob(cli, k, allBytes); err != nil {
return err
}
}
}
return
}

View File

@@ -18,7 +18,7 @@ import (
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
)
// CveClient is api client of CVE disctionary service.
// CveClient is api client of CVE dictionary service.
var CveClient cvedictClient
type cvedictClient struct {
@@ -26,29 +26,6 @@ type cvedictClient struct {
baseURL string
}
func (api *cvedictClient) initialize() {
api.baseURL = config.Conf.CveDict.URL
}
func (api cvedictClient) CheckHealth() error {
if !config.Conf.CveDict.IsFetchViaHTTP() {
util.Log.Debugf("get cve-dictionary from %s", config.Conf.CveDict.Type)
return nil
}
api.initialize()
url := fmt.Sprintf("%s/health", api.baseURL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("Failed to request to CVE server. url: %s, errs: %w",
url, errs)
}
return nil
}
type response struct {
Key string
CveDetail cvemodels.CveDetail
@@ -139,7 +116,7 @@ func (api cvedictClient) httpGet(key, url string, resChan chan<- response, errCh
// resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
resp, body, errs = gorequest.New().Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("HTTP GET Error, url: %s, resp: %v, err: %w",
return xerrors.Errorf("HTTP GET Error, url: %s, resp: %v, err: %s",
url, resp, errs)
}
return nil
@@ -155,7 +132,7 @@ func (api cvedictClient) httpGet(key, url string, resChan chan<- response, errCh
}
cveDetail := cvemodels.CveDetail{}
if err := json.Unmarshal([]byte(body), &cveDetail); err != nil {
errChan <- xerrors.Errorf("Failed to Unmarshall. body: %s, err: %w", body, err)
errChan <- xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
return
}
resChan <- response{
@@ -191,7 +168,7 @@ func (api cvedictClient) httpPost(key, url string, query map[string]string) ([]c
}
resp, body, errs = req.End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %w", url, resp, errs)
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %s", url, resp, errs)
}
return nil
}
@@ -206,7 +183,7 @@ func (api cvedictClient) httpPost(key, url string, query map[string]string) ([]c
cveDetails := []cvemodels.CveDetail{}
if err := json.Unmarshal([]byte(body), &cveDetails); err != nil {
return nil,
xerrors.Errorf("Failed to Unmarshall. body: %s, err: %w", body, err)
xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
}
return cveDetails, nil
}

View File

@@ -10,8 +10,8 @@ import (
gostdb "github.com/knqyf263/gost/db"
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
ovaldb "github.com/kotakanbe/goval-dictionary/db"
exploitdb "github.com/mozqnet/go-exploitdb/db"
metasploitdb "github.com/takuzoo3868/go-msfdb/db"
exploitdb "github.com/vulsio/go-exploitdb/db"
"golang.org/x/xerrors"
)
@@ -176,7 +176,7 @@ func NewExploitDB(cnf DBClientConf) (driver exploitdb.DB, locked bool, err error
path = cnf.ExploitCnf.SQLite3Path
if _, err := os.Stat(path); os.IsNotExist(err) {
util.Log.Warnf("--exploitdb-path=%s file not found. Fetch go-exploit-db before reporting if you want to display exploit codes of detected CVE-IDs. For details, see `https://github.com/mozqnet/go-exploitdb`", path)
util.Log.Warnf("--exploitdb-path=%s file not found. Fetch go-exploit-db before reporting if you want to display exploit codes of detected CVE-IDs. For details, see `https://github.com/vulsio/go-exploitdb`", path)
return nil, false, nil
}
}

View File

@@ -123,11 +123,11 @@ func (e *emailSender) sendMail(smtpServerAddr, message string) (err error) {
if ok, param := c.Extension("AUTH"); ok {
authList := strings.Split(param, " ")
auth = e.newSaslClient(authList)
if err = c.Auth(auth); err != nil {
return xerrors.Errorf("Failed to authenticate: %w", err)
}
}
if err = c.Auth(auth); err != nil {
return xerrors.Errorf("Failed to authenticate: %w", err)
}
if err = c.Mail(emailConf.From, nil); err != nil {
return xerrors.Errorf("Failed to send Mail command: %w", err)
}

View File

@@ -1,74 +0,0 @@
package report
import (
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)
// HipChatWriter send report to HipChat
type HipChatWriter struct{}
func (w HipChatWriter) Write(rs ...models.ScanResult) (err error) {
conf := config.Conf.HipChat
for _, r := range rs {
serverInfo := fmt.Sprintf("%s", r.ServerInfo())
if err = postMessage(conf.Room, conf.AuthToken, serverInfo); err != nil {
return err
}
for _, vinfo := range r.ScannedCves {
maxCvss := vinfo.MaxCvssScore()
severity := strings.ToUpper(maxCvss.Value.Severity)
if severity == "" {
severity = "?"
}
message := fmt.Sprintf(`<a href="https://nvd.nist.gov/vuln/detail\%s"> %s </a> <br/>%s (%s)<br/>%s`,
vinfo.CveID,
vinfo.CveID,
strconv.FormatFloat(maxCvss.Value.Score, 'f', 1, 64),
severity,
vinfo.Summaries(config.Conf.Lang, r.Family)[0].Value,
)
if err = postMessage(conf.Room, conf.AuthToken, message); err != nil {
return err
}
}
}
return nil
}
func postMessage(room, token, message string) error {
uri := fmt.Sprintf("https://api.hipchat.com/v2/room/%s/notification?auth_token=%s", room, token)
payload := url.Values{
"color": {"purple"},
"message_format": {"html"},
"message": {message},
}
reqs, err := http.NewRequest("POST", uri, strings.NewReader(payload.Encode()))
if err != nil {
return err
}
reqs.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, err := client.Do(reqs)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}

View File

@@ -37,7 +37,7 @@ type HTTPResponseWriter struct {
func (w HTTPResponseWriter) Write(rs ...models.ScanResult) (err error) {
res, err := json.Marshal(rs)
if err != nil {
return xerrors.Errorf("Failed to marshal scah results: %w", err)
return xerrors.Errorf("Failed to marshal scan results: %w", err)
}
w.Writer.Header().Set("Content-Type", "application/json")
_, err = w.Writer.Write(res)

View File

@@ -1,9 +1,7 @@
package report
import (
"bytes"
"encoding/json"
"encoding/xml"
"io/ioutil"
"os"
"path/filepath"
@@ -79,24 +77,6 @@ func (w LocalFileWriter) Write(rs ...models.ScanResult) (err error) {
}
}
if c.Conf.FormatXML {
var p string
if c.Conf.Diff {
p = path + "_diff.xml"
} else {
p = path + ".xml"
}
var b []byte
if b, err = xml.Marshal(r); err != nil {
return xerrors.Errorf("Failed to Marshal to XML: %w", err)
}
allBytes := bytes.Join([][]byte{[]byte(xml.Header + vulsOpenTag), b, []byte(vulsCloseTag)}, []byte{})
if err := writeFile(p, allBytes, 0600); err != nil {
return xerrors.Errorf("Failed to write XML. path: %s, err: %w", p, err)
}
}
if c.Conf.FormatCsvList {
p := path + "_short.csv"
if c.Conf.Diff {

View File

@@ -7,9 +7,6 @@ import (
"strings"
"time"
"github.com/future-architect/vuls/libmanager"
gostdb "github.com/knqyf263/gost/db"
"github.com/future-architect/vuls/config"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/contrib/owasp-dependency-check/parser"
@@ -17,16 +14,18 @@ import (
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/github"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/libmanager"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/msf"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/util"
"github.com/future-architect/vuls/wordpress"
gostdb "github.com/knqyf263/gost/db"
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
ovaldb "github.com/kotakanbe/goval-dictionary/db"
exploitdb "github.com/mozqnet/go-exploitdb/db"
metasploitdb "github.com/takuzoo3868/go-msfdb/db"
exploitdb "github.com/vulsio/go-exploitdb/db"
"golang.org/x/xerrors"
)
@@ -87,11 +86,12 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
return nil, xerrors.Errorf("Failed to detect CVE of `%s`: %w", cpeURIs, err)
}
if err := DetectGitHubCves(&r); err != nil {
repos := c.Conf.Servers[r.ServerName].GitHubRepos
if err := DetectGitHubCves(&r, repos); err != nil {
return nil, xerrors.Errorf("Failed to detect GitHub Cves: %w", err)
}
if err := DetectWordPressCves(&r); err != nil {
if err := DetectWordPressCves(&r, &config.Conf.WpScan); err != nil {
return nil, xerrors.Errorf("Failed to detect WordPress Cves: %w", err)
}
@@ -142,9 +142,9 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
for i, r := range rs {
r = r.FilterByCvssOver(c.Conf.CvssScoreOver)
r = r.FilterIgnoreCves()
r = r.FilterUnfixed()
r = r.FilterUnfixed(c.Conf.IgnoreUnfixed)
r = r.FilterIgnorePkgs()
r = r.FilterInactiveWordPressLibs()
r = r.FilterInactiveWordPressLibs(c.Conf.WpScan.DetectInactive)
if c.Conf.IgnoreUnscoredCves {
r.ScannedCves = r.ScannedCves.FindScoredVulns()
}
@@ -153,7 +153,7 @@ func FillCveInfos(dbclient DBClient, rs []models.ScanResult, dir string) ([]mode
return rs, nil
}
// DetectPkgCVEs detects OS pkg cves
// DetectPkgCves detects OS pkg cves
func DetectPkgCves(dbclient DBClient, r *models.ScanResult) error {
// Pkg Scan
if r.Release != "" {
@@ -168,7 +168,7 @@ func DetectPkgCves(dbclient DBClient, r *models.ScanResult) error {
}
} else if reuseScannedCves(r) {
util.Log.Infof("r.Release is empty. Use CVEs as it as.")
} else if r.Family == config.ServerTypePseudo {
} else if r.Family == c.ServerTypePseudo {
util.Log.Infof("pseudo type. Skip OVAL and gost detection")
} else {
return xerrors.Errorf("Failed to fill CVEs. r.Release is empty")
@@ -205,44 +205,37 @@ func DetectPkgCves(dbclient DBClient, r *models.ScanResult) error {
}
// DetectGitHubCves fetches CVEs from GitHub Security Alerts
func DetectGitHubCves(r *models.ScanResult) error {
repos := c.Conf.Servers[r.ServerName].GitHubRepos
if len(repos) == 0 {
func DetectGitHubCves(r *models.ScanResult, githubConfs map[string]c.GitHubConf) error {
if len(githubConfs) == 0 {
return nil
}
githubInts := GithubSecurityAlerts(repos)
ints := &integrationResults{}
for _, o := range []Integration{githubInts} {
if err := o.apply(r, ints); err != nil {
return xerrors.Errorf("Failed to detect CVE with integration: %w", err)
for ownerRepo, setting := range githubConfs {
ss := strings.Split(ownerRepo, "/")
if len(ss) != 2 {
return xerrors.Errorf("Failed to parse GitHub owner/repo: %s", ownerRepo)
}
owner, repo := ss[0], ss[1]
n, err := github.DetectGitHubSecurityAlerts(r, owner, repo, setting.Token)
if err != nil {
return xerrors.Errorf("Failed to access GitHub Security Alerts: %w", err)
}
util.Log.Infof("%s: %d CVEs detected with GHSA %s/%s",
r.FormatServerName(), n, owner, repo)
}
util.Log.Infof("%s: %d CVEs are detected with GitHub Security Alerts",
r.FormatServerName(), ints.GithubAlertsCveCounts)
return nil
}
// DetectWordPressCves detects CVEs of WordPress
func DetectWordPressCves(r *models.ScanResult) error {
token := c.Conf.Servers[r.ServerName].WordPress.WPVulnDBToken
if token == "" {
func DetectWordPressCves(r *models.ScanResult, wpCnf *c.WpScanConf) error {
if len(r.WordPressPackages) == 0 {
return nil
}
wpVulnCaches := map[string]string{}
wpOpt := WordPressOption{
token,
&wpVulnCaches,
util.Log.Infof("Detect WordPress CVE. pkgs: %d ", len(r.WordPressPackages))
n, err := wordpress.DetectWordPressCves(r, wpCnf)
if err != nil {
return xerrors.Errorf("Failed to detect WordPress CVE: %w", err)
}
ints := &integrationResults{}
for _, o := range []Integration{wpOpt} {
if err := o.apply(r, ints); err != nil {
return xerrors.Errorf("Failed to detect CVE with integration: %w", err)
}
}
util.Log.Infof("%s: %d CVEs are detected with wpscan API",
r.FormatServerName(), ints.WordPressCveCounts)
util.Log.Infof("%s: found %d WordPress CVEs", r.FormatServerName(), n)
return nil
}
@@ -423,9 +416,9 @@ func detectPkgsCvesWithGost(driver gostdb.DB, r *models.ScanResult) error {
}
// fillWithExploitDB fills Exploits with exploit dataabase
// https://github.com/mozqnet/go-exploitdb
// https://github.com/vulsio/go-exploitdb
func fillWithExploitDB(driver exploitdb.DB, r *models.ScanResult) (nExploitCve int, err error) {
return exploit.FillWithExploit(driver, r)
return exploit.FillWithExploit(driver, r, &config.Conf.Exploit)
}
// fillWithMetasploit fills metasploit modules with metasploit database
@@ -437,7 +430,7 @@ func fillWithMetasploit(driver metasploitdb.DB, r *models.ScanResult) (nMetasplo
// DetectCpeURIsCves detects CVEs of given CPE-URIs
func DetectCpeURIsCves(driver cvedb.DB, r *models.ScanResult, cpeURIs []string) error {
nCVEs := 0
if len(cpeURIs) != 0 && driver == nil && !config.Conf.CveDict.IsFetchViaHTTP() {
if len(cpeURIs) != 0 && driver == nil && !c.Conf.CveDict.IsFetchViaHTTP() {
return xerrors.Errorf("cpeURIs %s specified, but cve-dictionary DB not found. Fetch cve-dictionary before reporting. For details, see `https://github.com/kotakanbe/go-cve-dictionary#deploy-go-cve-dictionary`",
cpeURIs)
}
@@ -469,62 +462,6 @@ func DetectCpeURIsCves(driver cvedb.DB, r *models.ScanResult, cpeURIs []string)
return nil
}
type integrationResults struct {
GithubAlertsCveCounts int
WordPressCveCounts int
}
// Integration is integration of vuls report
type Integration interface {
apply(*models.ScanResult, *integrationResults) error
}
// GithubSecurityAlerts :
func GithubSecurityAlerts(githubConfs map[string]config.GitHubConf) Integration {
return GithubSecurityAlertOption{
GithubConfs: githubConfs,
}
}
// GithubSecurityAlertOption :
type GithubSecurityAlertOption struct {
GithubConfs map[string]config.GitHubConf
}
// https://help.github.com/articles/about-security-alerts-for-vulnerable-dependencies/
func (g GithubSecurityAlertOption) apply(r *models.ScanResult, ints *integrationResults) (err error) {
var nCVEs int
for ownerRepo, setting := range g.GithubConfs {
ss := strings.Split(ownerRepo, "/")
owner, repo := ss[0], ss[1]
n, err := github.FillGitHubSecurityAlerts(r, owner, repo, setting.Token)
if err != nil {
return xerrors.Errorf("Failed to access GitHub Security Alerts: %w", err)
}
nCVEs += n
}
ints.GithubAlertsCveCounts = nCVEs
return nil
}
// WordPressOption :
type WordPressOption struct {
token string
wpVulnCaches *map[string]string
}
func (g WordPressOption) apply(r *models.ScanResult, ints *integrationResults) (err error) {
if g.token == "" {
return nil
}
n, err := wordpress.FillWordPress(r, g.token, g.wpVulnCaches)
if err != nil {
return xerrors.Errorf("Failed to fetch from WPVulnDB. Check the WPVulnDBToken in config.toml. err: %w", err)
}
ints.WordPressCveCounts = n
return nil
}
func fillCweDict(r *models.ScanResult) {
uniqCweIDMap := map[string]bool{}
for _, vinfo := range r.ScannedCves {

View File

@@ -3,7 +3,6 @@ package report
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"path"
"time"
@@ -92,18 +91,6 @@ func (w S3Writer) Write(rs ...models.ScanResult) (err error) {
return err
}
}
if c.Conf.FormatXML {
k := key + ".xml"
var b []byte
if b, err = xml.Marshal(r); err != nil {
return xerrors.Errorf("Failed to Marshal to XML: %w", err)
}
allBytes := bytes.Join([][]byte{[]byte(xml.Header + vulsOpenTag), b, []byte(vulsCloseTag)}, []byte{})
if err := putObject(svc, k, allBytes); err != nil {
return err
}
}
}
return nil
}

View File

@@ -143,7 +143,7 @@ func send(msg message) error {
return nil
}
return xerrors.Errorf(
"HTTP POST error. url: %s, resp: %v, body: %s, err: %w",
"HTTP POST error. url: %s, resp: %v, body: %s, err: %s",
conf.HookURL, resp, body, errs)
}
return nil
@@ -248,7 +248,7 @@ func attachmentText(vinfo models.VulnInfo, osFamily string, cweDict map[string]m
maxCvss := vinfo.MaxCvssScore()
vectors := []string{}
scores := append(vinfo.Cvss3Scores(), vinfo.Cvss2Scores(osFamily)...)
scores := append(vinfo.Cvss3Scores(), vinfo.Cvss2Scores()...)
for _, cvss := range scores {
if cvss.Value.Severity == "" {
continue

View File

@@ -1,81 +0,0 @@
package report
import (
"bytes"
"fmt"
"net/http"
"strconv"
"strings"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)
// StrideWriter send report to Stride
type StrideWriter struct{}
type strideSender struct{}
func (w StrideWriter) Write(rs ...models.ScanResult) (err error) {
conf := config.Conf.Stride
for _, r := range rs {
w := strideSender{}
serverInfo := fmt.Sprintf("%s", r.ServerInfo())
message := fmt.Sprintf(`{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":" %s "}]}]}}`,
serverInfo,
)
if err = w.sendMessage(conf.HookURL, conf.AuthToken, message); err != nil {
return err
}
for _, vinfo := range r.ScannedCves {
maxCvss := vinfo.MaxCvssScore()
severity := strings.ToUpper(maxCvss.Value.Severity)
if severity == "" {
severity = "?"
}
message = fmt.Sprintf(`{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":" %s ","marks": [ { "type": "link", "attrs": { "href": "https://nvd.nist.gov/vuln/detail/%s", "title": "cve" } } ]}]}]}}`,
vinfo.CveID,
vinfo.CveID,
)
if err = w.sendMessage(conf.HookURL, conf.AuthToken, message); err != nil {
return err
}
message = fmt.Sprintf(`{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":" %s (%s) "}]}]}}`,
strconv.FormatFloat(maxCvss.Value.Score, 'f', 1, 64),
severity,
)
if err = w.sendMessage(conf.HookURL, conf.AuthToken, message); err != nil {
return err
}
message = fmt.Sprintf(`{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":" %s "}]}]}}`,
vinfo.Summaries(config.Conf.Lang, r.Family)[0].Value,
)
if err = w.sendMessage(conf.HookURL, conf.AuthToken, message); err != nil {
return err
}
}
}
return nil
}
func (w strideSender) sendMessage(uri, token, jsonStr string) error {
reqs, err := http.NewRequest("POST", uri, bytes.NewBuffer([]byte(jsonStr)))
if err != nil {
return err
}
reqs.Header.Add("Content-Type", "application/json")
reqs.Header.Add("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(reqs)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}

View File

@@ -2,9 +2,9 @@ package report
import (
"fmt"
"log/syslog"
"strings"
syslog "github.com/RackSec/srslog"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
@@ -59,7 +59,7 @@ func (w SyslogWriter) encodeSyslog(result models.ScanResult) (messages []string)
kvPairs = append(kvPairs, fmt.Sprintf(`packages="%s"`, pkgs))
kvPairs = append(kvPairs, fmt.Sprintf(`cve_id="%s"`, cveID))
for _, cvss := range vinfo.Cvss2Scores(result.Family) {
for _, cvss := range vinfo.Cvss2Scores() {
kvPairs = append(kvPairs, fmt.Sprintf(`cvss_score_%s_v2="%.2f"`, cvss.Type, cvss.Value.Score))
kvPairs = append(kvPairs, fmt.Sprintf(`cvss_vector_%s_v2="%s"`, cvss.Type, cvss.Value.Vector))
}
@@ -69,7 +69,7 @@ func (w SyslogWriter) encodeSyslog(result models.ScanResult) (messages []string)
kvPairs = append(kvPairs, fmt.Sprintf(`cvss_vector_%s_v3="%s"`, cvss.Type, cvss.Value.Vector))
}
if content, ok := vinfo.CveContents[models.NvdXML]; ok {
if content, ok := vinfo.CveContents[models.Nvd]; ok {
cwes := strings.Join(content.CweIDs, ",")
kvPairs = append(kvPairs, fmt.Sprintf(`cwe_ids="%s"`, cwes))
if config.Conf.Syslog.Verbose {

View File

@@ -33,11 +33,14 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
models.PackageFixStatus{Name: "pkg4"},
},
CveContents: models.CveContents{
models.NvdXML: models.CveContent{
models.Nvd: models.CveContent{
Cvss2Score: 5.0,
Cvss2Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
Cvss2Severity: "MEDIUM",
CweIDs: []string{"CWE-20"},
Cvss3Score: 9.8,
Cvss3Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
Cvss3Severity: "HIGH",
},
},
},
@@ -45,9 +48,10 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
},
expectedMessages: []string{
`scanned_at="2018-06-13 16:10:00 +0000 UTC" server_name="teste01" os_family="ubuntu" os_release="16.04" ipv4_addr="192.168.0.1,10.0.2.15" ipv6_addr="" packages="pkg1,pkg2" cve_id="CVE-2017-0001"`,
`scanned_at="2018-06-13 16:10:00 +0000 UTC" server_name="teste01" os_family="ubuntu" os_release="16.04" ipv4_addr="192.168.0.1,10.0.2.15" ipv6_addr="" packages="pkg3,pkg4" cve_id="CVE-2017-0002" cvss_score_nvdxml_v2="5.00" cvss_vector_nvdxml_v2="AV:L/AC:L/Au:N/C:N/I:N/A:C" cwe_ids="CWE-20"`,
`scanned_at="2018-06-13 16:10:00 +0000 UTC" server_name="teste01" os_family="ubuntu" os_release="16.04" ipv4_addr="192.168.0.1,10.0.2.15" ipv6_addr="" packages="pkg3,pkg4" cve_id="CVE-2017-0002" cvss_score_nvd_v2="5.00" cvss_vector_nvd_v2="AV:L/AC:L/Au:N/C:N/I:N/A:C" cvss_score_nvd_v3="9.80" cvss_vector_nvd_v3="AV:L/AC:L/Au:N/C:N/I:N/A:C" cwe_ids="CWE-20"`,
},
},
// 1
{
result: models.ScanResult{
ScannedAt: time.Date(2018, 6, 13, 17, 10, 0, 0, time.UTC),
@@ -62,10 +66,11 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
},
CveContents: models.CveContents{
models.RedHat: models.CveContent{
Cvss3Score: 5.0,
Cvss3Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
CweIDs: []string{"CWE-284"},
Title: "RHSA-2017:0001: pkg5 security update (Important)",
Cvss3Score: 5.0,
Cvss3Severity: "Medium",
Cvss3Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
CweIDs: []string{"CWE-284"},
Title: "RHSA-2017:0001: pkg5 security update (Important)",
},
},
},

View File

@@ -150,8 +150,6 @@ func keybindings(g *gocui.Gui) (err error) {
// errs = append(errs, g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg))
// errs = append(errs, g.SetKeybinding("detail", gocui.KeyEnter, gocui.ModNone, showMsg))
//TODO Help Ctrl-h
errs = append(errs, g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit))
// errs = append(errs, g.SetKeybinding("side", gocui.KeyEnter, gocui.ModNone, getLine))
// errs = append(errs, g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg))
@@ -937,20 +935,11 @@ func detailLines() (string, error) {
table := uitable.New()
table.MaxColWidth = maxColWidth
table.Wrap = true
scores := append(vinfo.Cvss3Scores(), vinfo.Cvss2Scores(r.Family)...)
scores := append(vinfo.Cvss3Scores(), vinfo.Cvss2Scores()...)
var cols []interface{}
for _, score := range scores {
if score.Value.Score == 0 && score.Value.Severity == "" {
continue
}
scoreStr := "-"
if 0 < score.Value.Score {
scoreStr = fmt.Sprintf("%3.1f", score.Value.Score)
}
scoreVec := fmt.Sprintf("%s/%s", scoreStr, score.Value.Vector)
cols = []interface{}{
scoreVec,
score.Value.Severity,
score.Value.Format(),
score.Type,
}
table.AddRow(cols...)

View File

@@ -42,6 +42,12 @@ func formatScanSummary(rs ...models.ScanResult) string {
fmt.Sprintf("%s%s", r.Family, r.Release),
r.FormatUpdatablePacksSummary(),
}
if 0 < len(r.WordPressPackages) {
cols = append(cols, fmt.Sprintf("%d WordPress pkgs", len(r.WordPressPackages)))
}
if 0 < len(r.LibraryScanners) {
cols = append(cols, fmt.Sprintf("%d libs", r.LibraryScanners.Total()))
}
} else {
cols = []interface{}{
r.FormatServerName(),
@@ -53,8 +59,7 @@ func formatScanSummary(rs ...models.ScanResult) string {
table.AddRow(cols...)
if len(r.Warnings) != 0 {
warnMsgs = append(warnMsgs, fmt.Sprintf("Warning for %s: %s",
r.FormatServerName(), r.Warnings))
warnMsgs = append(warnMsgs, fmt.Sprintf("Warning: %s", r.Warnings))
}
}
return fmt.Sprintf("%s\n\n%s", table, strings.Join(
@@ -208,7 +213,7 @@ No CVE-IDs are found in updatable packages.
}
}
for _, cvss := range vuln.Cvss2Scores(r.Family) {
for _, cvss := range vuln.Cvss2Scores() {
if cvssstr := cvss.Value.Format(); cvssstr != "" {
data = append(data, []string{string(cvss.Type), cvssstr})
}
@@ -601,7 +606,7 @@ func isCveFixed(current models.VulnInfo, previous models.ScanResult) bool {
func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
cTypes := []models.CveContentType{
models.NvdXML,
models.Nvd,
models.Jvn,
models.NewCveContentType(current.Family),
}

View File

@@ -42,7 +42,7 @@ func TestIsCveInfoUpdated(t *testing.T) {
CveID: "CVE-2017-0001",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2017-0001",
LastModified: time.Time{},
},
@@ -56,7 +56,7 @@ func TestIsCveInfoUpdated(t *testing.T) {
CveID: "CVE-2017-0001",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2017-0001",
LastModified: time.Time{},
},
@@ -113,7 +113,7 @@ func TestIsCveInfoUpdated(t *testing.T) {
CveID: "CVE-2017-0003",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2017-0002",
LastModified: new,
},
@@ -128,7 +128,7 @@ func TestIsCveInfoUpdated(t *testing.T) {
CveID: "CVE-2017-0003",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2017-0002",
LastModified: old,
},
@@ -150,7 +150,7 @@ func TestIsCveInfoUpdated(t *testing.T) {
CveID: "CVE-2017-0004",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2017-0002",
LastModified: old,
},
@@ -267,7 +267,7 @@ func TestDiff(t *testing.T) {
NewVersion: "5.1.73",
NewRelease: "8.el6_8",
Repository: "",
Changelog: models.Changelog{
Changelog: &models.Changelog{
Contents: "",
Method: "",
},
@@ -305,7 +305,7 @@ func TestDiff(t *testing.T) {
NewVersion: "5.1.73",
NewRelease: "8.el6_8",
Repository: "",
Changelog: models.Changelog{
Changelog: &models.Changelog{
Contents: "",
Method: "",
},
@@ -356,7 +356,7 @@ func TestIsCveFixed(t *testing.T) {
},
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2016-6662",
LastModified: time.Time{},
},
@@ -374,7 +374,7 @@ func TestIsCveFixed(t *testing.T) {
},
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2016-6662",
LastModified: time.Time{},
},
@@ -397,7 +397,7 @@ func TestIsCveFixed(t *testing.T) {
},
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2016-6662",
LastModified: time.Time{},
},
@@ -415,7 +415,7 @@ func TestIsCveFixed(t *testing.T) {
},
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NvdXML,
Type: models.Nvd,
CveID: "CVE-2016-6662",
LastModified: time.Time{},
},

View File

@@ -3,6 +3,7 @@ package saas
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
@@ -120,7 +121,7 @@ func (w Writer) Write(rs ...models.ScanResult) (err error) {
svc := s3.New(sess)
for _, r := range rs {
s3Key := renameKeyNameUTC(r.ScannedAt, r.ServerUUID, r.Container)
s3Key := renameKeyName(r.ServerUUID, r.Container)
var b []byte
if b, err = json.Marshal(r); err != nil {
return xerrors.Errorf("Failed to Marshal to JSON: %w", err)
@@ -140,3 +141,10 @@ func (w Writer) Write(rs ...models.ScanResult) (err error) {
util.Log.Infof("done")
return nil
}
func renameKeyName(uuid string, container models.Container) string {
if len(container.ContainerID) == 0 {
return fmt.Sprintf("%s.json", uuid)
}
return fmt.Sprintf("%s@%s.json", container.UUID, uuid)
}

View File

@@ -9,7 +9,6 @@ import (
"regexp"
"sort"
"strings"
"time"
"github.com/BurntSushi/toml"
c "github.com/future-architect/vuls/config"
@@ -19,14 +18,6 @@ import (
"golang.org/x/xerrors"
)
func renameKeyNameUTC(scannedAt time.Time, uuid string, container models.Container) string {
timestr := scannedAt.UTC().Format(time.RFC3339)
if len(container.ContainerID) == 0 {
return fmt.Sprintf("%s/%s.json", timestr, uuid)
}
return fmt.Sprintf("%s/%s@%s.json", timestr, container.UUID, uuid)
}
const reUUID = "[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}"
// Scanning with the -containers-only flag at scan time, the UUID of Container Host may not be generated,
@@ -101,7 +92,6 @@ func EnsureUUIDs(configPath string, results models.ScanResults) (err error) {
return err
}
server.UUIDs[name] = serverUUID
server = cleanForTOMLEncoding(server, c.Conf.Default)
c.Conf.Servers[r.ServerName] = server
if r.IsContainer() {
@@ -116,98 +106,16 @@ func EnsureUUIDs(configPath string, results models.ScanResults) (err error) {
server = cleanForTOMLEncoding(server, c.Conf.Default)
c.Conf.Servers[name] = server
}
email := &c.Conf.EMail
if email.SMTPAddr == "" {
email = nil
}
slack := &c.Conf.Slack
if slack.HookURL == "" {
slack = nil
}
cveDict := &c.Conf.CveDict
ovalDict := &c.Conf.OvalDict
gost := &c.Conf.Gost
exploit := &c.Conf.Exploit
metasploit := &c.Conf.Metasploit
http := &c.Conf.HTTP
if http.URL == "" {
http = nil
}
syslog := &c.Conf.Syslog
if syslog.Host == "" {
syslog = nil
}
aws := &c.Conf.AWS
if aws.S3Bucket == "" {
aws = nil
}
azure := &c.Conf.Azure
if azure.AccountName == "" {
azure = nil
}
stride := &c.Conf.Stride
if stride.HookURL == "" {
stride = nil
}
hipChat := &c.Conf.HipChat
if hipChat.AuthToken == "" {
hipChat = nil
}
chatWork := &c.Conf.ChatWork
if chatWork.APIToken == "" {
chatWork = nil
}
saas := &c.Conf.Saas
if saas.GroupID == 0 {
saas = nil
if c.Conf.Default.WordPress != nil && c.Conf.Default.WordPress.IsZero() {
c.Conf.Default.WordPress = nil
}
c := struct {
CveDict *c.GoCveDictConf `toml:"cveDict"`
OvalDict *c.GovalDictConf `toml:"ovalDict"`
Gost *c.GostConf `toml:"gost"`
Exploit *c.ExploitConf `toml:"exploit"`
Metasploit *c.MetasploitConf `toml:"metasploit"`
Slack *c.SlackConf `toml:"slack"`
Email *c.SMTPConf `toml:"email"`
HTTP *c.HTTPConf `toml:"http"`
Syslog *c.SyslogConf `toml:"syslog"`
AWS *c.AWS `toml:"aws"`
Azure *c.Azure `toml:"azure"`
Stride *c.StrideConf `toml:"stride"`
HipChat *c.HipChatConf `toml:"hipChat"`
ChatWork *c.ChatWorkConf `toml:"chatWork"`
Saas *c.SaasConf `toml:"saas"`
Saas *c.SaasConf `toml:"saas"`
Default c.ServerInfo `toml:"default"`
Servers map[string]c.ServerInfo `toml:"servers"`
}{
CveDict: cveDict,
OvalDict: ovalDict,
Gost: gost,
Exploit: exploit,
Metasploit: metasploit,
Slack: slack,
Email: email,
HTTP: http,
Syslog: syslog,
AWS: aws,
Azure: azure,
Stride: stride,
HipChat: hipChat,
ChatWork: chatWork,
Saas: saas,
Saas: &c.Conf.Saas,
Default: c.Conf.Default,
Servers: c.Conf.Servers,
}
@@ -290,5 +198,11 @@ func cleanForTOMLEncoding(server c.ServerInfo, def c.ServerInfo) c.ServerInfo {
}
}
if server.WordPress != nil {
if server.WordPress.IsZero() || reflect.DeepEqual(server.WordPress, def.WordPress) {
server.WordPress = nil
}
}
return server
}

View File

@@ -73,7 +73,6 @@ func (o *alpine) apkUpdate() error {
}
func (o *alpine) preCure() error {
o.log.Infof("Scanning in %s", o.getServerInfo().Mode)
if err := o.detectIPAddr(); err != nil {
o.log.Warnf("Failed to detect IP addresses: %s", err)
o.warns = append(o.warns, err)
@@ -92,6 +91,7 @@ func (o *alpine) detectIPAddr() (err error) {
}
func (o *alpine) scanPackages() error {
o.log.Infof("Scanning OS pkg in %s", o.getServerInfo().Mode)
if err := o.apkUpdate(); err != nil {
return err
}

View File

@@ -35,7 +35,7 @@ type base struct {
Platform models.Platform
osPackages
LibraryScanners []models.LibraryScanner
WordPress *models.WordPressPackages
WordPress models.WordPressPackages
log *logrus.Entry
errs []error
@@ -449,6 +449,7 @@ func (l *base) convertToModel() models.ScanResult {
RunningKernel: l.Kernel,
Packages: l.Packages,
SrcPackages: l.SrcPackages,
EnabledDnfModules: l.EnabledDnfModules,
WordPressPackages: l.WordPress,
LibraryScanners: l.LibraryScanners,
Optional: l.ServerInfo.Optional,
@@ -525,7 +526,6 @@ func (l *base) parseSystemctlStatus(stdout string) string {
}
func (l *base) scanLibraries() (err error) {
// image already detected libraries
if len(l.LibraryScanners) != 0 {
return nil
}
@@ -535,6 +535,8 @@ func (l *base) scanLibraries() (err error) {
return nil
}
l.log.Info("Scanning Lockfile...")
libFilemap := map[string][]byte{}
detectFiles := l.ServerInfo.Lockfiles
@@ -620,34 +622,14 @@ func (d *DummyFileInfo) IsDir() bool { return false }
func (d *DummyFileInfo) Sys() interface{} { return nil }
func (l *base) scanWordPress() (err error) {
wpOpts := []string{l.ServerInfo.WordPress.OSUser,
l.ServerInfo.WordPress.DocRoot,
l.ServerInfo.WordPress.CmdPath,
l.ServerInfo.WordPress.WPVulnDBToken,
}
var isScanWp, hasEmptyOpt bool
for _, opt := range wpOpts {
if opt != "" {
isScanWp = true
break
} else {
hasEmptyOpt = true
}
}
if !isScanWp {
if l.ServerInfo.WordPress.IsZero() || l.ServerInfo.Type == config.ServerTypePseudo {
return nil
}
if hasEmptyOpt {
return xerrors.Errorf("%s has empty WordPress opts: %s",
l.getServerInfo().GetServerName(), wpOpts)
}
l.log.Info("Scanning WordPress...")
cmd := fmt.Sprintf("sudo -u %s -i -- %s cli version --allow-root",
l.ServerInfo.WordPress.OSUser,
l.ServerInfo.WordPress.CmdPath)
if r := exec(l.ServerInfo, cmd, noSudo); !r.isSuccess() {
l.ServerInfo.WordPress.WPVulnDBToken = "secret"
return xerrors.Errorf("Failed to exec `%s`. Check the OS user, command path of wp-cli, DocRoot and permission: %#v", cmd, l.ServerInfo.WordPress)
}
@@ -655,7 +637,7 @@ func (l *base) scanWordPress() (err error) {
if err != nil {
return xerrors.Errorf("Failed to scan wordpress: %w", err)
}
l.WordPress = wp
l.WordPress = *wp
return nil
}
@@ -742,6 +724,7 @@ func (l *base) detectWpPlugins() ([]models.WpPackage, error) {
}
func (l *base) scanPorts() (err error) {
l.log.Info("Scanning listen port...")
dest := l.detectScanDest()
open, err := l.execPortsScan(dest)
if err != nil {
@@ -837,7 +820,7 @@ func (l *base) findPortTestSuccessOn(listenIPPorts []string, searchListenPort mo
for _, ipPort := range listenIPPorts {
ipPort, err := models.NewPortStat(ipPort)
if err != nil {
util.Log.Warnf("Failed to find: %+v", err)
l.log.Warnf("Failed to find: %+v", err)
continue
}
if searchListenPort.BindAddress == "*" {

View File

@@ -241,7 +241,6 @@ func (o *debian) checkDeps() error {
}
func (o *debian) preCure() error {
o.log.Infof("Scanning in %s", o.getServerInfo().Mode)
if err := o.detectIPAddr(); err != nil {
o.log.Warnf("Failed to detect IP addresses: %s", err)
o.warns = append(o.warns, err)
@@ -277,6 +276,7 @@ func (o *debian) detectIPAddr() (err error) {
}
func (o *debian) scanPackages() error {
o.log.Infof("Scanning OS pkg in %s", o.getServerInfo().Mode)
// collect the running kernel information
release, version, err := o.runningKernel()
if err != nil {
@@ -968,7 +968,7 @@ func (o *debian) getCveIDsFromChangelog(
// If the version is not in changelog, return entire changelog to put into cache
pack := o.Packages[name]
pack.Changelog = models.Changelog{
pack.Changelog = &models.Changelog{
Contents: changelog,
Method: models.FailedToFindVersionInChangelog,
}
@@ -1018,7 +1018,7 @@ func (o *debian) parseChangelog(changelog, name, ver string, confidence models.C
if !found {
if o.Distro.Family == config.Raspbian {
pack := o.Packages[name]
pack.Changelog = models.Changelog{
pack.Changelog = &models.Changelog{
Contents: strings.Join(buf, "\n"),
Method: models.ChangelogLenientMatchStr,
}
@@ -1032,7 +1032,7 @@ func (o *debian) parseChangelog(changelog, name, ver string, confidence models.C
}
pack := o.Packages[name]
pack.Changelog = models.Changelog{
pack.Changelog = &models.Changelog{
Contents: "",
Method: models.FailedToFindVersionInChangelog,
}
@@ -1046,7 +1046,7 @@ func (o *debian) parseChangelog(changelog, name, ver string, confidence models.C
Method: confidence.DetectionMethod,
}
pack := o.Packages[name]
pack.Changelog = clog
pack.Changelog = &clog
cves := []DetectedCveID{}
for _, id := range cveIDs {

View File

@@ -225,7 +225,7 @@ systemd (228-5) unstable; urgency=medium`,
for i, tt := range tests {
aCveIDs, aPack := d.getCveIDsFromChangelog(tt.in[2], tt.in[0], tt.in[1])
if len(aCveIDs) != len(tt.cveIDs) {
t.Errorf("[%d] Len of return array are'nt same. expected %#v, actual %#v", i, tt.cveIDs, aCveIDs)
t.Errorf("[%d] Len of return array aren't same. expected %#v, actual %#v", i, tt.cveIDs, aCveIDs)
t.Errorf(pp.Sprintf("%s", tt.in))
continue
}
@@ -433,7 +433,7 @@ func TestGetChangelogCache(t *testing.T) {
d := newDebian(config.ServerInfo{})
actual := d.getChangelogCache(&meta, pack)
if actual != "" {
t.Errorf("Failed to get empty stirng from cache:")
t.Errorf("Failed to get empty string from cache:")
}
clog := "changelog-text"
@@ -794,7 +794,7 @@ vlc (3.0.10-0+deb10u1) buster-security; urgency=medium`,
},
expect: expect{
cveIDs: []DetectedCveID{{"CVE-2020-13428", models.ChangelogExactMatch}},
pack: models.Package{Changelog: models.Changelog{
pack: models.Package{Changelog: &models.Changelog{
Contents: `vlc (3.0.11-0+deb10u1+rpt2) buster; urgency=medium
* Add MMAL patch 19
@@ -837,7 +837,7 @@ vlc (3.0.11-0+deb10u1) buster-security; urgency=high
},
expect: expect{
cveIDs: []DetectedCveID{},
pack: models.Package{Changelog: models.Changelog{
pack: models.Package{Changelog: &models.Changelog{
Contents: `realvnc-vnc (6.7.2.42622) stable; urgency=low
* Debian package for VNC Server

View File

@@ -69,9 +69,9 @@ func (o *bsd) checkDeps() error {
}
func (o *bsd) preCure() error {
o.log.Infof("Scanning in %s", o.getServerInfo().Mode)
if err := o.detectIPAddr(); err != nil {
o.log.Debugf("Failed to detect IP addresses: %s", err)
o.log.Warnf("Failed to detect IP addresses: %s", err)
o.warns = append(o.warns, err)
}
// Ignore this error as it just failed to detect the IP addresses
return nil
@@ -115,6 +115,7 @@ func (l *base) parseIfconfig(stdout string) (ipv4Addrs []string, ipv6Addrs []str
}
func (o *bsd) scanPackages() error {
o.log.Infof("Scanning OS pkg in %s", o.getServerInfo().Mode)
// collect the running kernel information
release, version, err := o.runningKernel()
if err != nil {

View File

@@ -52,7 +52,7 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
release := result[2]
switch strings.ToLower(result[1]) {
case "centos", "centos linux":
case "centos", "centos linux", "centos stream":
cent := newCentOS(c)
cent.setDistro(config.CentOS, release)
return true, cent
@@ -193,27 +193,27 @@ func (o *redhatBase) postScan() error {
}
func (o *redhatBase) detectIPAddr() (err error) {
o.log.Infof("Scanning in %s", o.getServerInfo().Mode)
o.ServerInfo.IPv4Addrs, o.ServerInfo.IPv6Addrs, err = o.ip()
return err
}
func (o *redhatBase) scanPackages() error {
installed, err := o.scanInstalledPackages()
func (o *redhatBase) scanPackages() (err error) {
o.log.Infof("Scanning OS pkg in %s", o.getServerInfo().Mode)
o.Packages, err = o.scanInstalledPackages()
if err != nil {
o.log.Errorf("Failed to scan installed packages: %s", err)
return err
return xerrors.Errorf("Failed to scan installed packages: %w", err)
}
o.Packages = installed
rebootRequired, err := o.rebootRequired()
if o.EnabledDnfModules, err = o.detectEnabledDnfModules(); err != nil {
return xerrors.Errorf("Failed to detect installed dnf modules: %w", err)
}
o.Kernel.RebootRequired, err = o.rebootRequired()
if err != nil {
err = xerrors.Errorf("Failed to detect the kernel reboot required: %w", err)
o.log.Warnf("err: %+v", err)
o.warns = append(o.warns, err)
// Only warning this error
} else {
o.Kernel.RebootRequired = rebootRequired
}
if o.getServerInfo().Mode.IsOffline() {
@@ -231,8 +231,7 @@ func (o *redhatBase) scanPackages() error {
o.warns = append(o.warns, err)
// Only warning this error
} else {
installed.MergeNewVersion(updatable)
o.Packages = installed
o.Packages.MergeNewVersion(updatable)
}
return nil
}
@@ -261,7 +260,7 @@ func (o *redhatBase) scanInstalledPackages() (models.Packages, error) {
Version: version,
}
r := o.exec(o.rpmQa(o.Distro), noSudo)
r := o.exec(o.rpmQa(), noSudo)
if !r.isSuccess() {
return nil, xerrors.Errorf("Scan packages failed: %s", r)
}
@@ -317,6 +316,11 @@ func (o *redhatBase) parseInstalledPackagesLine(line string) (models.Package, er
return models.Package{},
xerrors.Errorf("Failed to parse package line: %s", line)
}
if strings.HasSuffix(line, "Permission denied") {
return models.Package{},
xerrors.Errorf("Failed to parse package line: %s", line)
}
ver := ""
epoch := fields[1]
if epoch == "0" || epoch == "(none)" {
@@ -370,12 +374,6 @@ func (o *redhatBase) parseUpdatablePacksLines(stdout string) (models.Packages, e
updatable := models.Packages{}
lines := strings.Split(stdout, "\n")
for _, line := range lines {
// TODO remove
// if strings.HasPrefix(line, "Obsoleting") ||
// strings.HasPrefix(line, "Security:") {
// // see https://github.com/future-architect/vuls/issues/165
// continue
// }
if len(strings.TrimSpace(line)) == 0 {
continue
} else if strings.HasPrefix(line, "Loading") {
@@ -494,7 +492,7 @@ func (o *redhatBase) yumPs() error {
pidListenPorts := map[string][]models.PortStat{}
stdout, err = o.lsOfListen()
if err != nil {
return xerrors.Errorf("Failed to ls of: %w", err)
return xerrors.Errorf("Failed to lsof: %w", err)
}
portPids := o.parseLsOf(stdout)
for ipPort, pids := range portPids {
@@ -635,7 +633,7 @@ func (o *redhatBase) procPathToFQPN(execCommand string) (string, error) {
}
func (o *redhatBase) getPkgName(paths []string) (pkgNames []string, err error) {
cmd := o.rpmQf(o.Distro) + strings.Join(paths, " ")
cmd := o.rpmQf() + strings.Join(paths, " ")
r := o.exec(util.PrependProxyEnv(cmd), noSudo)
if !r.isSuccess(0, 2, 4, 8) {
return nil, xerrors.Errorf("Failed to rpm -qf: %s, cmd: %s", r, cmd)
@@ -654,36 +652,74 @@ func (o *redhatBase) getPkgName(paths []string) (pkgNames []string, err error) {
return pkgNames, nil
}
func (o *redhatBase) rpmQa(distro config.Distro) string {
func (o *redhatBase) rpmQa() string {
const old = `rpm -qa --queryformat "%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n"`
const new = `rpm -qa --queryformat "%{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE} %{ARCH}\n"`
switch distro.Family {
switch o.Distro.Family {
case config.SUSEEnterpriseServer:
if v, _ := distro.MajorVersion(); v < 12 {
if v, _ := o.Distro.MajorVersion(); v < 12 {
return old
}
return new
default:
if v, _ := distro.MajorVersion(); v < 6 {
if v, _ := o.Distro.MajorVersion(); v < 6 {
return old
}
return new
}
}
func (o *redhatBase) rpmQf(distro config.Distro) string {
func (o *redhatBase) rpmQf() string {
const old = `rpm -qf --queryformat "%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n" `
const new = `rpm -qf --queryformat "%{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE} %{ARCH}\n" `
switch distro.Family {
switch o.Distro.Family {
case config.SUSEEnterpriseServer:
if v, _ := distro.MajorVersion(); v < 12 {
if v, _ := o.Distro.MajorVersion(); v < 12 {
return old
}
return new
default:
if v, _ := distro.MajorVersion(); v < 6 {
if v, _ := o.Distro.MajorVersion(); v < 6 {
return old
}
return new
}
}
func (o *redhatBase) detectEnabledDnfModules() ([]string, error) {
switch o.Distro.Family {
case config.RedHat, config.CentOS:
//TODO OracleLinux
default:
return nil, nil
}
if v, _ := o.Distro.MajorVersion(); v < 8 {
return nil, nil
}
cmd := `dnf --nogpgcheck --cacheonly --color=never --quiet module list --enabled`
r := o.exec(util.PrependProxyEnv(cmd), noSudo)
if !r.isSuccess() {
if strings.Contains(r.Stdout, "Cache-only enabled but no cache") {
return nil, xerrors.Errorf("sudo yum check-update to make local cache before scanning: %s", r)
}
return nil, xerrors.Errorf("Failed to dnf module list: %s", r)
}
return o.parseDnfModuleList(r.Stdout)
}
func (o *redhatBase) parseDnfModuleList(stdout string) (labels []string, err error) {
scanner := bufio.NewScanner(strings.NewReader(stdout))
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "Hint:") || !strings.Contains(line, "[i]") {
continue
}
ss := strings.Fields(line)
if len(ss) < 2 {
continue
}
labels = append(labels, fmt.Sprintf("%s:%s", ss[0], ss[1]))
}
return
}

View File

@@ -137,12 +137,13 @@ kernel-devel 0 2.6.32 695.20.3.el6 x86_64`,
}
}
func TestParseScanedPackagesLineRedhat(t *testing.T) {
func TestParseInstalledPackagesLine(t *testing.T) {
r := newRHEL(config.ServerInfo{})
var packagetests = []struct {
in string
pack models.Package
err bool
}{
{
"openssl 0 1.0.1e 30.el6.11 x86_64",
@@ -151,6 +152,7 @@ func TestParseScanedPackagesLineRedhat(t *testing.T) {
Version: "1.0.1e",
Release: "30.el6.11",
},
false,
},
{
"Percona-Server-shared-56 1 5.6.19 rel67.0.el6 x84_64",
@@ -159,11 +161,23 @@ func TestParseScanedPackagesLineRedhat(t *testing.T) {
Version: "1:5.6.19",
Release: "rel67.0.el6",
},
false,
},
{
"error: file /run/log/journal/346a500b7fb944199748954baca56086/system.journal: Permission denied",
models.Package{},
true,
},
}
for _, tt := range packagetests {
p, _ := r.parseInstalledPackagesLine(tt.in)
for i, tt := range packagetests {
p, err := r.parseInstalledPackagesLine(tt.in)
if err == nil && tt.err {
t.Errorf("Expected err not occurred: %d", i)
}
if err != nil && !tt.err {
t.Errorf("UnExpected err not occurred: %d", i)
}
if p.Name != tt.pack.Name {
t.Errorf("name: expected %s, actual %s", tt.pack.Name, p.Name)
}
@@ -383,3 +397,44 @@ func TestParseNeedsRestarting(t *testing.T) {
}
}
}
func Test_redhatBase_parseDnfModuleList(t *testing.T) {
type args struct {
stdout string
}
tests := []struct {
name string
args args
wantLabels []string
wantErr bool
}{
{
name: "Success",
args: args{
stdout: `Red Hat Enterprise Linux 8 for x86_64 - AppStream from RHUI (RPMs)
Name Stream Profiles Summary
virt rhel [d][e] common [d] Virtualization module
nginx 1.14 [d][e] common [d] [i] nginx webserver
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled`,
},
wantLabels: []string{
"nginx:1.14",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &redhatBase{}
gotLabels, err := o.parseDnfModuleList(tt.args.stdout)
if (err != nil) != tt.wantErr {
t.Errorf("redhatBase.parseDnfModuleList() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotLabels, tt.wantLabels) {
t.Errorf("redhatBase.parseDnfModuleList() = %v, want %v", gotLabels, tt.wantLabels)
}
})
}
}

View File

@@ -70,6 +70,9 @@ type osPackages struct {
// installed source packages (Debian based only)
SrcPackages models.SrcPackages
// enabled dnf modules or packages
EnabledDnfModules []string
// unsecure packages
VulnInfos models.VulnInfos
@@ -170,25 +173,20 @@ func PrintSSHableServerNames() bool {
// InitServers detect the kind of OS distribution of target servers
func InitServers(timeoutSec int) error {
// use global servers, errServers when scan containers
servers, errServers = detectServerOSes(timeoutSec)
if len(servers) == 0 {
return xerrors.New("No scannable base servers")
hosts, errHosts := detectServerOSes(timeoutSec)
if len(hosts) == 0 {
return xerrors.New("No scannable host OS")
}
containers, errContainers := detectContainerOSes(hosts, timeoutSec)
// scan additional servers
var actives, inactives []osTypeInterface
oks, errs := detectContainerOSes(timeoutSec)
actives = append(actives, oks...)
inactives = append(inactives, errs...)
if config.Conf.ContainersOnly {
servers = actives
errServers = inactives
} else {
servers = append(servers, actives...)
errServers = append(errServers, inactives...)
// set to pkg global variable
for _, host := range hosts {
if !host.getServerInfo().ContainersOnly {
servers = append(servers, host)
}
}
servers = append(servers, containers...)
errServers = append(errHosts, errContainers...)
if len(servers) == 0 {
return xerrors.New("No scannable servers")
@@ -257,11 +255,11 @@ func detectServerOSes(timeoutSec int) (servers, errServers []osTypeInterface) {
return
}
func detectContainerOSes(timeoutSec int) (actives, inactives []osTypeInterface) {
func detectContainerOSes(hosts []osTypeInterface, timeoutSec int) (actives, inactives []osTypeInterface) {
util.Log.Info("Detecting OS of containers... ")
osTypesChan := make(chan []osTypeInterface, len(servers))
osTypesChan := make(chan []osTypeInterface, len(hosts))
defer close(osTypesChan)
for _, s := range servers {
for _, s := range hosts {
go func(s osTypeInterface) {
defer func() {
if p := recover(); p != nil {
@@ -274,7 +272,7 @@ func detectContainerOSes(timeoutSec int) (actives, inactives []osTypeInterface)
}
timeout := time.After(time.Duration(timeoutSec) * time.Second)
for i := 0; i < len(servers); i++ {
for i := 0; i < len(hosts); i++ {
select {
case res := <-osTypesChan:
for _, osi := range res {
@@ -492,7 +490,6 @@ func Scan(timeoutSec int) error {
}
}()
util.Log.Info("Scanning vulnerable OS packages...")
scannedAt := time.Now()
dir, err := EnsureResultDir(scannedAt)
if err != nil {
@@ -628,7 +625,7 @@ func setupChangelogCache() error {
// GetScanResults returns ScanResults from
func GetScanResults(scannedAt time.Time, timeoutSec int) (results models.ScanResults, err error) {
parallelExec(func(o osTypeInterface) (err error) {
if !(config.Conf.LibsOnly || config.Conf.WordPressOnly) {
if o.getServerInfo().Module.IsScanOSPkg() {
if err = o.preCure(); err != nil {
return err
}
@@ -639,14 +636,20 @@ func GetScanResults(scannedAt time.Time, timeoutSec int) (results models.ScanRes
return err
}
}
if err = o.scanWordPress(); err != nil {
return xerrors.Errorf("Failed to scan WordPress: %w", err)
if o.getServerInfo().Module.IsScanPort() {
if err = o.scanPorts(); err != nil {
return xerrors.Errorf("Failed to scan Ports: %w", err)
}
}
if err = o.scanLibraries(); err != nil {
return xerrors.Errorf("Failed to scan Library: %w", err)
if o.getServerInfo().Module.IsScanWordPress() {
if err = o.scanWordPress(); err != nil {
return xerrors.Errorf("Failed to scan WordPress: %w", err)
}
}
if err = o.scanPorts(); err != nil {
return xerrors.Errorf("Failed to scan Ports: %w", err)
if o.getServerInfo().Module.IsScanLockFile() {
if err = o.scanLibraries(); err != nil {
return xerrors.Errorf("Failed to scan Library: %w", err)
}
}
return nil
}, timeoutSec)
@@ -659,6 +662,7 @@ func GetScanResults(scannedAt time.Time, timeoutSec int) (results models.ScanRes
for _, s := range append(servers, errServers...) {
r := s.convertToModel()
checkEOL(&r)
r.ScannedAt = scannedAt
r.ScannedVersion = config.Version
r.ScannedRevision = config.Revision
@@ -676,6 +680,42 @@ func GetScanResults(scannedAt time.Time, timeoutSec int) (results models.ScanRes
return results, nil
}
func checkEOL(r *models.ScanResult) {
switch r.Family {
case config.ServerTypePseudo, config.Raspbian:
return
}
eol, found := config.GetEOL(r.Family, r.Release)
if !found {
r.Warnings = append(r.Warnings,
fmt.Sprintf("Failed to check EOL. Register the issue to https://github.com/future-architect/vuls/issues with the information in `Family: %s Release: %s`",
r.Family, r.Release))
return
}
now := time.Now()
if eol.IsStandardSupportEnded(now) {
r.Warnings = append(r.Warnings, "Standard OS support is EOL(End-of-Life). Purchase extended support if available or Upgrading your OS is strongly recommended.")
if eol.ExtendedSupportUntil.IsZero() {
return
}
if !eol.IsExtendedSuppportEnded(now) {
r.Warnings = append(r.Warnings,
fmt.Sprintf("Extended support available until %s. Check the vendor site.",
eol.ExtendedSupportUntil.Format("2006-01-02")))
} else {
r.Warnings = append(r.Warnings,
"Extended support is also EOL. There are many Vulnerabilities that are not detected, Upgrading your OS strongly recommended.")
}
} else if !eol.StandardSupportUntil.IsZero() &&
now.AddDate(0, 3, 0).After(eol.StandardSupportUntil) {
r.Warnings = append(r.Warnings,
fmt.Sprintf("Standard OS support will be end in 3 months. EOL date: %s",
eol.StandardSupportUntil.Format("2006-01-02")))
}
}
func writeScanResults(jsonDir string, results models.ScanResults) error {
config.Conf.FormatJSON = true
ws := []report.ResultWriter{
@@ -683,7 +723,7 @@ func writeScanResults(jsonDir string, results models.ScanResults) error {
}
for _, w := range ws {
if err := w.Write(results...); err != nil {
return xerrors.Errorf("Failed to write summary report: %s", err)
return xerrors.Errorf("Failed to write summary: %s", err)
}
}

View File

@@ -115,6 +115,7 @@ func (o *suse) checkIfSudoNoPasswd() error {
}
func (o *suse) scanPackages() error {
o.log.Infof("Scanning OS pkg in %s", o.getServerInfo().Mode)
installed, err := o.scanInstalledPackages()
if err != nil {
o.log.Errorf("Failed to scan installed packages: %s", err)

View File

@@ -36,7 +36,6 @@ func (*ConfigtestCmd) Usage() string {
[-log-dir=/path/to/log]
[-ask-key-password]
[-timeout=300]
[-ssh-config]
[-containers-only]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
@@ -68,12 +67,6 @@ func (p *ConfigtestCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&c.Conf.SSHNative, "ssh-native-insecure", false,
"Use Native Go implementation of SSH. Default: Use the external command")
f.BoolVar(&c.Conf.SSHConfig, "ssh-config", false,
"[Deprecated] Use SSH options specified in ssh_config preferentially")
f.BoolVar(&c.Conf.ContainersOnly, "containers-only", false,
"Test containers only. Default: Test both of hosts and containers")
f.BoolVar(&c.Conf.Vvv, "vvv", false, "ssh -vvv")
}
@@ -107,16 +100,6 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa
return subcommands.ExitUsageError
}
if c.Conf.SSHConfig {
msg := []string{
"-ssh-config is deprecated",
"If you update Vuls and get this error, there may be incompatible changes in config.toml",
"Please check config.toml template : https://vuls.io/docs/en/usage-settings.html",
}
util.Log.Errorf("%s", strings.Join(msg, "\n"))
return subcommands.ExitUsageError
}
var servernames []string
if 0 < len(f.Args()) {
servernames = f.Args()

View File

@@ -74,33 +74,33 @@ func (p *DiscoverCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface
func printConfigToml(ips []string) (err error) {
const tomlTemplate = `
# https://vuls.io/docs/en/usage-settings.html
# https://vuls.io/docs/en/config.toml.html#database-section
[cveDict]
type = "sqlite3"
sqlite3Path = "/path/to/cve.sqlite3"
#type = ["sqlite3", "mysql", "postgres", "redis", "http" ]
#sqlite3Path = "/path/to/cve.sqlite3"
#url = ""
[ovalDict]
type = "sqlite3"
sqlite3Path = "/path/to/oval.sqlite3"
#type = ["sqlite3", "mysql", "postgres", "redis", "http" ]
#sqlite3Path = "/path/to/oval.sqlite3"
#url = ""
[gost]
type = "sqlite3"
sqlite3Path = "/path/to/gost.sqlite3"
#type = ["sqlite3", "mysql", "postgres", "redis", "http" ]
#sqlite3Path = "/path/to/gost.sqlite3"
#url = ""
[exploit]
type = "sqlite3"
sqlite3Path = "/path/to/go-exploitdb.sqlite3"
#type = ["sqlite3", "mysql", "postgres", "redis", "http" ]
#sqlite3Path = "/path/to/go-exploitdb.sqlite3"
#url = ""
[metasploit]
type = "sqlite3"
sqlite3Path = "/path/to/go-msfdb.sqlite3"
#type = ["sqlite3", "mysql", "postgres", "redis", "http" ]
#sqlite3Path = "/path/to/go-msfdb.sqlite3"
#url = ""
# https://vuls.io/docs/en/usage-settings.html#slack-section
# https://vuls.io/docs/en/config.toml.html#slack-section
#[slack]
#hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
##legacyToken = "xoxp-11111111111-222222222222-3333333333"
@@ -110,7 +110,7 @@ sqlite3Path = "/path/to/go-msfdb.sqlite3"
#authUser = "username"
#notifyUsers = ["@username"]
# https://vuls.io/docs/en/usage-settings.html#email-section
# https://vuls.io/docs/en/config.toml.html#email-section
#[email]
#smtpAddr = "smtp.example.com"
#smtpPort = "587"
@@ -121,11 +121,11 @@ sqlite3Path = "/path/to/go-msfdb.sqlite3"
#cc = ["cc@example.com"]
#subjectPrefix = "[vuls]"
# https://vuls.io/docs/en/usage-settings.html#http-section
# https://vuls.io/docs/en/config.toml.html#http-section
#[http]
#url = "http://localhost:11234"
# https://vuls.io/docs/en/usage-settings.html#syslog-section
# https://vuls.io/docs/en/config.toml.html#syslog-section
#[syslog]
#protocol = "tcp"
#host = "localhost"
@@ -149,42 +149,38 @@ sqlite3Path = "/path/to/go-msfdb.sqlite3"
#accountKey = "xxxxxxxxxxxxxx"
#containerName = "vuls"
# https://vuls.io/docs/en/usage-settings.html#stride-section
#[stride]
#hookURL = "xxxxxxxxxxxxxxx"
#authToken = "xxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#hipchat-section
#[hipchat]
#room = "vuls"
#authToken = "xxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#chatwork-section
# https://vuls.io/docs/en/config.toml.html#chatwork-section
#[chatwork]
#room = "xxxxxxxxxxx"
#apiToken = "xxxxxxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#telegram-section
# https://vuls.io/docs/en/config.toml.html#telegram-section
#[telegram]
#chatID = "xxxxxxxxxxx"
#token = "xxxxxxxxxxxxxxxxxx"
# https://vuls.io/docs/en/usage-settings.html#default-section
#[wpscan]
#token = "xxxxxxxxxxx"
#detectInactive = false
# https://vuls.io/docs/en/config.toml.html#default-section
[default]
#port = "22"
#user = "username"
#keyPath = "/home/username/.ssh/id_rsa"
#scanMode = ["fast", "fast-root", "deep", "offline"]
#scanModules = ["ospkg", "wordpress", "lockfile", "port"]
#cpeNames = [
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
#]
#owaspDCXMLPath = "/tmp/dependency-check-report.xml"
#ignoreCves = ["CVE-2014-6271"]
#containersOnly = false
#containerType = "docker" #or "lxd" or "lxc" default: docker
#containersIncluded = ["${running}"]
#containersExcluded = ["container_name_a"]
# https://vuls.io/docs/en/usage-settings.html#servers-section
# https://vuls.io/docs/en/config.toml.html#servers-section
[servers]
{{- $names:= .Names}}
{{range $i, $ip := .IPs}}
@@ -195,11 +191,13 @@ host = "{{$ip}}"
#sshConfigPath = "/home/username/.ssh/config"
#keyPath = "/home/username/.ssh/id_rsa"
#scanMode = ["fast", "fast-root", "deep", "offline"]
#scanModules = ["ospkg", "wordpress", "lockfile", "port"]
#type = "pseudo"
#memo = "DB Server"
#cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:4.2.1" ]
#owaspDCXMLPath = "/path/to/dependency-check-report.xml"
#ignoreCves = ["CVE-2014-0160"]
#containersOnly = false
#containerType = "docker" #or "lxd" or "lxc" default: docker
#containersIncluded = ["${running}"]
#containersExcluded = ["container_name_a"]
@@ -216,8 +214,6 @@ host = "{{$ip}}"
#cmdPath = "/usr/local/bin/wp"
#osUser = "wordpress"
#docRoot = "/path/to/DocumentRoot/"
#wpVulnDBToken = "xxxxTokenxxxx"
#ignoreInactive = true
#[servers.{{index $names $i}}.optional]
#key = "value1"

View File

@@ -9,12 +9,9 @@ import (
"path/filepath"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/future-architect/vuls/config"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/msf"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
@@ -44,28 +41,23 @@ func (*ReportCmd) Usage() string {
[-refresh-cve]
[-cvss-over=7]
[-diff]
[-wp-ignore-inactive]
[-ignore-unscored-cves]
[-ignore-unfixed]
[-ignore-github-dismissed]
[-to-email]
[-to-http]
[-to-slack]
[-to-stride]
[-to-hipchat]
[-to-chatwork]
[-to-telegram]
[-to-localfile]
[-to-s3]
[-to-azure-blob]
[-format-json]
[-format-xml]
[-format-one-email]
[-format-one-line-text]
[-format-list]
[-format-full-text]
[-gzip]
[-uuid]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
[-debug-sql]
@@ -106,9 +98,6 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&c.Conf.Diff, "diff", false,
"Difference between previous result and current result ")
f.BoolVar(&c.Conf.WpIgnoreInactive, "wp-ignore-inactive", false,
"ignore inactive on wordpress's plugin and theme")
f.BoolVar(&c.Conf.IgnoreUnscoredCves, "ignore-unscored-cves", false,
"Don't report the unscored CVEs")
@@ -123,7 +112,6 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
"http://proxy-url:port (default: empty)")
f.BoolVar(&c.Conf.FormatJSON, "format-json", false, "JSON format")
f.BoolVar(&c.Conf.FormatXML, "format-xml", false, "XML format")
f.BoolVar(&c.Conf.FormatCsvList, "format-csv", false, "CSV format")
f.BoolVar(&c.Conf.FormatOneEMail, "format-one-email", false,
"Send all the host report via only one EMail (Specify with -to-email)")
@@ -134,18 +122,16 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
"Detail report in plain text")
f.BoolVar(&c.Conf.ToSlack, "to-slack", false, "Send report via Slack")
f.BoolVar(&c.Conf.ToStride, "to-stride", false, "Send report via Stride")
f.BoolVar(&c.Conf.ToHipChat, "to-hipchat", false, "Send report via hipchat")
f.BoolVar(&c.Conf.ToChatWork, "to-chatwork", false, "Send report via chatwork")
f.BoolVar(&c.Conf.ToTelegram, "to-telegram", false, "Send report via Telegram")
f.BoolVar(&c.Conf.ToEmail, "to-email", false, "Send report via Email")
f.BoolVar(&c.Conf.ToSyslog, "to-syslog", false, "Send report via Syslog")
f.BoolVar(&c.Conf.ToLocalFile, "to-localfile", false, "Write report to localfile")
f.BoolVar(&c.Conf.ToS3, "to-s3", false,
"Write report to S3 (bucket/yyyyMMdd_HHmm/servername.json/xml/txt)")
"Write report to S3 (bucket/yyyyMMdd_HHmm/servername.json/txt)")
f.BoolVar(&c.Conf.ToHTTP, "to-http", false, "Send report via HTTP POST")
f.BoolVar(&c.Conf.ToAzureBlob, "to-azure-blob", false,
"Write report to Azure Storage blob (container/yyyyMMdd_HHmm/servername.json/xml/txt)")
"Write report to Azure Storage blob (container/yyyyMMdd_HHmm/servername.json/txt)")
f.BoolVar(&c.Conf.GZIP, "gzip", false, "gzip compression")
f.BoolVar(&c.Conf.Pipe, "pipe", false, "Use args passed via PIPE")
@@ -163,7 +149,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
util.Log.Errorf("Error loading %s, %+v", p.configPath, err)
return subcommands.ExitUsageError
}
c.Conf.HTTP.Overwrite(p.httpConf)
c.Conf.HTTP.Init(p.httpConf)
var dir string
var err error
@@ -183,7 +169,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
}
if !(c.Conf.FormatJSON || c.Conf.FormatOneLineText ||
c.Conf.FormatList || c.Conf.FormatFullText || c.Conf.FormatXML || c.Conf.FormatCsvList) {
c.Conf.FormatList || c.Conf.FormatFullText || c.Conf.FormatCsvList) {
c.Conf.FormatList = true
}
@@ -221,50 +207,19 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
return subcommands.ExitUsageError
}
if c.Conf.CveDict.URL != "" {
if err := report.CveClient.CheckHealth(); err != nil {
util.Log.Errorf("CVE HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with `-cvedb-type=sqlite3 -cvedb-sqlite3-path` option instead of -cvedb-url")
for _, cnf := range []config.VulnSrcConf{
&c.Conf.CveDict,
&c.Conf.OvalDict,
&c.Conf.Gost,
&c.Conf.Exploit,
&c.Conf.Metasploit,
} {
if err := cnf.CheckHTTPHealth(); err != nil {
util.Log.Errorf("Run as server mode before reporting: %+v", err)
return subcommands.ExitFailure
}
}
if c.Conf.OvalDict.URL != "" {
err := oval.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("OVAL HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run goval-dictionary as server mode before reporting or run with `-ovaldb-type=sqlite3 -ovaldb-sqlite3-path` option instead of -ovaldb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Gost.URL != "" {
util.Log.Infof("gost: %s", c.Conf.Gost.URL)
err := gost.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("gost HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run gost as server mode before reporting or run with `-gostdb-type=sqlite3 -gostdb-sqlite3-path` option instead of -gostdb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Exploit.URL != "" {
err := exploit.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("exploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-exploitdb as server mode before reporting")
return subcommands.ExitFailure
}
}
if c.Conf.Metasploit.URL != "" {
err := msf.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("metasploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-msfdb as server mode before reporting")
return subcommands.ExitFailure
}
}
dbclient, locked, err := report.NewDBClient(report.DBClientConf{
CveDictCnf: c.Conf.CveDict,
OvalDictCnf: c.Conf.OvalDict,
@@ -297,14 +252,6 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
reports = append(reports, report.SlackWriter{})
}
if c.Conf.ToStride {
reports = append(reports, report.StrideWriter{})
}
if c.Conf.ToHipChat {
reports = append(reports, report.HipChatWriter{})
}
if c.Conf.ToChatWork {
reports = append(reports, report.ChatWorkWriter{})
}

View File

@@ -79,7 +79,7 @@ func (p *SaaSCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
}
util.Log.Info("Validating config...")
if !c.Conf.ValidateOnReport() {
if !c.Conf.ValidateOnSaaS() {
return subcommands.ExitUsageError
}

View File

@@ -39,11 +39,6 @@ func (*ScanCmd) Usage() string {
[-log-dir=/path/to/log]
[-cachedb-path=/path/to/cache.db]
[-ssh-native-insecure]
[-ssh-config]
[-containers-only]
[-libs-only]
[-wordpress-only]
[-skip-broken]
[-http-proxy=http://192.168.0.1:8080]
[-ask-key-password]
[-timeout=300]
@@ -81,21 +76,6 @@ func (p *ScanCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&c.Conf.SSHNative, "ssh-native-insecure", false,
"Use Native Go implementation of SSH. Default: Use the external command")
f.BoolVar(&c.Conf.SSHConfig, "ssh-config", false,
"[Deprecated] Use SSH options specified in ssh_config preferentially")
f.BoolVar(&c.Conf.ContainersOnly, "containers-only", false,
"Scan running containers only. Default: Scan both of hosts and running containers")
f.BoolVar(&c.Conf.LibsOnly, "libs-only", false,
"Scan libraries (lock files) specified in config.toml only.")
f.BoolVar(&c.Conf.WordPressOnly, "wordpress-only", false,
"Scan WordPress only.")
f.BoolVar(&c.Conf.SkipBroken, "skip-broken", false,
"[For CentOS] yum update changelog with --skip-broken option")
f.StringVar(&c.Conf.HTTPProxy, "http-proxy", "",
"http://proxy-url:port (default: empty)")
@@ -148,16 +128,6 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
return subcommands.ExitUsageError
}
if c.Conf.SSHConfig {
msg := []string{
"-ssh-config is deprecated",
"If you update Vuls and get this error, there may be incompatible changes in config.toml",
"Please check config.toml template : https://vuls.io/docs/en/usage-settings.html",
}
util.Log.Errorf("%s", strings.Join(msg, "\n"))
return subcommands.ExitUsageError
}
util.Log.Info("Start scanning")
util.Log.Infof("config: %s", p.configPath)
@@ -218,7 +188,6 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
util.Log.Info("Detecting IPS identifiers... ")
scan.DetectIPSs(p.timeoutSec)
util.Log.Info("Scanning vulnerabilities... ")
if err := scan.Scan(p.scanTimeoutSec); err != nil {
util.Log.Errorf("Failed to scan. err: %+v", err)
return subcommands.ExitFailure

View File

@@ -12,11 +12,8 @@ import (
// "github.com/future-architect/vuls/Server"
"github.com/future-architect/vuls/config"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/msf"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/server"
"github.com/future-architect/vuls/util"
@@ -109,50 +106,19 @@ func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
return subcommands.ExitUsageError
}
if c.Conf.CveDict.URL != "" {
if err := report.CveClient.CheckHealth(); err != nil {
util.Log.Errorf("CVE HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with `-cvedb-type=sqlite3 -cvedb-sqlite3-path` option instead of -cvedb-url")
for _, cnf := range []config.VulnSrcConf{
&c.Conf.CveDict,
&c.Conf.OvalDict,
&c.Conf.Gost,
&c.Conf.Exploit,
&c.Conf.Metasploit,
} {
if err := cnf.CheckHTTPHealth(); err != nil {
util.Log.Errorf("Run as server mode before reporting: %+v", err)
return subcommands.ExitFailure
}
}
if c.Conf.OvalDict.URL != "" {
err := oval.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("OVAL HTTP server is not running. err: %s", err)
util.Log.Errorf("Run goval-dictionary as server mode before reporting or run with `-ovaldb-type=sqlite3 -ovaldb-sqlite3-path` option instead of -ovaldb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Gost.URL != "" {
util.Log.Infof("gost: %s", c.Conf.Gost.URL)
err := gost.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("gost HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run gost as server mode before reporting or run with `-gostdb-type=sqlite3 -gostdb-sqlite3-path` option instead of -gostdb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Exploit.URL != "" {
err := exploit.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("exploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-exploitdb as server mode before reporting")
return subcommands.ExitFailure
}
}
if c.Conf.Metasploit.URL != "" {
err := msf.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("metasploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-msfdb as server mode before reporting")
return subcommands.ExitFailure
}
}
dbclient, locked, err := report.NewDBClient(report.DBClientConf{
CveDictCnf: c.Conf.CveDict,
OvalDictCnf: c.Conf.OvalDict,

View File

@@ -9,12 +9,9 @@ import (
"path/filepath"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/future-architect/vuls/config"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/exploit"
"github.com/future-architect/vuls/gost"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/msf"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
@@ -132,50 +129,19 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s
return subcommands.ExitUsageError
}
if c.Conf.CveDict.URL != "" {
if err := report.CveClient.CheckHealth(); err != nil {
util.Log.Errorf("CVE HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with `-cvedb-type=sqlite3 -cvedb-sqlite3-path` option instead of -cvedb-url")
for _, cnf := range []config.VulnSrcConf{
&c.Conf.CveDict,
&c.Conf.OvalDict,
&c.Conf.Gost,
&c.Conf.Exploit,
&c.Conf.Metasploit,
} {
if err := cnf.CheckHTTPHealth(); err != nil {
util.Log.Errorf("Run as server mode before reporting: %+v", err)
return subcommands.ExitFailure
}
}
if c.Conf.OvalDict.URL != "" {
err := oval.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("OVAL HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run goval-dictionary as server mode before reporting or run with `-ovaldb-type=sqlite3 -ovaldb-sqlite3-path` option instead of -ovaldb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Gost.URL != "" {
util.Log.Infof("gost: %s", c.Conf.Gost.URL)
err := gost.Base{}.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("gost HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run gost as server mode before reporting or run with `-gostdb-type=sqlite3 -gostdb-sqlite3-path` option instead of -gostdb-url")
return subcommands.ExitFailure
}
}
if c.Conf.Exploit.URL != "" {
err := exploit.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("exploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-exploitdb as server mode before reporting")
return subcommands.ExitFailure
}
}
if c.Conf.Metasploit.URL != "" {
err := msf.CheckHTTPHealth()
if err != nil {
util.Log.Errorf("metasploit HTTP server is not running. err: %+v", err)
util.Log.Errorf("Run go-msfdb as server mode before reporting")
return subcommands.ExitFailure
}
}
dbclient, locked, err := report.NewDBClient(report.DBClientConf{
CveDictCnf: c.Conf.CveDict,
OvalDictCnf: c.Conf.OvalDict,

View File

@@ -8,6 +8,7 @@ import (
"path/filepath"
"runtime"
"github.com/k0kubun/pp"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
@@ -26,12 +27,13 @@ func init() {
}
// NewCustomLogger creates logrus
func NewCustomLogger(c config.ServerInfo) *logrus.Entry {
func NewCustomLogger(server config.ServerInfo) *logrus.Entry {
log := logrus.New()
log.Formatter = &formatter.TextFormatter{MsgAnsiColor: c.LogMsgAnsiColor}
log.Formatter = &formatter.TextFormatter{MsgAnsiColor: server.LogMsgAnsiColor}
log.Level = logrus.InfoLevel
if config.Conf.Debug {
log.Level = logrus.DebugLevel
pp.ColoringEnabled = false
}
if flag.Lookup("test.v") != nil {
@@ -64,8 +66,8 @@ func NewCustomLogger(c config.ServerInfo) *logrus.Entry {
}
whereami := "localhost"
if 0 < len(c.ServerName) {
whereami = c.GetServerName()
if 0 < len(server.ServerName) {
whereami = server.GetServerName()
}
if _, err := os.Stat(logDir); err == nil {

View File

@@ -127,7 +127,7 @@ func ProxyEnv() string {
// PrependProxyEnv prepends proxy environment variable
func PrependProxyEnv(cmd string) string {
if len(config.Conf.HTTPProxy) == 0 {
if config.Conf.HTTPProxy == "" {
return cmd
}
return fmt.Sprintf("%s %s", ProxyEnv(), cmd)
@@ -163,3 +163,18 @@ func Distinct(ss []string) (distincted []string) {
}
return
}
// Major return the major version of the given semantic version
func Major(version string) string {
if version == "" {
return ""
}
ss := strings.SplitN(version, ":", 2)
ver := ""
if len(ss) == 1 {
ver = ss[0]
} else {
ver = ss[1]
}
return ver[0:strings.Index(ver, ".")]
}

View File

@@ -154,3 +154,29 @@ func TestTruncate(t *testing.T) {
}
}
}
func Test_major(t *testing.T) {
var tests = []struct {
in string
expected string
}{
{
in: "",
expected: "",
},
{
in: "4.1",
expected: "4",
},
{
in: "0:4.1",
expected: "4",
},
}
for i, tt := range tests {
a := Major(tt.in)
if tt.expected != a {
t.Errorf("[%d]\nexpected: %s\n actual: %s\n", i, tt.expected, a)
}
}
}

View File

@@ -9,13 +9,14 @@ import (
"time"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/errof"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
version "github.com/hashicorp/go-version"
"golang.org/x/xerrors"
)
//WpCveInfos is for wpvulndb's json
//WpCveInfos is for wpscan json
type WpCveInfos struct {
ReleaseDate string `json:"release_date"`
ChangelogURL string `json:"changelog_url"`
@@ -27,9 +28,9 @@ type WpCveInfos struct {
Error string `json:"error"`
}
//WpCveInfo is for wpvulndb's json
//WpCveInfo is for wpscan json
type WpCveInfo struct {
ID int `json:"id"`
ID string `json:"id"`
Title string `json:"title"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
@@ -39,141 +40,64 @@ type WpCveInfo struct {
FixedIn string `json:"fixed_in"`
}
//References is for wpvulndb's json
//References is for wpscan json
type References struct {
URL []string `json:"url"`
Cve []string `json:"cve"`
Secunia []string `json:"secunia"`
}
// FillWordPress access to wpvulndb and fetch scurity alerts and then set to the given ScanResult.
// DetectWordPressCves access to wpscan and fetch scurity alerts and then set to the given ScanResult.
// https://wpscan.com/
func FillWordPress(r *models.ScanResult, token string, wpVulnCaches *map[string]string) (int, error) {
// TODO move to report
func DetectWordPressCves(r *models.ScanResult, cnf *c.WpScanConf) (int, error) {
if len(r.WordPressPackages) == 0 {
return 0, nil
}
// Core
ver := strings.Replace(r.WordPressPackages.CoreVersion(), ".", "", -1)
if ver == "" {
return 0, xerrors.New("Failed to get WordPress core version")
}
body, ok := searchCache(ver, wpVulnCaches)
if !ok {
url := fmt.Sprintf("https://wpscan.com/api/v3/wordpresses/%s", ver)
var err error
body, err = httpRequest(url, token)
if err != nil {
return 0, err
}
if body == "" {
util.Log.Warnf("A result of REST access is empty: %s", url)
}
(*wpVulnCaches)[ver] = body
}
wpVinfos, err := convertToVinfos(models.WPCore, body)
url := fmt.Sprintf("https://wpscan.com/api/v3/wordpresses/%s", ver)
wpVinfos, err := wpscan(url, ver, cnf.Token)
if err != nil {
return 0, err
}
themes := r.WordPressPackages.Themes()
plugins := r.WordPressPackages.Plugins()
if c.Conf.WpIgnoreInactive {
themes = removeInactives(themes)
plugins = removeInactives(plugins)
}
// Themes
themes := r.WordPressPackages.Themes()
if !cnf.DetectInactive {
themes = removeInactives(themes)
}
for _, p := range themes {
body, ok := searchCache(p.Name, wpVulnCaches)
if !ok {
url := fmt.Sprintf("https://wpscan.com/api/v3/themes/%s", p.Name)
var err error
body, err = httpRequest(url, token)
if err != nil {
return 0, err
}
(*wpVulnCaches)[p.Name] = body
}
if body == "" {
continue
}
templateVinfos, err := convertToVinfos(p.Name, body)
url := fmt.Sprintf("https://wpscan.com/api/v3/themes/%s", p.Name)
candidates, err := wpscan(url, p.Name, cnf.Token)
if err != nil {
return 0, err
}
for _, v := range templateVinfos {
for _, fixstat := range v.WpPackageFixStats {
pkg, ok := r.WordPressPackages.Find(fixstat.Name)
if !ok {
continue
}
ok, err := match(pkg.Version, fixstat.FixedIn)
if err != nil {
util.Log.Infof("[poor] %s installed: %s, fixedIn: %s", pkg.Name, pkg.Version, fixstat.FixedIn)
continue
}
if ok {
wpVinfos = append(wpVinfos, v)
util.Log.Infof("[match] %s installed: %s, fixedIn: %s", pkg.Name, pkg.Version, fixstat.FixedIn)
} else {
util.Log.Debugf("[miss] %s installed: %s, fixedIn: %s", pkg.Name, pkg.Version, fixstat.FixedIn)
}
}
}
vulns := detect(p, candidates)
wpVinfos = append(wpVinfos, vulns...)
}
// Plugins
plugins := r.WordPressPackages.Plugins()
if !cnf.DetectInactive {
plugins = removeInactives(plugins)
}
for _, p := range plugins {
body, ok := searchCache(p.Name, wpVulnCaches)
if !ok {
url := fmt.Sprintf("https://wpscan.com/api/v3/plugins/%s", p.Name)
var err error
body, err = httpRequest(url, token)
if err != nil {
return 0, err
}
(*wpVulnCaches)[p.Name] = body
}
if body == "" {
continue
}
pluginVinfos, err := convertToVinfos(p.Name, body)
url := fmt.Sprintf("https://wpscan.com/api/v3/plugins/%s", p.Name)
candidates, err := wpscan(url, p.Name, cnf.Token)
if err != nil {
return 0, err
}
for _, v := range pluginVinfos {
for _, fixstat := range v.WpPackageFixStats {
pkg, ok := r.WordPressPackages.Find(fixstat.Name)
if !ok {
continue
}
ok, err := match(pkg.Version, fixstat.FixedIn)
if err != nil {
util.Log.Infof("[poor] %s installed: %s, fixedIn: %s", pkg.Name, pkg.Version, fixstat.FixedIn)
continue
}
if ok {
wpVinfos = append(wpVinfos, v)
//TODO Debugf
util.Log.Infof("[match] %s installed: %s, fixedIn: %s", pkg.Name, pkg.Version, fixstat.FixedIn)
} else {
//TODO Debugf
util.Log.Infof("[miss] %s installed: %s, fixedIn: %s", pkg.Name, pkg.Version, fixstat.FixedIn)
}
}
}
vulns := detect(p, candidates)
wpVinfos = append(wpVinfos, vulns...)
}
for _, wpVinfo := range wpVinfos {
if vinfo, ok := r.ScannedCves[wpVinfo.CveID]; ok {
vinfo.CveContents[models.WPVulnDB] = wpVinfo.CveContents[models.WPVulnDB]
vinfo.CveContents[models.WpScan] = wpVinfo.CveContents[models.WpScan]
vinfo.VulnType = wpVinfo.VulnType
vinfo.Confidences = append(vinfo.Confidences, wpVinfo.Confidences...)
vinfo.WpPackageFixStats = append(vinfo.WpPackageFixStats, wpVinfo.WpPackageFixStats...)
@@ -185,6 +109,41 @@ func FillWordPress(r *models.ScanResult, token string, wpVulnCaches *map[string]
return len(wpVinfos), nil
}
func wpscan(url, name, token string) (vinfos []models.VulnInfo, err error) {
body, err := httpRequest(url, token)
if err != nil {
return nil, errof.New(errof.ErrFailedToAccessWpScan,
fmt.Sprintf("Failed to access to wpscan.comm. body: %s, err: %s", string(body), err))
}
if body == "" {
util.Log.Debugf("wpscan.com response body is empty. URL: %s", url)
}
return convertToVinfos(name, body)
}
func detect(installed models.WpPackage, candidates []models.VulnInfo) (vulns []models.VulnInfo) {
for _, v := range candidates {
for _, fixstat := range v.WpPackageFixStats {
ok, err := match(installed.Version, fixstat.FixedIn)
if err != nil {
util.Log.Errorf("Failed to compare versions %s installed: %s, fixedIn: %s, v: %+v",
installed.Name, installed.Version, fixstat.FixedIn, v)
// continue scanning
continue
}
if ok {
vulns = append(vulns, v)
util.Log.Debugf("Affected: %s installed: %s, fixedIn: %s",
installed.Name, installed.Version, fixstat.FixedIn)
} else {
util.Log.Debugf("Not affected: %s : %s, fixedIn: %s",
installed.Name, installed.Version, fixstat.FixedIn)
}
}
}
return
}
func match(installedVer, fixedIn string) (bool, error) {
v1, err := version.NewVersion(installedVer)
if err != nil {
@@ -219,7 +178,7 @@ func extractToVulnInfos(pkgName string, cves []WpCveInfo) (vinfos []models.VulnI
var cveIDs []string
if len(vulnerability.References.Cve) == 0 {
cveIDs = append(cveIDs, fmt.Sprintf("WPVDBID-%d", vulnerability.ID))
cveIDs = append(cveIDs, fmt.Sprintf("WPVDBID-%s", vulnerability.ID))
}
for _, cveNumber := range vulnerability.References.Cve {
cveIDs = append(cveIDs, "CVE-"+cveNumber)
@@ -237,7 +196,7 @@ func extractToVulnInfos(pkgName string, cves []WpCveInfo) (vinfos []models.VulnI
CveID: cveID,
CveContents: models.NewCveContents(
models.CveContent{
Type: models.WPVulnDB,
Type: models.WpScan,
CveID: cveID,
Title: vulnerability.Title,
References: refs,
@@ -245,7 +204,7 @@ func extractToVulnInfos(pkgName string, cves []WpCveInfo) (vinfos []models.VulnI
),
VulnType: vulnerability.VulnType,
Confidences: []models.Confidence{
models.WPVulnDBMatch,
models.WpScanMatch,
},
WpPackageFixStats: []models.WpPackageFixStatus{{
Name: pkgName,
@@ -278,7 +237,7 @@ loop:
if resp.StatusCode == 200 {
return string(body), nil
} else if resp.StatusCode == 404 {
// This package is not in WPVulnDB
// This package is not in wpscan
return "", nil
} else if resp.StatusCode == 429 && retry <= 3 {
// 429 Too Many Requests
@@ -299,11 +258,3 @@ func removeInactives(pkgs models.WordPressPackages) (removed models.WordPressPac
}
return removed
}
func searchCache(name string, wpVulnCaches *map[string]string) (string, bool) {
value, ok := (*wpVulnCaches)[name]
if ok {
return value, true
}
return "", false
}

View File

@@ -79,52 +79,3 @@ func TestRemoveInactive(t *testing.T) {
}
}
}
func TestSearchCache(t *testing.T) {
var tests = []struct {
name string
wpVulnCache map[string]string
value string
ok bool
}{
{
name: "akismet",
wpVulnCache: map[string]string{
"akismet": "body",
},
value: "body",
ok: true,
},
{
name: "akismet",
wpVulnCache: map[string]string{
"BackWPup": "body",
"akismet": "body",
},
value: "body",
ok: true,
},
{
name: "akismet",
wpVulnCache: map[string]string{
"BackWPup": "body",
},
value: "",
ok: false,
},
{
name: "akismet",
wpVulnCache: nil,
value: "",
ok: false,
},
}
for i, tt := range tests {
value, ok := searchCache(tt.name, &tt.wpVulnCache)
if value != tt.value || ok != tt.ok {
t.Errorf("[%d] searchCache error ", i)
}
}
}