Compare commits

...

7 Commits

Author SHA1 Message Date
MaineK00n
abdb081af7 feat(scanner): skip ssh config validation if G option is unknown option (#1632) 2023-04-04 18:50:17 +09:00
kurita0
e506125017 feat(wp): support csh, no sudo scan (#1523)
Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2023-03-28 21:07:10 +09:00
MaineK00n
8ccaa8c3ef fix(scanner/windows): support installationType Domain Controller (#1627) 2023-03-28 21:04:17 +09:00
MaineK00n
de1ed8ecaa feat(ci): add windows for snmp2cpe (#1626) 2023-03-28 19:20:03 +09:00
MaineK00n
947d668452 feat(windows): support Windows (#1581)
* chore(deps): mod update

* fix(scanner): do not attach tty because there is no need to enter ssh password

* feat(windows): support Windows
2023-03-28 19:00:33 +09:00
MaineK00n
db21149f00 feat(contrib): add snmp2cpe (#1625) 2023-03-28 18:56:28 +09:00
dependabot[bot]
7f35f4e661 chore(deps): bump github.com/hashicorp/go-getter from 1.6.2 to 1.7.0 (#1606)
Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.6.2 to 1.7.0.
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.6.2...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-getter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-17 05:04:48 +09:00
52 changed files with 8487 additions and 381 deletions

View File

@@ -12,9 +12,6 @@ jobs:
-
name: Checkout
uses: actions/checkout@v3
-
name: install package for cross compile
run: sudo apt update && sudo apt install -y gcc-aarch64-linux-gnu
-
name: Unshallow
run: git fetch --prune --unshallow
@@ -22,13 +19,16 @@ jobs:
name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version-file: go.mod
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
docker run --rm \
-e CGO_ENABLED=1 \
-e GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
-v /var/run/docker.sock:/var/run/docker.sock \
-v `pwd`:/go/src/github.com/future-architect/vuls \
-w /go/src/github.com/future-architect/vuls \
ghcr.io/goreleaser/goreleaser-cross:v1.20 \
release --clean

2
.gitignore vendored
View File

@@ -20,3 +20,5 @@ vuls
!cmd/vuls
future-vuls
trivy-to-vuls
snmp2cpe
!snmp2cpe/

View File

@@ -6,7 +6,7 @@ release:
owner: future-architect
name: vuls
builds:
- id: vuls-amd64
- id: vuls-linux-amd64
goos:
- linux
goarch:
@@ -21,7 +21,7 @@ builds:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
binary: vuls
- id: vuls-arm64
- id: vuls-linux-arm64
goos:
- linux
goarch:
@@ -36,11 +36,42 @@ builds:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
binary: vuls
- id: vuls-windows-amd64
goos:
- windows
goarch:
- amd64
env:
- CGO_ENABLED=1
- CC=x86_64-w64-mingw32-gcc
main: ./cmd/vuls/main.go
flags:
- -a
ldflags:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
binary: vuls
- id: vuls-windows-arm64
goos:
- windows
goarch:
- arm64
env:
- CGO_ENABLED=1
- CC=/llvm-mingw/bin/aarch64-w64-mingw32-gcc
main: ./cmd/vuls/main.go
flags:
- -a
ldflags:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
binary: vuls
- id: vuls-scanner
env:
- CGO_ENABLED=0
goos:
- linux
- windows
goarch:
- 386
- amd64
@@ -60,6 +91,7 @@ builds:
- CGO_ENABLED=0
goos:
- linux
- windows
goarch:
- 386
- amd64
@@ -68,6 +100,8 @@ builds:
tags:
- scanner
main: ./contrib/trivy/cmd/main.go
ldflags:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
binary: trivy-to-vuls
- id: future-vuls
@@ -75,6 +109,7 @@ builds:
- CGO_ENABLED=0
goos:
- linux
- windows
goarch:
- 386
- amd64
@@ -84,16 +119,40 @@ builds:
- -a
tags:
- scanner
ldflags:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
main: ./contrib/future-vuls/cmd/main.go
binary: future-vuls
- id: snmp2cpe
env:
- CGO_ENABLED=0
goos:
- linux
- windows
goarch:
- 386
- amd64
- arm
- arm64
flags:
- -a
tags:
- scanner
ldflags:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
main: ./contrib/snmp2cpe/cmd/main.go
binary: snmp2cpe
archives:
- id: vuls
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
builds:
- vuls-amd64
- vuls-arm64
- vuls-linux-amd64
- vuls-linux-arm64
- vuls-windows-amd64
- vuls-windows-arm64
format: tar.gz
files:
- LICENSE
@@ -129,5 +188,16 @@ archives:
- LICENSE
- README*
- CHANGELOG.md
- id: snmp2cpe
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
builds:
- snmp2cpe
format: tar.gz
files:
- LICENSE
- README*
- CHANGELOG.md
snapshot:
name_template: SNAPSHOT-{{ .Commit }}

View File

@@ -81,12 +81,16 @@ build-trivy-to-vuls: ./contrib/trivy/cmd/main.go
build-future-vuls: ./contrib/future-vuls/cmd/main.go
$(GO) build -a -ldflags "$(LDFLAGS)" -o future-vuls ./contrib/future-vuls/cmd
# snmp2cpe
build-snmp2cpe: ./contrib/snmp2cpe/cmd/main.go
$(GO) build -a -ldflags "$(LDFLAGS)" -o snmp2cpe ./contrib/snmp2cpe/cmd
# integration-test
BASE_DIR := '${PWD}/integration/results'
# $(shell mkdir -p ${BASE_DIR})
NOW=$(shell date --iso-8601=seconds)
CURRENT := `find ${BASE_DIR} -type d -exec basename {} \; | sort -nr | head -n 1`
NOW=$(shell date '+%Y-%m-%dT%H-%M-%S%z')
NOW_JSON_DIR := '${BASE_DIR}/$(NOW)'
ONE_SEC_AFTER=$(shell date -d '+1 second' --iso-8601=seconds)
ONE_SEC_AFTER=$(shell date -d '+1 second' '+%Y-%m-%dT%H-%M-%S%z')
ONE_SEC_AFTER_JSON_DIR := '${BASE_DIR}/$(ONE_SEC_AFTER)'
LIBS := 'bundler' 'pip' 'pipenv' 'poetry' 'composer' 'npm' 'yarn' 'pnpm' 'cargo' 'gomod' 'gosum' 'gobinary' 'jar' 'pom' 'gradle' 'nuget-lock' 'nuget-config' 'dotnet-deps' 'conan' 'nvd_exact' 'nvd_rough' 'nvd_vendor_product' 'nvd_match_no_jvn' 'jvn_vendor_product' 'jvn_vendor_product_nover'
@@ -106,14 +110,14 @@ endif
mkdir -p ${NOW_JSON_DIR}
sleep 1
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
cp ${BASE_DIR}/$(CURRENT)/*.json ${NOW_JSON_DIR}
- cp integration/data/results/*.json ${NOW_JSON_DIR}
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${NOW}
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
sleep 1
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
cp ${BASE_DIR}/$(CURRENT)/*.json ${ONE_SEC_AFTER_JSON_DIR}
- cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${ONE_SEC_AFTER}
@@ -139,14 +143,14 @@ endif
mkdir -p ${NOW_JSON_DIR}
sleep 1
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp -f ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
cp -f ${BASE_DIR}/$(CURRENT)/*.json ${NOW_JSON_DIR}
- cp integration/data/results/*.json ${NOW_JSON_DIR}
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${NOW}
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
sleep 1
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp -f ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
cp -f ${BASE_DIR}/$(CURRENT)/*.json ${ONE_SEC_AFTER_JSON_DIR}
- cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${ONE_SEC_AFTER}
@@ -163,14 +167,14 @@ endif
sleep 1
# new vs new
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp -f ${BASE_DIR}/current/*.json ${NOW_JSON_DIR}
cp -f ${BASE_DIR}/$(CURRENT)/*.json ${NOW_JSON_DIR}
cp integration/data/results/*.json ${NOW_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml ${NOW}
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
sleep 1
./vuls.new scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
cp -f ${BASE_DIR}/current/*.json ${ONE_SEC_AFTER_JSON_DIR}
cp -f ${BASE_DIR}/$(CURRENT)/*.json ${ONE_SEC_AFTER_JSON_DIR}
cp integration/data/results/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml ${ONE_SEC_AFTER}

View File

@@ -48,10 +48,11 @@ Vuls is a tool created to solve the problems listed above. It has the following
### Scan for any vulnerabilities in Linux/FreeBSD Server
[Supports major Linux/FreeBSD](https://vuls.io/docs/en/supported-os.html)
[Supports major Linux/FreeBSD/Windows](https://vuls.io/docs/en/supported-os.html)
- Alpine, Amazon Linux, CentOS, AlmaLinux, Rocky Linux, Debian, Oracle Linux, Raspbian, RHEL, openSUSE, openSUSE Leap, SUSE Enterprise Linux, Fedora, and Ubuntu
- FreeBSD
- Windows
- Cloud, on-premise, Running Docker Container
### High-quality scan
@@ -72,6 +73,7 @@ Vuls is a tool created to solve the problems listed above. It has the following
- [Red Hat Security Advisories](https://access.redhat.com/security/security-updates/)
- [Debian Security Bug Tracker](https://security-tracker.debian.org/tracker/)
- [Ubuntu CVE Tracker](https://people.canonical.com/~ubuntu-security/cve/)
- [Microsoft CVRF](https://api.msrc.microsoft.com/cvrf/v2.0/swagger/index)
- Commands(yum, zypper, pkg-audit)
- RHSA / ALAS / ELSA / FreeBSD-SA

View File

@@ -1,3 +1,5 @@
//go:build !windows
package config
import (
@@ -7,9 +9,10 @@ import (
"strings"
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"golang.org/x/xerrors"
)
// Version of Vuls
@@ -117,6 +120,9 @@ func (c Config) ValidateOnScan() bool {
if es := server.PortScan.Validate(); 0 < len(es) {
errs = append(errs, es...)
}
if es := server.Windows.Validate(); 0 < len(es) {
errs = append(errs, es...)
}
}
for _, err := range errs {
@@ -245,6 +251,7 @@ type ServerInfo struct {
IgnoredJSONKeys []string `toml:"ignoredJSONKeys,omitempty" json:"ignoredJSONKeys,omitempty"`
WordPress *WordPressConf `toml:"wordpress,omitempty" json:"wordpress,omitempty"`
PortScan *PortScanConf `toml:"portscan,omitempty" json:"portscan,omitempty"`
Windows *WindowsConf `toml:"windows,omitempty" json:"windows,omitempty"`
IPv4Addrs []string `toml:"-" json:"ipv4Addrs,omitempty"`
IPv6Addrs []string `toml:"-" json:"ipv6Addrs,omitempty"`
@@ -271,6 +278,7 @@ type WordPressConf struct {
OSUser string `toml:"osUser,omitempty" json:"osUser,omitempty"`
DocRoot string `toml:"docRoot,omitempty" json:"docRoot,omitempty"`
CmdPath string `toml:"cmdPath,omitempty" json:"cmdPath,omitempty"`
NoSudo bool `toml:"noSudo,omitempty" json:"noSudo,omitempty"`
}
// IsZero return whether this struct is not specified in config.toml

351
config/config_windows.go Normal file
View File

@@ -0,0 +1,351 @@
//go:build windows
package config
import (
"fmt"
"os"
"strconv"
"strings"
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
)
// Version of Vuls
var Version = "`make build` or `make install` will show the version"
// Revision of Git
var Revision string
// Conf has Configuration
var Conf Config
// Config is struct of Configuration
type Config struct {
logging.LogOpts
// scan, report
HTTPProxy string `valid:"url" json:"httpProxy,omitempty"`
ResultsDir string `json:"resultsDir,omitempty"`
Pipe bool `json:"pipe,omitempty"`
Default ServerInfo `json:"default,omitempty"`
Servers map[string]ServerInfo `json:"servers,omitempty"`
ScanOpts
// report
CveDict GoCveDictConf `json:"cveDict,omitempty"`
OvalDict GovalDictConf `json:"ovalDict,omitempty"`
Gost GostConf `json:"gost,omitempty"`
Exploit ExploitConf `json:"exploit,omitempty"`
Metasploit MetasploitConf `json:"metasploit,omitempty"`
KEVuln KEVulnConf `json:"kevuln,omitempty"`
Cti CtiConf `json:"cti,omitempty"`
Slack SlackConf `json:"-"`
EMail SMTPConf `json:"-"`
HTTP HTTPConf `json:"-"`
AWS AWSConf `json:"-"`
Azure AzureConf `json:"-"`
ChatWork ChatWorkConf `json:"-"`
GoogleChat GoogleChatConf `json:"-"`
Telegram TelegramConf `json:"-"`
WpScan WpScanConf `json:"-"`
Saas SaasConf `json:"-"`
ReportOpts
}
// ReportConf is an interface to Validate Report Config
type ReportConf interface {
Validate() []error
}
// ScanOpts is options for scan
type ScanOpts struct {
Vvv bool `json:"vvv,omitempty"`
}
// ReportOpts is options for report
type ReportOpts struct {
CvssScoreOver float64 `json:"cvssScoreOver,omitempty"`
ConfidenceScoreOver int `json:"confidenceScoreOver,omitempty"`
TrivyCacheDBDir string `json:"trivyCacheDBDir,omitempty"`
NoProgress bool `json:"noProgress,omitempty"`
RefreshCve bool `json:"refreshCve,omitempty"`
IgnoreUnfixed bool `json:"ignoreUnfixed,omitempty"`
IgnoreUnscoredCves bool `json:"ignoreUnscoredCves,omitempty"`
DiffPlus bool `json:"diffPlus,omitempty"`
DiffMinus bool `json:"diffMinus,omitempty"`
Diff bool `json:"diff,omitempty"`
Lang string `json:"lang,omitempty"`
}
// ValidateOnConfigtest validates
func (c Config) ValidateOnConfigtest() bool {
errs := c.checkSSHKeyExist()
if _, err := govalidator.ValidateStruct(c); err != nil {
errs = append(errs, err)
}
for _, err := range errs {
logging.Log.Error(err)
}
return len(errs) == 0
}
// ValidateOnScan validates configuration
func (c Config) ValidateOnScan() bool {
errs := c.checkSSHKeyExist()
if len(c.ResultsDir) != 0 {
if ok, _ := govalidator.IsFilePath(c.ResultsDir); !ok {
errs = append(errs, xerrors.Errorf(
"JSON base directory must be a *Absolute* file path. -results-dir: %s", c.ResultsDir))
}
}
if _, err := govalidator.ValidateStruct(c); err != nil {
errs = append(errs, err)
}
for _, server := range c.Servers {
if !server.Module.IsScanPort() {
continue
}
if es := server.PortScan.Validate(); 0 < len(es) {
errs = append(errs, es...)
}
if es := server.Windows.Validate(); 0 < len(es) {
errs = append(errs, es...)
}
}
for _, err := range errs {
logging.Log.Error(err)
}
return len(errs) == 0
}
func (c Config) checkSSHKeyExist() (errs []error) {
for serverName, v := range c.Servers {
if v.Type == constant.ServerTypePseudo {
continue
}
if v.KeyPath != "" {
if _, err := os.Stat(v.KeyPath); err != nil {
errs = append(errs, xerrors.Errorf(
"%s is invalid. keypath: %s not exists", serverName, v.KeyPath))
}
}
}
return errs
}
// ValidateOnReport validates configuration
func (c *Config) ValidateOnReport() bool {
errs := []error{}
if len(c.ResultsDir) != 0 {
if ok, _ := govalidator.IsFilePath(c.ResultsDir); !ok {
errs = append(errs, xerrors.Errorf(
"JSON base directory must be a *Absolute* file path. -results-dir: %s", c.ResultsDir))
}
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
for _, rc := range []ReportConf{
&c.EMail,
&c.Slack,
&c.ChatWork,
&c.GoogleChat,
&c.Telegram,
&c.HTTP,
&c.AWS,
&c.Azure,
} {
if es := rc.Validate(); 0 < len(es) {
errs = append(errs, es...)
}
}
for _, cnf := range []VulnDictInterface{
&Conf.CveDict,
&Conf.OvalDict,
&Conf.Gost,
&Conf.Exploit,
&Conf.Metasploit,
&Conf.KEVuln,
&Conf.Cti,
} {
if err := cnf.Validate(); err != nil {
errs = append(errs, xerrors.Errorf("Failed to validate %s: %+v", cnf.GetName(), err))
}
if err := cnf.CheckHTTPHealth(); err != nil {
errs = append(errs, xerrors.Errorf("Run %s as server mode before reporting: %+v", cnf.GetName(), err))
}
}
for _, err := range errs {
logging.Log.Error(err)
}
return len(errs) == 0
}
// ValidateOnSaaS validates configuration
func (c Config) ValidateOnSaaS() bool {
saaserrs := c.Saas.Validate()
for _, err := range saaserrs {
logging.Log.Error("Failed to validate SaaS conf: %+w", err)
}
return len(saaserrs) == 0
}
// WpScanConf is wpscan.com config
type WpScanConf struct {
Token string `toml:"token,omitempty" json:"-"`
DetectInactive bool `toml:"detectInactive,omitempty" json:"detectInactive,omitempty"`
}
// ServerInfo has SSH Info, additional CPE packages to scan.
type ServerInfo struct {
BaseName string `toml:"-" json:"-"`
ServerName string `toml:"-" json:"serverName,omitempty"`
User string `toml:"user,omitempty" json:"user,omitempty"`
Host string `toml:"host,omitempty" json:"host,omitempty"`
IgnoreIPAddresses []string `toml:"ignoreIPAddresses,omitempty" json:"ignoreIPAddresses,omitempty"`
JumpServer []string `toml:"jumpServer,omitempty" json:"jumpServer,omitempty"`
Port string `toml:"port,omitempty" json:"port,omitempty"`
SSHConfigPath string `toml:"sshConfigPath,omitempty" json:"sshConfigPath,omitempty"`
KeyPath string `toml:"keyPath,omitempty" json:"keyPath,omitempty"`
CpeNames []string `toml:"cpeNames,omitempty" json:"cpeNames,omitempty"`
ScanMode []string `toml:"scanMode,omitempty" json:"scanMode,omitempty"`
ScanModules []string `toml:"scanModules,omitempty" json:"scanModules,omitempty"`
OwaspDCXMLPath string `toml:"owaspDCXMLPath,omitempty" json:"owaspDCXMLPath,omitempty"`
ContainersOnly bool `toml:"containersOnly,omitempty" json:"containersOnly,omitempty"`
ContainersIncluded []string `toml:"containersIncluded,omitempty" json:"containersIncluded,omitempty"`
ContainersExcluded []string `toml:"containersExcluded,omitempty" json:"containersExcluded,omitempty"`
ContainerType string `toml:"containerType,omitempty" json:"containerType,omitempty"`
Containers map[string]ContainerSetting `toml:"containers,omitempty" json:"containers,omitempty"`
IgnoreCves []string `toml:"ignoreCves,omitempty" json:"ignoreCves,omitempty"`
IgnorePkgsRegexp []string `toml:"ignorePkgsRegexp,omitempty" json:"ignorePkgsRegexp,omitempty"`
GitHubRepos map[string]GitHubConf `toml:"githubs" json:"githubs,omitempty"` // key: owner/repo
UUIDs map[string]string `toml:"uuids,omitempty" json:"uuids,omitempty"`
Memo string `toml:"memo,omitempty" json:"memo,omitempty"`
Enablerepo []string `toml:"enablerepo,omitempty" json:"enablerepo,omitempty"` // For CentOS, Alma, Rocky, RHEL, Amazon
Optional map[string]interface{} `toml:"optional,omitempty" json:"optional,omitempty"` // Optional key-value set that will be outputted to JSON
Lockfiles []string `toml:"lockfiles,omitempty" json:"lockfiles,omitempty"` // ie) path/to/package-lock.json
FindLock bool `toml:"findLock,omitempty" json:"findLock,omitempty"`
FindLockDirs []string `toml:"findLockDirs,omitempty" json:"findLockDirs,omitempty"`
Type string `toml:"type,omitempty" json:"type,omitempty"` // "pseudo" or ""
IgnoredJSONKeys []string `toml:"ignoredJSONKeys,omitempty" json:"ignoredJSONKeys,omitempty"`
WordPress *WordPressConf `toml:"wordpress,omitempty" json:"wordpress,omitempty"`
PortScan *PortScanConf `toml:"portscan,omitempty" json:"portscan,omitempty"`
Windows *WindowsConf `toml:"windows,omitempty" json:"windows,omitempty"`
IPv4Addrs []string `toml:"-" json:"ipv4Addrs,omitempty"`
IPv6Addrs []string `toml:"-" json:"ipv6Addrs,omitempty"`
IPSIdentifiers map[string]string `toml:"-" json:"ipsIdentifiers,omitempty"`
// internal use
LogMsgAnsiColor string `toml:"-" json:"-"` // DebugLog Color
Container Container `toml:"-" json:"-"`
Distro Distro `toml:"-" json:"-"`
Mode ScanMode `toml:"-" json:"-"`
Module ScanModule `toml:"-" json:"-"`
}
// ContainerSetting is used for loading container setting in config.toml
type ContainerSetting struct {
Cpes []string `json:"cpes,omitempty"`
OwaspDCXMLPath string `json:"owaspDCXMLPath,omitempty"`
IgnorePkgsRegexp []string `json:"ignorePkgsRegexp,omitempty"`
IgnoreCves []string `json:"ignoreCves,omitempty"`
}
// WordPressConf used for WordPress Scanning
type WordPressConf struct {
OSUser string `toml:"osUser,omitempty" json:"osUser,omitempty"`
DocRoot string `toml:"docRoot,omitempty" json:"docRoot,omitempty"`
CmdPath string `toml:"cmdPath,omitempty" json:"cmdPath,omitempty"`
NoSudo bool `toml:"noSudo,omitempty" json:"noSudo,omitempty"`
}
// IsZero return whether this struct is not specified in config.toml
func (cnf WordPressConf) IsZero() bool {
return cnf.OSUser == "" && cnf.DocRoot == "" && cnf.CmdPath == ""
}
// GitHubConf is used for GitHub Security Alerts
type GitHubConf struct {
Token string `json:"-"`
IgnoreGitHubDismissed bool `json:"ignoreGitHubDismissed,omitempty"`
}
// GetServerName returns ServerName if this serverInfo is about host.
// If this serverInfo is about a container, returns containerID@ServerName
func (s ServerInfo) GetServerName() string {
if len(s.Container.ContainerID) == 0 {
return s.ServerName
}
return fmt.Sprintf("%s@%s", s.Container.Name, s.ServerName)
}
// Distro has distribution info
type Distro struct {
Family string
Release string
}
func (l Distro) String() string {
return fmt.Sprintf("%s %s", l.Family, l.Release)
}
// MajorVersion returns Major version
func (l Distro) MajorVersion() (int, error) {
switch l.Family {
case constant.Amazon:
return strconv.Atoi(getAmazonLinuxVersion(l.Release))
case constant.CentOS:
if 0 < len(l.Release) {
return strconv.Atoi(strings.Split(strings.TrimPrefix(l.Release, "stream"), ".")[0])
}
case constant.OpenSUSE:
if l.Release != "" {
if l.Release == "tumbleweed" {
return 0, nil
}
return strconv.Atoi(strings.Split(l.Release, ".")[0])
}
default:
if 0 < len(l.Release) {
return strconv.Atoi(strings.Split(l.Release, ".")[0])
}
}
return 0, xerrors.New("Release is empty")
}
// IsContainer returns whether this ServerInfo is about container
func (s ServerInfo) IsContainer() bool {
return 0 < len(s.Container.ContainerID)
}
// SetContainer set container
func (s *ServerInfo) SetContainer(d Container) {
s.Container = d
}
// Container has Container information.
type Container struct {
ContainerID string
Name string
Image string
}

View File

@@ -315,6 +315,88 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"36": {StandardSupportUntil: time.Date(2023, 5, 16, 23, 59, 59, 0, time.UTC)},
"37": {StandardSupportUntil: time.Date(2023, 12, 15, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Windows:
// https://learn.microsoft.com/ja-jp/lifecycle/products/?products=windows
lhs, rhs, _ := strings.Cut(strings.TrimSuffix(release, "(Server Core installation)"), "for")
switch strings.TrimSpace(lhs) {
case "Windows 7":
eol, found = EOL{StandardSupportUntil: time.Date(2013, 4, 9, 23, 59, 59, 0, time.UTC)}, true
if strings.Contains(rhs, "Service Pack 1") {
eol, found = EOL{StandardSupportUntil: time.Date(2020, 1, 14, 23, 59, 59, 0, time.UTC)}, true
}
case "Windows 8":
eol, found = EOL{StandardSupportUntil: time.Date(2016, 1, 12, 23, 59, 59, 0, time.UTC)}, true
case "Windows 8.1":
eol, found = EOL{StandardSupportUntil: time.Date(2023, 1, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10":
eol, found = EOL{StandardSupportUntil: time.Date(2017, 5, 9, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1511":
eol, found = EOL{StandardSupportUntil: time.Date(2017, 10, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1607":
eol, found = EOL{StandardSupportUntil: time.Date(2018, 4, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1703":
eol, found = EOL{StandardSupportUntil: time.Date(2018, 10, 9, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1709":
eol, found = EOL{StandardSupportUntil: time.Date(2019, 4, 9, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1803":
eol, found = EOL{StandardSupportUntil: time.Date(2019, 11, 12, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1809":
eol, found = EOL{StandardSupportUntil: time.Date(2020, 11, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1903":
eol, found = EOL{StandardSupportUntil: time.Date(2020, 12, 8, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 1909":
eol, found = EOL{StandardSupportUntil: time.Date(2021, 5, 11, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 2004":
eol, found = EOL{StandardSupportUntil: time.Date(2021, 12, 14, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 20H2":
eol, found = EOL{StandardSupportUntil: time.Date(2022, 5, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 21H1":
eol, found = EOL{StandardSupportUntil: time.Date(2022, 12, 13, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 21H2":
eol, found = EOL{StandardSupportUntil: time.Date(2023, 6, 13, 23, 59, 59, 0, time.UTC)}, true
case "Windows 10 Version 22H2":
eol, found = EOL{StandardSupportUntil: time.Date(2024, 5, 14, 23, 59, 59, 0, time.UTC)}, true
case "Windows 11 Version 21H2":
eol, found = EOL{StandardSupportUntil: time.Date(2024, 10, 8, 23, 59, 59, 0, time.UTC)}, true
case "Windows 11 Version 22H2":
eol, found = EOL{StandardSupportUntil: time.Date(2025, 10, 14, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server 2008":
eol, found = EOL{StandardSupportUntil: time.Date(2011, 7, 12, 23, 59, 59, 0, time.UTC)}, true
if strings.Contains(rhs, "Service Pack 2") {
eol, found = EOL{StandardSupportUntil: time.Date(2020, 1, 14, 23, 59, 59, 0, time.UTC)}, true
}
case "Windows Server 2008 R2":
eol, found = EOL{StandardSupportUntil: time.Date(2013, 4, 9, 23, 59, 59, 0, time.UTC)}, true
if strings.Contains(rhs, "Service Pack 1") {
eol, found = EOL{StandardSupportUntil: time.Date(2020, 1, 14, 23, 59, 59, 0, time.UTC)}, true
}
case "Windows Server 2012":
eol, found = EOL{StandardSupportUntil: time.Date(2023, 10, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server 2012 R2":
eol, found = EOL{StandardSupportUntil: time.Date(2023, 10, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server 2016":
eol, found = EOL{StandardSupportUntil: time.Date(2027, 1, 12, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server, Version 1709":
eol, found = EOL{StandardSupportUntil: time.Date(2019, 4, 9, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server, Version 1803":
eol, found = EOL{StandardSupportUntil: time.Date(2019, 11, 12, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server, Version 1809":
eol, found = EOL{StandardSupportUntil: time.Date(2020, 11, 10, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server 2019":
eol, found = EOL{StandardSupportUntil: time.Date(2029, 1, 9, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server, Version 1903":
eol, found = EOL{StandardSupportUntil: time.Date(2020, 12, 8, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server, Version 1909":
eol, found = EOL{StandardSupportUntil: time.Date(2021, 5, 11, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server, Version 2004":
eol, found = EOL{StandardSupportUntil: time.Date(2021, 12, 14, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server, Version 20H2":
eol, found = EOL{StandardSupportUntil: time.Date(2022, 8, 9, 23, 59, 59, 0, time.UTC)}, true
case "Windows Server 2022":
eol, found = EOL{StandardSupportUntil: time.Date(2031, 10, 14, 23, 59, 59, 0, time.UTC)}, true
default:
}
}
return
}

View File

@@ -623,6 +623,22 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
extEnded: false,
found: false,
},
{
name: "Windows 10 EOL",
fields: fields{family: Windows, release: "Windows 10 for x64-based Systems"},
now: time.Date(2022, 12, 8, 23, 59, 59, 0, time.UTC),
stdEnded: true,
extEnded: true,
found: true,
},
{
name: "Windows 10 Version 22H2 supported",
fields: fields{family: Windows, release: "Windows 10 Version 22H2 for x64-based Systems"},
now: time.Date(2022, 12, 8, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -1,3 +1,5 @@
//go:build !windows
package config
import (

View File

@@ -294,6 +294,13 @@ func setDefaultIfEmpty(server *ServerInfo) error {
}
}
if server.Windows == nil {
server.Windows = Conf.Default.Windows
if server.Windows == nil {
server.Windows = &WindowsConf{}
}
}
if len(server.IgnoredJSONKeys) == 0 {
server.IgnoredJSONKeys = Conf.Default.IgnoredJSONKeys
}

27
config/windows.go Normal file
View File

@@ -0,0 +1,27 @@
package config
import (
"os"
"golang.org/x/xerrors"
)
// WindowsConf used for Windows Update Setting
type WindowsConf struct {
ServerSelection int `toml:"serverSelection,omitempty" json:"serverSelection,omitempty"`
CabPath string `toml:"cabPath,omitempty" json:"cabPath,omitempty"`
}
// Validate validates configuration
func (c *WindowsConf) Validate() []error {
switch c.ServerSelection {
case 0, 1, 2:
case 3:
if _, err := os.Stat(c.CabPath); err != nil {
return []error{xerrors.Errorf("%s does not exist. err: %w", c.CabPath, err)}
}
default:
return []error{xerrors.Errorf("ServerSelection: %d does not support . Reference: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-uamg/07e2bfa4-6795-4189-b007-cc50b476181a", c.ServerSelection)}
}
return nil
}

View File

@@ -11,7 +11,8 @@ COPY . $GOPATH/src/$REPOSITORY
RUN cd $GOPATH/src/$REPOSITORY && \
make build-scanner && mv vuls $GOPATH/bin && \
make build-trivy-to-vuls && mv trivy-to-vuls $GOPATH/bin && \
make build-future-vuls && mv future-vuls $GOPATH/bin
make build-future-vuls && mv future-vuls $GOPATH/bin && \
make build-snmp2cpe && mv snmp2cpe $GOPATH/bin
FROM alpine:3.15
@@ -25,7 +26,7 @@ RUN apk add --no-cache \
nmap \
&& mkdir -p $WORKDIR $LOGDIR
COPY --from=builder /go/bin/vuls /go/bin/trivy-to-vuls /go/bin/future-vuls /usr/local/bin/
COPY --from=builder /go/bin/vuls /go/bin/trivy-to-vuls /go/bin/future-vuls /go/bin/snmp2cpe /usr/local/bin/
COPY --from=aquasec/trivy:latest /usr/local/bin/trivy /usr/local/bin/trivy
VOLUME ["$WORKDIR", "$LOGDIR"]

View File

@@ -0,0 +1,50 @@
# snmp2cpe
## Main Features
- Estimate hardware and OS CPE from SNMP reply of network devices
## Installation
```console
$ git clone https://github.com/future-architect/vuls.git
$ make build-snmp2cpe
```
## Command Reference
```console
$ snmp2cpe help
snmp2cpe: SNMP reply To CPE
Usage:
snmp2cpe [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
convert snmpget reply to CPE
help Help about any command
v1 snmpget with SNMPv1
v2c snmpget with SNMPv2c
v3 snmpget with SNMPv3
version Print the version
Flags:
-h, --help help for snmp2cpe
Use "snmp2cpe [command] --help" for more information about a command.
```
## Usage
```console
$ snmp2cpe v2c --debug 192.168.1.99 public
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.1.1.0 ->
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.47.1.1.1.1.12.1 -> Fortinet
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.47.1.1.1.1.7.1 -> FGT_50E
2023/03/28 14:16:54 DEBUG: .1.3.6.1.2.1.47.1.1.1.1.10.1 -> FortiGate-50E v5.4.6,build1165b1165,171018 (GA)
{"192.168.1.99":{"entPhysicalTables":{"1":{"entPhysicalMfgName":"Fortinet","entPhysicalName":"FGT_50E","entPhysicalSoftwareRev":"FortiGate-50E v5.4.6,build1165b1165,171018 (GA)"}}}}
$ snmp2cpe v2c 192.168.1.99 public | snmp2cpe convert
{"192.168.1.99":["cpe:2.3:h:fortinet:fortigate-50e:-:*:*:*:*:*:*:*","cpe:2.3:o:fortinet:fortios:5.4.6:*:*:*:*:*:*:*"]}
```

View File

@@ -0,0 +1,15 @@
package main
import (
"fmt"
"os"
rootCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/root"
)
func main() {
if err := rootCmd.NewCmdRoot().Execute(); err != nil {
fmt.Fprintf(os.Stderr, "failed to exec snmp2cpe: %s\n", fmt.Sprintf("%+v", err))
os.Exit(1)
}
}

View File

@@ -0,0 +1,52 @@
package convert
import (
"encoding/json"
"os"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cpe"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
)
// NewCmdConvert ...
func NewCmdConvert() *cobra.Command {
cmd := &cobra.Command{
Use: "convert",
Short: "snmpget reply to CPE",
Args: cobra.MaximumNArgs(1),
Example: `$ snmp2cpe v2c 192.168.11.11 public | snmp2cpe convert
$ snmp2cpe v2c 192.168.11.11 public | snmp2cpe convert -
$ snmp2cpe v2c 192.168.11.11 public > v2c.json && snmp2cpe convert v2c.json`,
RunE: func(_ *cobra.Command, args []string) error {
r := os.Stdin
if len(args) == 1 && args[0] != "-" {
f, err := os.Open(args[0])
if err != nil {
return errors.Wrapf(err, "failed to open %s", args[0])
}
defer f.Close()
r = f
}
var reply map[string]snmp.Result
if err := json.NewDecoder(r).Decode(&reply); err != nil {
return errors.Wrap(err, "failed to decode")
}
converted := map[string][]string{}
for ipaddr, res := range reply {
converted[ipaddr] = cpe.Convert(res)
}
if err := json.NewEncoder(os.Stdout).Encode(converted); err != nil {
return errors.Wrap(err, "failed to encode")
}
return nil
},
}
return cmd
}

View File

@@ -0,0 +1,30 @@
package root
import (
"github.com/spf13/cobra"
convertCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/convert"
v1Cmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/v1"
v2cCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/v2c"
v3Cmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/v3"
versionCmd "github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cmd/version"
)
// NewCmdRoot ...
func NewCmdRoot() *cobra.Command {
cmd := &cobra.Command{
Use: "snmp2cpe <command>",
Short: "snmp2cpe",
Long: "snmp2cpe: SNMP reply To CPE",
SilenceErrors: true,
SilenceUsage: true,
}
cmd.AddCommand(v1Cmd.NewCmdV1())
cmd.AddCommand(v2cCmd.NewCmdV2c())
cmd.AddCommand(v3Cmd.NewCmdV3())
cmd.AddCommand(convertCmd.NewCmdConvert())
cmd.AddCommand(versionCmd.NewCmdVersion())
return cmd
}

View File

@@ -0,0 +1,47 @@
package v1
import (
"encoding/json"
"os"
"github.com/gosnmp/gosnmp"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
)
// SNMPv1Options ...
type SNMPv1Options struct {
Debug bool
}
// NewCmdV1 ...
func NewCmdV1() *cobra.Command {
opts := &SNMPv1Options{
Debug: false,
}
cmd := &cobra.Command{
Use: "v1 <IP Address> <Community>",
Short: "snmpget with SNMPv1",
Example: "$ snmp2cpe v1 192.168.100.1 public",
Args: cobra.ExactArgs(2),
RunE: func(_ *cobra.Command, args []string) error {
r, err := snmp.Get(gosnmp.Version1, args[0], snmp.WithCommunity(args[1]), snmp.WithDebug(opts.Debug))
if err != nil {
return errors.Wrap(err, "failed to snmpget")
}
if err := json.NewEncoder(os.Stdout).Encode(map[string]snmp.Result{args[0]: r}); err != nil {
return errors.Wrap(err, "failed to encode")
}
return nil
},
}
cmd.Flags().BoolVarP(&opts.Debug, "debug", "", false, "debug mode")
return cmd
}

View File

@@ -0,0 +1,47 @@
package v2c
import (
"encoding/json"
"os"
"github.com/gosnmp/gosnmp"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
)
// SNMPv2cOptions ...
type SNMPv2cOptions struct {
Debug bool
}
// NewCmdV2c ...
func NewCmdV2c() *cobra.Command {
opts := &SNMPv2cOptions{
Debug: false,
}
cmd := &cobra.Command{
Use: "v2c <IP Address> <Community>",
Short: "snmpget with SNMPv2c",
Example: "$ snmp2cpe v2c 192.168.100.1 public",
Args: cobra.ExactArgs(2),
RunE: func(_ *cobra.Command, args []string) error {
r, err := snmp.Get(gosnmp.Version2c, args[0], snmp.WithCommunity(args[1]), snmp.WithDebug(opts.Debug))
if err != nil {
return errors.Wrap(err, "failed to snmpget")
}
if err := json.NewEncoder(os.Stdout).Encode(map[string]snmp.Result{args[0]: r}); err != nil {
return errors.Wrap(err, "failed to encode")
}
return nil
},
}
cmd.Flags().BoolVarP(&opts.Debug, "debug", "", false, "debug mode")
return cmd
}

View File

@@ -0,0 +1,39 @@
package v3
import (
"github.com/gosnmp/gosnmp"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
)
// SNMPv3Options ...
type SNMPv3Options struct {
Debug bool
}
// NewCmdV3 ...
func NewCmdV3() *cobra.Command {
opts := &SNMPv3Options{
Debug: false,
}
cmd := &cobra.Command{
Use: "v3 <args>",
Short: "snmpget with SNMPv3",
Example: "$ snmp2cpe v3",
RunE: func(_ *cobra.Command, _ []string) error {
_, err := snmp.Get(gosnmp.Version3, "", snmp.WithDebug(opts.Debug))
if err != nil {
return errors.Wrap(err, "failed to snmpget")
}
return nil
},
}
cmd.Flags().BoolVarP(&opts.Debug, "debug", "", false, "debug mode")
return cmd
}

View File

@@ -0,0 +1,23 @@
package version
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/future-architect/vuls/config"
)
// NewCmdVersion ...
func NewCmdVersion() *cobra.Command {
cmd := &cobra.Command{
Use: "version",
Short: "Print the version",
Args: cobra.NoArgs,
Run: func(_ *cobra.Command, _ []string) {
fmt.Fprintf(os.Stdout, "snmp2cpe %s %s\n", config.Version, config.Revision)
},
}
return cmd
}

View File

@@ -0,0 +1,212 @@
package cpe
import (
"fmt"
"strings"
"github.com/hashicorp/go-version"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/util"
)
// Convert ...
func Convert(result snmp.Result) []string {
var cpes []string
switch detectVendor(result) {
case "Cisco":
var p, v string
lhs, _, _ := strings.Cut(result.SysDescr0, " RELEASE SOFTWARE")
for _, s := range strings.Split(lhs, ",") {
s = strings.TrimSpace(s)
switch {
case strings.Contains(s, "Cisco NX-OS"):
p = "nx-os"
case strings.Contains(s, "Cisco IOS Software"), strings.Contains(s, "Cisco Internetwork Operating System Software IOS"):
p = "ios"
if strings.Contains(lhs, "IOSXE") || strings.Contains(lhs, "IOS-XE") {
p = "ios_xe"
}
case strings.HasPrefix(s, "Version "):
v = strings.ToLower(strings.TrimPrefix(s, "Version "))
}
}
if p != "" && v != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:cisco:%s:%s:*:*:*:*:*:*:*", p, v))
}
if t, ok := result.EntPhysicalTables[1]; ok {
if t.EntPhysicalName != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:cisco:%s:-:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalName)))
}
if p != "" && t.EntPhysicalSoftwareRev != "" {
s, _, _ := strings.Cut(t.EntPhysicalSoftwareRev, " RELEASE SOFTWARE")
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:cisco:%s:%s:*:*:*:*:*:*:*", p, strings.ToLower(strings.TrimSuffix(s, ","))))
}
}
case "Juniper Networks":
if strings.HasPrefix(result.SysDescr0, "Juniper Networks, Inc.") {
for _, s := range strings.Split(strings.TrimPrefix(result.SysDescr0, "Juniper Networks, Inc. "), ",") {
s = strings.TrimSpace(s)
switch {
case strings.HasPrefix(s, "qfx"), strings.HasPrefix(s, "ex"), strings.HasPrefix(s, "mx"), strings.HasPrefix(s, "ptx"), strings.HasPrefix(s, "acx"), strings.HasPrefix(s, "bti"), strings.HasPrefix(s, "srx"):
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:juniper:%s:-:*:*:*:*:*:*:*", strings.Fields(s)[0]))
case strings.HasPrefix(s, "kernel JUNOS "):
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:juniper:junos:%s:*:*:*:*:*:*:*", strings.ToLower(strings.Fields(strings.TrimPrefix(s, "kernel JUNOS "))[0])))
}
}
if t, ok := result.EntPhysicalTables[1]; ok {
if t.EntPhysicalSoftwareRev != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:juniper:junos:%s:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalSoftwareRev)))
}
}
} else {
h, v, ok := strings.Cut(result.SysDescr0, " version ")
if ok {
cpes = append(cpes,
fmt.Sprintf("cpe:2.3:h:juniper:%s:-:*:*:*:*:*:*:*", strings.ToLower(h)),
fmt.Sprintf("cpe:2.3:o:juniper:screenos:%s:*:*:*:*:*:*:*", strings.ToLower(strings.Fields(v)[0])),
)
}
}
case "Arista Networks":
v, h, ok := strings.Cut(result.SysDescr0, " running on an ")
if ok {
if strings.HasPrefix(v, "Arista Networks EOS version ") {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:arista:eos:%s:*:*:*:*:*:*:*", strings.ToLower(strings.TrimPrefix(v, "Arista Networks EOS version "))))
}
cpes = append(cpes, fmt.Sprintf("cpe:/h:arista:%s:-:*:*:*:*:*:*:*", strings.ToLower(strings.TrimPrefix(h, "Arista Networks "))))
}
if t, ok := result.EntPhysicalTables[1]; ok {
if t.EntPhysicalSoftwareRev != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:arista:eos:%s:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalSoftwareRev)))
}
}
case "Fortinet":
if t, ok := result.EntPhysicalTables[1]; ok {
if strings.HasPrefix(t.EntPhysicalName, "FGT_") {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:fortinet:fortigate-%s:-:*:*:*:*:*:*:*", strings.ToLower(strings.TrimPrefix(t.EntPhysicalName, "FGT_"))))
}
for _, s := range strings.Fields(t.EntPhysicalSoftwareRev) {
switch {
case strings.HasPrefix(s, "FortiGate-"):
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:fortinet:%s:-:*:*:*:*:*:*:*", strings.ToLower(s)))
case strings.HasPrefix(s, "v") && strings.Contains(s, "build"):
if v, _, found := strings.Cut(strings.TrimPrefix(s, "v"), ",build"); found {
if _, err := version.NewVersion(v); err == nil {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:fortinet:fortios:%s:*:*:*:*:*:*:*", v))
}
}
}
}
}
case "YAMAHA":
var h, v string
for _, s := range strings.Fields(result.SysDescr0) {
switch {
case strings.HasPrefix(s, "RTX"), strings.HasPrefix(s, "NVR"), strings.HasPrefix(s, "RTV"), strings.HasPrefix(s, "RT"),
strings.HasPrefix(s, "SRT"), strings.HasPrefix(s, "FWX"), strings.HasPrefix(s, "YSL-V810"):
h = strings.ToLower(s)
case strings.HasPrefix(s, "Rev."):
if _, err := version.NewVersion(strings.TrimPrefix(s, "Rev.")); err == nil {
v = strings.TrimPrefix(s, "Rev.")
}
}
}
if h != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:yamaha:%s:-:*:*:*:*:*:*:*", h))
if v != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:yamaha:%s:%s:*:*:*:*:*:*:*", h, v))
}
}
case "NEC":
var h, v string
for _, s := range strings.Split(result.SysDescr0, ",") {
s = strings.TrimSpace(s)
switch {
case strings.HasPrefix(s, "IX Series "):
h = strings.ToLower(strings.TrimSuffix(strings.TrimPrefix(s, "IX Series "), " (magellan-sec) Software"))
case strings.HasPrefix(s, "Version "):
if _, err := version.NewVersion(strings.TrimSpace(strings.TrimPrefix(s, "Version "))); err == nil {
v = strings.TrimSpace(strings.TrimPrefix(s, "Version "))
}
}
}
if h != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:nec:%s:-:*:*:*:*:*:*:*", h))
if v != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:nec:%s:%s:*:*:*:*:*:*:*", h, v))
}
}
case "Palo Alto Networks":
if t, ok := result.EntPhysicalTables[1]; ok {
if t.EntPhysicalName != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:h:paloaltonetworks:%s:-:*:*:*:*:*:*:*", strings.ToLower(t.EntPhysicalName)))
}
if t.EntPhysicalSoftwareRev != "" {
cpes = append(cpes, fmt.Sprintf("cpe:2.3:o:paloaltonetworks:pan-os:%s:*:*:*:*:*:*:*", t.EntPhysicalSoftwareRev))
}
}
default:
return []string{}
}
return util.Unique(cpes)
}
func detectVendor(r snmp.Result) string {
if t, ok := r.EntPhysicalTables[1]; ok {
switch t.EntPhysicalMfgName {
case "Cisco":
return "Cisco"
case "Juniper Networks":
return "Juniper Networks"
case "Arista Networks":
return "Arista Networks"
case "Fortinet":
return "Fortinet"
case "YAMAHA":
return "YAMAHA"
case "NEC":
return "NEC"
case "Palo Alto Networks":
return "Palo Alto Networks"
}
}
switch {
case strings.Contains(r.SysDescr0, "Cisco"):
return "Cisco"
case strings.Contains(r.SysDescr0, "Juniper Networks"),
strings.Contains(r.SysDescr0, "SSG5"), strings.Contains(r.SysDescr0, "SSG20"), strings.Contains(r.SysDescr0, "SSG140"),
strings.Contains(r.SysDescr0, "SSG320"), strings.Contains(r.SysDescr0, "SSG350"), strings.Contains(r.SysDescr0, "SSG520"),
strings.Contains(r.SysDescr0, "SSG550"):
return "Juniper Networks"
case strings.Contains(r.SysDescr0, "Arista Networks"):
return "Arista Networks"
case strings.Contains(r.SysDescr0, "Fortinet"), strings.Contains(r.SysDescr0, "FortiGate"):
return "Fortinet"
case strings.Contains(r.SysDescr0, "YAMAHA"),
strings.Contains(r.SysDescr0, "RTX810"), strings.Contains(r.SysDescr0, "RTX830"),
strings.Contains(r.SysDescr0, "RTX1000"), strings.Contains(r.SysDescr0, "RTX1100"),
strings.Contains(r.SysDescr0, "RTX1200"), strings.Contains(r.SysDescr0, "RTX1210"), strings.Contains(r.SysDescr0, "RTX1220"),
strings.Contains(r.SysDescr0, "RTX1300"), strings.Contains(r.SysDescr0, "RTX1500"), strings.Contains(r.SysDescr0, "RTX2000"),
strings.Contains(r.SysDescr0, "RTX3000"), strings.Contains(r.SysDescr0, "RTX3500"), strings.Contains(r.SysDescr0, "RTX5000"),
strings.Contains(r.SysDescr0, "NVR500"), strings.Contains(r.SysDescr0, "NVR510"), strings.Contains(r.SysDescr0, "NVR700W"),
strings.Contains(r.SysDescr0, "RTV01"), strings.Contains(r.SysDescr0, "RTV700"),
strings.Contains(r.SysDescr0, "RT105i"), strings.Contains(r.SysDescr0, "RT105p"), strings.Contains(r.SysDescr0, "RT105e"),
strings.Contains(r.SysDescr0, "RT107e"), strings.Contains(r.SysDescr0, "RT250i"), strings.Contains(r.SysDescr0, "RT300i"),
strings.Contains(r.SysDescr0, "SRT100"),
strings.Contains(r.SysDescr0, "FWX100"),
strings.Contains(r.SysDescr0, "YSL-V810"):
return "YAMAHA"
case strings.Contains(r.SysDescr0, "NEC"):
return "NEC"
case strings.Contains(r.SysDescr0, "Palo Alto Networks"):
return "Palo Alto Networks"
default:
return ""
}
}

View File

@@ -0,0 +1,244 @@
package cpe_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/cpe"
"github.com/future-architect/vuls/contrib/snmp2cpe/pkg/snmp"
)
func TestConvert(t *testing.T) {
tests := []struct {
name string
args snmp.Result
want []string
}{
{
name: "Cisco NX-OS Version 7.1(4)N1(1)",
args: snmp.Result{
SysDescr0: "Cisco NX-OS(tm) n6000, Software (n6000-uk9), Version 7.1(4)N1(1), RELEASE SOFTWARE Copyright (c) 2002-2012 by Cisco Systems, Inc. Device Manager Version 6.0(2)N1(1),Compiled 9/2/2016 10:00:00",
},
want: []string{"cpe:2.3:o:cisco:nx-os:7.1(4)n1(1):*:*:*:*:*:*:*"},
},
{
name: "Cisco IOS Version 15.1(4)M3",
args: snmp.Result{
SysDescr0: `Cisco IOS Software, 2800 Software (C2800NM-ADVENTERPRISEK9-M), Version 15.1(4)M3, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2011 by Cisco Systems, Inc.
Compiled Tue 06-Dec-11 16:21 by prod_rel_team`,
},
want: []string{"cpe:2.3:o:cisco:ios:15.1(4)m3:*:*:*:*:*:*:*"},
},
{
name: "Cisco IOS Version 15.1(4)M4",
args: snmp.Result{
SysDescr0: `Cisco IOS Software, C181X Software (C181X-ADVENTERPRISEK9-M), Version 15.1(4)M4, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2012 by Cisco Systems, Inc.
Compiled Tue 20-Mar-12 23:34 by prod_rel_team`,
},
want: []string{"cpe:2.3:o:cisco:ios:15.1(4)m4:*:*:*:*:*:*:*"},
},
{
name: "Cisco IOS Vresion 15.5(3)M on Cisco 892J-K9-V02",
args: snmp.Result{
SysDescr0: `Cisco IOS Software, C890 Software (C890-UNIVERSALK9-M), Version 15.5(3)M, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2015 by Cisco Systems, Inc.
Compiled Thu 23-Jul-15 03:08 by prod_rel_team`,
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Cisco",
EntPhysicalName: "892",
EntPhysicalSoftwareRev: "15.5(3)M, RELEASE SOFTWARE (fc1)",
}},
},
want: []string{"cpe:2.3:h:cisco:892:-:*:*:*:*:*:*:*", "cpe:2.3:o:cisco:ios:15.5(3)m:*:*:*:*:*:*:*"},
},
{
name: "Cisco IOS Version 15.4(3)M5 on Cisco C892FSP-K9-V02",
args: snmp.Result{
SysDescr0: `Cisco IOS Software, C800 Software (C800-UNIVERSALK9-M), Version 15.4(3)M5, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2016 by Cisco Systems, Inc.
Compiled Tue 09-Feb-16 06:15 by prod_rel_team`,
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Cisco",
EntPhysicalName: "C892FSP-K9",
EntPhysicalSoftwareRev: "15.4(3)M5, RELEASE SOFTWARE (fc1)",
}},
},
want: []string{"cpe:2.3:h:cisco:c892fsp-k9:-:*:*:*:*:*:*:*", "cpe:2.3:o:cisco:ios:15.4(3)m5:*:*:*:*:*:*:*"},
},
{
name: "Cisco IOS Version 12.2(17d)SXB11",
args: snmp.Result{
SysDescr0: `Cisco Internetwork Operating System Software IOS (tm) s72033_rp Software (s72033_rp-JK9SV-M), Version 12.2(17d)SXB11, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2005 by cisco Systems, Inc.`,
},
want: []string{"cpe:2.3:o:cisco:ios:12.2(17d)sxb11:*:*:*:*:*:*:*"},
},
{
name: "Cisco IOX-XE Version 16.12.4",
args: snmp.Result{
SysDescr0: `Cisco IOS Software [Gibraltar], Catalyst L3 Switch Software (CAT9K_LITE_IOSXE), Version 16.12.4, RELEASE SOFTWARE (fc5)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2020 by Cisco Systems, Inc.
Compiled Thu 09-Jul-20 19:31 by m`,
},
want: []string{"cpe:2.3:o:cisco:ios_xe:16.12.4:*:*:*:*:*:*:*"},
},
{
name: "Cisco IOX-XE Version 03.06.07.E",
args: snmp.Result{
SysDescr0: `Cisco IOS Software, IOS-XE Software, Catalyst 4500 L3 Switch Software (cat4500es8-UNIVERSALK9-M), Version 03.06.07.E RELEASE SOFTWARE (fc3)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2017 by Cisco Systems, Inc.
Compiled Wed`,
},
want: []string{"cpe:2.3:o:cisco:ios_xe:03.06.07.e:*:*:*:*:*:*:*"},
},
{
name: "Juniper SSG-5-SH-BT",
args: snmp.Result{
SysDescr0: "SSG5-ISDN version 6.3.0r14.0 (SN: 0000000000000001, Firewall+VPN)",
},
want: []string{"cpe:2.3:h:juniper:ssg5-isdn:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:screenos:6.3.0r14.0:*:*:*:*:*:*:*"},
},
{
name: "JUNOS 20.4R3-S4.8 on Juniper MX240",
args: snmp.Result{
SysDescr0: "Juniper Networks, Inc. mx240 internet router, kernel JUNOS 20.4R3-S4.8, Build date: 2022-08-16 20:42:11 UTC Copyright (c) 1996-2022 Juniper Networks, Inc.",
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Juniper Networks",
EntPhysicalName: "CHAS-BP3-MX240-S",
EntPhysicalSoftwareRev: "20.4R3-S4.8",
}},
},
want: []string{"cpe:2.3:h:juniper:mx240:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:20.4r3-s4.8:*:*:*:*:*:*:*"},
},
{
name: "JUNOS 12.1X46-D65.4 on Juniper SRX220H",
args: snmp.Result{
SysDescr0: "Juniper Networks, Inc. srx220h internet router, kernel JUNOS 12.1X46-D65.4 #0: 2016-12-30 01:34:30 UTC builder@quoarth.juniper.net:/volume/build/junos/12.1/service/12.1X46-D65.4/obj-octeon/junos/bsd/kernels/JSRXNLE/kernel Build date: 2016-12-30 02:59",
},
want: []string{"cpe:2.3:h:juniper:srx220h:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:12.1x46-d65.4:*:*:*:*:*:*:*"},
},
{
name: "JUNOS 12.3X48-D30.7 on Juniper SRX220H2",
args: snmp.Result{
SysDescr0: "Juniper Networks, Inc. srx220h2 internet router, kernel JUNOS 12.3X48-D30.7, Build date: 2016-04-29 00:01:04 UTC Copyright (c) 1996-2016 Juniper Networks, Inc.",
},
want: []string{"cpe:2.3:h:juniper:srx220h2:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:12.3x48-d30.7:*:*:*:*:*:*:*"},
},
{
name: "JUNOS 20.4R3-S4.8 on Juniper SRX4600",
args: snmp.Result{
SysDescr0: "Juniper Networks, Inc. srx4600 internet router, kernel JUNOS 20.4R3-S4.8, Build date: 2022-08-16 20:42:11 UTC Copyright (c) 1996-2022 Juniper Networks, Inc.",
},
want: []string{"cpe:2.3:h:juniper:srx4600:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:20.4r3-s4.8:*:*:*:*:*:*:*"},
},
{
name: "cpe:2.3:o:juniper:junos:20.4:r2-s2.2:*:*:*:*:*:*",
args: snmp.Result{
SysDescr0: "Juniper Networks, Inc. ex4300-32f Ethernet Switch, kernel JUNOS 20.4R3-S4.8, Build date: 2022-08-16 21:10:45 UTC Copyright (c) 1996-2022 Juniper Networks, Inc.",
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Juniper Networks",
EntPhysicalName: "",
EntPhysicalSoftwareRev: "20.4R3-S4.8",
}},
},
want: []string{"cpe:2.3:h:juniper:ex4300-32f:-:*:*:*:*:*:*:*", "cpe:2.3:o:juniper:junos:20.4r3-s4.8:*:*:*:*:*:*:*"},
},
{
name: "Arista Networks EOS version 4.28.4M on DCS-7050TX-64",
args: snmp.Result{
SysDescr0: "Arista Networks EOS version 4.28.4M running on an Arista Networks DCS-7050TX-64",
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Arista Networks",
EntPhysicalName: "",
EntPhysicalSoftwareRev: "4.28.4M",
}},
},
want: []string{"cpe:/h:arista:dcs-7050tx-64:-:*:*:*:*:*:*:*", "cpe:2.3:o:arista:eos:4.28.4m:*:*:*:*:*:*:*"},
},
{
name: "FortiGate-50E",
args: snmp.Result{
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Fortinet",
EntPhysicalName: "FGT_50E",
EntPhysicalSoftwareRev: "FortiGate-50E v5.4.6,build1165b1165,171018 (GA)",
}},
},
want: []string{"cpe:2.3:h:fortinet:fortigate-50e:-:*:*:*:*:*:*:*", "cpe:2.3:o:fortinet:fortios:5.4.6:*:*:*:*:*:*:*"},
},
{
name: "FortiGate-60F",
args: snmp.Result{
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Fortinet",
EntPhysicalName: "FGT_60F",
EntPhysicalSoftwareRev: "FortiGate-60F v6.4.11,build2030,221031 (GA.M)",
}},
},
want: []string{"cpe:2.3:h:fortinet:fortigate-60f:-:*:*:*:*:*:*:*", "cpe:2.3:o:fortinet:fortios:6.4.11:*:*:*:*:*:*:*"},
},
{
name: "YAMAHA RTX1000",
args: snmp.Result{
SysDescr0: "RTX1000 Rev.8.01.29 (Fri Apr 15 11:50:44 2011)",
},
want: []string{"cpe:2.3:h:yamaha:rtx1000:-:*:*:*:*:*:*:*", "cpe:2.3:o:yamaha:rtx1000:8.01.29:*:*:*:*:*:*:*"},
},
{
name: "YAMAHA RTX810",
args: snmp.Result{
SysDescr0: "RTX810 Rev.11.01.34 (Tue Nov 26 18:39:12 2019)",
},
want: []string{"cpe:2.3:h:yamaha:rtx810:-:*:*:*:*:*:*:*", "cpe:2.3:o:yamaha:rtx810:11.01.34:*:*:*:*:*:*:*"},
},
{
name: "NEC IX2105",
args: snmp.Result{
SysDescr0: "NEC Portable Internetwork Core Operating System Software, IX Series IX2105 (magellan-sec) Software, Version 8.8.22, RELEASE SOFTWARE, Compiled Jul 04-Wed-2012 14:18:46 JST #2, IX2105",
},
want: []string{"cpe:2.3:h:nec:ix2105:-:*:*:*:*:*:*:*", "cpe:2.3:o:nec:ix2105:8.8.22:*:*:*:*:*:*:*"},
},
{
name: "NEC IX2235",
args: snmp.Result{
SysDescr0: "NEC Portable Internetwork Core Operating System Software, IX Series IX2235 (magellan-sec) Software, Version 10.6.21, RELEASE SOFTWARE, Compiled Dec 15-Fri-YYYY HH:MM:SS JST #2, IX2235",
},
want: []string{"cpe:2.3:h:nec:ix2235:-:*:*:*:*:*:*:*", "cpe:2.3:o:nec:ix2235:10.6.21:*:*:*:*:*:*:*"},
},
{
name: "Palo Alto Networks PAN-OS 10.0.0 on PA-220",
args: snmp.Result{
SysDescr0: "Palo Alto Networks PA-220 series firewall",
EntPhysicalTables: map[int]snmp.EntPhysicalTable{1: {
EntPhysicalMfgName: "Palo Alto Networks",
EntPhysicalName: "PA-220",
EntPhysicalSoftwareRev: "10.0.0",
}},
},
want: []string{"cpe:2.3:h:paloaltonetworks:pa-220:-:*:*:*:*:*:*:*", "cpe:2.3:o:paloaltonetworks:pan-os:10.0.0:*:*:*:*:*:*:*"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
opts := []cmp.Option{
cmpopts.SortSlices(func(i, j string) bool {
return i < j
}),
}
if diff := cmp.Diff(cpe.Convert(tt.args), tt.want, opts...); diff != "" {
t.Errorf("Convert() value is mismatch (-got +want):%s\n", diff)
}
})
}
}

View File

@@ -0,0 +1,131 @@
package snmp
import (
"log"
"strconv"
"strings"
"time"
"github.com/gosnmp/gosnmp"
"github.com/pkg/errors"
)
type options struct {
community string
debug bool
}
// Option ...
type Option interface {
apply(*options)
}
type communityOption string
func (c communityOption) apply(opts *options) {
opts.community = string(c)
}
// WithCommunity ...
func WithCommunity(c string) Option {
return communityOption(c)
}
type debugOption bool
func (d debugOption) apply(opts *options) {
opts.debug = bool(d)
}
// WithDebug ...
func WithDebug(d bool) Option {
return debugOption(d)
}
// Get ...
func Get(version gosnmp.SnmpVersion, ipaddr string, opts ...Option) (Result, error) {
var options options
for _, o := range opts {
o.apply(&options)
}
r := Result{SysDescr0: "", EntPhysicalTables: map[int]EntPhysicalTable{}}
params := &gosnmp.GoSNMP{
Target: ipaddr,
Port: 161,
Version: version,
Timeout: time.Duration(2) * time.Second,
Retries: 3,
ExponentialTimeout: true,
MaxOids: gosnmp.MaxOids,
}
switch version {
case gosnmp.Version1, gosnmp.Version2c:
params.Community = options.community
case gosnmp.Version3:
return Result{}, errors.New("not implemented")
}
if err := params.Connect(); err != nil {
return Result{}, errors.Wrap(err, "failed to connect")
}
defer params.Conn.Close()
for _, oid := range []string{"1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.47.1.1.1.1.12.1", "1.3.6.1.2.1.47.1.1.1.1.7.1", "1.3.6.1.2.1.47.1.1.1.1.10.1"} {
resp, err := params.Get([]string{oid})
if err != nil {
return Result{}, errors.Wrap(err, "send SNMP GET request")
}
for _, v := range resp.Variables {
if options.debug {
switch v.Type {
case gosnmp.OctetString:
log.Printf("DEBUG: %s -> %s", v.Name, string(v.Value.([]byte)))
default:
log.Printf("DEBUG: %s -> %v", v.Name, v.Value)
}
}
switch {
case v.Name == ".1.3.6.1.2.1.1.1.0":
if v.Type == gosnmp.OctetString {
r.SysDescr0 = string(v.Value.([]byte))
}
case strings.HasPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.12."):
i, err := strconv.Atoi(strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.12."))
if err != nil {
return Result{}, errors.Wrap(err, "failed to get index")
}
if v.Type == gosnmp.OctetString {
b := r.EntPhysicalTables[i]
b.EntPhysicalMfgName = string(v.Value.([]byte))
r.EntPhysicalTables[i] = b
}
case strings.HasPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.7."):
i, err := strconv.Atoi(strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.7."))
if err != nil {
return Result{}, errors.Wrap(err, "failed to get index")
}
if v.Type == gosnmp.OctetString {
b := r.EntPhysicalTables[i]
b.EntPhysicalName = string(v.Value.([]byte))
r.EntPhysicalTables[i] = b
}
case strings.HasPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.10."):
i, err := strconv.Atoi(strings.TrimPrefix(v.Name, ".1.3.6.1.2.1.47.1.1.1.1.10."))
if err != nil {
return Result{}, errors.Wrap(err, "failed to get index")
}
if v.Type == gosnmp.OctetString {
b := r.EntPhysicalTables[i]
b.EntPhysicalSoftwareRev = string(v.Value.([]byte))
r.EntPhysicalTables[i] = b
}
}
}
}
return r, nil
}

View File

@@ -0,0 +1,14 @@
package snmp
// Result ...
type Result struct {
SysDescr0 string `json:"sysDescr0,omitempty"`
EntPhysicalTables map[int]EntPhysicalTable `json:"entPhysicalTables,omitempty"`
}
// EntPhysicalTable ...
type EntPhysicalTable struct {
EntPhysicalMfgName string `json:"entPhysicalMfgName,omitempty"`
EntPhysicalName string `json:"entPhysicalName,omitempty"`
EntPhysicalSoftwareRev string `json:"entPhysicalSoftwareRev,omitempty"`
}

View File

@@ -0,0 +1,12 @@
package util
import "golang.org/x/exp/maps"
// Unique return unique elements
func Unique[T comparable](s []T) []T {
m := map[T]struct{}{}
for _, v := range s {
m[v] = struct{}{}
}
return maps.Keys(m)
}

View File

@@ -473,7 +473,7 @@ func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult, logOpts l
nCVEs, err := client.DetectCVEs(r, true)
if err != nil {
switch r.Family {
case constant.Debian, constant.Ubuntu:
case constant.Debian, constant.Ubuntu, constant.Windows:
return xerrors.Errorf("Failed to detect CVEs with gost: %w", err)
default:
return xerrors.Errorf("Failed to detect unfixed CVEs with gost: %w", err)
@@ -481,7 +481,7 @@ func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult, logOpts l
}
switch r.Family {
case constant.Debian, constant.Ubuntu:
case constant.Debian, constant.Ubuntu, constant.Windows:
logging.Log.Infof("%s: %d CVEs are detected with gost", r.FormatServerName(), nCVEs)
default:
logging.Log.Infof("%s: %d unfixed CVEs are detected with gost", r.FormatServerName(), nCVEs)

View File

@@ -6,11 +6,9 @@ package detector
import (
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"time"
@@ -221,25 +219,23 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
return false
}
// jsonDirPattern is file name pattern of JSON directory
// 2016-11-16T10:43:28+09:00
// 2016-11-16T10:43:28Z
var jsonDirPattern = regexp.MustCompile(
`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2})$`)
// ListValidJSONDirs returns valid json directory as array
// Returned array is sorted so that recent directories are at the head
func ListValidJSONDirs(resultsDir string) (dirs []string, err error) {
var dirInfo []fs.DirEntry
if dirInfo, err = os.ReadDir(resultsDir); err != nil {
err = xerrors.Errorf("Failed to read %s: %w",
config.Conf.ResultsDir, err)
return
dirInfo, err := os.ReadDir(resultsDir)
if err != nil {
return nil, xerrors.Errorf("Failed to read %s: %w", config.Conf.ResultsDir, err)
}
for _, d := range dirInfo {
if d.IsDir() && jsonDirPattern.MatchString(d.Name()) {
jsonDir := filepath.Join(resultsDir, d.Name())
dirs = append(dirs, jsonDir)
if !d.IsDir() {
continue
}
for _, layout := range []string{"2006-01-02T15:04:05Z", "2006-01-02T15:04:05-07:00", "2006-01-02T15-04-05-0700"} {
if _, err := time.Parse(layout, d.Name()); err == nil {
dirs = append(dirs, filepath.Join(resultsDir, d.Name()))
break
}
}
}
sort.Slice(dirs, func(i, j int) bool {

33
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/future-architect/vuls
go 1.18
go 1.20
require (
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible
@@ -19,6 +19,7 @@ require (
github.com/emersion/go-smtp v0.14.0
github.com/google/subcommands v1.2.0
github.com/google/uuid v1.3.0
github.com/gosnmp/gosnmp v1.35.0
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.6.0
@@ -35,20 +36,23 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/package-url/packageurl-go v0.1.1-0.20220203205134-d70459300c8a
github.com/parnurzeal/gorequest v0.2.16
github.com/pkg/errors v0.9.1
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.6.1
github.com/vulsio/go-cti v0.0.2-0.20220613013115-8c7e57a6aa86
github.com/vulsio/go-cve-dictionary v0.8.2
github.com/vulsio/go-cti v0.0.2
github.com/vulsio/go-cve-dictionary v0.8.3
github.com/vulsio/go-exploitdb v0.4.4
github.com/vulsio/go-kev v0.1.1-0.20220118062020-5f69b364106f
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14
github.com/vulsio/gost v0.4.2-0.20230203045609-dcfab39a9ff4
github.com/vulsio/goval-dictionary v0.8.0
github.com/vulsio/go-kev v0.1.1
github.com/vulsio/go-msfdb v0.2.1
github.com/vulsio/gost v0.4.2
github.com/vulsio/goval-dictionary v0.8.2
go.etcd.io/bbolt v1.3.6
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb
golang.org/x/oauth2 v0.1.0
golang.org/x/sync v0.1.0
golang.org/x/text v0.7.0
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
)
@@ -65,9 +69,9 @@ require (
github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/PuerkitoBio/goquery v1.6.1 // indirect
github.com/PuerkitoBio/goquery v1.8.1 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce // indirect
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 // indirect
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
@@ -103,7 +107,7 @@ require (
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.6.2 // indirect
github.com/hashicorp/go-getter v1.7.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
@@ -128,13 +132,12 @@ require (
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/nsf/termbox-go v1.1.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
@@ -142,7 +145,7 @@ require (
github.com/sergi/go-diff v1.3.1 // indirect
github.com/smartystreets/assertions v1.13.0 // indirect
github.com/spdx/tools-golang v0.3.0 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/afero v1.9.4 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
@@ -150,7 +153,7 @@ require (
github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
@@ -162,7 +165,7 @@ require (
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/term v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/api v0.107.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

431
go.sum
View File

@@ -17,35 +17,176 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0=
cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=
cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=
cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=
cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=
cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=
cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=
cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=
cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=
cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk=
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=
cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=
cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=
cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=
cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=
cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=
cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=
cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=
cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=
cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=
cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=
cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=
cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=
cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=
cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=
cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=
cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ=
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=
cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=
cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=
cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible h1:bmmC38SlE8/E81nNADlgmVGurPWMHDX2YNXVQMrBpEE=
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -89,10 +230,11 @@ github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmy
github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFGCWpk=
github.com/PuerkitoBio/goquery v1.6.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f h1:U5oMIt9/cuLbHnVgNddFoJ6ebcMx52Unq2+/Wglo1XU=
github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f/go.mod h1:bWPItdcCK9CkZcAaC7yS9N+t2zijtIjAWBcQtOzV9nM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
@@ -102,9 +244,9 @@ github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
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/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
@@ -127,7 +269,7 @@ github.com/aquasecurity/trivy-db v0.0.0-20220627104749-930461748b63 h1:hgGD7zqlN
github.com/aquasecurity/trivy-db v0.0.0-20220627104749-930461748b63/go.mod h1:/nULgnDeq/JMPMVwE1dmf4kWlYn++7VrM3O2naj4BHA=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.136 h1:J1KJJssa8pjU8jETYUxwRS37KTcxjACfKd9GK8t+5ZU=
github.com/aws/aws-sdk-go v1.44.136/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
@@ -146,6 +288,8 @@ github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5
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=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
@@ -159,6 +303,12 @@ 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/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
github.com/containerd/stargz-snapshotter/estargz v0.12.1 h1:+7nYmHJb0tEkcRaAW+MHqoKaJYZmkikupxCqVtmPuY0=
github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
@@ -201,6 +351,10 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
@@ -212,6 +366,7 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
@@ -259,6 +414,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
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=
@@ -274,8 +431,10 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.3/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/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
@@ -291,6 +450,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.12.0 h1:nidOEtFYlgPCRqxCKj/4c/js940HVWplCWc5ftdfdUA=
@@ -303,6 +465,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -313,6 +476,11 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
@@ -320,12 +488,23 @@ github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
github.com/googleapis/enterprise-certificate-proxy v0.2.1 h1:RY7tHKZcRlk788d5WSo/e83gOyyy742E8GSs771ySpg=
github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
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/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
@@ -333,17 +512,20 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/websocket v1.2.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=
github.com/gosnmp/gosnmp v1.35.0 h1:EuWWNPxTCdAUx2/NbQcSa3WdNxjzpy4Phv57b4MWpJM=
github.com/gosnmp/gosnmp v1.35.0/go.mod h1:2AvKZ3n9aEl5TJEo/fFmf/FGO4Nj4cVeEc5yuk88CYc=
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-getter v1.6.2 h1:7jX7xcB+uVCliddZgeKyNxv0xoT7qL5KDtH7rU4IqIk=
github.com/hashicorp/go-getter v1.6.2/go.mod h1:IZCrswsZPeWv9IkVnLElzRU/gz/QPi6pZHn4tv6vbwA=
github.com/hashicorp/go-getter v1.7.0 h1:bzrYP+qu/gMrL1au7/aDvkoOVGUJpeKBgbqRHACAFDY=
github.com/hashicorp/go-getter v1.7.0/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
@@ -354,7 +536,6 @@ github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhE
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -387,7 +568,6 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/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=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
@@ -405,7 +585,6 @@ github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3t
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg=
@@ -468,11 +647,10 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -532,6 +710,7 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
@@ -540,6 +719,8 @@ github.com/rubenv/sql-migrate v1.1.2 h1:9M6oj4e//owVVHYrFISmY9LBRw6gzkCNmD9MV36t
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
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/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/samber/lo v1.33.0 h1:2aKucr+rQV6gHpY3bpeZu69uYoQOzVhGT3J22Op6Cjk=
github.com/samber/lo v1.33.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
@@ -556,12 +737,13 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs=
github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
github.com/spdx/tools-golang v0.3.0 h1:rtm+DHk3aAt74Fh0Wgucb4pCxjXV8SqHCPEb2iBd30k=
github.com/spdx/tools-golang v0.3.0/go.mod h1:RO4Y3IFROJnz+43JKm1YOrbtgQNljW4gAPpA/sY2eqo=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/afero v1.9.4 h1:Sd43wM1IWz/s1aVXdOBkjJvuP8UdyqioeE4AmM0QsBs=
github.com/spf13/afero v1.9.4/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
@@ -590,25 +772,25 @@ github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
github.com/vulsio/go-cti v0.0.2-0.20220613013115-8c7e57a6aa86 h1:/Xie1YmCGo+SMpOP5xhZ7bzRBTvTu6zGZlCv1cahE8E=
github.com/vulsio/go-cti v0.0.2-0.20220613013115-8c7e57a6aa86/go.mod h1:EBt6G1VZylPciq3CHKmBIth6nDbcPOU59lqOily2aZM=
github.com/vulsio/go-cve-dictionary v0.8.2 h1:abj5449xjuHVRPIeNS41TE+MDMZmw+nbjxm3QZbL4Ks=
github.com/vulsio/go-cve-dictionary v0.8.2/go.mod h1:GOeHvUi9MaPJgNgnYXry73lnypShLett5yfpw00IJrg=
github.com/vulsio/go-cti v0.0.2 h1:EL11fvKgeQxuwlLDrN5szafH364B2VWGuRSoATT/KaU=
github.com/vulsio/go-cti v0.0.2/go.mod h1:oICScdF/y+skYH6yORuwSaSYCuIYy30SZRiK+kUUm8k=
github.com/vulsio/go-cve-dictionary v0.8.3 h1:76meG1GJrXqUdI0HeliUBsdGuMm55XNEPnkPDdQdqyE=
github.com/vulsio/go-cve-dictionary v0.8.3/go.mod h1:aqf+5NVAvmW8iLJImsrWYb7nHetX1dqP0O/8FYfrI4I=
github.com/vulsio/go-exploitdb v0.4.4 h1:h5y6xI4wrpzwo6kmLKU7eb/GryP2kcqgjo8C+VvAFXE=
github.com/vulsio/go-exploitdb v0.4.4/go.mod h1:nUQwEq6AEp62jeHV1Bf2wq080/7qxu+wguDW/lAnLIo=
github.com/vulsio/go-kev v0.1.1-0.20220118062020-5f69b364106f h1:s28XqL35U+N2xkl6bLXPH68IqzmliuqeF37x5pzNLuc=
github.com/vulsio/go-kev v0.1.1-0.20220118062020-5f69b364106f/go.mod h1:NrXTTkGG83ZYl7ypHHLqqzx6HvVkWH37qCizU5UoCS8=
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14 h1:2uYZw2gQ0kymwerTS1FXZbNgptnlye+SB7o3QlLDIBo=
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14/go.mod h1:NGdcwWxCK/ES8vZ/crzREqI69S5gH1MivCpSp1pa2Rc=
github.com/vulsio/gost v0.4.2-0.20230203045609-dcfab39a9ff4 h1:aitlGPmn5WPb9aR6MFsikt+/EaxJtMNttaeayXsDxs0=
github.com/vulsio/gost v0.4.2-0.20230203045609-dcfab39a9ff4/go.mod h1:6xRvzXkpm8nJ/jMmL/TJZvabfVZyy2aB1nr4wtmJ1KI=
github.com/vulsio/goval-dictionary v0.8.0 h1:hwxIwSEo7C3yPGOcrzr5jyKhBnxEidtUVNPIlbrBg+8=
github.com/vulsio/goval-dictionary v0.8.0/go.mod h1:6gfsQfQN0jkO3ZNJlHP5r+2iyx375CBiMBdCcL8MmwM=
github.com/vulsio/go-kev v0.1.1 h1:Xi0FjUj2czQpnurfbXxSrJFbaePolbTrM+gfYxsvj2o=
github.com/vulsio/go-kev v0.1.1/go.mod h1:3CiN3/Ojlodj9ACt2SAhAk5L36m27czTKDfSEf8U8Qg=
github.com/vulsio/go-msfdb v0.2.1 h1:s3Czz+WdgtaXjHRy+1fUzSdEjZGXie354IvT+9syAY0=
github.com/vulsio/go-msfdb v0.2.1/go.mod h1:8A7AyeSqZtFxfd5bljiB1/z2hvkFPe3/jpRtV/mqGbo=
github.com/vulsio/gost v0.4.2 h1:WtjSeTkvvmJdhn6Dv2Ew934MC4dGmojjC6cu7Q9sHhA=
github.com/vulsio/gost v0.4.2/go.mod h1:PxCHzwylur7/EiP7Jo6UPRYkipi76EhA015FOTjKol0=
github.com/vulsio/goval-dictionary v0.8.2 h1:6aI10z/RFZjADzP4fvf7I1zGqbY3EfAsF0I1VOh/ep0=
github.com/vulsio/goval-dictionary v0.8.2/go.mod h1:yRO+Xuce12lSQiV6gdMb86uc8V5Vncgzc6U84WvB/5k=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
@@ -633,8 +815,10 @@ 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.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
@@ -682,6 +866,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
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=
@@ -696,7 +881,6 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -728,10 +912,24 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/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/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
@@ -745,6 +943,21 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -758,7 +971,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -797,17 +1012,40 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -824,6 +1062,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
@@ -832,7 +1071,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -880,6 +1120,10 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
@@ -888,6 +1132,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@@ -909,6 +1156,35 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
google.golang.org/api v0.107.0 h1:I2SlFjD8ZWabaIFOfeEDg3pf0BHJDh6iYQ1ic3Yu/UU=
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -942,6 +1218,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
@@ -954,7 +1231,73 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY=
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -970,11 +1313,31 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk=
google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -987,6 +1350,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -4,17 +4,23 @@
package gost
import (
"encoding/json"
"fmt"
"regexp"
"net/http"
"strconv"
"strings"
"time"
"github.com/cenkalti/backoff"
"github.com/hashicorp/go-version"
"github.com/parnurzeal/gorequest"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/vulsio/gost/models"
)
@@ -23,123 +29,256 @@ type Microsoft struct {
Base
}
var kbIDPattern = regexp.MustCompile(`KB(\d{6,7})`)
// DetectCVEs fills cve information that has in Gost
func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
if ms.driver == nil {
return 0, nil
var applied, unapplied []string
if r.WindowsKB != nil {
applied = r.WindowsKB.Applied
unapplied = r.WindowsKB.Unapplied
}
if ms.driver == nil {
u, err := util.URLPathJoin(ms.baseURL, "microsoft", "kbs")
if err != nil {
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
var osName string
osName, ok := r.Optional["OSName"].(string)
if !ok {
logging.Log.Warnf("This Windows has wrong type option(OSName). UUID: %s", r.ServerUUID)
content := map[string]interface{}{"applied": applied, "unapplied": unapplied}
var body []byte
var errs []error
var resp *http.Response
f := func() error {
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Post(u).SendStruct(content).Type("json").EndBytes()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs)
}
return nil
}
notify := func(err error, t time.Duration) {
logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err)
}
if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil {
return 0, xerrors.Errorf("HTTP Error: %w", err)
}
var r struct {
Applied []string `json:"applied"`
Unapplied []string `json:"unapplied"`
}
if err := json.Unmarshal(body, &r); err != nil {
return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
}
applied = r.Applied
unapplied = r.Unapplied
} else {
applied, unapplied, err = ms.driver.GetExpandKB(applied, unapplied)
if err != nil {
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
}
}
var products []string
if _, ok := r.Optional["InstalledProducts"]; ok {
switch ps := r.Optional["InstalledProducts"].(type) {
case []interface{}:
for _, p := range ps {
pname, ok := p.(string)
if !ok {
logging.Log.Warnf("skip products: %v", p)
continue
}
products = append(products, pname)
}
case []string:
for _, p := range ps {
products = append(products, p)
}
case nil:
logging.Log.Warnf("This Windows has no option(InstalledProducts). UUID: %s", r.ServerUUID)
}
}
applied, unapplied := map[string]struct{}{}, map[string]struct{}{}
if _, ok := r.Optional["KBID"]; ok {
switch kbIDs := r.Optional["KBID"].(type) {
case []interface{}:
for _, kbID := range kbIDs {
s, ok := kbID.(string)
if !ok {
logging.Log.Warnf("skip KBID: %v", kbID)
continue
}
unapplied[strings.TrimPrefix(s, "KB")] = struct{}{}
}
case []string:
for _, kbID := range kbIDs {
unapplied[strings.TrimPrefix(kbID, "KB")] = struct{}{}
}
case nil:
logging.Log.Warnf("This Windows has no option(KBID). UUID: %s", r.ServerUUID)
if ms.driver == nil {
u, err := util.URLPathJoin(ms.baseURL, "microsoft", "products")
if err != nil {
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
for _, pkg := range r.Packages {
matches := kbIDPattern.FindAllStringSubmatch(pkg.Name, -1)
for _, match := range matches {
applied[match[1]] = struct{}{}
content := map[string]interface{}{"release": r.Release, "kbs": append(applied, unapplied...)}
var body []byte
var errs []error
var resp *http.Response
f := func() error {
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Post(u).SendStruct(content).Type("json").EndBytes()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs)
}
return nil
}
notify := func(err error, t time.Duration) {
logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err)
}
if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil {
return 0, xerrors.Errorf("HTTP Error: %w", err)
}
if err := json.Unmarshal(body, &products); err != nil {
return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
}
} else {
switch kbIDs := r.Optional["AppliedKBID"].(type) {
case []interface{}:
for _, kbID := range kbIDs {
s, ok := kbID.(string)
if !ok {
logging.Log.Warnf("skip KBID: %v", kbID)
continue
}
applied[strings.TrimPrefix(s, "KB")] = struct{}{}
}
case []string:
for _, kbID := range kbIDs {
applied[strings.TrimPrefix(kbID, "KB")] = struct{}{}
}
case nil:
logging.Log.Warnf("This Windows has no option(AppliedKBID). UUID: %s", r.ServerUUID)
}
switch kbIDs := r.Optional["UnappliedKBID"].(type) {
case []interface{}:
for _, kbID := range kbIDs {
s, ok := kbID.(string)
if !ok {
logging.Log.Warnf("skip KBID: %v", kbID)
continue
}
unapplied[strings.TrimPrefix(s, "KB")] = struct{}{}
}
case []string:
for _, kbID := range kbIDs {
unapplied[strings.TrimPrefix(kbID, "KB")] = struct{}{}
}
case nil:
logging.Log.Warnf("This Windows has no option(UnappliedKBID). UUID: %s", r.ServerUUID)
ps, err := ms.driver.GetRelatedProducts(r.Release, append(applied, unapplied...))
if err != nil {
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
}
products = ps
}
logging.Log.Debugf(`GetCvesByMicrosoftKBID query body {"osName": %s, "installedProducts": %q, "applied": %q, "unapplied: %q"}`, osName, products, maps.Keys(applied), maps.Keys(unapplied))
cves, err := ms.driver.GetCvesByMicrosoftKBID(osName, products, maps.Keys(applied), maps.Keys(unapplied))
if err != nil {
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
m := map[string]struct{}{}
for _, p := range products {
m[p] = struct{}{}
}
for _, n := range []string{"Microsoft Edge (Chromium-based)", fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (Chromium-based) in IE Mode on %s", r.Release), fmt.Sprintf("Microsoft Edge (EdgeHTML-based) on %s", r.Release)} {
delete(m, n)
}
filtered := []string{r.Release}
for _, p := range r.Packages {
switch p.Name {
case "Microsoft Edge":
if ss := strings.Split(p.Version, "."); len(ss) > 0 {
v, err := strconv.ParseInt(ss[0], 10, 8)
if err != nil {
continue
}
if v > 44 {
filtered = append(filtered, "Microsoft Edge (Chromium-based)", fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (Chromium-based) in IE Mode on %s", r.Release))
} else {
filtered = append(filtered, fmt.Sprintf("Microsoft Edge on %s", r.Release), fmt.Sprintf("Microsoft Edge (EdgeHTML-based) on %s", r.Release))
}
}
default:
}
}
filtered = unique(append(filtered, maps.Keys(m)...))
var cves map[string]gostmodels.MicrosoftCVE
if ms.driver == nil {
u, err := util.URLPathJoin(ms.baseURL, "microsoft", "filtered-cves")
if err != nil {
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
content := map[string]interface{}{"products": filtered, "kbs": append(applied, unapplied...)}
var body []byte
var errs []error
var resp *http.Response
f := func() error {
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Post(u).SendStruct(content).Type("json").EndBytes()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", u, resp, errs)
}
return nil
}
notify := func(err error, t time.Duration) {
logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err)
}
if err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify); err != nil {
return 0, xerrors.Errorf("HTTP Error: %w", err)
}
if err := json.Unmarshal(body, &cves); err != nil {
return 0, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
}
} else {
cves, err = ms.driver.GetFilteredCvesMicrosoft(filtered, append(applied, unapplied...))
if err != nil {
return 0, xerrors.Errorf("Failed to detect CVEs. err: %w", err)
}
}
for cveID, cve := range cves {
var ps []gostmodels.MicrosoftProduct
for _, p := range cve.Products {
if len(p.KBs) == 0 {
ps = append(ps, p)
continue
}
var kbs []gostmodels.MicrosoftKB
for _, kb := range p.KBs {
if _, err := strconv.Atoi(kb.Article); err != nil {
switch {
case strings.HasPrefix(p.Name, "Microsoft Edge"):
p, ok := r.Packages["Microsoft Edge"]
if !ok {
break
}
if kb.FixedBuild == "" {
kbs = append(kbs, kb)
break
}
vera, err := version.NewVersion(p.Version)
if err != nil {
kbs = append(kbs, kb)
break
}
verb, err := version.NewVersion(kb.FixedBuild)
if err != nil {
kbs = append(kbs, kb)
break
}
if vera.LessThan(verb) {
kbs = append(kbs, kb)
}
}
} else {
if slices.Contains(applied, kb.Article) {
kbs = []gostmodels.MicrosoftKB{}
break
}
if slices.Contains(unapplied, kb.Article) {
kbs = append(kbs, kb)
}
}
}
if len(kbs) > 0 {
p.KBs = kbs
ps = append(ps, p)
}
}
cve.Products = ps
if len(cve.Products) == 0 {
continue
}
nCVEs++
cveCont, mitigations := ms.ConvertToModel(&cve)
uniqKB := map[string]struct{}{}
var stats models.PackageFixStatuses
for _, p := range cve.Products {
for _, kb := range p.KBs {
if _, err := strconv.Atoi(kb.Article); err == nil {
uniqKB[fmt.Sprintf("KB%s", kb.Article)] = struct{}{}
if _, err := strconv.Atoi(kb.Article); err != nil {
switch {
case strings.HasPrefix(p.Name, "Microsoft Edge"):
s := models.PackageFixStatus{
Name: "Microsoft Edge",
FixState: "fixed",
FixedIn: kb.FixedBuild,
}
if kb.FixedBuild == "" {
s.FixState = "unknown"
}
stats = append(stats, s)
default:
stats = append(stats, models.PackageFixStatus{
Name: p.Name,
FixState: "unknown",
FixedIn: kb.FixedBuild,
})
}
} else {
uniqKB[kb.Article] = struct{}{}
uniqKB[fmt.Sprintf("KB%s", kb.Article)] = struct{}{}
}
}
}
if len(uniqKB) == 0 && len(stats) == 0 {
for _, p := range cve.Products {
switch {
case strings.HasPrefix(p.Name, "Microsoft Edge"):
stats = append(stats, models.PackageFixStatus{
Name: "Microsoft Edge",
FixState: "unknown",
})
default:
stats = append(stats, models.PackageFixStatus{
Name: p.Name,
FixState: "unknown",
})
}
}
}
advisories := []models.DistroAdvisory{}
for kb := range uniqKB {
advisories = append(advisories, models.DistroAdvisory{
@@ -149,14 +288,16 @@ func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err err
}
r.ScannedCves[cveID] = models.VulnInfo{
CveID: cveID,
Confidences: models.Confidences{models.WindowsUpdateSearch},
DistroAdvisories: advisories,
CveContents: models.NewCveContents(*cveCont),
Mitigations: mitigations,
CveID: cveID,
Confidences: models.Confidences{models.WindowsUpdateSearch},
DistroAdvisories: advisories,
CveContents: models.NewCveContents(*cveCont),
Mitigations: mitigations,
AffectedPackages: stats,
WindowsKBFixedIns: maps.Keys(uniqKB),
}
}
return len(cves), nil
return nCVEs, nil
}
// ConvertToModel converts gost model to vuls model

View File

@@ -10,6 +10,7 @@ import (
"github.com/cenkalti/backoff"
"github.com/parnurzeal/gorequest"
"golang.org/x/exp/maps"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/logging"
@@ -189,3 +190,11 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
func major(osVer string) (majorVersion string) {
return strings.Split(osVer, ".")[0]
}
func unique[T comparable](s []T) []T {
m := map[T]struct{}{}
for _, v := range s {
m[v] = struct{}{}
}
return maps.Keys(m)
}

View File

@@ -53,6 +53,7 @@ type ScanResult struct {
WordPressPackages WordPressPackages `json:",omitempty"`
GitHubManifests DependencyGraphManifests `json:"gitHubManifests,omitempty"`
LibraryScanners LibraryScanners `json:"libraries,omitempty"`
WindowsKB *WindowsKB `json:"windowsKB,omitempty"`
CweDict CweDict `json:"cweDict,omitempty"`
Optional map[string]interface{} `json:",omitempty"`
Config struct {
@@ -83,6 +84,12 @@ type Kernel struct {
RebootRequired bool `json:"rebootRequired"`
}
// WindowsKB has applied and unapplied KBs
type WindowsKB struct {
Applied []string `json:"applied,omitempty"`
Unapplied []string `json:"unapplied,omitempty"`
}
// FilterInactiveWordPressLibs is filter function.
func (r *ScanResult) FilterInactiveWordPressLibs(detectInactive bool) {
if detectInactive {

View File

@@ -267,6 +267,7 @@ type VulnInfo struct {
GitHubSecurityAlerts GitHubSecurityAlerts `json:"gitHubSecurityAlerts,omitempty"`
WpPackageFixStats WpPackageFixStats `json:"wpPackageFixStats,omitempty"`
LibraryFixedIns LibraryFixedIns `json:"libraryFixedIns,omitempty"`
WindowsKBFixedIns []string `json:"windowsKBFixedIns,omitempty"`
VulnType string `json:"vulnType,omitempty"`
DiffStatus DiffStatus `json:"diffStatus,omitempty"`
}
@@ -531,7 +532,7 @@ func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) {
// Cvss3Scores returns CVSS V3 Score
func (v VulnInfo) Cvss3Scores() (values []CveContentCvss) {
order := []CveContentType{RedHatAPI, RedHat, SUSE, Nvd, Jvn}
order := []CveContentType{RedHatAPI, RedHat, SUSE, Microsoft, Nvd, Jvn}
for _, ctype := range order {
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
@@ -661,6 +662,7 @@ func (v VulnInfo) PatchStatus(packs Packages) string {
if len(v.CpeURIs) != 0 {
return ""
}
for _, p := range v.AffectedPackages {
if p.NotFixedYet {
return "unfixed"
@@ -680,6 +682,13 @@ func (v VulnInfo) PatchStatus(packs Packages) string {
}
}
}
for _, c := range v.Confidences {
if c == WindowsUpdateSearch && len(v.WindowsKBFixedIns) == 0 {
return "unfixed"
}
}
return "fixed"
}

View File

@@ -1717,3 +1717,103 @@ func TestVulnInfos_FilterByConfidenceOver(t *testing.T) {
})
}
}
func TestVulnInfo_PatchStatus(t *testing.T) {
type fields struct {
Confidences Confidences
AffectedPackages PackageFixStatuses
CpeURIs []string
WindowsKBFixedIns []string
}
type args struct {
packs Packages
}
tests := []struct {
name string
fields fields
args args
want string
}{
{
name: "cpe",
fields: fields{
CpeURIs: []string{"cpe:/a:microsoft:internet_explorer:10"},
},
want: "",
},
{
name: "package unfixed",
fields: fields{
AffectedPackages: PackageFixStatuses{
{
Name: "bash",
NotFixedYet: true,
},
},
},
want: "unfixed",
},
{
name: "package unknown",
fields: fields{
AffectedPackages: PackageFixStatuses{
{
Name: "bash",
},
},
},
args: args{
packs: Packages{"bash": {
Name: "bash",
}},
},
want: "unknown",
},
{
name: "package fixed",
fields: fields{
AffectedPackages: PackageFixStatuses{
{
Name: "bash",
},
},
},
args: args{
packs: Packages{"bash": {
Name: "bash",
Version: "4.3-9.1",
NewVersion: "5.0-4",
}},
},
want: "fixed",
},
{
name: "windows unfixed",
fields: fields{
Confidences: Confidences{WindowsUpdateSearch},
},
want: "unfixed",
},
{
name: "windows fixed",
fields: fields{
Confidences: Confidences{WindowsUpdateSearch},
WindowsKBFixedIns: []string{"000000"},
},
want: "fixed",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := VulnInfo{
Confidences: tt.fields.Confidences,
AffectedPackages: tt.fields.AffectedPackages,
CpeURIs: tt.fields.CpeURIs,
WindowsKBFixedIns: tt.fields.WindowsKBFixedIns,
}
if got := v.PatchStatus(tt.args.packs); got != tt.want {
t.Errorf("VulnInfo.PatchStatus() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,3 +1,5 @@
//go:build !windows
package reporter
import (

View File

@@ -10,7 +10,6 @@ import (
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"strings"
"time"
@@ -81,24 +80,23 @@ func loadOneServerScanResult(jsonFile string) (*models.ScanResult, error) {
return result, nil
}
// jsonDirPattern is file name pattern of JSON directory
// 2016-11-16T10:43:28+09:00
// 2016-11-16T10:43:28Z
var jsonDirPattern = regexp.MustCompile(
`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2})$`)
// ListValidJSONDirs returns valid json directory as array
// Returned array is sorted so that recent directories are at the head
func ListValidJSONDirs(resultsDir string) (dirs []string, err error) {
var dirInfo []fs.DirEntry
if dirInfo, err = os.ReadDir(resultsDir); err != nil {
err = xerrors.Errorf("Failed to read %s: %w", resultsDir, err)
return
dirInfo, err := os.ReadDir(resultsDir)
if err != nil {
return nil, xerrors.Errorf("Failed to read %s: %w", resultsDir, err)
}
for _, d := range dirInfo {
if d.IsDir() && jsonDirPattern.MatchString(d.Name()) {
jsonDir := filepath.Join(resultsDir, d.Name())
dirs = append(dirs, jsonDir)
if !d.IsDir() {
continue
}
for _, layout := range []string{"2006-01-02T15:04:05Z", "2006-01-02T15:04:05-07:00", "2006-01-02T15-04-05-0700"} {
if _, err := time.Parse(layout, d.Name()); err == nil {
dirs = append(dirs, filepath.Join(resultsDir, d.Name()))
break
}
}
}
sort.Slice(dirs, func(i, j int) bool {
@@ -258,9 +256,13 @@ No CVE-IDs are found in updatable packages.
// v2max := vinfo.MaxCvss2Score().Value.Score
// v3max := vinfo.MaxCvss3Score().Value.Score
packnames := strings.Join(vinfo.AffectedPackages.Names(), ", ")
// packname := vinfo.AffectedPackages.FormatTuiSummary()
// packname += strings.Join(vinfo.CpeURIs, ", ")
pkgNames := vinfo.AffectedPackages.Names()
pkgNames = append(pkgNames, vinfo.CpeURIs...)
pkgNames = append(pkgNames, vinfo.GitHubSecurityAlerts.Names()...)
pkgNames = append(pkgNames, vinfo.WpPackageFixStats.Names()...)
pkgNames = append(pkgNames, vinfo.LibraryFixedIns.Names()...)
pkgNames = append(pkgNames, vinfo.WindowsKBFixedIns...)
packnames := strings.Join(pkgNames, ", ")
exploits := ""
if 0 < len(vinfo.Exploits) || 0 < len(vinfo.Metasploits) {
@@ -431,6 +433,10 @@ No CVE-IDs are found in updatable packages.
}
}
if len(vuln.WindowsKBFixedIns) > 0 {
data = append(data, []string{"Windows KB", fmt.Sprintf("FixedIn: %s", strings.Join(vuln.WindowsKBFixedIns, ", "))})
}
for _, confidence := range vuln.Confidences {
data = append(data, []string{"Confidence", confidence.String()})
}

View File

@@ -60,6 +60,7 @@ type base struct {
osPackages
LibraryScanners []models.LibraryScanner
WordPress models.WordPressPackages
windowsKB *models.WindowsKB
log logging.Logger
errs []error
@@ -506,6 +507,7 @@ func (l *base) convertToModel() models.ScanResult {
EnabledDnfModules: l.EnabledDnfModules,
WordPressPackages: l.WordPress,
LibraryScanners: l.LibraryScanners,
WindowsKB: l.windowsKB,
Optional: l.ServerInfo.Optional,
Errors: errs,
Warnings: warns,
@@ -815,20 +817,48 @@ func (d *DummyFileInfo) IsDir() bool { return false }
// Sys is
func (d *DummyFileInfo) Sys() interface{} { return nil }
func (l *base) buildWpCliCmd(wpCliArgs string, suppressStderr bool, shell string) string {
cmd := fmt.Sprintf("%s %s --path=%s", l.ServerInfo.WordPress.CmdPath, wpCliArgs, l.ServerInfo.WordPress.DocRoot)
if !l.ServerInfo.WordPress.NoSudo {
cmd = fmt.Sprintf("sudo -u %s -i -- %s --allow-root", l.ServerInfo.WordPress.OSUser, cmd)
} else if l.ServerInfo.User != l.ServerInfo.WordPress.OSUser {
cmd = fmt.Sprintf("su %s -c '%s'", l.ServerInfo.WordPress.OSUser, cmd)
}
if suppressStderr {
switch shell {
case "csh", "tcsh":
cmd = fmt.Sprintf("( %s > /dev/tty ) >& /dev/null", cmd)
default:
cmd = fmt.Sprintf("%s 2>/dev/null", cmd)
}
}
return cmd
}
func (l *base) scanWordPress() error {
if l.ServerInfo.WordPress.IsZero() || l.ServerInfo.Type == constant.ServerTypePseudo {
return nil
}
shell, err := l.detectShell()
if err != nil {
return xerrors.Errorf("Failed to detect shell. err: %w", err)
}
l.log.Info("Scanning WordPress...")
cmd := fmt.Sprintf("sudo -u %s -i -- %s core version --path=%s --allow-root",
l.ServerInfo.WordPress.OSUser,
l.ServerInfo.WordPress.CmdPath,
l.ServerInfo.WordPress.DocRoot)
if l.ServerInfo.WordPress.NoSudo && l.ServerInfo.User != l.ServerInfo.WordPress.OSUser {
if r := l.exec(fmt.Sprintf("timeout 2 su %s -c exit", l.ServerInfo.WordPress.OSUser), noSudo); !r.isSuccess() {
return xerrors.New("Failed to switch user without password. err: please configure to switch users without password")
}
}
cmd := l.buildWpCliCmd("core version", false, shell)
if r := exec(l.ServerInfo, cmd, noSudo); !r.isSuccess() {
return xerrors.Errorf("Failed to exec `%s`. Check the OS user, command path of wp-cli, DocRoot and permission: %#v", cmd, l.ServerInfo.WordPress)
}
wp, err := l.detectWordPress()
wp, err := l.detectWordPress(shell)
if err != nil {
return xerrors.Errorf("Failed to scan wordpress: %w", err)
}
@@ -836,18 +866,44 @@ func (l *base) scanWordPress() error {
return nil
}
func (l *base) detectWordPress() (*models.WordPressPackages, error) {
ver, err := l.detectWpCore()
func (l *base) detectShell() (string, error) {
if r := l.exec("printenv SHELL", noSudo); r.isSuccess() {
if t := strings.TrimSpace(r.Stdout); t != "" {
return filepath.Base(t), nil
}
}
if r := l.exec(fmt.Sprintf(`grep "^%s" /etc/passwd | awk -F: '/%s/ { print $7 }'`, l.ServerInfo.User, l.ServerInfo.User), noSudo); r.isSuccess() {
if t := strings.TrimSpace(r.Stdout); t != "" {
return filepath.Base(t), nil
}
}
if isLocalExec(l.ServerInfo.Port, l.ServerInfo.Host) {
if r := l.exec("ps -p $$ | tail +2 | awk '{print $NF}'", noSudo); r.isSuccess() {
return strings.TrimSpace(r.Stdout), nil
}
if r := l.exec("ps -p %self | tail +2 | awk '{print $NF}'", noSudo); r.isSuccess() {
return strings.TrimSpace(r.Stdout), nil
}
}
return "", xerrors.New("shell cannot be determined")
}
func (l *base) detectWordPress(shell string) (*models.WordPressPackages, error) {
ver, err := l.detectWpCore(shell)
if err != nil {
return nil, err
}
themes, err := l.detectWpThemes()
themes, err := l.detectWpThemes(shell)
if err != nil {
return nil, err
}
plugins, err := l.detectWpPlugins()
plugins, err := l.detectWpPlugins(shell)
if err != nil {
return nil, err
}
@@ -864,11 +920,8 @@ func (l *base) detectWordPress() (*models.WordPressPackages, error) {
return &pkgs, nil
}
func (l *base) detectWpCore() (string, error) {
cmd := fmt.Sprintf("sudo -u %s -i -- %s core version --path=%s --allow-root 2>/dev/null",
l.ServerInfo.WordPress.OSUser,
l.ServerInfo.WordPress.CmdPath,
l.ServerInfo.WordPress.DocRoot)
func (l *base) detectWpCore(shell string) (string, error) {
cmd := l.buildWpCliCmd("core version", true, shell)
r := exec(l.ServerInfo, cmd, noSudo)
if !r.isSuccess() {
@@ -877,11 +930,8 @@ func (l *base) detectWpCore() (string, error) {
return strings.TrimSpace(r.Stdout), nil
}
func (l *base) detectWpThemes() ([]models.WpPackage, error) {
cmd := fmt.Sprintf("sudo -u %s -i -- %s theme list --path=%s --format=json --allow-root 2>/dev/null",
l.ServerInfo.WordPress.OSUser,
l.ServerInfo.WordPress.CmdPath,
l.ServerInfo.WordPress.DocRoot)
func (l *base) detectWpThemes(shell string) ([]models.WpPackage, error) {
cmd := l.buildWpCliCmd("theme list --format=json", true, shell)
var themes []models.WpPackage
r := exec(l.ServerInfo, cmd, noSudo)
@@ -898,11 +948,8 @@ func (l *base) detectWpThemes() ([]models.WpPackage, error) {
return themes, nil
}
func (l *base) detectWpPlugins() ([]models.WpPackage, error) {
cmd := fmt.Sprintf("sudo -u %s -i -- %s plugin list --path=%s --format=json --allow-root 2>/dev/null",
l.ServerInfo.WordPress.OSUser,
l.ServerInfo.WordPress.CmdPath,
l.ServerInfo.WordPress.DocRoot)
func (l *base) detectWpPlugins(shell string) ([]models.WpPackage, error) {
cmd := l.buildWpCliCmd("plugin list --format=json", true, shell)
var plugins []models.WpPackage
r := exec(l.ServerInfo, cmd, noSudo)

View File

@@ -42,16 +42,10 @@ func newDebian(c config.ServerInfo) *debian {
// Ubuntu, Debian, Raspbian
// https://github.com/serverspec/specinfra/blob/master/lib/specinfra/helper/detect_os/debian.rb
func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
func detectDebian(c config.ServerInfo) (bool, osTypeInterface) {
if r := exec(c, "ls /etc/debian_version", noSudo); !r.isSuccess() {
if r.Error != nil {
return false, nil, nil
}
if r.ExitStatus == 255 {
return false, &unknown{base{ServerInfo: c}}, xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings.\n%s", r)
}
logging.Log.Debugf("Not Debian like Linux. %s", r)
return false, nil, nil
return false, nil
}
// Raspbian
@@ -64,7 +58,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
if len(result) > 2 && result[0] == constant.Raspbian {
deb := newDebian(c)
deb.setDistro(strings.ToLower(trim(result[0])), trim(result[2]))
return true, deb, nil
return true, deb
}
}
@@ -84,7 +78,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
distro := strings.ToLower(trim(result[1]))
deb.setDistro(distro, trim(result[2]))
}
return true, deb, nil
return true, deb
}
if r := exec(c, "cat /etc/lsb-release", noSudo); r.isSuccess() {
@@ -104,7 +98,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
distro := strings.ToLower(trim(result[1]))
deb.setDistro(distro, trim(result[2]))
}
return true, deb, nil
return true, deb
}
// Debian
@@ -112,11 +106,11 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
if r := exec(c, cmd, noSudo); r.isSuccess() {
deb := newDebian(c)
deb.setDistro(constant.Debian, trim(r.Stdout))
return true, deb, nil
return true, deb
}
logging.Log.Debugf("Not Debian like Linux: %s", c.ServerName)
return false, nil, nil
return false, nil
}
func trim(str string) string {

View File

@@ -3,17 +3,24 @@ package scanner
import (
"bytes"
"fmt"
"io"
ex "os/exec"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
homedir "github.com/mitchellh/go-homedir"
"github.com/saintfish/chardet"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
homedir "github.com/mitchellh/go-homedir"
)
type execResult struct {
@@ -152,15 +159,14 @@ func localExec(c config.ServerInfo, cmdstr string, sudo bool) (result execResult
cmdstr = decorateCmd(c, cmdstr, sudo)
var cmd *ex.Cmd
switch c.Distro.Family {
// case conf.FreeBSD, conf.Alpine, conf.Debian:
// cmd = ex.Command("/bin/sh", "-c", cmdstr)
case constant.Windows:
cmd = ex.Command("powershell.exe", "-NoProfile", "-NonInteractive", cmdstr)
default:
cmd = ex.Command("/bin/sh", "-c", cmdstr)
}
var stdoutBuf, stderrBuf bytes.Buffer
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
if err := cmd.Run(); err != nil {
result.Error = err
if exitError, ok := err.(*ex.ExitError); ok {
@@ -172,42 +178,47 @@ func localExec(c config.ServerInfo, cmdstr string, sudo bool) (result execResult
} else {
result.ExitStatus = 0
}
result.Stdout = stdoutBuf.String()
result.Stderr = stderrBuf.String()
result.Stdout = toUTF8(stdoutBuf.String())
result.Stderr = toUTF8(stderrBuf.String())
result.Cmd = strings.Replace(cmdstr, "\n", "", -1)
return
}
func sshExecExternal(c config.ServerInfo, cmd string, sudo bool) (result execResult) {
func sshExecExternal(c config.ServerInfo, cmdstr string, sudo bool) (result execResult) {
sshBinaryPath, err := ex.LookPath("ssh")
if err != nil {
return execResult{Error: err}
}
if runtime.GOOS == "windows" {
sshBinaryPath = "ssh.exe"
}
args := []string{"-tt"}
var args []string
if c.SSHConfigPath != "" {
args = append(args, "-F", c.SSHConfigPath)
} else {
home, err := homedir.Dir()
if err != nil {
msg := fmt.Sprintf("Failed to get HOME directory: %s", err)
result.Stderr = msg
result.ExitStatus = 997
return
}
controlPath := filepath.Join(home, ".vuls", `controlmaster-%r-`+c.ServerName+`.%p`)
args = append(args,
"-o", "StrictHostKeyChecking=yes",
"-o", "LogLevel=quiet",
"-o", "ConnectionAttempts=3",
"-o", "ConnectTimeout=10",
"-o", "ControlMaster=auto",
"-o", fmt.Sprintf("ControlPath=%s", controlPath),
"-o", "Controlpersist=10m",
)
if runtime.GOOS != "windows" {
home, err := homedir.Dir()
if err != nil {
msg := fmt.Sprintf("Failed to get HOME directory: %s", err)
result.Stderr = msg
result.ExitStatus = 997
return
}
controlPath := filepath.Join(home, ".vuls", `controlmaster-%r-`+c.ServerName+`.%p`)
args = append(args,
"-o", "ControlMaster=auto",
"-o", fmt.Sprintf("ControlPath=%s", controlPath),
"-o", "Controlpersist=10m")
}
}
if config.Conf.Vvv {
@@ -228,16 +239,18 @@ func sshExecExternal(c config.ServerInfo, cmd string, sudo bool) (result execRes
}
args = append(args, c.Host)
cmd = decorateCmd(c, cmd, sudo)
cmd = fmt.Sprintf("stty cols 1000; %s", cmd)
args = append(args, cmd)
execCmd := ex.Command(sshBinaryPath, args...)
cmdstr = decorateCmd(c, cmdstr, sudo)
var cmd *ex.Cmd
switch c.Distro.Family {
case constant.Windows:
cmd = ex.Command(sshBinaryPath, append(args, "powershell.exe", "-NoProfile", "-NonInteractive", fmt.Sprintf(`"%s`, cmdstr))...)
default:
cmd = ex.Command(sshBinaryPath, append(args, fmt.Sprintf("stty cols 1000; %s", cmdstr))...)
}
var stdoutBuf, stderrBuf bytes.Buffer
execCmd.Stdout = &stdoutBuf
execCmd.Stderr = &stderrBuf
if err := execCmd.Run(); err != nil {
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
if err := cmd.Run(); err != nil {
if e, ok := err.(*ex.ExitError); ok {
if s, ok := e.Sys().(syscall.WaitStatus); ok {
result.ExitStatus = s.ExitStatus()
@@ -250,9 +263,8 @@ func sshExecExternal(c config.ServerInfo, cmd string, sudo bool) (result execRes
} else {
result.ExitStatus = 0
}
result.Stdout = stdoutBuf.String()
result.Stderr = stderrBuf.String()
result.Stdout = toUTF8(stdoutBuf.String())
result.Stderr = toUTF8(stderrBuf.String())
result.Servername = c.ServerName
result.Container = c.Container
result.Host = c.Host
@@ -280,7 +292,7 @@ func dockerShell(family string) string {
func decorateCmd(c config.ServerInfo, cmd string, sudo bool) string {
if sudo && c.User != "root" && !c.IsContainer() {
cmd = fmt.Sprintf("sudo -S %s", cmd)
cmd = fmt.Sprintf("sudo %s", cmd)
}
// If you are using pipe and you want to detect preprocessing errors, remove comment out
@@ -306,10 +318,40 @@ func decorateCmd(c config.ServerInfo, cmd string, sudo bool) string {
c.Container.Name, dockerShell(c.Distro.Family), cmd)
// LXC required root privilege
if c.User != "root" {
cmd = fmt.Sprintf("sudo -S %s", cmd)
cmd = fmt.Sprintf("sudo %s", cmd)
}
}
}
// cmd = fmt.Sprintf("set -x; %s", cmd)
return cmd
}
func toUTF8(s string) string {
d := chardet.NewTextDetector()
res, err := d.DetectBest([]byte(s))
if err != nil {
return s
}
var bs []byte
switch res.Charset {
case "UTF-8":
bs, err = []byte(s), nil
case "UTF-16LE":
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder()))
case "UTF-16BE":
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), unicode.UTF16(unicode.BigEndian, unicode.UseBOM).NewDecoder()))
case "Shift_JIS":
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), japanese.ShiftJIS.NewDecoder()))
case "EUC-JP":
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), japanese.EUCJP.NewDecoder()))
case "ISO-2022-JP":
bs, err = io.ReadAll(transform.NewReader(strings.NewReader(s), japanese.ISO2022JP.NewDecoder()))
default:
bs, err = []byte(s), nil
}
if err != nil {
return s
}
return string(bs)
}

View File

@@ -39,14 +39,14 @@ func TestDecorateCmd(t *testing.T) {
conf: config.ServerInfo{User: "non-root"},
cmd: "ls",
sudo: true,
expected: "sudo -S ls",
expected: "sudo ls",
},
// non-root sudo true
{
conf: config.ServerInfo{User: "non-root"},
cmd: "ls | grep hoge",
sudo: true,
expected: "sudo -S ls | grep hoge",
expected: "sudo ls | grep hoge",
},
// -------------docker-------------
// root sudo false docker
@@ -192,7 +192,7 @@ func TestDecorateCmd(t *testing.T) {
},
cmd: "ls",
sudo: false,
expected: `sudo -S lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
expected: `sudo lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
},
// non-root sudo true, lxc
{
@@ -203,7 +203,7 @@ func TestDecorateCmd(t *testing.T) {
},
cmd: "ls",
sudo: true,
expected: `sudo -S lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
expected: `sudo lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls'`,
},
// non-root sudo true lxc
{
@@ -214,7 +214,7 @@ func TestDecorateCmd(t *testing.T) {
},
cmd: "ls | grep hoge",
sudo: true,
expected: `sudo -S lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls | grep hoge'`,
expected: `sudo lxc-attach -n def 2>/dev/null -- /bin/sh -c 'ls | grep hoge'`,
},
}

View File

@@ -6,10 +6,12 @@ import (
"net/http"
"os"
ex "os/exec"
"runtime"
"strings"
"time"
debver "github.com/knqyf263/go-deb-version"
"golang.org/x/exp/maps"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/cache"
@@ -149,64 +151,123 @@ func (s Scanner) Configtest() error {
// ViaHTTP scans servers by HTTP header and body
func ViaHTTP(header http.Header, body string, toLocalFile bool) (models.ScanResult, error) {
family := header.Get("X-Vuls-OS-Family")
if family == "" {
return models.ScanResult{}, errOSFamilyHeader
}
release := header.Get("X-Vuls-OS-Release")
if release == "" {
return models.ScanResult{}, errOSReleaseHeader
}
kernelRelease := header.Get("X-Vuls-Kernel-Release")
if kernelRelease == "" {
logging.Log.Warn("If X-Vuls-Kernel-Release is not specified, there is a possibility of false detection")
}
kernelVersion := header.Get("X-Vuls-Kernel-Version")
if family == constant.Debian {
if kernelVersion == "" {
logging.Log.Warn("X-Vuls-Kernel-Version is empty. skip kernel vulnerability detection.")
} else {
if _, err := debver.NewVersion(kernelVersion); err != nil {
logging.Log.Warnf("X-Vuls-Kernel-Version is invalid. skip kernel vulnerability detection. actual kernelVersion: %s, err: %s", kernelVersion, err)
kernelVersion = ""
}
}
}
serverName := header.Get("X-Vuls-Server-Name")
if toLocalFile && serverName == "" {
return models.ScanResult{}, errServerNameHeader
}
distro := config.Distro{
Family: family,
Release: release,
family := header.Get("X-Vuls-OS-Family")
if family == "" {
return models.ScanResult{}, errOSFamilyHeader
}
kernel := models.Kernel{
Release: kernelRelease,
Version: kernelVersion,
}
installedPackages, srcPackages, err := ParseInstalledPkgs(distro, kernel, body)
if err != nil {
return models.ScanResult{}, err
}
switch family {
case constant.Windows:
osInfo, hotfixs, err := parseSystemInfo(toUTF8(body))
if err != nil {
return models.ScanResult{}, xerrors.Errorf("Failed to parse systeminfo.exe. err: %w", err)
}
return models.ScanResult{
ServerName: serverName,
Family: family,
Release: release,
RunningKernel: models.Kernel{
release := header.Get("X-Vuls-OS-Release")
if release == "" {
logging.Log.Debugf("osInfo(systeminfo.exe): %+v", osInfo)
release, err = detectOSName(osInfo)
if err != nil {
return models.ScanResult{}, xerrors.Errorf("Failed to detect os name. err: %w", err)
}
}
kernelVersion := header.Get("X-Vuls-Kernel-Version")
if kernelVersion == "" {
kernelVersion = formatKernelVersion(osInfo)
}
w := &windows{
base: base{
Distro: config.Distro{Family: family, Release: release},
osPackages: osPackages{
Kernel: models.Kernel{Version: kernelVersion},
},
log: logging.Log,
},
}
kbs, err := w.detectKBsFromKernelVersion()
if err != nil {
return models.ScanResult{}, xerrors.Errorf("Failed to detect KBs from kernel version. err: %w", err)
}
applied, unapplied := map[string]struct{}{}, map[string]struct{}{}
for _, kb := range hotfixs {
applied[kb] = struct{}{}
}
for _, kb := range kbs.Applied {
applied[kb] = struct{}{}
}
for _, kb := range kbs.Unapplied {
unapplied[kb] = struct{}{}
}
return models.ScanResult{
ServerName: serverName,
Family: family,
Release: release,
RunningKernel: models.Kernel{
Version: kernelVersion,
},
WindowsKB: &models.WindowsKB{Applied: maps.Keys(applied), Unapplied: maps.Keys(unapplied)},
ScannedCves: models.VulnInfos{},
}, nil
default:
release := header.Get("X-Vuls-OS-Release")
if release == "" {
return models.ScanResult{}, errOSReleaseHeader
}
kernelRelease := header.Get("X-Vuls-Kernel-Release")
if kernelRelease == "" {
logging.Log.Warn("If X-Vuls-Kernel-Release is not specified, there is a possibility of false detection")
}
kernelVersion := header.Get("X-Vuls-Kernel-Version")
if family == constant.Debian {
if kernelVersion == "" {
logging.Log.Warn("X-Vuls-Kernel-Version is empty. skip kernel vulnerability detection.")
} else {
if _, err := debver.NewVersion(kernelVersion); err != nil {
logging.Log.Warnf("X-Vuls-Kernel-Version is invalid. skip kernel vulnerability detection. actual kernelVersion: %s, err: %s", kernelVersion, err)
kernelVersion = ""
}
}
}
distro := config.Distro{
Family: family,
Release: release,
}
kernel := models.Kernel{
Release: kernelRelease,
Version: kernelVersion,
},
Packages: installedPackages,
SrcPackages: srcPackages,
ScannedCves: models.VulnInfos{},
}, nil
}
installedPackages, srcPackages, err := ParseInstalledPkgs(distro, kernel, body)
if err != nil {
return models.ScanResult{}, err
}
return models.ScanResult{
ServerName: serverName,
Family: family,
Release: release,
RunningKernel: models.Kernel{
Release: kernelRelease,
Version: kernelVersion,
},
Packages: installedPackages,
SrcPackages: srcPackages,
ScannedCves: models.VulnInfos{},
}, nil
}
}
// ParseInstalledPkgs parses installed pkgs line
@@ -342,7 +403,14 @@ func validateSSHConfig(c *config.ServerInfo) error {
logging.Log.Debugf("Validating SSH Settings for Server:%s ...", c.GetServerName())
sshBinaryPath, err := ex.LookPath("ssh")
if runtime.GOOS == "windows" {
c.Distro.Family = constant.Windows
}
defer func(c *config.ServerInfo) {
c.Distro.Family = ""
}(c)
sshBinaryPath, err := lookpath(c.Distro.Family, "ssh")
if err != nil {
return xerrors.Errorf("Failed to lookup ssh binary path. err: %w", err)
}
@@ -351,6 +419,10 @@ func validateSSHConfig(c *config.ServerInfo) error {
logging.Log.Debugf("Executing... %s", strings.Replace(sshConfigCmd, "\n", "", -1))
configResult := localExec(*c, sshConfigCmd, noSudo)
if !configResult.isSuccess() {
if strings.Contains(configResult.Stderr, "unknown option -- G") {
logging.Log.Warn("SSH configuration validation is skipped. To enable validation, G option introduced in OpenSSH 6.8 must be enabled.")
return nil
}
return xerrors.Errorf("Failed to print SSH configuration. err: %w", configResult.Error)
}
sshConfig := parseSSHConfiguration(configResult.Stdout)
@@ -381,7 +453,7 @@ func validateSSHConfig(c *config.ServerInfo) error {
return xerrors.New("Failed to find any known_hosts to use. Please check the UserKnownHostsFile and GlobalKnownHostsFile settings for SSH")
}
sshKeyscanBinaryPath, err := ex.LookPath("ssh-keyscan")
sshKeyscanBinaryPath, err := lookpath(c.Distro.Family, "ssh-keyscan")
if err != nil {
return xerrors.Errorf("Failed to lookup ssh-keyscan binary path. err: %w", err)
}
@@ -392,7 +464,7 @@ func validateSSHConfig(c *config.ServerInfo) error {
}
serverKeys := parseSSHScan(r.Stdout)
sshKeygenBinaryPath, err := ex.LookPath("ssh-keygen")
sshKeygenBinaryPath, err := lookpath(c.Distro.Family, "ssh-keygen")
if err != nil {
return xerrors.Errorf("Failed to lookup ssh-keygen binary path. err: %w", err)
}
@@ -428,6 +500,19 @@ func validateSSHConfig(c *config.ServerInfo) error {
buildSSHKeyScanCmd(sshKeyscanBinaryPath, c.Port, knownHostsPaths[0], sshConfig))
}
func lookpath(family, file string) (string, error) {
switch family {
case constant.Windows:
return fmt.Sprintf("%s.exe", strings.TrimPrefix(file, ".exe")), nil
default:
p, err := ex.LookPath(file)
if err != nil {
return "", err
}
return p, nil
}
}
func buildSSHBaseCmd(sshBinaryPath string, c *config.ServerInfo, options []string) []string {
cmd := []string{sshBinaryPath}
if len(options) > 0 {
@@ -483,6 +568,7 @@ type sshConfiguration struct {
func parseSSHConfiguration(stdout string) sshConfiguration {
sshConfig := sshConfiguration{}
for _, line := range strings.Split(stdout, "\n") {
line = strings.TrimSuffix(line, "\r")
switch {
case strings.HasPrefix(line, "user "):
sshConfig.user = strings.TrimPrefix(line, "user ")
@@ -512,6 +598,7 @@ func parseSSHConfiguration(stdout string) sshConfiguration {
func parseSSHScan(stdout string) map[string]string {
keys := map[string]string{}
for _, line := range strings.Split(stdout, "\n") {
line = strings.TrimSuffix(line, "\r")
if line == "" || strings.HasPrefix(line, "# ") {
continue
}
@@ -524,6 +611,7 @@ func parseSSHScan(stdout string) map[string]string {
func parseSSHKeygen(stdout string) (string, string, error) {
for _, line := range strings.Split(stdout, "\n") {
line = strings.TrimSuffix(line, "\r")
if line == "" || strings.HasPrefix(line, "# ") {
continue
}
@@ -669,10 +757,20 @@ func (s Scanner) detectOS(c config.ServerInfo) osTypeInterface {
return osType
}
if itsMe, osType, fatalErr := s.detectDebianWithRetry(c); fatalErr != nil {
osType.setErrs([]error{xerrors.Errorf("Failed to detect OS: %w", fatalErr)})
if !isLocalExec(c.Port, c.Host) {
if err := testFirstSSHConnection(c); err != nil {
osType := &unknown{base{ServerInfo: c}}
osType.setErrs([]error{xerrors.Errorf("Failed to test first SSH Connection. err: %w", err)})
return osType
}
}
if itsMe, osType := detectWindows(c); itsMe {
logging.Log.Debugf("Windows. Host: %s:%s", c.Host, c.Port)
return osType
} else if itsMe {
}
if itsMe, osType := detectDebian(c); itsMe {
logging.Log.Debugf("Debian based Linux. Host: %s:%s", c.Host, c.Port)
return osType
}
@@ -702,28 +800,23 @@ func (s Scanner) detectOS(c config.ServerInfo) osTypeInterface {
return osType
}
// Retry as it may stall on the first SSH connection
// https://github.com/future-architect/vuls/pull/753
func (s Scanner) detectDebianWithRetry(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err error) {
type Response struct {
itsMe bool
deb osTypeInterface
err error
}
resChan := make(chan Response, 1)
go func(c config.ServerInfo) {
itsMe, osType, fatalErr := detectDebian(c)
resChan <- Response{itsMe, osType, fatalErr}
}(c)
timeout := time.After(time.Duration(3) * time.Second)
select {
case res := <-resChan:
return res.itsMe, res.deb, res.err
case <-timeout:
time.Sleep(100 * time.Millisecond)
return detectDebian(c)
func testFirstSSHConnection(c config.ServerInfo) error {
for i := 3; i > 0; i-- {
rChan := make(chan execResult, 1)
go func() {
rChan <- exec(c, "exit", noSudo)
}()
select {
case r := <-rChan:
if r.ExitStatus == 255 {
return xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings.\n%s", r)
}
return nil
case <-time.After(time.Duration(3) * time.Second):
}
}
logging.Log.Warnf("First SSH Connection to Host: %s:%s timeout", c.Host, c.Port)
return nil
}
// checkScanModes checks scan mode

View File

@@ -5,6 +5,8 @@ import (
"reflect"
"testing"
"golang.org/x/exp/slices"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/models"
@@ -104,6 +106,74 @@ func TestViaHTTP(t *testing.T) {
},
},
},
{
header: map[string]string{
"X-Vuls-OS-Family": "windows",
},
body: `
Host Name: DESKTOP
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.19044 N/A Build 19044
OS Manufacturer: Microsoft Corporation
OS Configuration: Member Workstation
OS Build Type: Multiprocessor Free
Registered Owner: Windows User
Registered Organization:
Product ID: 00000-00000-00000-AA000
Original Install Date: 2022/04/13, 12:25:41
System Boot Time: 2022/06/06, 16:43:45
System Manufacturer: HP
System Model: HP EliteBook 830 G7 Notebook PC
System Type: x64-based PC
Processor(s): 1 Processor(s) Installed.
[01]: Intel64 Family 6 Model 142 Stepping 12 GenuineIntel ~1803 Mhz
BIOS Version: HP S70 Ver. 01.05.00, 2021/04/26
Windows Directory: C:\WINDOWS
System Directory: C:\WINDOWS\system32
Boot Device: \Device\HarddiskVolume2
System Locale: en-us;English (United States)
Input Locale: en-us;English (United States)
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
Total Physical Memory: 15,709 MB
Available Physical Memory: 12,347 MB
Virtual Memory: Max Size: 18,141 MB
Virtual Memory: Available: 14,375 MB
Virtual Memory: In Use: 3,766 MB
Page File Location(s): C:\pagefile.sys
Domain: WORKGROUP
Logon Server: \\DESKTOP
Hotfix(s): 7 Hotfix(s) Installed.
[01]: KB5012117
[02]: KB4562830
[03]: KB5003791
[04]: KB5007401
[05]: KB5012599
[06]: KB5011651
[07]: KB5005699
Network Card(s): 1 NIC(s) Installed.
[01]: Intel(R) Wi-Fi 6 AX201 160MHz
Connection Name: Wi-Fi
DHCP Enabled: Yes
DHCP Server: 192.168.0.1
IP address(es)
[01]: 192.168.0.205
Hyper-V Requirements: VM Monitor Mode Extensions: Yes
Virtualization Enabled In Firmware: Yes
Second Level Address Translation: Yes
Data Execution Prevention Available: Yes
`,
expectedResult: models.ScanResult{
Family: "windows",
Release: "Windows 10 Version 21H2 for x64-based Systems",
RunningKernel: models.Kernel{
Version: "10.0.19044",
},
WindowsKB: &models.WindowsKB{
Applied: []string{"5012117", "4562830", "5003791", "5007401", "5012599", "5011651", "5005699"},
Unapplied: []string{},
},
},
},
}
for _, tt := range tests {
@@ -144,6 +214,18 @@ func TestViaHTTP(t *testing.T) {
t.Errorf("release: expected %s, actual %s", expectedPack.Release, pack.Release)
}
}
if tt.expectedResult.WindowsKB != nil {
slices.Sort(tt.expectedResult.WindowsKB.Applied)
slices.Sort(tt.expectedResult.WindowsKB.Unapplied)
}
if result.WindowsKB != nil {
slices.Sort(result.WindowsKB.Applied)
slices.Sort(result.WindowsKB.Unapplied)
}
if !reflect.DeepEqual(tt.expectedResult.WindowsKB, result.WindowsKB) {
t.Errorf("windows KB: expected %s, actual %s", tt.expectedResult.WindowsKB, result.WindowsKB)
}
}
}

View File

@@ -42,7 +42,7 @@ func isRunningKernel(pack models.Package, family string, kernel models.Kernel) (
// EnsureResultDir ensures the directory for scan results
func EnsureResultDir(resultsDir string, scannedAt time.Time) (currentDir string, err error) {
jsonDirName := scannedAt.Format(time.RFC3339)
jsonDirName := scannedAt.Format("2006-01-02T15-04-05-0700")
if resultsDir == "" {
wd, _ := os.Getwd()
resultsDir = filepath.Join(wd, "results")
@@ -51,19 +51,6 @@ func EnsureResultDir(resultsDir string, scannedAt time.Time) (currentDir string,
if err := os.MkdirAll(jsonDir, 0700); err != nil {
return "", xerrors.Errorf("Failed to create dir: %w", err)
}
symlinkPath := filepath.Join(resultsDir, "current")
if _, err := os.Lstat(symlinkPath); err == nil {
if err := os.Remove(symlinkPath); err != nil {
return "", xerrors.Errorf(
"Failed to remove symlink. path: %s, err: %w", symlinkPath, err)
}
}
if err := os.Symlink(jsonDir, symlinkPath); err != nil {
return "", xerrors.Errorf(
"Failed to create symlink: path: %s, err: %w", symlinkPath, err)
}
return jsonDir, nil
}

4452
scanner/windows.go Normal file

File diff suppressed because it is too large Load Diff

905
scanner/windows_test.go Normal file
View File

@@ -0,0 +1,905 @@
package scanner
import (
"reflect"
"testing"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"golang.org/x/exp/slices"
)
func Test_parseSystemInfo(t *testing.T) {
tests := []struct {
name string
args string
osInfo osInfo
kbs []string
wantErr bool
}{
{
name: "Workstation",
args: `
Host Name: DESKTOP
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.19044 N/A Build 19044
OS Manufacturer: Microsoft Corporation
OS Configuration: Member Workstation
OS Build Type: Multiprocessor Free
Registered Owner: Windows User
Registered Organization:
Product ID: 00000-00000-00000-AA000
Original Install Date: 2022/04/13, 12:25:41
System Boot Time: 2022/06/06, 16:43:45
System Manufacturer: HP
System Model: HP EliteBook 830 G7 Notebook PC
System Type: x64-based PC
Processor(s): 1 Processor(s) Installed.
[01]: Intel64 Family 6 Model 142 Stepping 12 GenuineIntel ~1803 Mhz
BIOS Version: HP S70 Ver. 01.05.00, 2021/04/26
Windows Directory: C:\WINDOWS
System Directory: C:\WINDOWS\system32
Boot Device: \Device\HarddiskVolume2
System Locale: en-us;English (United States)
Input Locale: en-us;English (United States)
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
Total Physical Memory: 15,709 MB
Available Physical Memory: 12,347 MB
Virtual Memory: Max Size: 18,141 MB
Virtual Memory: Available: 14,375 MB
Virtual Memory: In Use: 3,766 MB
Page File Location(s): C:\pagefile.sys
Domain: WORKGROUP
Logon Server: \\DESKTOP
Hotfix(s): 7 Hotfix(s) Installed.
[01]: KB5012117
[02]: KB4562830
[03]: KB5003791
[04]: KB5007401
[05]: KB5012599
[06]: KB5011651
[07]: KB5005699
Network Card(s): 1 NIC(s) Installed.
[01]: Intel(R) Wi-Fi 6 AX201 160MHz
Connection Name: Wi-Fi
DHCP Enabled: Yes
DHCP Server: 192.168.0.1
IP address(es)
[01]: 192.168.0.205
Hyper-V Requirements: VM Monitor Mode Extensions: Yes
Virtualization Enabled In Firmware: Yes
Second Level Address Translation: Yes
Data Execution Prevention Available: Yes
`,
osInfo: osInfo{
productName: "Microsoft Windows 10 Pro",
version: "10.0",
build: "19044",
revision: "",
edition: "",
servicePack: "",
arch: "x64-based",
installationType: "Client",
},
kbs: []string{"5012117", "4562830", "5003791", "5007401", "5012599", "5011651", "5005699"},
},
{
name: "Server",
args: `
Host Name: WIN-RIBN7SM07BK
OS Name: Microsoft Windows Server 2022 Standard
OS Version: 10.0.20348 N/A Build 20348
OS Manufacturer: Microsoft Corporation
OS Configuration: Standalone Server
OS Build Type: Multiprocessor Free
Registered Owner: Windows User
Registered Organization:
Product ID: 00454-10000-00001-AA483
Original Install Date: 10/1/2021, 4:15:34 PM
System Boot Time: 10/22/2021, 8:36:55 AM
System Manufacturer: Microsoft Corporation
System Model: Virtual Machine
System Type: x64-based PC
Processor(s): 1 Processor(s) Installed.
[01]: Intel64 Family 6 Model 158 Stepping 9 GenuineIntel ~2808 Mhz
BIOS Version: Microsoft Corporation Hyper-V UEFI Release v4.0, 12/17/2019
Windows Directory: C:\Windows
System Directory: C:\Windows\system32
Boot Device: \Device\HarddiskVolume1
System Locale: en-us;English (United States)
Input Locale: en-us;English (United States)
Time Zone: (UTC-08:00) Pacific Time (US & Canada)
Total Physical Memory: 2,047 MB
Available Physical Memory: 900 MB
Virtual Memory: Max Size: 3,199 MB
Virtual Memory: Available: 2,143 MB
Virtual Memory: In Use: 1,056 MB
Page File Location(s): C:\pagefile.sys
Domain: WORKGROUP
Logon Server: \\WIN-RIBN7SM07BK
Hotfix(s): 3 Hotfix(s) Installed.
[01]: KB5004330
[02]: KB5005039
[03]: KB5005552
Network Card(s): 1 NIC(s) Installed.
[01]: Microsoft Hyper-V Network Adapter
Connection Name: Ethernet
DHCP Enabled: Yes
DHCP Server: 192.168.254.254
IP address(es)
[01]: 192.168.254.172
[02]: fe80::b4a1:11cc:2c4:4f57
Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.
`,
osInfo: osInfo{
productName: "Microsoft Windows Server 2022 Standard",
version: "10.0",
build: "20348",
revision: "",
edition: "",
servicePack: "",
arch: "x64-based",
installationType: "Server",
},
kbs: []string{"5004330", "5005039", "5005552"},
},
{
name: "Domain Controller",
args: `
Host Name: vuls
OS Name: Microsoft Windows Server 2019 Datacenter
OS Version: 10.0.17763 N/A Build 17763
OS Manufacturer: Microsoft Corporation
OS Configuration: Primary Domain Controller
OS Build Type: Multiprocessor Free
Registered Owner: N/A
Registered Organization: N/A
Product ID: 00430-00000-00000-AA602
Original Install Date: 1/16/2023, 10:04:07 AM
System Boot Time: 3/28/2023, 8:37:14 AM
System Manufacturer: Microsoft Corporation
System Model: Virtual Machine
System Type: x64-based PC
Processor(s): 1 Processor(s) Installed.
[01]: Intel64 Family 6 Model 85 Stepping 4 GenuineIntel ~2095 Mhz
BIOS Version: Microsoft Corporation Hyper-V UEFI Release v4.1, 5/9/2022
Windows Directory: C:\Windows
System Directory: C:\Windows\system32
Boot Device: \Device\HarddiskVolume3
System Locale: en-us;English (United States)
Input Locale: en-us;English (United States)
Time Zone: (UTC) Coordinated Universal Time
Total Physical Memory: 16,383 MB
Available Physical Memory: 13,170 MB
Virtual Memory: Max Size: 18,431 MB
Virtual Memory: Available: 15,208 MB
Virtual Memory: In Use: 3,223 MB
Page File Location(s): C:\pagefile.sys
Domain: vuls
Logon Server: \\vuls
Hotfix(s): 5 Hotfix(s) Installed.
[01]: KB5022511
[02]: KB5012170
[03]: KB5023702
[04]: KB5020374
[05]: KB5023789
Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.
`,
osInfo: osInfo{
productName: "Microsoft Windows Server 2019 Datacenter",
version: "10.0",
build: "17763",
revision: "",
edition: "",
servicePack: "",
arch: "x64-based",
installationType: "Domain Controller",
},
kbs: []string{"5022511", "5012170", "5023702", "5020374", "5023789"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
osInfo, kbs, err := parseSystemInfo(tt.args)
if (err != nil) != tt.wantErr {
t.Errorf("parseSystemInfo() error = %v, wantErr %v", err, tt.wantErr)
return
}
if osInfo != tt.osInfo {
t.Errorf("parseSystemInfo() got = %v, want %v", osInfo, tt.osInfo)
}
if !reflect.DeepEqual(kbs, tt.kbs) {
t.Errorf("parseSystemInfo() got = %v, want %v", kbs, tt.kbs)
}
})
}
}
func Test_parseGetComputerInfo(t *testing.T) {
tests := []struct {
name string
args string
want osInfo
wantErr bool
}{
{
name: "happy",
args: `
WindowsProductName : Windows 10 Pro
OsVersion : 10.0.19044
WindowsEditionId : Professional
OsCSDVersion :
CsSystemType : x64-based PC
WindowsInstallationType : Client
`,
want: osInfo{
productName: "Windows 10 Pro",
version: "10.0",
build: "19044",
revision: "",
edition: "Professional",
servicePack: "",
arch: "x64-based",
installationType: "Client",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseGetComputerInfo(tt.args)
if (err != nil) != tt.wantErr {
t.Errorf("parseGetComputerInfo() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("parseGetComputerInfo() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseWmiObject(t *testing.T) {
tests := []struct {
name string
args string
want osInfo
wantErr bool
}{
{
name: "happy",
args: `
Caption : Microsoft Windows 10 Pro
Version : 10.0.19044
OperatingSystemSKU : 48
CSDVersion :
DomainRole : 1
SystemType : x64-based PC`,
want: osInfo{
productName: "Microsoft Windows 10 Pro",
version: "10.0",
build: "19044",
revision: "",
edition: "Professional",
servicePack: "",
arch: "x64-based",
installationType: "Client",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseWmiObject(tt.args)
if (err != nil) != tt.wantErr {
t.Errorf("parseWmiObject() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("parseWmiObject() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseRegistry(t *testing.T) {
type args struct {
stdout string
arch string
}
tests := []struct {
name string
args args
want osInfo
wantErr bool
}{
{
name: "happy",
args: args{
stdout: `
ProductName : Windows 10 Pro
CurrentVersion : 6.3
CurrentMajorVersionNumber : 10
CurrentMinorVersionNumber : 0
CurrentBuildNumber : 19044
UBR : 2364
EditionID : Professional
InstallationType : Client`,
arch: "AMD64",
},
want: osInfo{
productName: "Windows 10 Pro",
version: "10.0",
build: "19044",
revision: "2364",
edition: "Professional",
servicePack: "",
arch: "x64-based",
installationType: "Client",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseRegistry(tt.args.stdout, tt.args.arch)
if (err != nil) != tt.wantErr {
t.Errorf("parseRegistry() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseRegistry() = %v, want %v", got, tt.want)
}
})
}
}
func Test_detectOSName(t *testing.T) {
tests := []struct {
name string
args osInfo
want string
wantErr bool
}{
{
name: "Windows 10 for x64-based Systems",
args: osInfo{
productName: "Microsoft Windows 10 Pro",
version: "10.0",
build: "10585",
revision: "",
edition: "Professional",
servicePack: "",
arch: "x64-based",
installationType: "Client",
},
want: "Windows 10 for x64-based Systems",
},
{
name: "Windows 10 Version 21H2 for x64-based Systems",
args: osInfo{
productName: "Microsoft Windows 10 Pro",
version: "10.0",
build: "19044",
revision: "",
edition: "Professional",
servicePack: "",
arch: "x64-based",
installationType: "Client",
},
want: "Windows 10 Version 21H2 for x64-based Systems",
},
{
name: "Windows Server 2022",
args: osInfo{
productName: "Windows Server",
version: "10.0",
build: "30000",
revision: "",
edition: "",
servicePack: "",
arch: "x64-based",
installationType: "Server",
},
want: "Windows Server 2022",
},
{
name: "Windows Server 2019",
args: osInfo{
productName: "Microsoft Windows Server 2019 Datacenter",
version: "10.0",
build: "17763",
revision: "",
edition: "",
servicePack: "",
arch: "x64-based",
installationType: "Domain Controller",
},
want: "Windows Server 2019",
},
{
name: "err",
args: osInfo{
productName: "Microsoft Windows 10 Pro",
version: "10.0",
build: "build",
revision: "",
edition: "Professional",
servicePack: "",
arch: "x64-based",
installationType: "Client",
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := detectOSName(tt.args)
if (err != nil) != tt.wantErr {
t.Errorf("detectOSName() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("detectOSName() = %v, want %v", got, tt.want)
}
})
}
}
func Test_formatKernelVersion(t *testing.T) {
tests := []struct {
name string
args osInfo
want string
}{
{
name: "major.minor.build.revision",
args: osInfo{
version: "10.0",
build: "19045",
revision: "2130",
},
want: "10.0.19045.2130",
},
{
name: "major.minor.build",
args: osInfo{
version: "10.0",
build: "19045",
},
want: "10.0.19045",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := formatKernelVersion(tt.args); got != tt.want {
t.Errorf("formatKernelVersion() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseInstalledPackages(t *testing.T) {
type args struct {
stdout string
}
tests := []struct {
name string
args args
want models.Packages
wantErr bool
}{
{
name: "happy",
args: args{
stdout: `
Name : Git
Version : 2.35.1.2
ProviderName : Programs
Name : Oracle Database 11g Express Edition
Version : 11.2.0
ProviderName : msi
Name : 2022-12 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5021233)
Version :
ProviderName : msu
`,
},
want: models.Packages{
"Git": {
Name: "Git",
Version: "2.35.1.2",
},
"Oracle Database 11g Express Edition": {
Name: "Oracle Database 11g Express Edition",
Version: "11.2.0",
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &windows{}
got, _, err := o.parseInstalledPackages(tt.args.stdout)
if (err != nil) != tt.wantErr {
t.Errorf("windows.parseInstalledPackages() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("windows.parseInstalledPackages() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseGetHotfix(t *testing.T) {
type args struct {
stdout string
}
tests := []struct {
name string
args args
want []string
wantErr bool
}{
{
name: "happy",
args: args{
stdout: `
HotFixID : KB5020872
HotFixID : KB4562830
`,
},
want: []string{"5020872", "4562830"},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &windows{}
got, err := o.parseGetHotfix(tt.args.stdout)
if (err != nil) != tt.wantErr {
t.Errorf("windows.parseGetHotfix() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("windows.parseGetHotfix() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseGetPackageMSU(t *testing.T) {
type args struct {
stdout string
}
tests := []struct {
name string
args args
want []string
wantErr bool
}{
{
name: "happy",
args: args{
stdout: `
Name : Git
Version : 2.35.1.2
ProviderName : Programs
Name : Oracle Database 11g Express Edition
Version : 11.2.0
ProviderName : msi
Name : 2022-12 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5021233)
Version :
ProviderName : msu
`,
},
want: []string{"5021233"},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &windows{}
got, err := o.parseGetPackageMSU(tt.args.stdout)
if (err != nil) != tt.wantErr {
t.Errorf("windows.parseGetPackageMSU() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("windows.parseGetPackageMSU() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseWindowsUpdaterSearch(t *testing.T) {
type args struct {
stdout string
}
tests := []struct {
name string
args args
want []string
wantErr bool
}{
{
name: "happy",
args: args{
stdout: `5012170
5021233
5021088
`,
},
want: []string{"5012170", "5021233", "5021088"},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &windows{}
got, err := o.parseWindowsUpdaterSearch(tt.args.stdout)
if (err != nil) != tt.wantErr {
t.Errorf("windows.parseWindowsUpdaterSearch() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("windows.parseWindowsUpdaterSearch() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parseWindowsUpdateHistory(t *testing.T) {
type args struct {
stdout string
}
tests := []struct {
name string
args args
want []string
wantErr bool
}{
{
name: "happy",
args: args{
stdout: `
Title : 2022-10 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5020435)
Operation : 1
ResultCode : 2
Title : 2022-10 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5020435)
Operation : 2
ResultCode : 2
Title : 2022-12 x64 (KB5021088) 向け Windows 10 Version 21H2 用 .NET Framework 3.5、4.8 および 4.8.1 の累積的な更新プログラム
Operation : 1
ResultCode : 2
Title : 2022-12 x64 ベース システム用 Windows 10 Version 21H2 の累積更新プログラム (KB5021233)
Operation : 1
ResultCode : 2
`,
},
want: []string{"5021088", "5021233"},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &windows{}
got, err := o.parseWindowsUpdateHistory(tt.args.stdout)
if (err != nil) != tt.wantErr {
t.Errorf("windows.parseWindowsUpdateHistory() error = %v, wantErr %v", err, tt.wantErr)
return
}
slices.Sort(got)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("windows.parseWindowsUpdateHistory() = %v, want %v", got, tt.want)
}
})
}
}
func Test_windows_detectKBsFromKernelVersion(t *testing.T) {
tests := []struct {
name string
base base
want models.WindowsKB
wantErr bool
}{
{
name: "10.0.19045.2129",
base: base{
Distro: config.Distro{Release: "Windows 10 Version 22H2 for x64-based Systems"},
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.19045.2129"}},
},
want: models.WindowsKB{
Applied: nil,
Unapplied: []string{"5020953", "5019959", "5020030", "5021233", "5022282", "5019275", "5022834", "5022906"},
},
},
{
name: "10.0.19045.2130",
base: base{
Distro: config.Distro{Release: "Windows 10 Version 22H2 for x64-based Systems"},
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.19045.2130"}},
},
want: models.WindowsKB{
Applied: nil,
Unapplied: []string{"5020953", "5019959", "5020030", "5021233", "5022282", "5019275", "5022834", "5022906"},
},
},
{
name: "10.0.22621.1105",
base: base{
Distro: config.Distro{Release: "Windows 11 Version 22H2 for x64-based Systems"},
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.22621.1105"}},
},
want: models.WindowsKB{
Applied: []string{"5019311", "5017389", "5018427", "5019509", "5018496", "5019980", "5020044", "5021255", "5022303"},
Unapplied: []string{"5022360", "5022845"},
},
},
{
name: "10.0.20348.1547",
base: base{
Distro: config.Distro{Release: "Windows Server 2022"},
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0.20348.1547"}},
},
want: models.WindowsKB{
Applied: []string{"5005575", "5005619", "5006699", "5006745", "5007205", "5007254", "5008223", "5010197", "5009555", "5010796", "5009608", "5010354", "5010421", "5011497", "5011558", "5012604", "5012637", "5013944", "5015013", "5014021", "5014678", "5014665", "5015827", "5015879", "5016627", "5016693", "5017316", "5017381", "5018421", "5020436", "5018485", "5019081", "5021656", "5020032", "5021249", "5022553", "5022291", "5022842"},
Unapplied: nil,
},
},
{
name: "err",
base: base{
Distro: config.Distro{Release: "Windows 10 Version 22H2 for x64-based Systems"},
osPackages: osPackages{Kernel: models.Kernel{Version: "10.0"}},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &windows{
base: tt.base,
}
got, err := o.detectKBsFromKernelVersion()
if (err != nil) != tt.wantErr {
t.Errorf("windows.detectKBsFromKernelVersion() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("windows.detectKBsFromKernelVersion() = %v, want %v", got, tt.want)
}
})
}
}
func Test_windows_parseIP(t *testing.T) {
tests := []struct {
name string
args string
ipv4Addrs []string
ipv6Addrs []string
}{
{
name: "en",
args: `
Windows IP Configuration
Ethernet adapter イーサネット 4:
Connection-specific DNS Suffix . : vuls.local
Link-local IPv6 Address . . . . . : fe80::19b6:ae27:d1fe:2041%33
Link-local IPv6 Address . . . . . : fe80::7080:8828:5cc8:c0ba%33
IPv4 Address. . . . . . . . . . . : 10.145.8.50
Subnet Mask . . . . . . . . . . . : 255.255.0.0
Default Gateway . . . . . . . . . : ::
Ethernet adapter イーサネット 2:
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::f49d:2c16:4270:759d%9
IPv4 Address. . . . . . . . . . . : 192.168.56.1
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . :
Wireless LAN adapter ローカル エリア接続* 1:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
Wireless LAN adapter ローカル エリア接続* 2:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
Wireless LAN adapter Wi-Fi:
Connection-specific DNS Suffix . :
IPv4 Address. . . . . . . . . . . : 192.168.0.205
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.0.1
Ethernet adapter Bluetooth ネットワーク接続:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
`,
ipv4Addrs: []string{"10.145.8.50", "192.168.56.1", "192.168.0.205"},
ipv6Addrs: []string{"fe80::19b6:ae27:d1fe:2041", "fe80::7080:8828:5cc8:c0ba", "fe80::f49d:2c16:4270:759d"},
},
{
name: "ja",
args: `
Windows IP 構成
イーサネット アダプター イーサネット 4:
接続固有の DNS サフィックス . . . . .: future.co.jp
リンクローカル IPv6 アドレス. . . . .: fe80::19b6:ae27:d1fe:2041%33
リンクローカル IPv6 アドレス. . . . .: fe80::7080:8828:5cc8:c0ba%33
IPv4 アドレス . . . . . . . . . . . .: 10.145.8.50
サブネット マスク . . . . . . . . . .: 255.255.0.0
デフォルト ゲートウェイ . . . . . . .: ::
イーサネット アダプター イーサネット 2:
接続固有の DNS サフィックス . . . . .:
リンクローカル IPv6 アドレス. . . . .: fe80::f49d:2c16:4270:759d%9
IPv4 アドレス . . . . . . . . . . . .: 192.168.56.1
サブネット マスク . . . . . . . . . .: 255.255.255.0
デフォルト ゲートウェイ . . . . . . .:
Wireless LAN adapter ローカル エリア接続* 1:
メディアの状態. . . . . . . . . . . .: メディアは接続されていません
接続固有の DNS サフィックス . . . . .:
Wireless LAN adapter ローカル エリア接続* 2:
メディアの状態. . . . . . . . . . . .: メディアは接続されていません
接続固有の DNS サフィックス . . . . .:
Wireless LAN adapter Wi-Fi:
接続固有の DNS サフィックス . . . . .:
IPv4 アドレス . . . . . . . . . . . .: 192.168.0.205
サブネット マスク . . . . . . . . . .: 255.255.255.0
デフォルト ゲートウェイ . . . . . . .: 192.168.0.1
イーサネット アダプター Bluetooth ネットワーク接続:
メディアの状態. . . . . . . . . . . .: メディアは接続されていません
接続固有の DNS サフィックス . . . . .:
`,
ipv4Addrs: []string{"10.145.8.50", "192.168.56.1", "192.168.0.205"},
ipv6Addrs: []string{"fe80::19b6:ae27:d1fe:2041", "fe80::7080:8828:5cc8:c0ba", "fe80::f49d:2c16:4270:759d"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotIPv4s, gotIPv6s := (&windows{}).parseIP(tt.args)
if !reflect.DeepEqual(gotIPv4s, tt.ipv4Addrs) {
t.Errorf("windows.parseIP() got = %v, want %v", gotIPv4s, tt.ipv4Addrs)
}
if !reflect.DeepEqual(gotIPv6s, tt.ipv6Addrs) {
t.Errorf("windows.parseIP() got = %v, want %v", gotIPv6s, tt.ipv6Addrs)
}
})
}
}

View File

@@ -39,13 +39,14 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
if mediatype == "application/json" {
switch mediatype {
case "application/json":
if err = json.NewDecoder(req.Body).Decode(&r); err != nil {
logging.Log.Error(err)
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
} else if mediatype == "text/plain" {
case "text/plain":
buf := new(bytes.Buffer)
if _, err := io.Copy(buf, req.Body); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
@@ -56,7 +57,7 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
} else {
default:
logging.Log.Error(mediatype)
http.Error(w, fmt.Sprintf("Invalid Content-Type: %s", contentType), http.StatusUnsupportedMediaType)
return

View File

@@ -240,6 +240,7 @@ host = "{{$ip}}"
#cmdPath = "/usr/local/bin/wp"
#osUser = "wordpress"
#docRoot = "/path/to/DocumentRoot/"
#noSudo = false
#[servers.{{index $names $i}}.portscan]
#scannerBinPath = "/usr/bin/nmap"
@@ -247,6 +248,10 @@ host = "{{$ip}}"
#scanTechniques = ["sS"]
#sourcePort = "65535"
#[servers.{{index $names $i}}.windows]
#serverSelection = 3
#cabPath = "/path/to/wsusscn2.cab"
#[servers.{{index $names $i}}.optional]
#key = "value1"

View File

@@ -1,5 +1,4 @@
//go:build !scanner
// +build !scanner
//go:build !scanner && !windows
package subcmds

372
subcmds/report_windows.go Normal file
View File

@@ -0,0 +1,372 @@
//go:build !scanner && windows
package subcmds
import (
"context"
"flag"
"os"
"path/filepath"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/google/subcommands"
"github.com/k0kubun/pp"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/detector"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/reporter"
)
// ReportCmd is subcommand for reporting
type ReportCmd struct {
configPath string
formatJSON bool
formatOneEMail bool
formatCsv bool
formatFullText bool
formatOneLineText bool
formatList bool
formatCycloneDXJSON bool
formatCycloneDXXML bool
gzip bool
toSlack bool
toChatWork bool
toGoogleChat bool
toTelegram bool
toEmail bool
toLocalFile bool
toS3 bool
toAzureBlob bool
toHTTP bool
}
// Name return subcommand name
func (*ReportCmd) Name() string { return "report" }
// Synopsis return synopsis
func (*ReportCmd) Synopsis() string { return "Reporting" }
// Usage return usage
func (*ReportCmd) Usage() string {
return `report:
report
[-lang=en|ja]
[-config=/path/to/config.toml]
[-results-dir=/path/to/results]
[-log-to-file]
[-log-dir=/path/to/log]
[-refresh-cve]
[-cvss-over=7]
[-confidence-over=80]
[-diff]
[-diff-minus]
[-diff-plus]
[-ignore-unscored-cves]
[-ignore-unfixed]
[-to-email]
[-to-http]
[-to-slack]
[-to-chatwork]
[-to-googlechat]
[-to-telegram]
[-to-localfile]
[-to-s3]
[-to-azure-blob]
[-format-json]
[-format-one-email]
[-format-one-line-text]
[-format-list]
[-format-full-text]
[-format-csv]
[-format-cyclonedx-json]
[-format-cyclonedx-xml]
[-gzip]
[-http-proxy=http://192.168.0.1:8080]
[-debug]
[-debug-sql]
[-quiet]
[-no-progress]
[-pipe]
[-http="http://vuls-report-server"]
[-trivy-cachedb-dir=/path/to/dir]
[RFC3339 datetime format under results dir]
`
}
// SetFlags set flag
func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&config.Conf.Lang, "lang", "en", "[en|ja]")
f.BoolVar(&config.Conf.Debug, "debug", false, "debug mode")
f.BoolVar(&config.Conf.DebugSQL, "debug-sql", false, "SQL debug mode")
f.BoolVar(&config.Conf.Quiet, "quiet", false, "Quiet mode. No output on stdout")
f.BoolVar(&config.Conf.NoProgress, "no-progress", false, "Suppress progress bar")
wd, _ := os.Getwd()
defaultConfPath := filepath.Join(wd, "config.toml")
f.StringVar(&p.configPath, "config", defaultConfPath, "/path/to/toml")
defaultResultsDir := filepath.Join(wd, "results")
f.StringVar(&config.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results")
defaultLogDir := logging.GetDefaultLogDir()
f.StringVar(&config.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log")
f.BoolVar(&config.Conf.LogToFile, "log-to-file", false, "Output log to file")
f.BoolVar(&config.Conf.RefreshCve, "refresh-cve", false,
"Refresh CVE information in JSON file under results dir")
f.Float64Var(&config.Conf.CvssScoreOver, "cvss-over", 0,
"-cvss-over=6.5 means reporting CVSS Score 6.5 and over (default: 0 (means report all))")
f.IntVar(&config.Conf.ConfidenceScoreOver, "confidence-over", 80,
"-confidence-over=40 means reporting Confidence Score 40 and over (default: 80)")
f.BoolVar(&config.Conf.DiffMinus, "diff-minus", false,
"Minus Difference between previous result and current result")
f.BoolVar(&config.Conf.DiffPlus, "diff-plus", false,
"Plus Difference between previous result and current result")
f.BoolVar(&config.Conf.Diff, "diff", false,
"Plus & Minus Difference between previous result and current result")
f.BoolVar(&config.Conf.IgnoreUnscoredCves, "ignore-unscored-cves", false,
"Don't report the unscored CVEs")
f.BoolVar(&config.Conf.IgnoreUnfixed, "ignore-unfixed", false,
"Don't report the unfixed CVEs")
f.StringVar(
&config.Conf.HTTPProxy, "http-proxy", "",
"http://proxy-url:port (default: empty)")
f.BoolVar(&p.formatJSON, "format-json", false, "JSON format")
f.BoolVar(&p.formatCsv, "format-csv", false, "CSV format")
f.BoolVar(&p.formatOneEMail, "format-one-email", false,
"Send all the host report via only one EMail (Specify with -to-email)")
f.BoolVar(&p.formatOneLineText, "format-one-line-text", false,
"One line summary in plain text")
f.BoolVar(&p.formatList, "format-list", false, "Display as list format")
f.BoolVar(&p.formatFullText, "format-full-text", false,
"Detail report in plain text")
f.BoolVar(&p.formatCycloneDXJSON, "format-cyclonedx-json", false, "CycloneDX JSON format")
f.BoolVar(&p.formatCycloneDXXML, "format-cyclonedx-xml", false, "CycloneDX XML format")
f.BoolVar(&p.toSlack, "to-slack", false, "Send report via Slack")
f.BoolVar(&p.toChatWork, "to-chatwork", false, "Send report via chatwork")
f.BoolVar(&p.toGoogleChat, "to-googlechat", false, "Send report via Google Chat")
f.BoolVar(&p.toTelegram, "to-telegram", false, "Send report via Telegram")
f.BoolVar(&p.toEmail, "to-email", false, "Send report via Email")
f.BoolVar(&p.toLocalFile, "to-localfile", false, "Write report to localfile")
f.BoolVar(&p.toS3, "to-s3", false, "Write report to S3 (bucket/yyyyMMdd_HHmm/servername.json/txt)")
f.BoolVar(&p.toHTTP, "to-http", false, "Send report via HTTP POST")
f.BoolVar(&p.toAzureBlob, "to-azure-blob", false,
"Write report to Azure Storage blob (container/yyyyMMdd_HHmm/servername.json/txt)")
f.BoolVar(&p.gzip, "gzip", false, "gzip compression")
f.BoolVar(&config.Conf.Pipe, "pipe", false, "Use args passed via PIPE")
f.StringVar(&config.Conf.TrivyCacheDBDir, "trivy-cachedb-dir",
utils.DefaultCacheDir(), "/path/to/dir")
}
// Execute execute
func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
logging.Log = logging.NewCustomLogger(config.Conf.Debug, config.Conf.Quiet, config.Conf.LogToFile, config.Conf.LogDir, "", "")
logging.Log.Infof("vuls-%s-%s", config.Version, config.Revision)
if p.configPath == "" {
for _, cnf := range []config.VulnDictInterface{
&config.Conf.CveDict,
&config.Conf.OvalDict,
&config.Conf.Gost,
&config.Conf.Exploit,
&config.Conf.Metasploit,
&config.Conf.KEVuln,
} {
cnf.Init()
}
} else {
if err := config.Load(p.configPath); err != nil {
logging.Log.Errorf("Error loading %s. err: %+v", p.configPath, err)
return subcommands.ExitUsageError
}
}
config.Conf.Slack.Enabled = p.toSlack
config.Conf.ChatWork.Enabled = p.toChatWork
config.Conf.GoogleChat.Enabled = p.toGoogleChat
config.Conf.Telegram.Enabled = p.toTelegram
config.Conf.EMail.Enabled = p.toEmail
config.Conf.AWS.Enabled = p.toS3
config.Conf.Azure.Enabled = p.toAzureBlob
config.Conf.HTTP.Enabled = p.toHTTP
if config.Conf.Diff {
config.Conf.DiffPlus, config.Conf.DiffMinus = true, true
}
var dir string
var err error
if config.Conf.DiffPlus || config.Conf.DiffMinus {
dir, err = reporter.JSONDir(config.Conf.ResultsDir, []string{})
} else {
dir, err = reporter.JSONDir(config.Conf.ResultsDir, f.Args())
}
if err != nil {
logging.Log.Errorf("Failed to read from JSON: %+v", err)
return subcommands.ExitFailure
}
logging.Log.Info("Validating config...")
if !config.Conf.ValidateOnReport() {
return subcommands.ExitUsageError
}
if !(p.formatJSON || p.formatOneLineText ||
p.formatList || p.formatFullText || p.formatCsv ||
p.formatCycloneDXJSON || p.formatCycloneDXXML) {
p.formatList = true
}
var loaded models.ScanResults
if loaded, err = reporter.LoadScanResults(dir); err != nil {
logging.Log.Error(err)
return subcommands.ExitFailure
}
logging.Log.Infof("Loaded: %s", dir)
var res models.ScanResults
hasError := false
for _, r := range loaded {
if len(r.Errors) == 0 {
res = append(res, r)
} else {
logging.Log.Errorf("Ignored since errors occurred during scanning: %s, err: %v",
r.ServerName, r.Errors)
hasError = true
}
}
if len(res) == 0 {
return subcommands.ExitFailure
}
for _, r := range res {
logging.Log.Debugf("%s: %s",
r.ServerInfo(), pp.Sprintf("%s", config.Conf.Servers[r.ServerName]))
}
if res, err = detector.Detect(res, dir); err != nil {
logging.Log.Errorf("%+v", err)
return subcommands.ExitFailure
}
// report
reports := []reporter.ResultWriter{
reporter.StdoutWriter{
FormatFullText: p.formatFullText,
FormatOneLineText: p.formatOneLineText,
FormatList: p.formatList,
},
}
if p.toSlack {
reports = append(reports, reporter.SlackWriter{
FormatOneLineText: p.formatOneLineText,
Cnf: config.Conf.Slack,
Proxy: config.Conf.HTTPProxy,
})
}
if p.toChatWork {
reports = append(reports, reporter.ChatWorkWriter{Cnf: config.Conf.ChatWork, Proxy: config.Conf.HTTPProxy})
}
if p.toGoogleChat {
reports = append(reports, reporter.GoogleChatWriter{Cnf: config.Conf.GoogleChat, Proxy: config.Conf.HTTPProxy})
}
if p.toTelegram {
reports = append(reports, reporter.TelegramWriter{Cnf: config.Conf.Telegram})
}
if p.toEmail {
reports = append(reports, reporter.EMailWriter{
FormatOneEMail: p.formatOneEMail,
FormatOneLineText: p.formatOneLineText,
FormatList: p.formatList,
Cnf: config.Conf.EMail,
})
}
if p.toHTTP {
reports = append(reports, reporter.HTTPRequestWriter{URL: config.Conf.HTTP.URL})
}
if p.toLocalFile {
reports = append(reports, reporter.LocalFileWriter{
CurrentDir: dir,
DiffPlus: config.Conf.DiffPlus,
DiffMinus: config.Conf.DiffMinus,
FormatJSON: p.formatJSON,
FormatCsv: p.formatCsv,
FormatFullText: p.formatFullText,
FormatOneLineText: p.formatOneLineText,
FormatList: p.formatList,
FormatCycloneDXJSON: p.formatCycloneDXJSON,
FormatCycloneDXXML: p.formatCycloneDXXML,
Gzip: p.gzip,
})
}
if p.toS3 {
w := reporter.S3Writer{
FormatJSON: p.formatJSON,
FormatFullText: p.formatFullText,
FormatOneLineText: p.formatOneLineText,
FormatList: p.formatList,
Gzip: p.gzip,
AWSConf: config.Conf.AWS,
}
if err := w.Validate(); err != nil {
logging.Log.Errorf("Check if there is a bucket beforehand: %s, err: %+v", config.Conf.AWS.S3Bucket, err)
return subcommands.ExitUsageError
}
reports = append(reports, w)
}
if p.toAzureBlob {
w := reporter.AzureBlobWriter{
FormatJSON: p.formatJSON,
FormatFullText: p.formatFullText,
FormatOneLineText: p.formatOneLineText,
FormatList: p.formatList,
Gzip: p.gzip,
AzureConf: config.Conf.Azure,
}
if err := w.Validate(); err != nil {
logging.Log.Errorf("Check if there is a container beforehand: %s, err: %+v", config.Conf.Azure.ContainerName, err)
return subcommands.ExitUsageError
}
reports = append(reports, w)
}
for _, w := range reports {
if err := w.Write(res...); err != nil {
logging.Log.Errorf("Failed to report. err: %+v", err)
return subcommands.ExitFailure
}
}
if hasError {
return subcommands.ExitFailure
}
return subcommands.ExitSuccess
}

View File

@@ -614,6 +614,7 @@ func summaryLines(r models.ScanResult) string {
pkgNames = append(pkgNames, vinfo.GitHubSecurityAlerts.Names()...)
pkgNames = append(pkgNames, vinfo.WpPackageFixStats.Names()...)
pkgNames = append(pkgNames, vinfo.LibraryFixedIns.Names()...)
pkgNames = append(pkgNames, vinfo.WindowsKBFixedIns...)
av := vinfo.AttackVector()
for _, pname := range vinfo.AffectedPackages.Names() {