Compare commits

...

67 Commits

Author SHA1 Message Date
Kota Kanbe
f047a6fe0c breaking-change: Update vuls-dictionaries (#1307)
* chore: udpate dictionaries

* update gost

* chore: update gost

* chore(go-cve-dict): use v0.8.1

* chore: change linter from golint to revive

* chore(linter): set revive config

* chore: fix commands and update golangci-lint version

* fix: lint errs

* chore: update gost

Co-authored-by: MaineK00n <mainek00n.1229@gmail.com>
2021-09-21 05:10:29 +09:00
MaineK00n
7f15a86d6a chore: change repository owner (#1306) 2021-09-16 11:05:37 +09:00
Kota Kanbe
da1e515253 breaking-change(goval): change-redis-architecture (#1305)
https://github.com/kotakanbe/goval-dictionary/pull/145
2021-09-15 08:25:14 +09:00
MaineK00n
591786fde6 feat(oval): support new goval-dictionary model (#1280)
* feat(oval): support new goval-dictionary model

* chore: fix lint err

* chore: set len of slice to 0

* fix(oval): avoid contamination of AffectedPackages by writing directly to defPacks

* fix(oval): avoid contamination of AffectedPackages by writing directly to defPacks

* feat(report): do not add duplicate CveContent

* chore: goval-dictionary update

* chore: go mod tidy

* fix(oval): preload Advisory.Cves for Ubuntu

https://github.com/kotakanbe/goval-dictionary/pull/152

Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
2021-09-13 10:19:59 +09:00
Kota Kanbe
47e6ea249d chore: fix lint warning (#1301) 2021-09-12 20:35:56 +09:00
Kota Kanbe
4a72295de7 feat(saas): support for library-only scanning (#1300) 2021-09-10 15:38:35 +09:00
MaineK00n
9ed5f2cac5 feat(debian): support Debian 11(bullseye) (#1298)
* feat(debian): support bullseye

* fix(debian): fix test case
2021-09-08 10:47:34 +09:00
Kota Kanbe
3e67f04fe4 breaking-change(cpescan): Improve Cpe scan (#1290)
* chore(cpescan): enable to pass useJvn to detector.DetectCpeURIsCves()

* review comment

* chore: go mod update go-cve

* feat(cpescan): set JvnVendorProductMatch to confidence If detected by JVN

* add NvdExactVersionMatch andd NvdRoughVersionMatch

* add confidence-over option to report

* sort CveContetens

* fix integration-test
2021-09-07 16:18:59 +09:00
Kota Kanbe
b9416ae062 fix(report): too many SQL variables (#1296)
* fix(report): too many SQL variables

https://github.com/kotakanbe/go-cve-dictionary/pull/210

* fix lint err
2021-09-01 10:42:19 +09:00
otuki
b4e49e093e feat(GAdocker): Publish docker image with Github Actions (#1291)
* feat(GAdocker): publish docker image with Github Actions

* feat(master): publish Docker image with GHActions:

* feat(docker): publish docker image with GHAtions

* feat(master): remove unnecessary GHActions

* feat(master): remove unnecessary GHActions

* feat(master): Add user ID and password at Docker GHActions

* feat(master): Add user ID and password with docker/login
2021-09-01 08:44:55 +09:00
Kota Kanbe
020f6ac609 fix(scan): warning if err occurred while scanning ports (#1294)
[Aug 26 20:59:11] ERROR [localhost] Error on host, err: [Failed to scan Ports:
    github.com/future-architect/vuls/scanner.Scanner.getScanResults.func1
        /go/src/github.com/future-architect/vuls/scanner/serverapi.go:658
  - dial tcp 172.19.0.1:80: connect: no route to host]

Scan Summary
================
host    Error           Use configtest subcommand or scan with --debug to view the details

[Aug 26 20:59:11] ERROR [localhost] Failed to scan: Failed to scan. err:
    github.com/future-architect/vuls/scanner.Scanner.Scan
        /go/src/github.com/future-architect/vuls/scanner/serverapi.go:103
  - An error occurred on [host]
2021-08-27 06:20:50 +09:00
sadayuki-matsuno
7e71cbdd46 fix(gost) sort in ms converter (#1293) 2021-08-26 14:32:45 +09:00
Kota Kanbe
1003f62212 chore: update go-cve-dictionary (#1292) 2021-08-26 13:45:40 +09:00
Kota Kanbe
9b18e1f9f0 breaking-change(go-exploitdb): support new go-exploitdb (#1288) 2021-08-20 08:00:57 +09:00
Kota Kanbe
24f790f474 feat(go-cve): update go-cve-dictionary (#1287)
diff: a31a3152c1...5043255
2021-08-19 05:34:03 +09:00
MaineK00n
fb8749fc5e fix(cpescan): fix confidence in cpe uri scan (#1286)
* fix(cpescan): fix confidence in cpe uri scan

* feat(cpe): add NA case

* chore: use HasNvd, HasJvn instead of len

* chore: go-cve-dictionary update
2021-08-19 04:59:09 +09:00
MaineK00n
96c3592db1 breaking-change(go-cve-dict): support new go-cve-dictionary (#1277)
* feat(model): change CveContents(map[string]CveContent) to map[string][]CveContent

* fix(cpescan): use CveIDSource

* chore: check Nvd, Jvn data

* chore: go-cve-dictionary update

* chore: add to cveDetails as is, since CveID is embedded in the response
2021-08-13 18:00:55 +09:00
Kota Kanbe
d65421cf46 fix(cpescan): JVN scan False-Negative on RDB-backend (#1283)
https://github.com/kotakanbe/go-cve-dictionary/pull/199
2021-08-13 09:58:04 +09:00
Kota Kanbe
c52ba448cd chore: update readme (#1282) 2021-08-12 09:37:45 +09:00
Kota Kanbe
21adce463b update readme 2021-08-12 09:31:12 +09:00
MaineK00n
f24240bf90 feat(library): update trivy v0.19.2 (#1278) 2021-08-02 05:40:57 +09:00
kazuminn
ff83cadd6e feat(os) : support Alma Linux (#1261)
* support Alma Linux

* fix miss

* feat(os) : support Rocky linux  (#1260)

* support rocky linux scan

* fix miss

* lint

* fix : like #1266 and error Failed to parse CentOS

* pass make test

* fix miss

* fix pointed out with comment

* fix golangci-lint error
2021-08-02 04:36:43 +09:00
Phil
e8c09282d9 Update ubuntu.go (#1279)
URI correction for ubuntu; see gost project: https://github.com/knqyf263/gost/blob/master/server/server.go#L48
2021-08-02 04:25:51 +09:00
Kota Kanbe
5f4d68cde4 feat(go-msf): update deps (#1275)
https://github.com/takuzoo3868/go-msfdb/pull/22
2021-07-21 09:13:34 +09:00
Kota Kanbe
9077a83ea8 fix(docker): docker build error (#1274) 2021-07-20 05:31:05 +09:00
Kota Kanbe
543dc99ecd fix(cpescan): CpeVendorProductMatch not set when Redis Backend (#1273)
* fix(cpescan): CpeVendorProductMatch not set when Redis Backend

* fix(integration): deprecated CPE URI

* fix(integration-test): add a test case for CpeVendorProductMatch

* fix review

* update deps go-cve-dict v0.6.2
2021-07-19 08:43:58 +09:00
Kota Kanbe
f0b3a8b1db feat(cpescan): Use JVN as a second DB for CPE scan (#1268)
* feat(cpescan): Use JVN as a second DB for CPE scan

* feat(tui): display score of detectionmethod

* update go.mod
2021-07-08 12:39:46 +09:00
Norihiro NAKAOKA
0b9ec05181 Support scanning Ubuntu using Gost (#1243)
* chore: add vuls binary in gitignore

* feat(gost): support ubuntu

* chore(debian): fix typo

* feat(ubuntu): more detail on CveContent

* chore: update .gitignore

* chore: update gost deps

* feat(ubuntu): add test in gost/ubuntu

* chore: fix typo

* Revert "chore: fix typo"

This reverts commit 9f2f1db233.

* docs: update README
2021-07-08 08:31:46 +09:00
Norihiro NAKAOKA
0bf12412d6 fix(rocky): fix Scan in Rocky Linux (#1266)
* fix(rocky): fix OVAL scan in Rocky Linux

* chore: add FreeBSD13 EOL, fix #1245

* chore(rocky): add Rocky Linux EOL tests

* feat(rocky): implement with reference to CentOS

* feat(raspbian): add Raspbian to Server mode

* feat(rocky): support gost scan

* fix(rocky): rocky support lessThan

* chore: update doc and comment
2021-07-08 05:39:48 +09:00
Peter Sedgewick
0ea4d58c63 fix(gost): Use DBDriver ctx in Psuedo (#1264) 2021-07-02 06:18:44 +09:00
kazuminn
5755b00576 feat(os) : support Rocky linux (#1260)
* support rocky linux scan

* fix miss

* lint
2021-07-02 05:35:47 +09:00
Shigechika AIKAWA
1c8e074c9d Feat report googlechat (#1257) (#1258)
* feat: Support Ubuntu21

* feat(report): Send report via Google Chat

* feat(report): Send report via Google Chat

* Snip too long message as (The rest is omitted).

* sorry for mixed feat-ubuntu21 branch. exlucded it

* append diff, attack vector and exploits info

* add ServerName filter by regexp

* rename variables and rewrite validators

* fix renaming miss

* fix renaming miss, again
2021-07-02 05:32:00 +09:00
Shigechika AIKAWA
0e0e5ce4be feat: Support Ubuntu21 (#1231) 2021-06-28 10:28:54 +09:00
Kota Kanbe
23dfe53885 chore: update go-exploitdb (#1262) 2021-06-28 08:29:16 +09:00
Norihiro NAKAOKA
8e6351a9e4 feat(oval): goval-dictionary update (#1259)
* feat(oval): err check for GetLastModified

* feat(oval): goval-dictionary update
2021-06-25 14:08:50 +09:00
Shigechika AIKAWA
3086e2760f fix Ubuntu 20.10 End of Life on July 22 2021 (#1256) 2021-06-23 08:14:38 +09:00
Norihiro NAKAOKA
b8db2e0b74 feat(report): Change the priority of CVE information in Debian (#1202)
* fix (bug) : using ScanResults refs #1019

* feat(gost): WIP change priority of CVE Info in Debian

* feat(report): change priority of CVE Info in Debian

* refactor: move RemoveRaspbianPackFromResult

* style: remove comment

* fix: lint error

* style: change coding style

* feat(report): support reporting with gost alone

* fix: merge error

* refactor(debian): change code to be simple
2021-06-21 15:14:41 +09:00
Kota Kanbe
43b46cb324 chore: add test data for integration test (#1254) 2021-06-17 14:01:10 +09:00
Kota Kanbe
d0559c7719 chore: update gost deps (#1253) 2021-06-16 18:45:48 +09:00
Kota Kanbe
231c63cf62 fix(libscan): support empty LibraryFixedIn (#1252) 2021-06-16 13:28:12 +09:00
Kota Kanbe
2a9aebe059 fix(report): improve cpe match logic (#1251)
* fix(report): improve cpe match logic

https://github.com/kotakanbe/go-cve-dictionary/pull/189

* fix vet error
2021-06-11 14:39:41 +09:00
Kota Kanbe
4e535d792f chore: fix build-tags in .goreleaser.yml (#1250) 2021-06-09 09:49:26 +09:00
Kota Kanbe
4b487503d4 chore: add go.sum test data for integration test (#1249)
* add go.sum test data for integration test

* chore: .gitignore
2021-06-09 09:18:32 +09:00
Kota Kanbe
0095c40e69 fix(vet): go vet err of make build-scanner (#1248) 2021-06-09 08:00:52 +09:00
Kota Kanbe
82c1abfd3a fix(report): detection logic bugs for Oracle Linux (#1247)
* fix(report): continue detecting if arch is emtpy for Oracle Linux

* fix test case

* fix(report): a bug of `Not Fixed Yet` of Oracle linux scanning
2021-06-09 05:46:42 +09:00
sadayuki-matsuno
40988401bd feat(scanner) separate func analize libraries (#1246)
* feat(scanner) separate func analize libraries

* fix(scanner) fix typo
2021-06-04 07:42:29 +09:00
Kota Kanbe
e8e3f4d138 feat(lib): support of Go (go.sum) scan (#1244)
* chore: update trivy deps

* fix(test): fix sort order in json

* parse go.sum in scanning

* feat(lib): support go.sum
2021-06-03 11:31:37 +09:00
Norihiro NAKAOKA
7eb77f5b51 feat(scan): support external port scanner(nmap) in host machine (#1207)
* feat(scan): load portscan settings from config.toml

* feat(scan): support external port scanner:nmap

* style: rename variable

* feat(scan): logging apply options

* feat(scan): remove spoof ip address option

* feat(scan): more validate port scan config

* style: change comment

* fix: parse port number as uint16

* feat(discover): add portscan section

* feat(discover): change default scanTechniques

* feat(docker): add nmap and version update

* feat(scan): nmap module upgrade

* fix: wrap err using %w

* feat(scan): print cmd using external port scanner

* feat(scan): more details external port scan command

* feat(scan): add capability check in validation

* fix(scanner): format error

* chore: change format
2021-05-26 09:35:28 +09:00
Kota Kanbe
e115235299 fix(test): dev mode to false in package-lock.json (#1242)
* fix(test): dev mode to false in package-lock.json

* fix: vet warning
2021-05-17 08:04:16 +09:00
otuki
151d4b2d30 fix(scan): Avoid panic when SSH connection refused (#1236)
* fix(fix-ssh-fata): Avoid panic when SSH connection refused

* chore(fix-ssh-fata): fix typo
2021-05-12 18:30:26 +09:00
Kota Kanbe
e553f8b4c5 feat(trivy): go mod update trivy v0.17.2 (#1235)
* feat(trivy): go mod update trivy v0.17.2

* wg.Wait

* fix reporting

* fix test case

* add gemfile.lock of redmine to integration test

* fix(test): add Pipfile.lock

* add poetry.lock to integration test

* add composer.lock to integration test

* add integration test case
2021-05-12 18:27:55 +09:00
Kota Kanbe
47652ef0fb fix(report): include the num of criticals in total #1233 (#1234) 2021-05-07 07:57:33 +09:00
Kota Kanbe
ab0e950800 fix(oracle): extracting only advisory ID from OVAL.title (#1232) 2021-04-29 12:54:36 +09:00
otuki
a7b0ce1c85 refactor(git-conf): config template in github section changed (#1229) 2021-04-28 14:53:11 +09:00
otuki
dc9c0edece refactor(git-conf): Specifing ignoreGitHubDismissed per repository (#1224)
* refactor(git-conf): Specifing ignoreGitHubDismissed per repository with config.toml

* refactor(git-conf): change json tag into camelCase

* refactor(git-conf): change first char of json tag into lowercase
2021-04-28 13:41:38 +09:00
Kota Kanbe
17ae386d1e chore: add a test case #1227 (#1228) 2021-04-28 12:18:18 +09:00
Kota Kanbe
2d369d0cfe Fix false positive for Oracle Linux (#1227)
* fix(oracle): false-positive(handle arch of pkgs)

* fix(oracle): false positive kernel-related CVEs

* add a test case for ksplice1

* fix(scan): handle uek kernel for Oracle linux

* fix(scan): hanlde uek kernel for reboot required

* fix(oracle): false-positive for redis-backend
2021-04-27 20:38:45 +09:00
Kota Kanbe
c36e645d9b fix(report): false positive for kernel-related CVE for RedHat, CentOS, Oracle and Amazon #1199 (#1223) 2021-04-23 08:59:46 +09:00
Kota Kanbe
40039c07e2 fix(report): panic when closing db connection of gost (#1222) 2021-04-23 06:14:12 +09:00
Kota Kanbe
a692cec0ef fix(gost): close gost DB connection in server mode #1217 (#1221) 2021-04-21 11:59:11 +09:00
otuki
e7ca491a94 fix(report): Avoid http reports error (#1216) 2021-04-21 10:00:58 +09:00
Shigechika AIKAWA
23f3e2fc11 fix(config): add Ubuntu 20.10 (#1218) 2021-04-21 09:05:33 +09:00
Kota Kanbe
27b3e17b79 feat(saas): delete json dir automatically after upload (#1212)
* feat(saas): delete json dir automatically after upload

* fix lint err
2021-04-15 05:58:41 +09:00
Kota Kanbe
740781af56 feat(logging): add -log-to-file and don't output to file by default (#1209)
* feat(logging): add -log-to-file and don't output to file by default

* update go-cve-dict

* fix lint err
2021-04-05 17:41:07 +09:00
Kota Kanbe
36c9c229b8 fix(report): avoid nil pointer when report FreeBSD (#1208) 2021-04-05 12:54:27 +09:00
Norihiro NAKAOKA
183fdcbdef fix: support for missing files in the results or results directory (#1206)
* fix: support for missing files in the results or results directory

* fix: support for missing files in the results or results directory
2021-04-05 07:28:20 +09:00
Kota Kanbe
a2a697900a refactor: move const to constant pkg (#1205) 2021-04-02 15:33:02 +09:00
115 changed files with 34420 additions and 4690 deletions

45
.github/workflows/docker-publish.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Publish Docker image
on:
push:
branches:
- 'master'
tags:
- '*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: vuls/vuls
tags: |
type=ref,event=tag
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
push: true
tags: |
vuls/vuls:latest
${{ steps.meta.outputs.tags }}
secrets: |
"github_token=${{ secrets.GITHUB_TOKEN }}"

View File

@@ -16,7 +16,7 @@ jobs:
uses: golangci/golangci-lint-action@v2
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.32
version: v1.42
args: --timeout=10m
# Optional: working directory, useful for monorepos

7
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.vscode
*.txt
*.swp
*.sqlite3*
*.db
tags
@@ -8,9 +9,13 @@ coverage.out
issues/
vendor/
log/
results/
results
!integration/data/results
config.toml
!setup/docker/*
.DS_Store
dist/
.idea
vuls.*
vuls
!cmd/vuls

View File

@@ -1,14 +1,44 @@
name: golang-ci
linters-settings:
errcheck:
revive:
# see https://github.com/mgechev/revive#available-rules for details.
ignore-generated-header: true
severity: warning
confidence: 0.8
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
- name: error-strings
- name: error-naming
- name: exported
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unused-parameter
- name: unreachable-code
- name: redefines-builtin-id
# errcheck:
#exclude: /path/to/file.txt
linters:
disable-all: true
enable:
- goimports
- golint
- revive
- govet
- misspell
- errcheck

View File

@@ -31,7 +31,8 @@ builds:
main: ./cmd/scanner/main.go
flags:
- -a
- -tags=scanner
tags:
- scanner
ldflags:
- -s -w -X github.com/future-architect/vuls/config.Version={{.Version}} -X github.com/future-architect/vuls/config.Revision={{.Commit}}-{{ .CommitDate }}
binary: vuls-scanner
@@ -46,6 +47,8 @@ builds:
- amd64
- arm
- arm64
tags:
- scanner
main: ./contrib/trivy/cmd/main.go
binary: trivy-to-vuls
@@ -61,7 +64,8 @@ builds:
- arm64
flags:
- -a
- -tags=scanner
tags:
- scanner
main: ./contrib/future-vuls/cmd/main.go
binary: future-vuls

30
.revive.toml Normal file
View File

@@ -0,0 +1,30 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]

View File

@@ -10,10 +10,7 @@ ENV REPOSITORY github.com/future-architect/vuls
COPY . $GOPATH/src/$REPOSITORY
RUN cd $GOPATH/src/$REPOSITORY && make install
FROM alpine:3.11
MAINTAINER hikachan sadayuki-matsuno
FROM alpine:3.14
ENV LOGDIR /var/log/vuls
ENV WORKDIR /vuls
@@ -22,6 +19,7 @@ RUN apk add --no-cache \
openssh-client \
ca-certificates \
git \
nmap \
&& mkdir -p $WORKDIR $LOGDIR
COPY --from=builder /go/bin/vuls /usr/local/bin/

View File

@@ -24,7 +24,7 @@ CGO_UNABLED := CGO_ENABLED=0 go
GO_OFF := GO111MODULE=off go
all: build
all: b
build: ./cmd/vuls/main.go pretest fmt
$(GO) build -a -ldflags "$(LDFLAGS)" -o vuls ./cmd/vuls
@@ -32,22 +32,25 @@ build: ./cmd/vuls/main.go pretest fmt
b: ./cmd/vuls/main.go
$(GO) build -a -ldflags "$(LDFLAGS)" -o vuls ./cmd/vuls
install: ./cmd/vuls/main.go pretest fmt
install: ./cmd/vuls/main.go
$(GO) install -ldflags "$(LDFLAGS)" ./cmd/vuls
build-scanner: ./cmd/scanner/main.go pretest fmt
build-scanner: ./cmd/scanner/main.go
$(CGO_UNABLED) build -tags=scanner -a -ldflags "$(LDFLAGS)" -o vuls ./cmd/scanner
install-scanner: ./cmd/scanner/main.go pretest fmt
install-scanner: ./cmd/scanner/main.go
$(CGO_UNABLED) install -tags=scanner -ldflags "$(LDFLAGS)" ./cmd/scanner
lint:
$(GO_OFF) get -u golang.org/x/lint/golint
golint $(PKGS)
$(GO_OFF) get -u github.com/mgechev/revive
revive -config ./.revive.toml -formatter plain $(PKGS)
vet:
echo $(PKGS) | xargs env $(GO) vet || exit;
golangci:
golangci-lint run
fmt:
gofmt -s -w $(SRCS)
@@ -57,7 +60,7 @@ mlint:
fmtcheck:
$(foreach file,$(SRCS),gofmt -s -d $(file);)
pretest: lint vet fmtcheck
pretest: lint vet fmtcheck golangci
test:
$(GO) test -cover -v ./... || exit;
@@ -68,7 +71,7 @@ unused:
cov:
@ go get -v github.com/axw/gocov/gocov
@ go get golang.org/x/tools/cmd/cover
gocov test | gocov report
gocov test -v ./... | gocov report
clean:
echo $(PKGS) | xargs go clean || exit;
@@ -84,10 +87,12 @@ build-future-vuls: pretest fmt
# integration-test
BASE_DIR := '${PWD}/integration/results'
# $(shell mkdir -p ${BASE_DIR})
NOW=$(shell date --iso-8601=seconds)
NOW_JSON_DIR := '${BASE_DIR}/$(NOW)'
ONE_SEC_AFTER=$(shell date -d '+1 second' --iso-8601=seconds)
ONE_SEC_AFTER_JSON_DIR := '${BASE_DIR}/$(ONE_SEC_AFTER)'
LIBS := 'gemfile' 'pipfile' 'poetry' 'composer' 'packagelock' 'yarn' 'cargo' 'gomod' 'nvd_exact' 'nvd_rough' 'nvd_vendor_product' 'nvd_match_no_jvn' 'jvn_vendor_product' 'jvn_vendor_product_nover'
diff:
# git clone git@github.com:vulsio/vulsctl.git
@@ -99,17 +104,27 @@ diff:
# ln -s oldvuls vuls.old
# make int
# (ex. test 10 times: for i in `seq 10`; do make int ARGS=-quiet ; done)
mv ${BASE_DIR}/* /tmp
ifneq ($(shell ls -U1 ${BASE_DIR} | wc -l), 0)
mv ${BASE_DIR} /tmp/${NOW}
endif
mkdir -p ${NOW_JSON_DIR}
cp integration/data/*.json ${NOW_JSON_DIR}
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml $(ARGS)
sleep 1
./vuls.old scan -config=./integration/int-config.toml --results-dir=${BASE_DIR} ${LIBS}
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}
cp integration/data/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml $(ARGS)
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
diff -c ${NOW_JSON_DIR} ${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 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}
$(call sed-d)
- diff -c ${NOW_JSON_DIR} ${ONE_SEC_AFTER_JSON_DIR}
echo "old: ${NOW_JSON_DIR} , new: ${ONE_SEC_AFTER_JSON_DIR}"
$(call count-cve)
diff-redis:
# docker network create redis-nw
@@ -122,44 +137,51 @@ diff-redis:
# ln -s vuls vuls.new
# ln -s oldvuls vuls.old
# make int-redis
mv ${BASE_DIR}/* /tmp
ifneq ($(shell ls -U1 ${BASE_DIR} | wc -l), 0)
mv ${BASE_DIR} /tmp/${NOW}
endif
mkdir -p ${NOW_JSON_DIR}
cp integration/data/*.json ${NOW_JSON_DIR}
./vuls.old report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml
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 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}
cp integration/data/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
diff -c ${NOW_JSON_DIR} ${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 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}
$(call sed-d)
- diff -c ${NOW_JSON_DIR} ${ONE_SEC_AFTER_JSON_DIR}
echo "old: ${NOW_JSON_DIR} , new: ${ONE_SEC_AFTER_JSON_DIR}"
$(call count-cve)
diff-rdb-redis:
mv ${BASE_DIR}/* /tmp
ifneq ($(shell ls -U1 ${BASE_DIR} | wc -l), 0)
mv ${BASE_DIR} /tmp/${NOW}
endif
mkdir -p ${NOW_JSON_DIR}
cp integration/data/*.json ${NOW_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-config.toml
mkdir -p ${ONE_SEC_AFTER_JSON_DIR}
cp integration/data/*.json ${ONE_SEC_AFTER_JSON_DIR}
./vuls.new report --format-json --refresh-cve --results-dir=${BASE_DIR} -config=./integration/int-redis-config.toml
# remove reportedAt line
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
# remove "Type": line
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/"Type":/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/"Type":/d' {} \;
# remove "SQLite3Path": line
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/"SQLite3Path":/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/"SQLite3Path":/d' {} \;
diff -c ${NOW_JSON_DIR} ${ONE_SEC_AFTER_JSON_DIR}
echo "old: ${NOW_JSON_DIR} , new: ${ONE_SEC_AFTER_JSON_DIR}"
for jsonfile in ${NOW_JSON_DIR}/*.json ; do \
echo $$jsonfile; cat $$jsonfile | jq ".scannedCves | length" ; \
done
for jsonfile in ${ONE_SEC_AFTER_JSON_DIR}/*.json ; do \
echo $$jsonfile; cat $$jsonfile | jq ".scannedCves | length" ; \
done
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 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 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}
$(call sed-d)
- diff -c ${NOW_JSON_DIR} ${ONE_SEC_AFTER_JSON_DIR}
echo "old: ${NOW_JSON_DIR} , new: ${ONE_SEC_AFTER_JSON_DIR}"
$(call count-cve)
head= $(shell git rev-parse HEAD)
prev= $(shell git rev-parse HEAD^)
@@ -177,10 +199,14 @@ build-integration:
make build
mv -f ./vuls ./vuls.${prev}
git checkout ${branch}
git stash apply stash@\{0\}
# master
git checkout master
make build
mv -f ./vuls ./vuls.master
# working tree
git checkout ${branch}
git stash apply stash@\{0\}
make build
# for integration testing, vuls.new and vuls.old needed.
@@ -189,5 +215,32 @@ build-integration:
# $ ln -s ./vuls.${head} ./vuls.old
# or
# $ ln -s ./vuls.${prev} ./vuls.old
# $ make int
# $ make int-redis
# then
# $ make diff
# $ make diff-redis
# $ make diff-rdb-redis
define sed-d
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/scannedAt/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/scannedAt/d' {} \;
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/reportedAt/d' {} \;
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/"Type":/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/"Type":/d' {} \;
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/"SQLite3Path":/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/"SQLite3Path":/d' {} \;
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/reportedRevision/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/reportedRevision/d' {} \;
find ${NOW_JSON_DIR} -type f -exec sed -i -e '/scannedRevision/d' {} \;
find ${ONE_SEC_AFTER_JSON_DIR} -type f -exec sed -i -e '/scannedRevision/d' {} \;
endef
define count-cve
for jsonfile in ${NOW_JSON_DIR}/*.json ; do \
echo $$jsonfile; cat $$jsonfile | jq ".scannedCves | length" ; \
done
for jsonfile in ${ONE_SEC_AFTER_JSON_DIR}/*.json ; do \
echo $$jsonfile; cat $$jsonfile | jq ".scannedCves | length" ; \
done
endef

View File

@@ -50,7 +50,7 @@ Vuls is a tool created to solve the problems listed above. It has the following
[Supports major Linux/FreeBSD](https://vuls.io/docs/en/supported-os.html)
- Alpine, Amazon Linux, CentOS, Debian, Oracle Linux, Raspbian, RHEL, SUSE Enterprise Linux, and Ubuntu
- Alpine, Amazon Linux, CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Raspbian, RHEL, SUSE Enterprise Linux, and Ubuntu
- FreeBSD
- Cloud, on-premise, Running Docker Container
@@ -71,6 +71,7 @@ Vuls is a tool created to solve the problems listed above. It has the following
- [Alpine-secdb](https://git.alpinelinux.org/cgit/alpine-secdb/)
- [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/)
- Commands(yum, zypper, pkg-audit)
- RHSA / ALAS / ELSA / FreeBSD-SA
@@ -79,6 +80,8 @@ Vuls is a tool created to solve the problems listed above. It has the following
- PoC, Exploit
- [Exploit Database](https://www.exploit-db.com/)
- [Metasploit-Framework modules](https://www.rapid7.com/db/?q=&type=metasploit)
- [qazbnm456/awesome-cve-poc](https://github.com/qazbnm456/awesome-cve-poc)
- [nomi-sec/PoC-in-GitHub](https://github.com/nomi-sec/PoC-in-GitHub)
- CERT
- [US-CERT](https://www.us-cert.gov/ncas/alerts)
@@ -100,15 +103,15 @@ Vuls is a tool created to solve the problems listed above. It has the following
- Scan without root privilege, no dependencies
- Almost no load on the scan target server
- Offline mode scan with no internet access. (CentOS, Debian, Oracle Linux, Red Hat, and Ubuntu)
- Offline mode scan with no internet access. (CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Red Hat, and Ubuntu)
[Fast Root Scan](https://vuls.io/docs/en/architecture-fast-root-scan.html)
- Scan with root privilege
- Almost no load on the scan target server
- Detect processes affected by update using yum-ps (Amazon Linux, CentOS, Oracle Linux, and RedHat)
- Detect processes affected by update using yum-ps (Amazon Linux, CentOS, Alma Linux, Rocky Linux, Oracle Linux, and RedHat)
- Detect processes which updated before but not restarting yet using checkrestart of debian-goodies (Debian and Ubuntu)
- Offline mode scan with no internet access. (CentOS, Debian, Oracle Linux, Red Hat, and Ubuntu)
- Offline mode scan with no internet access. (CentOS, Alma Linux, Rocky Linux, Debian, Oracle Linux, Red Hat, and Ubuntu)
### [Remote, Local scan mode, Server mode](https://vuls.io/docs/en/architecture-remote-local.html)

View File

@@ -42,16 +42,17 @@ type Config struct {
Exploit ExploitConf `json:"exploit,omitempty"`
Metasploit MetasploitConf `json:"metasploit,omitempty"`
Slack SlackConf `json:"-"`
EMail SMTPConf `json:"-"`
HTTP HTTPConf `json:"-"`
Syslog SyslogConf `json:"-"`
AWS AWSConf `json:"-"`
Azure AzureConf `json:"-"`
ChatWork ChatWorkConf `json:"-"`
Telegram TelegramConf `json:"-"`
WpScan WpScanConf `json:"-"`
Saas SaasConf `json:"-"`
Slack SlackConf `json:"-"`
EMail SMTPConf `json:"-"`
HTTP HTTPConf `json:"-"`
Syslog SyslogConf `json:"-"`
AWS AWSConf `json:"-"`
Azure AzureConf `json:"-"`
ChatWork ChatWorkConf `json:"-"`
GoogleChat GoogleChatConf `json:"-"`
Telegram TelegramConf `json:"-"`
WpScan WpScanConf `json:"-"`
Saas SaasConf `json:"-"`
ReportOpts
}
@@ -68,20 +69,17 @@ type ScanOpts struct {
// ReportOpts is options for report
type ReportOpts struct {
// refactored
CvssScoreOver float64 `json:"cvssScoreOver,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"`
//TODO move to GitHubConf
IgnoreGitHubDismissed bool `json:"ignore_git_hub_dismissed,omitempty"`
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
@@ -109,6 +107,16 @@ func (c Config) ValidateOnScan() bool {
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...)
}
}
for _, err := range errs {
logging.Log.Error(err)
}
@@ -150,6 +158,7 @@ func (c *Config) ValidateOnReport() bool {
&c.EMail,
&c.Slack,
&c.ChatWork,
&c.GoogleChat,
&c.Telegram,
&c.Syslog,
&c.HTTP,
@@ -221,16 +230,18 @@ type ServerInfo struct {
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, RHEL, Amazon
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"`
Type string `toml:"type,omitempty" json:"type,omitempty"` // "pseudo" or ""
IgnoredJSONKeys []string `toml:"ignoredJSONKeys,omitempty" json:"ignoredJSONKeys,omitempty"`
IPv4Addrs []string `toml:"-" json:"ipv4Addrs,omitempty"`
IPv6Addrs []string `toml:"-" json:"ipv6Addrs,omitempty"`
IPSIdentifiers map[string]string `toml:"-" json:"ipsIdentifiers,omitempty"`
WordPress *WordPressConf `toml:"wordpress,omitempty" json:"wordpress,omitempty"`
PortScan *PortScanConf `toml:"portscan,omitempty" json:"portscan,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
@@ -262,7 +273,8 @@ func (cnf WordPressConf) IsZero() bool {
// GitHubConf is used for GitHub Security Alerts
type GitHubConf struct {
Token string `json:"-"`
Token string `json:"-"`
IgnoreGitHubDismissed bool `json:"ignoreGitHubDismissed,omitempty"`
}
// GetServerName returns ServerName if this serverInfo is about host.

32
config/googlechatconf.go Normal file
View File

@@ -0,0 +1,32 @@
package config
import (
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// GoogleChatConf is GoogleChat config
type GoogleChatConf struct {
WebHookURL string `valid:"url" json:"-" toml:"webHookURL,omitempty"`
SkipIfNoCve bool `valid:"type(bool)" json:"-" toml:"skipIfNoCve"`
ServerNameRegexp string `valid:"type(string)" json:"-" toml:"serverNameRegexp,omitempty"`
Enabled bool `valid:"type(bool)" json:"-" toml:"-"`
}
// Validate validates configuration
func (c *GoogleChatConf) Validate() (errs []error) {
if !c.Enabled {
return
}
if len(c.WebHookURL) == 0 {
errs = append(errs, xerrors.New("googleChatConf.webHookURL must not be empty"))
}
if !govalidator.IsRegex(c.ServerNameRegexp) {
errs = append(errs, xerrors.New("googleChatConf.serverNameRegexp must be regex"))
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}

View File

@@ -7,6 +7,6 @@ type JSONLoader struct {
}
// Load load the configuration JSON file specified by path arg.
func (c JSONLoader) Load(path, sudoPass, keyPass string) (err error) {
func (c JSONLoader) Load(_, _, _ string) (err error) {
return xerrors.New("Not implement yet")
}

View File

@@ -75,6 +75,14 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"7": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
"8": {StandardSupportUntil: time.Date(2021, 12, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Alma:
eol, found = map[string]EOL{
"8": {StandardSupportUntil: time.Date(2029, 12, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Rocky:
eol, found = map[string]EOL{
"8": {StandardSupportUntil: time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Oracle:
eol, found = map[string]EOL{
// Source:
@@ -102,6 +110,7 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"8": {Ended: true},
"9": {StandardSupportUntil: time.Date(2022, 6, 30, 23, 59, 59, 0, time.UTC)},
"10": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
"11": {StandardSupportUntil: time.Date(2026, 6, 30, 23, 59, 59, 0, time.UTC)},
}[major(release)]
case constant.Raspbian:
// Not found
@@ -131,8 +140,11 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"20.04": {
StandardSupportUntil: time.Date(2025, 4, 1, 23, 59, 59, 0, time.UTC),
},
"20.10": {
StandardSupportUntil: time.Date(2021, 7, 22, 23, 59, 59, 0, time.UTC),
},
"21.04": {
StandardSupportUntil: time.Date(2022, 1, 1, 23, 59, 59, 0, time.UTC),
StandardSupportUntil: time.Date(2022, 1, 22, 23, 59, 59, 0, time.UTC),
},
"21.10": {
StandardSupportUntil: time.Date(2022, 7, 1, 23, 59, 59, 0, time.UTC),
@@ -176,6 +188,7 @@ func GetEOL(family, release string) (eol EOL, found bool) {
"10": {Ended: true},
"11": {StandardSupportUntil: time.Date(2021, 9, 30, 23, 59, 59, 0, time.UTC)},
"12": {StandardSupportUntil: time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC)},
"13": {StandardSupportUntil: time.Date(2026, 1, 31, 23, 59, 59, 0, time.UTC)},
}[major(release)]
}
return

View File

@@ -111,6 +111,56 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
extEnded: false,
found: false,
},
// Alma
{
name: "Alma Linux 8 supported",
fields: fields{family: Alma, release: "8"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Alma Linux 8 EOL",
fields: fields{family: Alma, release: "8"},
now: time.Date(2029, 2, 1, 0, 0, 0, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Alma Linux 9 Not Found",
fields: fields{family: Alma, release: "9"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
// Rocky
{
name: "Rocky Linux 8 supported",
fields: fields{family: Rocky, release: "8"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Rocky Linux 8 EOL",
fields: fields{family: Rocky, release: "8"},
now: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Rocky Linux 9 Not Found",
fields: fields{family: Rocky, release: "9"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//Oracle
{
name: "Oracle Linux 7 supported",
@@ -193,6 +243,14 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
stdEnded: false,
extEnded: false,
},
{
name: "Ubuntu 20.10 supported",
fields: fields{family: Ubuntu, release: "20.10"},
now: time.Date(2021, 5, 1, 23, 59, 59, 0, time.UTC),
found: true,
stdEnded: false,
extEnded: false,
},
{
name: "Ubuntu 21.04 supported",
fields: fields{family: Ubuntu, release: "21.04"},
@@ -232,6 +290,14 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "Debian 12 is not supported yet",
fields: fields{family: Debian, release: "12"},
now: time.Date(2021, 1, 6, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: false,
},
//alpine
@@ -300,6 +366,14 @@ func TestEOL_IsStandardSupportEnded(t *testing.T) {
extEnded: false,
found: true,
},
{
name: "freebsd 13 supported",
fields: fields{family: FreeBSD, release: "13"},
now: time.Date(2021, 7, 2, 23, 59, 59, 0, time.UTC),
stdEnded: false,
extEnded: false,
found: true,
},
{
name: "freebsd 10 eol",
fields: fields{family: FreeBSD, release: "10"},

222
config/portscan.go Normal file
View File

@@ -0,0 +1,222 @@
package config
import (
"os"
"os/exec"
"strconv"
"strings"
"github.com/asaskevich/govalidator"
"golang.org/x/xerrors"
)
// PortScanConf is the setting for using an external port scanner
type PortScanConf struct {
IsUseExternalScanner bool `toml:"-" json:"-"`
// Path to external scanner
ScannerBinPath string `toml:"scannerBinPath,omitempty" json:"scannerBinPath,omitempty"`
// set user has privileged
HasPrivileged bool `toml:"hasPrivileged,omitempty" json:"hasPrivileged,omitempty"`
// set the ScanTechniques for ScannerBinPath
ScanTechniques []string `toml:"scanTechniques,omitempty" json:"scanTechniques,omitempty"`
// set the FIREWALL/IDS EVASION AND SPOOFING(Use given port number)
SourcePort string `toml:"sourcePort,omitempty" json:"sourcePort,omitempty"`
}
// ScanTechnique is implemented to represent the supported ScanTechniques in an Enum.
type ScanTechnique int
const (
// NotSupportTechnique is a ScanTechnique that is currently not supported.
NotSupportTechnique ScanTechnique = iota
// TCPSYN is SYN scan
TCPSYN
// TCPConnect is TCP connect scan
TCPConnect
// TCPACK is ACK scan
TCPACK
// TCPWindow is Window scan
TCPWindow
// TCPMaimon is Maimon scan
TCPMaimon
// TCPNull is Null scan
TCPNull
// TCPFIN is FIN scan
TCPFIN
// TCPXmas is Xmas scan
TCPXmas
)
var scanTechniqueMap = map[ScanTechnique]string{
TCPSYN: "sS",
TCPConnect: "sT",
TCPACK: "sA",
TCPWindow: "sW",
TCPMaimon: "sM",
TCPNull: "sN",
TCPFIN: "sF",
TCPXmas: "sX",
}
func (s ScanTechnique) String() string {
switch s {
case TCPSYN:
return "TCPSYN"
case TCPConnect:
return "TCPConnect"
case TCPACK:
return "TCPACK"
case TCPWindow:
return "TCPWindow"
case TCPMaimon:
return "TCPMaimon"
case TCPNull:
return "TCPNull"
case TCPFIN:
return "TCPFIN"
case TCPXmas:
return "TCPXmas"
default:
return "NotSupportTechnique"
}
}
// GetScanTechniques converts ScanTechniques loaded from config.toml to []scanTechniques.
func (c *PortScanConf) GetScanTechniques() []ScanTechnique {
if len(c.ScanTechniques) == 0 {
return []ScanTechnique{}
}
scanTechniques := []ScanTechnique{}
for _, technique := range c.ScanTechniques {
findScanTechniqueFlag := false
for key, value := range scanTechniqueMap {
if strings.EqualFold(value, technique) {
scanTechniques = append(scanTechniques, key)
findScanTechniqueFlag = true
break
}
}
if !findScanTechniqueFlag {
scanTechniques = append(scanTechniques, NotSupportTechnique)
}
}
if len(scanTechniques) == 0 {
return []ScanTechnique{NotSupportTechnique}
}
return scanTechniques
}
// Validate validates configuration
func (c *PortScanConf) Validate() (errs []error) {
if !c.IsUseExternalScanner {
if c.IsZero() {
return
}
errs = append(errs, xerrors.New("To enable the PortScan option, ScannerBinPath must be set."))
}
if _, err := os.Stat(c.ScannerBinPath); err != nil {
errs = append(errs, xerrors.Errorf(
"scanner is not found. ScannerBinPath: %s not exists", c.ScannerBinPath))
}
scanTechniques := c.GetScanTechniques()
for _, scanTechnique := range scanTechniques {
if scanTechnique == NotSupportTechnique {
errs = append(errs, xerrors.New("There is an unsupported option in ScanTechniques."))
}
}
// It does not currently support multiple ScanTechniques.
// But if it supports UDP scanning, it will need to accept multiple ScanTechniques.
if len(scanTechniques) > 1 {
errs = append(errs, xerrors.New("Currently multiple ScanTechniques are not supported."))
}
if c.HasPrivileged {
if os.Geteuid() != 0 {
output, err := exec.Command("getcap", c.ScannerBinPath).Output()
if err != nil {
errs = append(errs, xerrors.Errorf("Failed to check capability of %s. error message: %w", c.ScannerBinPath, err))
} else {
parseOutput := strings.SplitN(string(output), "=", 2)
if len(parseOutput) != 2 {
errs = append(errs, xerrors.Errorf("Failed to parse getcap outputs. please execute this command: `$ getcap %s`. If the following string (`/usr/bin/nmap = ... `) is not displayed, you need to set the capability with the following command. `$ setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip %s`", c.ScannerBinPath, c.ScannerBinPath))
} else {
parseCapability := strings.Split(strings.TrimSpace(parseOutput[1]), "+")
capabilities := strings.Split(parseCapability[0], ",")
for _, needCap := range []string{"cap_net_bind_service", "cap_net_admin", "cap_net_raw"} {
existCapFlag := false
for _, cap := range capabilities {
if needCap == cap {
existCapFlag = true
break
}
}
if existCapFlag {
continue
}
errs = append(errs, xerrors.Errorf("Not enough capability to execute. needs: ['cap_net_bind_service', 'cap_net_admin', 'cap_net_raw'], actual: %s. To fix this, run the following command. `$ setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip %s`", capabilities, c.ScannerBinPath))
break
}
if parseCapability[1] != "eip" {
errs = append(errs, xerrors.Errorf("Capability(`cap_net_bind_service,cap_net_admin,cap_net_raw`) must belong to the following capability set(need: eip, actual: %s). To fix this, run the following command. `$ setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip %s`", parseCapability[1], c.ScannerBinPath))
}
}
}
}
}
if !c.HasPrivileged {
for _, scanTechnique := range scanTechniques {
if scanTechnique != TCPConnect && scanTechnique != NotSupportTechnique {
errs = append(errs, xerrors.New("If not privileged, only TCPConnect Scan(-sT) can be used."))
break
}
}
}
if c.SourcePort != "" {
for _, scanTechnique := range scanTechniques {
if scanTechnique == TCPConnect {
errs = append(errs, xerrors.New("SourcePort Option(-g/--source-port) is incompatible with the default TCPConnect Scan(-sT)."))
break
}
}
portNumber, err := strconv.Atoi(c.SourcePort)
if err != nil {
errs = append(errs, xerrors.Errorf("SourcePort conversion failed. %w", err))
} else {
if portNumber < 0 || 65535 < portNumber {
errs = append(errs, xerrors.Errorf("SourcePort(%s) must be between 0 and 65535.", c.SourcePort))
}
if portNumber == 0 {
errs = append(errs, xerrors.New("SourcePort(0) may not work on all systems."))
}
}
}
_, err := govalidator.ValidateStruct(c)
if err != nil {
errs = append(errs, err)
}
return
}
// IsZero return whether this struct is not specified in config.toml
func (c PortScanConf) IsZero() bool {
return c.ScannerBinPath == "" && !c.HasPrivileged && len(c.ScanTechniques) == 0 && c.SourcePort == ""
}

69
config/portscan_test.go Normal file
View File

@@ -0,0 +1,69 @@
package config
import (
"reflect"
"testing"
)
func TestPortScanConf_getScanTechniques(t *testing.T) {
tests := []struct {
name string
techniques []string
want []ScanTechnique
}{
{
name: "nil",
techniques: []string{},
want: []ScanTechnique{},
},
{
name: "single",
techniques: []string{"sS"},
want: []ScanTechnique{TCPSYN},
},
{
name: "multiple",
techniques: []string{"sS", "sT"},
want: []ScanTechnique{TCPSYN, TCPConnect},
},
{
name: "unknown",
techniques: []string{"sU"},
want: []ScanTechnique{NotSupportTechnique},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := PortScanConf{ScanTechniques: tt.techniques}
if got := c.GetScanTechniques(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("PortScanConf.getScanTechniques() = %v, want %v", got, tt.want)
}
})
}
}
func TestPortScanConf_IsZero(t *testing.T) {
tests := []struct {
name string
conf PortScanConf
want bool
}{
{
name: "not zero",
conf: PortScanConf{ScannerBinPath: "/usr/bin/nmap"},
want: false,
},
{
name: "zero",
conf: PortScanConf{},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.conf.IsZero(); got != tt.want {
t.Errorf("PortScanConf.IsZero() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -84,7 +84,7 @@ func (s ScanMode) String() string {
return ss + " mode"
}
func setScanMode(server *ServerInfo, d ServerInfo) error {
func setScanMode(server *ServerInfo) error {
if len(server.ScanMode) == 0 {
server.ScanMode = Conf.Default.ScanMode
}

View File

@@ -15,7 +15,7 @@ type TOMLLoader struct {
}
// Load load the configuration TOML file specified by path arg.
func (c TOMLLoader) Load(pathToToml, keyPass string) error {
func (c TOMLLoader) Load(pathToToml, _ string) error {
// util.Log.Infof("Loading config: %s", pathToToml)
if _, err := toml.DecodeFile(pathToToml, &Conf); err != nil {
return err
@@ -34,11 +34,11 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
index := 0
for name, server := range Conf.Servers {
server.ServerName = name
if err := setDefaultIfEmpty(&server, Conf.Default); err != nil {
if err := setDefaultIfEmpty(&server); err != nil {
return xerrors.Errorf("Failed to set default value to config. server: %s, err: %w", name, err)
}
if err := setScanMode(&server, Conf.Default); err != nil {
if err := setScanMode(&server); err != nil {
return xerrors.Errorf("Failed to set ScanMode: %w", err)
}
@@ -125,6 +125,10 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
}
}
if server.PortScan.ScannerBinPath != "" {
server.PortScan.IsUseExternalScanner = true
}
server.LogMsgAnsiColor = Colors[index%len(Colors)]
index++
@@ -133,7 +137,7 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
return nil
}
func setDefaultIfEmpty(server *ServerInfo, d ServerInfo) error {
func setDefaultIfEmpty(server *ServerInfo) error {
if server.Type != constant.ServerTypePseudo {
if len(server.Host) == 0 {
return xerrors.Errorf("server.host is empty")
@@ -203,6 +207,13 @@ func setDefaultIfEmpty(server *ServerInfo, d ServerInfo) error {
}
}
if server.PortScan == nil {
server.PortScan = Conf.Default.PortScan
if server.PortScan == nil {
server.PortScan = &PortScanConf{}
}
}
if len(server.IgnoredJSONKeys) == 0 {
server.IgnoredJSONKeys = Conf.Default.IgnoredJSONKeys
}

View File

@@ -17,6 +17,12 @@ const (
// CentOS is
CentOS = "centos"
// Alma is
Alma = "alma"
// Rocky is
Rocky = "rocky"
// Fedora is
// Fedora = "fedora"
@@ -55,4 +61,7 @@ const (
// ServerTypePseudo is used for ServerInfo.Type, r.Family
ServerTypePseudo = "pseudo"
// DeepSecurity is
DeepSecurity = "deepsecurity"
)

View File

@@ -6,8 +6,11 @@ import (
"time"
"github.com/aquasecurity/fanal/analyzer/os"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/models"
)
@@ -22,9 +25,7 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
vulnInfos := models.VulnInfos{}
uniqueLibraryScannerPaths := map[string]models.LibraryScanner{}
for _, trivyResult := range trivyResults {
if IsTrivySupportedOS(trivyResult.Type) {
overrideServerData(scanResult, &trivyResult)
}
setScanResultMeta(scanResult, &trivyResult)
for _, vuln := range trivyResult.Vulnerabilities {
if _, ok := vulnInfos[vuln.VulnerabilityID]; !ok {
vulnInfos[vuln.VulnerabilityID] = models.VulnInfo{
@@ -71,17 +72,17 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
}
vulnInfo.CveContents = models.CveContents{
models.Trivy: models.CveContent{
models.Trivy: []models.CveContent{{
Cvss3Severity: vuln.Severity,
References: references,
Title: vuln.Title,
Summary: vuln.Description,
Published: published,
LastModified: lastModified,
},
}},
}
// do only if image type is Vuln
if IsTrivySupportedOS(trivyResult.Type) {
if isTrivySupportedOS(trivyResult.Type) {
pkgs[vuln.PkgName] = models.Package{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
@@ -93,7 +94,6 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
FixedIn: vuln.FixedVersion,
})
} else {
// LibraryScanの結果
vulnInfo.LibraryFixedIns = append(vulnInfo.LibraryFixedIns, models.LibraryFixedIn{
Key: trivyResult.Type,
Name: vuln.PkgName,
@@ -101,6 +101,7 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
FixedIn: vuln.FixedVersion,
})
libScanner := uniqueLibraryScannerPaths[trivyResult.Target]
libScanner.Type = trivyResult.Type
libScanner.Libs = append(libScanner.Libs, types.Library{
Name: vuln.PkgName,
Version: vuln.InstalledVersion,
@@ -128,6 +129,7 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
})
libscanner := models.LibraryScanner{
Type: v.Type,
Path: path,
Libs: libraries,
}
@@ -142,39 +144,70 @@ func Parse(vulnJSON []byte, scanResult *models.ScanResult) (result *models.ScanR
return scanResult, nil
}
// IsTrivySupportedOS :
func IsTrivySupportedOS(family string) bool {
supportedFamilies := []string{
os.RedHat,
os.Debian,
os.Ubuntu,
os.CentOS,
os.Fedora,
os.Amazon,
os.Oracle,
os.Windows,
os.OpenSUSE,
os.OpenSUSELeap,
os.OpenSUSETumbleweed,
os.SLES,
os.Photon,
os.Alpine,
}
for _, supportedFamily := range supportedFamilies {
if family == supportedFamily {
return true
}
}
return false
}
const trivyTarget = "trivy-target"
func overrideServerData(scanResult *models.ScanResult, trivyResult *report.Result) {
scanResult.Family = trivyResult.Type
scanResult.ServerName = trivyResult.Target
scanResult.Optional = map[string]interface{}{
"trivy-target": trivyResult.Target,
func setScanResultMeta(scanResult *models.ScanResult, trivyResult *report.Result) {
if isTrivySupportedOS(trivyResult.Type) {
scanResult.Family = trivyResult.Type
scanResult.ServerName = trivyResult.Target
scanResult.Optional = map[string]interface{}{
trivyTarget: trivyResult.Target,
}
} else if isTrivySupportedLib(trivyResult.Type) {
if scanResult.Family == "" {
scanResult.Family = constant.ServerTypePseudo
}
if scanResult.ServerName == "" {
scanResult.ServerName = "library scan by trivy"
}
if _, ok := scanResult.Optional[trivyTarget]; !ok {
scanResult.Optional = map[string]interface{}{
trivyTarget: trivyResult.Target,
}
}
}
scanResult.ScannedAt = time.Now()
scanResult.ScannedBy = "trivy"
scanResult.ScannedVia = "trivy"
}
// isTrivySupportedOS :
func isTrivySupportedOS(family string) bool {
supportedFamilies := map[string]interface{}{
os.RedHat: struct{}{},
os.Debian: struct{}{},
os.Ubuntu: struct{}{},
os.CentOS: struct{}{},
os.Fedora: struct{}{},
os.Amazon: struct{}{},
os.Oracle: struct{}{},
os.Windows: struct{}{},
os.OpenSUSE: struct{}{},
os.OpenSUSELeap: struct{}{},
os.OpenSUSETumbleweed: struct{}{},
os.SLES: struct{}{},
os.Photon: struct{}{},
os.Alpine: struct{}{},
}
_, ok := supportedFamilies[family]
return ok
}
func isTrivySupportedLib(typestr string) bool {
supportedLibs := map[string]interface{}{
ftypes.Bundler: struct{}{},
ftypes.Cargo: struct{}{},
ftypes.Composer: struct{}{},
ftypes.Npm: struct{}{},
ftypes.NuGet: struct{}{},
ftypes.Pip: struct{}{},
ftypes.Pipenv: struct{}{},
ftypes.Poetry: struct{}{},
ftypes.Yarn: struct{}{},
ftypes.Jar: struct{}{},
ftypes.GoBinary: struct{}{},
ftypes.GoMod: struct{}{},
}
_, ok := supportedLibs[typestr]
return ok
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package detector
@@ -15,9 +16,9 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/util"
cvedb "github.com/kotakanbe/go-cve-dictionary/db"
cvelog "github.com/kotakanbe/go-cve-dictionary/log"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
cvedb "github.com/vulsio/go-cve-dictionary/db"
cvelog "github.com/vulsio/go-cve-dictionary/log"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
)
type goCveDictClient struct {
@@ -26,7 +27,9 @@ type goCveDictClient struct {
}
func newGoCveDictClient(cnf config.VulnDictInterface, o logging.LogOpts) (*goCveDictClient, error) {
cvelog.SetLogger(o.LogDir, o.Quiet, o.Debug, false)
if err := cvelog.SetLogger(o.LogToFile, o.LogDir, o.Debug, false); err != nil {
return nil, err
}
driver, locked, err := newCveDB(cnf)
if locked {
@@ -53,11 +56,7 @@ func (api goCveDictClient) fetchCveDetails(cveIDs []string) (cveDetails []cvemod
if err != nil {
return nil, xerrors.Errorf("Failed to fetch CVE. err: %w", err)
}
if len(cveDetail.CveID) == 0 {
cveDetails = append(cveDetails, cvemodels.CveDetail{CveID: cveID})
} else {
cveDetails = append(cveDetails, *cveDetail)
}
cveDetails = append(cveDetails, *cveDetail)
}
return
}
@@ -103,13 +102,7 @@ func (api goCveDictClient) fetchCveDetailsViaHTTP(cveIDs []string) (cveDetails [
for range cveIDs {
select {
case res := <-resChan:
if len(res.CveDetail.CveID) == 0 {
cveDetails = append(cveDetails, cvemodels.CveDetail{
CveID: res.Key,
})
} else {
cveDetails = append(cveDetails, res.CveDetail)
}
cveDetails = append(cveDetails, res.CveDetail)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
@@ -154,21 +147,40 @@ func (api goCveDictClient) httpGet(key, url string, resChan chan<- response, err
}
}
func (api goCveDictClient) fetchCveDetailsByCpeName(cpeName string) ([]cvemodels.CveDetail, error) {
func (api goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves []cvemodels.CveDetail, err error) {
if api.cnf.IsFetchViaHTTP() {
url, err := util.URLPathJoin(api.cnf.GetURL(), "cpes")
if err != nil {
return nil, err
}
query := map[string]string{"name": cpeName}
query := map[string]string{"name": cpeURI}
logging.Log.Debugf("HTTP Request to %s, query: %#v", url, query)
return api.httpPost(cpeName, url, query)
if cves, err = api.httpPost(url, query); err != nil {
return nil, err
}
} else {
if cves, err = api.driver.GetByCpeURI(cpeURI); err != nil {
return nil, err
}
}
return api.driver.GetByCpeURI(cpeName)
if useJVN {
return cves, nil
}
nvdCves := []cvemodels.CveDetail{}
for _, cve := range cves {
if !cve.HasNvd() {
continue
}
cve.Jvns = []cvemodels.Jvn{}
nvdCves = append(nvdCves, cve)
}
return nvdCves, nil
}
func (api goCveDictClient) httpPost(key, url string, query map[string]string) ([]cvemodels.CveDetail, error) {
func (api goCveDictClient) httpPost(url string, query map[string]string) ([]cvemodels.CveDetail, error) {
var body string
var errs []error
var resp *http.Response

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package detector
@@ -17,10 +18,16 @@ import (
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/reporter"
"github.com/future-architect/vuls/util"
cvemodels "github.com/kotakanbe/go-cve-dictionary/models"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
"golang.org/x/xerrors"
)
// Cpe :
type Cpe struct {
CpeURI string
UseJVN bool
}
// Detect vulns and fill CVE detailed information
func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
@@ -36,7 +43,16 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
r.ScannedCves = models.VulnInfos{}
}
if err := DetectLibsCves(&r, config.Conf.TrivyCacheDBDir, config.Conf.NoProgress); err != nil {
return nil, xerrors.Errorf("Failed to fill with Library dependency: %w", err)
}
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost); err != nil {
return nil, xerrors.Errorf("Failed to detect Pkg CVE: %w", err)
}
cpeURIs, owaspDCXMLPath := []string{}, ""
cpes := []Cpe{}
if len(r.Container.ContainerID) == 0 {
cpeURIs = config.Conf.Servers[r.ServerName].CpeNames
owaspDCXMLPath = config.Conf.Servers[r.ServerName].OwaspDCXMLPath
@@ -56,21 +72,18 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
}
cpeURIs = append(cpeURIs, cpes...)
}
if err := DetectLibsCves(&r, config.Conf.TrivyCacheDBDir, config.Conf.NoProgress); err != nil {
return nil, xerrors.Errorf("Failed to fill with Library dependency: %w", err)
for _, uri := range cpeURIs {
cpes = append(cpes, Cpe{
CpeURI: uri,
UseJVN: true,
})
}
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost); err != nil {
return nil, xerrors.Errorf("Failed to detect Pkg CVE: %w", err)
}
if err := DetectCpeURIsCves(&r, cpeURIs, config.Conf.CveDict, config.Conf.LogOpts); err != nil {
if err := DetectCpeURIsCves(&r, cpes, config.Conf.CveDict, config.Conf.LogOpts); err != nil {
return nil, xerrors.Errorf("Failed to detect CVE of `%s`: %w", cpeURIs, err)
}
repos := config.Conf.Servers[r.ServerName].GitHubRepos
if err := DetectGitHubCves(&r, repos, config.Conf.IgnoreGitHubDismissed); err != nil {
if err := DetectGitHubCves(&r, repos); err != nil {
return nil, xerrors.Errorf("Failed to detect GitHub Cves: %w", err)
}
@@ -78,12 +91,10 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
return nil, xerrors.Errorf("Failed to detect WordPress Cves: %w", err)
}
logging.Log.Infof("Fill CVE detailed with gost")
if err := gost.FillCVEsWithRedHat(&r, config.Conf.Gost); err != nil {
return nil, xerrors.Errorf("Failed to fill with gost: %w", err)
}
logging.Log.Infof("Fill CVE detailed with go-cve-dictionary")
if err := FillCvesWithNvdJvn(&r, config.Conf.CveDict, config.Conf.LogOpts); err != nil {
return nil, xerrors.Errorf("Failed to fill with CVE: %w", err)
}
@@ -92,13 +103,13 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
if err != nil {
return nil, xerrors.Errorf("Failed to fill with exploit: %w", err)
}
logging.Log.Infof("%s: %d exploits are detected", r.FormatServerName(), nExploitCve)
logging.Log.Infof("%s: %d PoC are detected", r.FormatServerName(), nExploitCve)
nMetasploitCve, err := FillWithMetasploit(&r, config.Conf.Metasploit)
if err != nil {
return nil, xerrors.Errorf("Failed to fill with metasploit: %w", err)
}
logging.Log.Infof("%s: %d modules are detected", r.FormatServerName(), nMetasploitCve)
logging.Log.Infof("%s: %d exploits are detected", r.FormatServerName(), nMetasploitCve)
FillCweDict(&r)
@@ -136,6 +147,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
for i, r := range rs {
r.ScannedCves = r.ScannedCves.FilterByCvssOver(config.Conf.CvssScoreOver)
r.ScannedCves = r.ScannedCves.FilterUnfixed(config.Conf.IgnoreUnfixed)
r.ScannedCves = r.ScannedCves.FilterByConfidenceOver(config.Conf.ConfidenceScoreOver)
// IgnoreCves
ignoreCves := []string{}
@@ -171,6 +183,11 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf config.GostConf) error {
// Pkg Scan
if r.Release != "" {
// OVAL, gost(Debian Security Tracker) does not support Package for Raspbian, so skip it.
if r.Family == constant.Raspbian {
r = r.RemoveRaspbianPackFromResult()
}
// OVAL
if err := detectPkgsCvesWithOval(ovalCnf, r); err != nil {
return xerrors.Errorf("Failed to detect CVE with OVAL: %w", err)
@@ -185,7 +202,7 @@ func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf c
} else if r.Family == constant.ServerTypePseudo {
logging.Log.Infof("pseudo type. Skip OVAL and gost detection")
} else {
return xerrors.Errorf("Failed to fill CVEs. r.Release is empty")
logging.Log.Infof("r.Release is empty. detect as pseudo type. Skip OVAL and gost detection")
}
for i, v := range r.ScannedCves {
@@ -219,7 +236,7 @@ func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf c
}
// DetectGitHubCves fetches CVEs from GitHub Security Alerts
func DetectGitHubCves(r *models.ScanResult, githubConfs map[string]config.GitHubConf, ignoreDismissed bool) error {
func DetectGitHubCves(r *models.ScanResult, githubConfs map[string]config.GitHubConf) error {
if len(githubConfs) == 0 {
return nil
}
@@ -229,7 +246,7 @@ func DetectGitHubCves(r *models.ScanResult, githubConfs map[string]config.GitHub
return xerrors.Errorf("Failed to parse GitHub owner/repo: %s", ownerRepo)
}
owner, repo := ss[0], ss[1]
n, err := DetectGitHubSecurityAlerts(r, owner, repo, setting.Token, ignoreDismissed)
n, err := DetectGitHubSecurityAlerts(r, owner, repo, setting.Token, setting.IgnoreGitHubDismissed)
if err != nil {
return xerrors.Errorf("Failed to access GitHub Security Alerts: %w", err)
}
@@ -244,7 +261,7 @@ func DetectWordPressCves(r *models.ScanResult, wpCnf config.WpScanConf) error {
if len(r.WordPressPackages) == 0 {
return nil
}
logging.Log.Infof("Detect WordPress CVE. pkgs: %d ", len(r.WordPressPackages))
logging.Log.Infof("%s: Detect WordPress CVE. Number of pkgs: %d ", r.ServerInfo(), len(r.WordPressPackages))
n, err := detectWordPressCves(r, wpCnf)
if err != nil {
return xerrors.Errorf("Failed to detect WordPress CVE: %w", err)
@@ -281,8 +298,8 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
}
for _, d := range ds {
nvd, exploits, mitigations := models.ConvertNvdJSONToModel(d.CveID, d.NvdJSON)
jvn := models.ConvertJvnToModel(d.CveID, d.Jvn)
nvds, exploits, mitigations := models.ConvertNvdToModel(d.CveID, d.Nvds)
jvns := models.ConvertJvnToModel(d.CveID, d.Jvns)
alerts := fillCertAlerts(&d)
for cveID, vinfo := range r.ScannedCves {
@@ -290,9 +307,23 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
if vinfo.CveContents == nil {
vinfo.CveContents = models.CveContents{}
}
for _, con := range []*models.CveContent{nvd, jvn} {
if con != nil && !con.Empty() {
vinfo.CveContents[con.Type] = *con
for _, con := range nvds {
if !con.Empty() {
vinfo.CveContents[con.Type] = []models.CveContent{con}
}
}
for _, con := range jvns {
if !con.Empty() {
found := false
for _, cveCont := range vinfo.CveContents[con.Type] {
if con.SourceLink == cveCont.SourceLink {
found = true
break
}
}
if !found {
vinfo.CveContents[con.Type] = append(vinfo.CveContents[con.Type], con)
}
}
}
vinfo.AlertDict = alerts
@@ -307,8 +338,8 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
}
func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
if cvedetail.NvdJSON != nil {
for _, cert := range cvedetail.NvdJSON.Certs {
for _, nvd := range cvedetail.Nvds {
for _, cert := range nvd.Certs {
dict.En = append(dict.En, models.Alert{
URL: cert.Link,
Title: cert.Title,
@@ -316,8 +347,9 @@ func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
})
}
}
if cvedetail.Jvn != nil {
for _, cert := range cvedetail.Jvn.Certs {
for _, jvn := range cvedetail.Jvns {
for _, cert := range jvn.Certs {
dict.Ja = append(dict.Ja, models.Alert{
URL: cert.Link,
Title: cert.Title,
@@ -325,6 +357,7 @@ func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
})
}
}
return dict
}
@@ -334,6 +367,9 @@ func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult) erro
if err != nil {
return err
}
if ovalClient == nil {
return nil
}
logging.Log.Debugf("Check if oval fetched: %s %s", r.Family, r.Release)
ok, err := ovalClient.CheckIfOvalFetched(r.Family, r.Release)
@@ -341,7 +377,12 @@ func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult) erro
return err
}
if !ok {
return xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see `https://github.com/kotakanbe/goval-dictionary#usage`", r.Family, r.Release)
if r.Family == constant.Debian {
logging.Log.Infof("Skip OVAL and Scan with gost alone.")
logging.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), 0)
return nil
}
return xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see `https://github.com/vulsio/goval-dictionary#usage`", r.Family, r.Release)
}
logging.Log.Debugf("Check if oval fresh: %s %s", r.Family, r.Release)
@@ -366,17 +407,32 @@ func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult) error {
return xerrors.Errorf("Failed to new a gost client: %w", err)
}
nCVEs, err := client.DetectUnfixed(r, true)
defer func() {
if err := client.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close the gost DB. err: %+v", err)
}
}()
nCVEs, err := client.DetectCVEs(r, true)
if err != nil {
if r.Family == constant.Debian {
return xerrors.Errorf("Failed to detect CVEs with gost: %w", err)
}
return xerrors.Errorf("Failed to detect unfixed CVEs with gost: %w", err)
}
logging.Log.Infof("%s: %d unfixed CVEs are detected with gost", r.FormatServerName(), nCVEs)
if r.Family == constant.Debian {
logging.Log.Infof("%s: %d CVEs are detected with gost",
r.FormatServerName(), nCVEs)
} else {
logging.Log.Infof("%s: %d unfixed CVEs are detected with gost",
r.FormatServerName(), nCVEs)
}
return nil
}
// DetectCpeURIsCves detects CVEs of given CPE-URIs
func DetectCpeURIsCves(r *models.ScanResult, cpeURIs []string, cnf config.GoCveDictConf, logOpts logging.LogOpts) error {
func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictConf, logOpts logging.LogOpts) error {
client, err := newGoCveDictClient(&cnf, logOpts)
if err != nil {
return err
@@ -388,23 +444,34 @@ func DetectCpeURIsCves(r *models.ScanResult, cpeURIs []string, cnf config.GoCveD
}()
nCVEs := 0
for _, name := range cpeURIs {
details, err := client.fetchCveDetailsByCpeName(name)
for _, cpe := range cpes {
details, err := client.detectCveByCpeURI(cpe.CpeURI, cpe.UseJVN)
if err != nil {
return err
}
for _, detail := range details {
advisories := []models.DistroAdvisory{}
if !detail.HasNvd() && detail.HasJvn() {
for _, jvn := range detail.Jvns {
advisories = append(advisories, models.DistroAdvisory{
AdvisoryID: jvn.JvnID,
})
}
}
maxConfidence := getMaxConfidence(detail)
if val, ok := r.ScannedCves[detail.CveID]; ok {
names := val.CpeURIs
names = util.AppendIfMissing(names, name)
val.CpeURIs = names
val.Confidences.AppendIfMissing(models.CpeNameMatch)
val.CpeURIs = util.AppendIfMissing(val.CpeURIs, cpe.CpeURI)
val.Confidences.AppendIfMissing(maxConfidence)
val.DistroAdvisories = advisories
r.ScannedCves[detail.CveID] = val
} else {
v := models.VulnInfo{
CveID: detail.CveID,
CpeURIs: []string{name},
Confidences: models.Confidences{models.CpeNameMatch},
CveID: detail.CveID,
CpeURIs: []string{cpe.CpeURI},
Confidences: models.Confidences{maxConfidence},
DistroAdvisories: advisories,
}
r.ScannedCves[detail.CveID] = v
nCVEs++
@@ -415,15 +482,39 @@ func DetectCpeURIsCves(r *models.ScanResult, cpeURIs []string, cnf config.GoCveD
return nil
}
func getMaxConfidence(detail cvemodels.CveDetail) (max models.Confidence) {
if !detail.HasNvd() && detail.HasJvn() {
return models.JvnVendorProductMatch
} else if detail.HasNvd() {
for _, nvd := range detail.Nvds {
confidence := models.Confidence{}
switch nvd.DetectionMethod {
case cvemodels.NvdExactVersionMatch:
confidence = models.NvdExactVersionMatch
case cvemodels.NvdRoughVersionMatch:
confidence = models.NvdRoughVersionMatch
case cvemodels.NvdVendorProductMatch:
confidence = models.NvdVendorProductMatch
}
if max.Score < confidence.Score {
max = confidence
}
}
}
return max
}
// FillCweDict fills CWE
func FillCweDict(r *models.ScanResult) {
uniqCweIDMap := map[string]bool{}
for _, vinfo := range r.ScannedCves {
for _, cont := range vinfo.CveContents {
for _, id := range cont.CweIDs {
if strings.HasPrefix(id, "CWE-") {
id = strings.TrimPrefix(id, "CWE-")
uniqCweIDMap[id] = true
for _, conts := range vinfo.CveContents {
for _, cont := range conts {
for _, id := range cont.CweIDs {
if strings.HasPrefix(id, "CWE-") {
id = strings.TrimPrefix(id, "CWE-")
uniqCweIDMap[id] = true
}
}
}
}

90
detector/detector_test.go Normal file
View File

@@ -0,0 +1,90 @@
//go:build !scanner
// +build !scanner
package detector
import (
"reflect"
"testing"
"github.com/future-architect/vuls/models"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
)
func Test_getMaxConfidence(t *testing.T) {
type args struct {
detail cvemodels.CveDetail
}
tests := []struct {
name string
args args
wantMax models.Confidence
}{
{
name: "JvnVendorProductMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{},
Jvns: []cvemodels.Jvn{{}},
},
},
wantMax: models.JvnVendorProductMatch,
},
{
name: "NvdExactVersionMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{
{DetectionMethod: cvemodels.NvdRoughVersionMatch},
{DetectionMethod: cvemodels.NvdVendorProductMatch},
{DetectionMethod: cvemodels.NvdExactVersionMatch},
},
Jvns: []cvemodels.Jvn{{DetectionMethod: cvemodels.JvnVendorProductMatch}},
},
},
wantMax: models.NvdExactVersionMatch,
},
{
name: "NvdRoughVersionMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{
{DetectionMethod: cvemodels.NvdRoughVersionMatch},
{DetectionMethod: cvemodels.NvdVendorProductMatch},
},
Jvns: []cvemodels.Jvn{},
},
},
wantMax: models.NvdRoughVersionMatch,
},
{
name: "NvdVendorProductMatch",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{
{DetectionMethod: cvemodels.NvdVendorProductMatch},
},
Jvns: []cvemodels.Jvn{{DetectionMethod: cvemodels.JvnVendorProductMatch}},
},
},
wantMax: models.NvdVendorProductMatch,
},
{
name: "empty",
args: args{
detail: cvemodels.CveDetail{
Nvds: []cvemodels.Nvd{},
Jvns: []cvemodels.Jvn{},
},
},
wantMax: models.Confidence{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotMax := getMaxConfidence(tt.args.detail); !reflect.DeepEqual(gotMax, tt.wantMax) {
t.Errorf("getMaxConfidence() = %v, want %v", gotMax, tt.wantMax)
}
})
}
}

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package detector
@@ -32,7 +33,7 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
return 0, err
}
for _, res := range responses {
exps := []*exploitmodels.Exploit{}
exps := []exploitmodels.Exploit{}
if err := json.Unmarshal([]byte(res.json), &exps); err != nil {
return 0, err
}
@@ -76,7 +77,7 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
}
// ConvertToModels converts gost model to vuls model
func ConvertToModels(es []*exploitmodels.Exploit) (exploits []models.Exploit) {
func ConvertToModels(es []exploitmodels.Exploit) (exploits []models.Exploit) {
for _, e := range es {
var documentURL, shellURL *string
if e.OffensiveSecurity != nil {

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package detector
import (
@@ -123,7 +126,7 @@ func DetectGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string,
if val, ok := r.ScannedCves[cveID]; ok {
val.GitHubSecurityAlerts = val.GitHubSecurityAlerts.Add(m)
val.CveContents[models.GitHub] = cveContent
val.CveContents[models.GitHub] = []models.CveContent{cveContent}
r.ScannedCves[cveID] = val
} else {
v := models.VulnInfo{

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package detector
import (

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package detector
@@ -6,8 +7,8 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
metasploitdb "github.com/takuzoo3868/go-msfdb/db"
metasploitmodels "github.com/takuzoo3868/go-msfdb/models"
metasploitdb "github.com/vulsio/go-msfdb/db"
metasploitmodels "github.com/vulsio/go-msfdb/models"
"golang.org/x/xerrors"
)
@@ -22,7 +23,7 @@ func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf) (nMetas
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v")
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
@@ -44,7 +45,7 @@ func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf) (nMetas
}
// ConvertToModelsMsf converts gost model to vuls model
func ConvertToModelsMsf(ms []*metasploitmodels.Metasploit) (modules []models.Metasploit) {
func ConvertToModelsMsf(ms []metasploitmodels.Metasploit) (modules []models.Metasploit) {
for _, m := range ms {
var links []string
if 0 < len(m.References) {
@@ -71,7 +72,7 @@ func newMetasploitDB(cnf config.VulnDictInterface) (driver metasploitdb.DB, lock
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), false); err != nil {
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL()); err != nil {
if locked {
return nil, true, xerrors.Errorf("metasploitDB is locked. err: %w", err)
}

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package detector
import (
@@ -6,6 +9,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"time"
@@ -64,10 +68,9 @@ func loadPrevious(currs models.ScanResults, resultsDir string) (prevs models.Sca
prevs = append(prevs, *r)
logging.Log.Infof("Previous json found: %s", path)
break
} else {
logging.Log.Infof("Previous json is different family.Release: %s, pre: %s.%s cur: %s.%s",
path, r.Family, r.Release, result.Family, result.Release)
}
logging.Log.Infof("Previous json is different family.Release: %s, pre: %s.%s cur: %s.%s",
path, r.Family, r.Release, result.Family, result.Release)
}
}
return prevs, nil
@@ -141,7 +144,7 @@ func getPlusDiffCves(previous, current models.ScanResult) models.VulnInfos {
// TODO commented out because a bug of diff logic when multiple oval defs found for a certain CVE-ID and same updated_at
// if these OVAL defs have different affected packages, this logic detects as updated.
// This logic will be uncomented after integration with gost https://github.com/knqyf263/gost
// This logic will be uncomented after integration with gost https://github.com/vulsio/gost
// } else if isCveFixed(v, previous) {
// updated[v.CveID] = v
// logging.Log.Debugf("fixed: %s", v.CveID)
@@ -194,30 +197,34 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
models.NewCveContentType(current.Family),
}
prevLastModified := map[models.CveContentType]time.Time{}
prevLastModified := map[models.CveContentType][]time.Time{}
preVinfo, ok := previous.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if content, ok := preVinfo.CveContents[cType]; ok {
prevLastModified[cType] = content.LastModified
if conts, ok := preVinfo.CveContents[cType]; ok {
for _, cont := range conts {
prevLastModified[cType] = append(prevLastModified[cType], cont.LastModified)
}
}
}
curLastModified := map[models.CveContentType]time.Time{}
curLastModified := map[models.CveContentType][]time.Time{}
curVinfo, ok := current.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if content, ok := curVinfo.CveContents[cType]; ok {
curLastModified[cType] = content.LastModified
if conts, ok := curVinfo.CveContents[cType]; ok {
for _, cont := range conts {
curLastModified[cType] = append(curLastModified[cType], cont.LastModified)
}
}
}
for _, t := range cTypes {
if !curLastModified[t].Equal(prevLastModified[t]) {
if !reflect.DeepEqual(curLastModified[t], prevLastModified[t]) {
logging.Log.Debugf("%s LastModified not equal: \n%s\n%s",
cveID, curLastModified[t], prevLastModified[t])
return true

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package detector
import (

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package detector
import (

145
go.mod
View File

@@ -1,24 +1,33 @@
module github.com/future-architect/vuls
go 1.16
go 1.17
require (
github.com/Azure/azure-sdk-for-go v50.2.0+incompatible
github.com/BurntSushi/toml v0.3.1
github.com/aquasecurity/fanal v0.0.0-20210119051230-28c249da7cfd
github.com/aquasecurity/trivy v0.16.0
github.com/aquasecurity/trivy-db v0.0.0-20210121143430-2a5c54036a86
github.com/BurntSushi/toml v0.4.1
github.com/Ullaakut/nmap/v2 v2.1.2-0.20210406060955-59a52fe80a4f
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/aquasecurity/fanal v0.0.0-20210815095355-42429a80d0e3
github.com/aquasecurity/trivy v0.19.3-0.20210909113250-19c0b70d2613
github.com/aquasecurity/trivy-db v0.0.0-20210809142931-da8e09204404
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/aws/aws-sdk-go v1.36.31
github.com/aws/aws-sdk-go v1.40.22
github.com/boltdb/bolt v1.3.1
github.com/briandowns/spinner v1.16.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheggaaa/pb/v3 v3.0.8 // indirect
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
github.com/emersion/go-smtp v0.14.0
github.com/fatih/color v1.12.0 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-redis/redis/v8 v8.11.3 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/google/subcommands v1.2.0
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.2.1
github.com/hashicorp/go-version v1.3.0
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
github.com/jesseduffield/gocui v0.3.0
github.com/k0kubun/pp v3.0.1+incompatible
@@ -26,35 +35,119 @@ require (
github.com/knqyf263/go-cpe v0.0.0-20201213041631-54f6ab28673f
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
github.com/knqyf263/gost v0.1.10
github.com/kotakanbe/go-cve-dictionary v0.5.10
github.com/kotakanbe/go-pingscanner v0.1.0
github.com/kotakanbe/goval-dictionary v0.3.3
github.com/kotakanbe/logrus-prefixed-formatter v0.0.0-20180123152602-928f7356cb96
github.com/lib/pq v1.10.0 // indirect
github.com/magiconair/properties v1.8.4 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/nlopes/slack v0.6.0
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 // indirect
github.com/olekukonko/tablewriter v0.0.5
github.com/parnurzeal/gorequest v0.2.16
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
github.com/sirupsen/logrus v1.7.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/afero v1.6.0
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.1.3
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/takuzoo3868/go-msfdb v0.1.5
github.com/vulsio/go-exploitdb v0.1.7
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
golang.org/x/net v0.0.0-20210323141857-08027d57d8cf // indirect
golang.org/x/oauth2 v0.0.0-20210125201302-af13f521f196
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.2.1
github.com/vulsio/go-cve-dictionary v0.8.1
github.com/vulsio/go-exploitdb v0.4.0
github.com/vulsio/go-msfdb v0.2.0
github.com/vulsio/gost v0.4.1-0.20210919121048-2a7957bf1885
github.com/vulsio/goval-dictionary v0.6.1
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20210902165921-8d991716f632 // indirect
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect
gorm.io/driver/mysql v1.1.2 // indirect
gorm.io/driver/postgres v1.1.1 // indirect
gorm.io/driver/sqlite v1.1.5 // indirect
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009
)
require (
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.1 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.0 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/PuerkitoBio/goquery v1.7.1 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/aquasecurity/go-dep-parser v0.0.0-20210815080135-5be65146849a // 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
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
github.com/caarlos0/env/v6 v6.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-github/v33 v33.0.0 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/wire v0.4.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/htcat/htcat v1.0.2 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.10.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.1.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.8.1 // indirect
github.com/jackc/pgx/v4 v4.13.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.8.1 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/ymomoi/goval-parser v0.0.0-20170813122243-0a0be1dd9d08 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.17.0 // indirect
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gorm.io/gorm v1.21.15 // indirect
moul.io/http2curl v1.0.0 // indirect
)

1474
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package gost
@@ -5,11 +6,12 @@ package gost
import (
"encoding/json"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/knqyf263/gost/models"
debver "github.com/knqyf263/go-deb-version"
gostmodels "github.com/vulsio/gost/models"
"golang.org/x/xerrors"
)
// Debian is Gost client for Debian GNU/Linux
@@ -21,6 +23,7 @@ type packCves struct {
packName string
isSrcPack bool
cves []models.CveContent
fixes models.PackageFixStatuses
}
func (deb Debian) supported(major string) bool {
@@ -28,23 +31,23 @@ func (deb Debian) supported(major string) bool {
"8": "jessie",
"9": "stretch",
"10": "buster",
"11": "bullseye",
}[major]
return ok
}
// DetectUnfixed fills cve information that has in Gost
func (deb Debian) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err error) {
// DetectCVEs fills cve information that has in Gost
func (deb Debian) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
if !deb.supported(major(r.Release)) {
// only logging
logging.Log.Warnf("Debian %s is not supported yet", r.Release)
return 0, nil
}
linuxImage := "linux-image-" + r.RunningKernel.Release
// Add linux and set the version of running kernel to search OVAL.
// Add linux and set the version of running kernel to search Gost.
if r.Container.ContainerID == "" {
newVer := ""
if p, ok := r.Packages[linuxImage]; ok {
if p, ok := r.Packages["linux-image-"+r.RunningKernel.Release]; ok {
newVer = p.NewVersion
}
r.Packages["linux"] = models.Package{
@@ -54,18 +57,35 @@ func (deb Debian) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err er
}
}
// Debian Security Tracker does not support Package for Raspbian, so skip it.
var scanResult models.ScanResult
if r.Family != constant.Raspbian {
scanResult = *r
} else {
scanResult = r.RemoveRaspbianPackFromResult()
stashLinuxPackage := r.Packages["linux"]
nFixedCVEs, err := deb.detectCVEsWithFixState(r, "resolved")
if err != nil {
return 0, err
}
r.Packages["linux"] = stashLinuxPackage
nUnfixedCVEs, err := deb.detectCVEsWithFixState(r, "open")
if err != nil {
return 0, err
}
return (nFixedCVEs + nUnfixedCVEs), nil
}
func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string) (nCVEs int, err error) {
if fixStatus != "resolved" && fixStatus != "open" {
return 0, xerrors.Errorf(`Failed to detectCVEsWithFixState. fixStatus is not allowed except "open" and "resolved"(actual: fixStatus -> %s).`, fixStatus)
}
packCvesList := []packCves{}
if deb.DBDriver.Cnf.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(deb.DBDriver.Cnf.GetURL(), "debian", major(scanResult.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, url)
url, _ := util.URLPathJoin(deb.DBDriver.Cnf.GetURL(), "debian", major(r.Release), "pkgs")
s := "unfixed-cves"
if s == "resolved" {
s = "fixed-cves"
}
responses, err := getCvesWithFixStateViaHTTP(r, url, s)
if err != nil {
return 0, err
}
@@ -76,43 +96,40 @@ func (deb Debian) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err er
return 0, err
}
cves := []models.CveContent{}
fixes := []models.PackageFixStatus{}
for _, debcve := range debCves {
cves = append(cves, *deb.ConvertToModel(&debcve))
fixes = append(fixes, checkPackageFixStatus(&debcve)...)
}
packCvesList = append(packCvesList, packCves{
packName: res.request.packName,
isSrcPack: res.request.isSrcPack,
cves: cves,
fixes: fixes,
})
}
} else {
if deb.DBDriver.DB == nil {
return 0, nil
}
for _, pack := range scanResult.Packages {
cveDebs := deb.DBDriver.DB.GetUnfixedCvesDebian(major(scanResult.Release), pack.Name)
cves := []models.CveContent{}
for _, cveDeb := range cveDebs {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
}
for _, pack := range r.Packages {
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: false,
cves: cves,
fixes: fixes,
})
}
// SrcPack
for _, pack := range scanResult.SrcPackages {
cveDebs := deb.DBDriver.DB.GetUnfixedCvesDebian(major(scanResult.Release), pack.Name)
cves := []models.CveContent{}
for _, cveDeb := range cveDebs {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
}
for _, pack := range r.SrcPackages {
cves, fixes := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: true,
cves: cves,
fixes: fixes,
})
}
}
@@ -120,13 +137,14 @@ func (deb Debian) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err er
delete(r.Packages, "linux")
for _, p := range packCvesList {
for _, cve := range p.cves {
for i, cve := range p.cves {
v, ok := r.ScannedCves[cve.CveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.DebianSecurityTracker] = cve
v.CveContents[models.DebianSecurityTracker] = []models.CveContent{cve}
v.Confidences = models.Confidences{models.DebianSecurityTrackerMatch}
}
} else {
v = models.VulnInfo{
@@ -134,6 +152,31 @@ func (deb Debian) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err er
CveContents: models.NewCveContents(cve),
Confidences: models.Confidences{models.DebianSecurityTrackerMatch},
}
if fixStatus == "resolved" {
versionRelease := ""
if p.isSrcPack {
versionRelease = r.SrcPackages[p.packName].Version
} else {
versionRelease = r.Packages[p.packName].FormatVer()
}
if versionRelease == "" {
break
}
affected, err := isGostDefAffected(versionRelease, p.fixes[i].FixedIn)
if err != nil {
logging.Log.Debugf("Failed to parse versions: %s, Ver: %s, Gost: %s",
err, versionRelease, p.fixes[i].FixedIn)
continue
}
if !affected {
continue
}
}
nCVEs++
}
@@ -148,25 +191,65 @@ func (deb Debian) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err er
}
} else {
if p.packName == "linux" {
names = append(names, linuxImage)
names = append(names, "linux-image-"+r.RunningKernel.Release)
} else {
names = append(names, p.packName)
}
}
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixState: "open",
NotFixedYet: true,
})
if fixStatus == "resolved" {
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixedIn: p.fixes[i].FixedIn,
})
}
} else {
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixState: "open",
NotFixedYet: true,
})
}
}
r.ScannedCves[cve.CveID] = v
}
}
return nCVEs, nil
}
func isGostDefAffected(versionRelease, gostVersion string) (affected bool, err error) {
vera, err := debver.NewVersion(versionRelease)
if err != nil {
return false, err
}
verb, err := debver.NewVersion(gostVersion)
if err != nil {
return false, err
}
return vera.LessThan(verb), nil
}
func (deb Debian) getCvesDebianWithfixStatus(fixStatus, release, pkgName string) (cves []models.CveContent, fixes []models.PackageFixStatus) {
var f func(string, string) map[string]gostmodels.DebianCVE
if fixStatus == "resolved" {
f = deb.DBDriver.DB.GetFixedCvesDebian
} else {
f = deb.DBDriver.DB.GetUnfixedCvesDebian
}
for _, cveDeb := range f(release, pkgName) {
cves = append(cves, *deb.ConvertToModel(&cveDeb))
fixes = append(fixes, checkPackageFixStatus(&cveDeb)...)
}
return
}
// ConvertToModel converts gost model to vuls model
func (deb Debian) ConvertToModel(cve *gostmodels.DebianCVE) *models.CveContent {
severity := ""
@@ -188,3 +271,22 @@ func (deb Debian) ConvertToModel(cve *gostmodels.DebianCVE) *models.CveContent {
},
}
}
func checkPackageFixStatus(cve *gostmodels.DebianCVE) []models.PackageFixStatus {
fixes := []models.PackageFixStatus{}
for _, p := range cve.Package {
for _, r := range p.Release {
f := models.PackageFixStatus{Name: p.PackageName}
if r.Status == "open" {
f.NotFixedYet = true
} else {
f.FixedIn = r.FixedVersion
}
fixes = append(fixes, f)
}
}
return fixes
}

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package gost
import "testing"
@@ -36,10 +39,17 @@ func TestDebian_Supported(t *testing.T) {
want: true,
},
{
name: "11 is not supported yet",
name: "11 is supported",
args: args{
major: "11",
},
want: true,
},
{
name: "12 is not supported yet",
args: args{
major: "12",
},
want: false,
},
{

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package gost
@@ -6,7 +7,7 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/knqyf263/gost/db"
"github.com/vulsio/gost/db"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
@@ -20,7 +21,8 @@ type DBDriver struct {
// Client is the interface of OVAL client.
type Client interface {
DetectUnfixed(*models.ScanResult, bool) (int, error)
DetectCVEs(*models.ScanResult, bool) (int, error)
CloseDB() error
}
// Base is a base struct
@@ -28,6 +30,14 @@ type Base struct {
DBDriver DBDriver
}
// CloseDB close a DB connection
func (b Base) CloseDB() error {
if b.DBDriver.DB == nil {
return nil
}
return b.DBDriver.DB.CloseDB()
}
// FillCVEsWithRedHat fills CVE detailed with Red Hat Security
func FillCVEsWithRedHat(r *models.ScanResult, cnf config.GostConf) error {
db, locked, err := newGostDB(cnf)
@@ -56,14 +66,16 @@ func NewClient(cnf config.GostConf, family string) (Client, error) {
driver := DBDriver{DB: db, Cnf: &cnf}
switch family {
case constant.RedHat, constant.CentOS:
case constant.RedHat, constant.CentOS, constant.Rocky, constant.Alma:
return RedHat{Base{DBDriver: driver}}, nil
case constant.Debian, constant.Raspbian:
return Debian{Base{DBDriver: driver}}, nil
case constant.Ubuntu:
return Ubuntu{Base{DBDriver: driver}}, nil
case constant.Windows:
return Microsoft{Base{DBDriver: driver}}, nil
default:
return Pseudo{}, nil
return Pseudo{Base{DBDriver: driver}}, nil
}
}

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package gost
import (
@@ -5,7 +8,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
func TestSetPackageStates(t *testing.T) {

View File

@@ -1,12 +1,14 @@
//go:build !scanner
// +build !scanner
package gost
import (
"sort"
"strings"
"github.com/future-architect/vuls/models"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
// Microsoft is Gost client for windows
@@ -14,8 +16,8 @@ type Microsoft struct {
Base
}
// DetectUnfixed fills cve information that has in Gost
func (ms Microsoft) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err error) {
// DetectCVEs fills cve information that has in Gost
func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
if ms.DBDriver.DB == nil {
return 0, nil
}
@@ -32,7 +34,7 @@ func (ms Microsoft) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err
if v.CveContents == nil {
v.CveContents = models.CveContents{}
}
v.CveContents[models.Microsoft] = *cveCont
v.CveContents[models.Microsoft] = []models.CveContent{*cveCont}
v.Mitigations = append(v.Mitigations, mitigations...)
r.ScannedCves[cveID] = v
}
@@ -41,6 +43,9 @@ func (ms Microsoft) DetectUnfixed(r *models.ScanResult, _ bool) (nCVEs int, err
// ConvertToModel converts gost model to vuls model
func (ms Microsoft) ConvertToModel(cve *gostmodels.MicrosoftCVE) (*models.CveContent, []models.Mitigation) {
sort.Slice(cve.ScoreSets, func(i, j int) bool {
return cve.ScoreSets[i].Vector < cve.ScoreSets[j].Vector
})
v3score := 0.0
var v3Vector string
for _, scoreSet := range cve.ScoreSets {

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package gost
@@ -11,7 +12,7 @@ type Pseudo struct {
Base
}
// DetectUnfixed fills cve information that has in Gost
func (pse Pseudo) DetectUnfixed(r *models.ScanResult, _ bool) (int, error) {
// DetectCVEs fills cve information that has in Gost
func (pse Pseudo) DetectCVEs(_ *models.ScanResult, _ bool) (int, error) {
return 0, nil
}

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package gost
@@ -10,7 +11,7 @@ import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/knqyf263/gost/models"
gostmodels "github.com/vulsio/gost/models"
)
// RedHat is Gost client for RedHat family linux
@@ -18,8 +19,8 @@ type RedHat struct {
Base
}
// DetectUnfixed fills cve information that has in Gost
func (red RedHat) DetectUnfixed(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
// DetectCVEs fills cve information that has in Gost
func (red RedHat) DetectCVEs(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs int, err error) {
if red.DBDriver.Cnf.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(red.DBDriver.Cnf.GetURL(), "redhat", major(r.Release), "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
@@ -102,7 +103,7 @@ func (red RedHat) setFixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models.S
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
v.CveContents[models.RedHatAPI] = []models.CveContent{*cveCont}
}
} else {
v = models.VulnInfo{
@@ -122,7 +123,7 @@ func (red RedHat) setUnfixedCveToScanResult(cve *gostmodels.RedhatCVE, r *models
if v.CveContents == nil {
v.CveContents = models.NewCveContents(*cveCont)
} else {
v.CveContents[models.RedHatAPI] = *cveCont
v.CveContents[models.RedHatAPI] = []models.CveContent{*cveCont}
}
} else {
v = models.VulnInfo{

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package gost
import (

191
gost/ubuntu.go Normal file
View File

@@ -0,0 +1,191 @@
//go:build !scanner
// +build !scanner
package gost
import (
"encoding/json"
"strings"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
gostmodels "github.com/vulsio/gost/models"
)
// Ubuntu is Gost client for Ubuntu
type Ubuntu struct {
Base
}
func (ubu Ubuntu) supported(version string) bool {
_, ok := map[string]string{
"1404": "trusty",
"1604": "xenial",
"1804": "bionic",
"2004": "focal",
"2010": "groovy",
"2104": "hirsute",
}[version]
return ok
}
// DetectCVEs fills cve information that has in Gost
func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
ubuReleaseVer := strings.Replace(r.Release, ".", "", 1)
if !ubu.supported(ubuReleaseVer) {
logging.Log.Warnf("Ubuntu %s is not supported yet", r.Release)
return 0, nil
}
linuxImage := "linux-image-" + r.RunningKernel.Release
// Add linux and set the version of running kernel to search Gost.
if r.Container.ContainerID == "" {
newVer := ""
if p, ok := r.Packages[linuxImage]; ok {
newVer = p.NewVersion
}
r.Packages["linux"] = models.Package{
Name: "linux",
Version: r.RunningKernel.Version,
NewVersion: newVer,
}
}
packCvesList := []packCves{}
if ubu.DBDriver.Cnf.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(ubu.DBDriver.Cnf.GetURL(), "ubuntu", ubuReleaseVer, "pkgs")
responses, err := getAllUnfixedCvesViaHTTP(r, url)
if err != nil {
return 0, err
}
for _, res := range responses {
ubuCves := map[string]gostmodels.UbuntuCVE{}
if err := json.Unmarshal([]byte(res.json), &ubuCves); err != nil {
return 0, err
}
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
}
packCvesList = append(packCvesList, packCves{
packName: res.request.packName,
isSrcPack: res.request.isSrcPack,
cves: cves,
})
}
} else {
if ubu.DBDriver.DB == nil {
return 0, nil
}
for _, pack := range r.Packages {
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: false,
cves: cves,
})
}
// SrcPack
for _, pack := range r.SrcPackages {
ubuCves := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
cves = append(cves, *ubu.ConvertToModel(&ubucve))
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
isSrcPack: true,
cves: cves,
})
}
}
delete(r.Packages, "linux")
for _, p := range packCvesList {
for _, cve := range p.cves {
v, ok := r.ScannedCves[cve.CveID]
if ok {
if v.CveContents == nil {
v.CveContents = models.NewCveContents(cve)
} else {
v.CveContents[models.UbuntuAPI] = []models.CveContent{cve}
}
} else {
v = models.VulnInfo{
CveID: cve.CveID,
CveContents: models.NewCveContents(cve),
Confidences: models.Confidences{models.UbuntuAPIMatch},
}
nCVEs++
}
names := []string{}
if p.isSrcPack {
if srcPack, ok := r.SrcPackages[p.packName]; ok {
for _, binName := range srcPack.BinaryNames {
if _, ok := r.Packages[binName]; ok {
names = append(names, binName)
}
}
}
} else {
if p.packName == "linux" {
names = append(names, linuxImage)
} else {
names = append(names, p.packName)
}
}
for _, name := range names {
v.AffectedPackages = v.AffectedPackages.Store(models.PackageFixStatus{
Name: name,
FixState: "open",
NotFixedYet: true,
})
}
r.ScannedCves[cve.CveID] = v
}
}
return nCVEs, nil
}
// ConvertToModel converts gost model to vuls model
func (ubu Ubuntu) ConvertToModel(cve *gostmodels.UbuntuCVE) *models.CveContent {
references := []models.Reference{}
for _, r := range cve.References {
if strings.Contains(r.Reference, "https://cve.mitre.org/cgi-bin/cvename.cgi?name=") {
references = append(references, models.Reference{Source: "CVE", Link: r.Reference})
} else {
references = append(references, models.Reference{Link: r.Reference})
}
}
for _, b := range cve.Bugs {
references = append(references, models.Reference{Source: "Bug", Link: b.Bug})
}
for _, u := range cve.Upstreams {
for _, upstreamLink := range u.UpstreamLinks {
references = append(references, models.Reference{Source: "UPSTREAM", Link: upstreamLink.Link})
}
}
return &models.CveContent{
Type: models.UbuntuAPI,
CveID: cve.Candidate,
Summary: cve.Description,
Cvss2Severity: cve.Priority,
Cvss3Severity: cve.Priority,
SourceLink: "https://ubuntu.com/security/" + cve.Candidate,
References: references,
Published: cve.PublicDate,
}
}

137
gost/ubuntu_test.go Normal file
View File

@@ -0,0 +1,137 @@
package gost
import (
"reflect"
"testing"
"time"
"github.com/future-architect/vuls/models"
gostmodels "github.com/vulsio/gost/models"
)
func TestUbuntu_Supported(t *testing.T) {
type args struct {
ubuReleaseVer string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "14.04 is supported",
args: args{
ubuReleaseVer: "1404",
},
want: true,
},
{
name: "16.04 is supported",
args: args{
ubuReleaseVer: "1604",
},
want: true,
},
{
name: "18.04 is supported",
args: args{
ubuReleaseVer: "1804",
},
want: true,
},
{
name: "20.04 is supported",
args: args{
ubuReleaseVer: "2004",
},
want: true,
},
{
name: "20.10 is supported",
args: args{
ubuReleaseVer: "2010",
},
want: true,
},
{
name: "21.04 is supported",
args: args{
ubuReleaseVer: "2104",
},
want: true,
},
{
name: "empty string is not supported yet",
args: args{
ubuReleaseVer: "",
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ubu := Ubuntu{}
if got := ubu.supported(tt.args.ubuReleaseVer); got != tt.want {
t.Errorf("Ubuntu.Supported() = %v, want %v", got, tt.want)
}
})
}
}
func TestUbuntuConvertToModel(t *testing.T) {
tests := []struct {
name string
input gostmodels.UbuntuCVE
expected models.CveContent
}{
{
name: "gost Ubuntu.ConvertToModel",
input: gostmodels.UbuntuCVE{
Candidate: "CVE-2021-3517",
PublicDate: time.Date(2021, 5, 19, 14, 15, 0, 0, time.UTC),
References: []gostmodels.UbuntuReference{
{Reference: "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3517"},
{Reference: "https://gitlab.gnome.org/GNOME/libxml2/-/issues/235"},
{Reference: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/bf22713507fe1fc3a2c4b525cf0a88c2dc87a3a2"}},
Description: "description.",
Notes: []gostmodels.UbuntuNote{},
Bugs: []gostmodels.UbuntuBug{{Bug: "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=987738"}},
Priority: "medium",
Patches: []gostmodels.UbuntuPatch{
{PackageName: "libxml2", ReleasePatches: []gostmodels.UbuntuReleasePatch{
{ReleaseName: "focal", Status: "needed", Note: ""},
}},
},
Upstreams: []gostmodels.UbuntuUpstream{{
PackageName: "libxml2", UpstreamLinks: []gostmodels.UbuntuUpstreamLink{
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/50f06b3efb638efb0abd95dc62dca05ae67882c2"},
},
}},
},
expected: models.CveContent{
Type: models.UbuntuAPI,
CveID: "CVE-2021-3517",
Summary: "description.",
Cvss2Severity: "medium",
Cvss3Severity: "medium",
SourceLink: "https://ubuntu.com/security/CVE-2021-3517",
References: []models.Reference{
{Source: "CVE", Link: "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3517"},
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/issues/235"},
{Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/bf22713507fe1fc3a2c4b525cf0a88c2dc87a3a2"},
{Source: "Bug", Link: "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=987738"},
{Source: "UPSTREAM", Link: "https://gitlab.gnome.org/GNOME/libxml2/-/commit/50f06b3efb638efb0abd95dc62dca05ae67882c2"}},
Published: time.Date(2021, 5, 19, 14, 15, 0, 0, time.UTC),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ubu := Ubuntu{}
got := ubu.ConvertToModel(&tt.input)
if !reflect.DeepEqual(got, &tt.expected) {
t.Errorf("Ubuntu.ConvertToModel() = %#v, want %#v", got, &tt.expected)
}
})
}
}

View File

@@ -1,3 +1,6 @@
//go:build !scanner
// +build !scanner
package gost
import (
@@ -83,7 +86,10 @@ type request struct {
func getAllUnfixedCvesViaHTTP(r *models.ScanResult, urlPrefix string) (
responses []response, err error) {
return getCvesWithFixStateViaHTTP(r, urlPrefix, "unfixed-cves")
}
func getCvesWithFixStateViaHTTP(r *models.ScanResult, urlPrefix, fixState string) (responses []response, err error) {
nReq := len(r.Packages) + len(r.SrcPackages)
reqChan := make(chan request, nReq)
resChan := make(chan response, nReq)
@@ -118,7 +124,7 @@ func getAllUnfixedCvesViaHTTP(r *models.ScanResult, urlPrefix string) (
url, err := util.URLPathJoin(
urlPrefix,
req.packName,
"unfixed-cves",
fixState,
)
if err != nil {
errChan <- err

4231
integration/data/lockfile/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,311 @@
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.2.6)
actionpack (= 4.2.6)
actionview (= 4.2.6)
activejob (= 4.2.6)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.6)
actionview (= 4.2.6)
activesupport (= 4.2.6)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionpack-action_caching (1.1.1)
actionpack (>= 4.0.0, < 5.0)
actionpack-xml_parser (1.0.2)
actionpack (>= 4.0.0, < 5)
actionview (4.2.6)
activesupport (= 4.2.6)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.6)
activesupport (= 4.2.6)
globalid (>= 0.3.0)
activemodel (4.2.6)
activesupport (= 4.2.6)
builder (~> 3.1)
activerecord (4.2.6)
activemodel (= 4.2.6)
activesupport (= 4.2.6)
arel (~> 6.0)
activesupport (4.2.6)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.4.0)
arel (6.0.3)
bourbon (4.2.7)
sass (~> 3.4)
thor (~> 0.19)
builder (3.2.2)
byebug (8.2.4)
capistrano (3.4.1)
i18n
rake (>= 10.0.0)
sshkit (~> 1.3)
capistrano-bundler (1.1.4)
capistrano (~> 3.1)
sshkit (~> 1.2)
capistrano-passenger (0.2.0)
capistrano (~> 3.0)
capistrano-rails (1.1.6)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
capybara (2.7.0)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
childprocess (0.5.9)
ffi (~> 1.0, >= 1.0.11)
coderay (1.1.1)
concurrent-ruby (1.0.1)
css_parser (1.3.7)
addressable
daemons (1.2.3)
database_cleaner (1.5.2)
diff-lcs (1.2.5)
docile (1.1.5)
erubis (2.7.0)
eventmachine (1.2.0.1)
faraday (0.8.11)
multipart-post (~> 1.2.0)
faraday_middleware (0.9.2)
faraday (>= 0.7.4, < 0.10)
ffi (1.9.10)
fuubar (2.0.0)
rspec (~> 3.0)
ruby-progressbar (~> 1.4)
gemoji (1.5.0)
globalid (0.3.6)
activesupport (>= 4.1.0)
hashie (1.2.0)
headless (2.2.3)
htmlentities (4.3.1)
i18n (0.7.0)
inifile (3.0.0)
jquery-rails (3.1.4)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
le (2.7.1)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.4)
mime-types (>= 1.16, < 4)
metaclass (0.0.4)
method_source (0.8.2)
mime-types (3.0)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0221)
mini_portile2 (2.0.0)
minitest (5.8.4)
mocha (1.1.0)
metaclass (~> 0.0.1)
multi_json (1.11.2)
multipart-post (1.2.0)
net-ldap (0.12.1)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (3.1.1)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
pg (0.18.4)
power_assert (0.2.7)
protected_attributes (1.1.3)
activemodel (>= 4.0.1, < 5.0)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-byebug (3.3.0)
byebug (~> 8.0)
pry (~> 0.10)
pry-nav (0.2.4)
pry (>= 0.9.10, < 0.11.0)
rack (1.6.4)
rack-openid (1.4.2)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.6)
actionmailer (= 4.2.6)
actionpack (= 4.2.6)
actionview (= 4.2.6)
activejob (= 4.2.6)
activemodel (= 4.2.6)
activerecord (= 4.2.6)
activesupport (= 4.2.6)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.6)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (1.0.7)
activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
railties (4.2.6)
actionpack (= 4.2.6)
activesupport (= 4.2.6)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (11.1.2)
rbpdf (1.19.0)
htmlentities (= 4.3.1)
rbpdf-font (~> 1.19.0)
rbpdf-font (1.19.0)
rdoc (4.2.2)
json (~> 1.4)
redcarpet (3.3.4)
request_store (1.0.5)
rmagick (2.15.4)
roadie (3.1.1)
css_parser (~> 1.3.4)
nokogiri (>= 1.5.0, < 1.7.0)
roadie-rails (1.1.1)
railties (>= 3.0, < 5.1)
roadie (~> 3.1)
rspec (3.4.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-core (3.4.4)
rspec-support (~> 3.4.0)
rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-mocks (3.4.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-rails (3.4.2)
actionpack (>= 3.0, < 4.3)
activesupport (>= 3.0, < 4.3)
railties (>= 3.0, < 4.3)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-support (~> 3.4.0)
rspec-support (3.4.1)
ruby-openid (2.3.0)
ruby-progressbar (1.7.5)
rubyzip (1.2.0)
sass (3.4.22)
selenium-webdriver (2.53.0)
childprocess (~> 0.5)
rubyzip (~> 1.0)
websocket (~> 1.0)
simplecov (0.9.2)
docile (~> 1.1.0)
multi_json (~> 1.0)
simplecov-html (~> 0.9.0)
simplecov-html (0.9.0)
simplecov-rcov (0.2.3)
simplecov (>= 0.4.1)
slim (3.0.6)
temple (~> 0.7.3)
tilt (>= 1.3.3, < 2.1)
slop (3.6.0)
sprockets (3.6.0)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.0.4)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sshkit (1.9.0)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
temple (0.7.6)
test-unit (3.1.8)
power_assert
thin (1.6.4)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (~> 1.0)
thor (0.19.1)
thread_safe (0.3.5)
tilt (2.0.2)
transifex-ruby-fork-jg (0.1.0)
faraday (~> 0.8.0)
faraday_middleware (~> 0.9.0)
hashie (~> 1.2.0)
tzinfo (1.2.2)
thread_safe (~> 0.1)
websocket (1.2.3)
xpath (2.0.0)
nokogiri (~> 1.3)
yard (0.8.7.6)
PLATFORMS
ruby
DEPENDENCIES
actionpack-action_caching
actionpack-xml_parser
activerecord-jdbc-adapter (~> 1.3.2)
activerecord-jdbcpostgresql-adapter
bourbon
builder (>= 3.0.4)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1.2)
capistrano-passenger
capistrano-rails (~> 1.1)
capybara
coderay (~> 1.1.0)
database_cleaner
fuubar
gemoji (= 1.5.0)
headless
inifile
jquery-rails (~> 3.1.4)
le
mime-types (~> 3.0)
minitest
mocha
net-ldap (~> 0.12.0)
nokogiri (>= 1.6.7.2)
pg (~> 0.18.1)
protected_attributes
pry
pry-byebug
pry-nav
rack-openid
rails (= 4.2.6)
rails-dom-testing
rails-html-sanitizer (>= 1.0.3)
rbpdf (~> 1.19.0)
rdoc (>= 2.4.2)
redcarpet (~> 3.3.2)
request_store (= 1.0.5)
rmagick (>= 2.14.0)
roadie-rails
rspec (~> 3.0)
rspec-rails
ruby-openid (~> 2.3.0)
sass
selenium-webdriver
simplecov (~> 0.9.1)
simplecov-rcov
slim
test-unit
thin
transifex-ruby-fork-jg (= 0.1.0)
tzinfo-data
yard
BUNDLED WITH
1.11.2

650
integration/data/lockfile/Pipfile.lock generated Normal file
View File

@@ -0,0 +1,650 @@
{
"_meta": {
"hash": {
"sha256": "947e36f68d4acdd1ec855ae6f4a38c54c59773bf89725674a97dc4d5d4f512ca"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.9"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"babel": {
"hashes": [
"sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5",
"sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.9.0"
},
"certifi": {
"hashes": [
"sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
"sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
],
"version": "==2020.12.5"
},
"chardet": {
"hashes": [
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"click": {
"hashes": [
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==7.1.2"
},
"flask": {
"hashes": [
"sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060",
"sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"
],
"index": "pypi",
"version": "==0.1.2"
},
"flask-talisman": {
"hashes": [
"sha256:468131464a249274ed226efc21b372518f442487e58918ccab8357eaa638fd1f",
"sha256:eaa754f4b771dfbe473843391d69643b79e3a38c865790011ac5e4179c68e3ec"
],
"index": "pypi",
"version": "==0.7.0"
},
"gunicorn": {
"hashes": [
"sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626",
"sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"
],
"index": "pypi",
"version": "==20.0.4"
},
"idna": {
"hashes": [
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
},
"itsdangerous": {
"hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.0"
},
"jinja2": {
"hashes": [
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==0.11.3"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
"sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f",
"sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39",
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
"sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014",
"sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f",
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
"sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85",
"sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1",
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
"sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850",
"sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0",
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
"sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb",
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
"sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1",
"sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2",
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
"sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7",
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
"sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8",
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
"sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193",
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
"sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b",
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
"sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5",
"sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c",
"sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032",
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.1"
},
"omise": {
"hashes": [
"sha256:15d5f0ae466d6d5fda7d53f99fd92c08be86d3b4e8162ae7e75ff2246e35d57c",
"sha256:d4fa58da2aae4e08ece622db8b27fe24158a7ecb2d50acf90b5496d7bdd3a73f"
],
"index": "pypi",
"version": "==0.11.0"
},
"py-money": {
"hashes": [
"sha256:6c0f3597022a7d16fe65273c046614b7f30dd63aa0a0765ac7044092e2959014",
"sha256:e2ba7fe399a2986913753735874063c5cb816941bba737db7ec1353a04321338"
],
"index": "pypi",
"version": "==0.5.0"
},
"python-dotenv": {
"hashes": [
"sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e",
"sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"
],
"index": "pypi",
"version": "==0.15.0"
},
"pytz": {
"hashes": [
"sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
"sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
],
"version": "==2021.1"
},
"requests": {
"hashes": [
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.25.1"
},
"six": {
"hashes": [
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.15.0"
},
"urllib3": {
"hashes": [
"sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80",
"sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==0.26.3"
},
"werkzeug": {
"hashes": [
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.0.1"
}
},
"develop": {
"appdirs": {
"hashes": [
"sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
"sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
],
"version": "==1.4.4"
},
"astroid": {
"hashes": [
"sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703",
"sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"
],
"markers": "python_version >= '3.5'",
"version": "==2.4.2"
},
"attrs": {
"hashes": [
"sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
"sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.3.0"
},
"autopep8": {
"hashes": [
"sha256:9e136c472c475f4ee4978b51a88a494bfcd4e3ed17950a44a988d9e434837bea",
"sha256:cae4bc0fb616408191af41d062d7ec7ef8679c7f27b068875ca3a9e2878d5443"
],
"index": "pypi",
"version": "==1.5.5"
},
"black": {
"hashes": [
"sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"
],
"markers": "python_version >= '3.6'",
"version": "==20.8b1"
},
"click": {
"hashes": [
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==7.1.2"
},
"flake8": {
"hashes": [
"sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839",
"sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"
],
"version": "==3.8.4"
},
"iniconfig": {
"hashes": [
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
"sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
],
"version": "==1.1.1"
},
"isort": {
"hashes": [
"sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e",
"sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"
],
"markers": "python_version >= '3.6' and python_version < '4.0'",
"version": "==5.7.0"
},
"jedi": {
"hashes": [
"sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20",
"sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"
],
"index": "pypi",
"version": "==0.17.2"
},
"lazy-object-proxy": {
"hashes": [
"sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d",
"sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449",
"sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08",
"sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a",
"sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50",
"sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd",
"sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239",
"sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb",
"sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea",
"sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e",
"sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156",
"sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142",
"sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442",
"sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62",
"sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db",
"sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531",
"sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383",
"sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a",
"sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357",
"sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4",
"sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.4.3"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"mypy": {
"hashes": [
"sha256:0d2fc8beb99cd88f2d7e20d69131353053fbecea17904ee6f0348759302c52fa",
"sha256:2b216eacca0ec0ee124af9429bfd858d5619a0725ee5f88057e6e076f9eb1a7b",
"sha256:319ee5c248a7c3f94477f92a729b7ab06bf8a6d04447ef3aa8c9ba2aa47c6dcf",
"sha256:3e0c159a7853e3521e3f582adb1f3eac66d0b0639d434278e2867af3a8c62653",
"sha256:5615785d3e2f4f03ab7697983d82c4b98af5c321614f51b8f1034eb9ebe48363",
"sha256:5ff616787122774f510caeb7b980542a7cc2222be3f00837a304ea85cd56e488",
"sha256:6f8425fecd2ba6007e526209bb985ce7f49ed0d2ac1cc1a44f243380a06a84fb",
"sha256:74f5aa50d0866bc6fb8e213441c41e466c86678c800700b87b012ed11c0a13e0",
"sha256:90b6f46dc2181d74f80617deca611925d7e63007cf416397358aa42efb593e07",
"sha256:947126195bfe4709c360e89b40114c6746ae248f04d379dca6f6ab677aa07641",
"sha256:a301da58d566aca05f8f449403c710c50a9860782148332322decf73a603280b",
"sha256:aa9d4901f3ee1a986a3a79fe079ffbf7f999478c281376f48faa31daaa814e86",
"sha256:b9150db14a48a8fa114189bfe49baccdff89da8c6639c2717750c7ae62316738",
"sha256:b95068a3ce3b50332c40e31a955653be245666a4bc7819d3c8898aa9fb9ea496",
"sha256:ca7ad5aed210841f1e77f5f2f7d725b62c78fa77519312042c719ed2ab937876",
"sha256:d16c54b0dffb861dc6318a8730952265876d90c5101085a4bc56913e8521ba19",
"sha256:e0202e37756ed09daf4b0ba64ad2c245d357659e014c3f51d8cd0681ba66940a",
"sha256:e1c84c65ff6d69fb42958ece5b1255394714e0aac4df5ffe151bc4fe19c7600a",
"sha256:e32b7b282c4ed4e378bba8b8dfa08e1cfa6f6574067ef22f86bee5b1039de0c9",
"sha256:e3b8432f8df19e3c11235c4563a7250666dc9aa7cdda58d21b4177b20256ca9f",
"sha256:e497a544391f733eca922fdcb326d19e894789cd4ff61d48b4b195776476c5cf",
"sha256:f5fdf935a46aa20aa937f2478480ebf4be9186e98e49cc3843af9a5795a49a25"
],
"markers": "python_version >= '3.5'",
"version": "==0.800"
},
"mypy-extensions": {
"hashes": [
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
],
"version": "==0.4.3"
},
"packaging": {
"hashes": [
"sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
"sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.9"
},
"parso": {
"hashes": [
"sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea",
"sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.7.1"
},
"pathspec": {
"hashes": [
"sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd",
"sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"
],
"version": "==0.8.1"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.13.1"
},
"py": {
"hashes": [
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.10.0"
},
"pycodestyle": {
"hashes": [
"sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
"sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
],
"version": "==2.6.0"
},
"pydocstyle": {
"hashes": [
"sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325",
"sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"
],
"version": "==5.1.1"
},
"pyflakes": {
"hashes": [
"sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
"sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
],
"version": "==2.2.0"
},
"pylint": {
"hashes": [
"sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210",
"sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"
],
"version": "==2.6.0"
},
"pyls-black": {
"hashes": [
"sha256:33700e5ed605636ea7ba39188a1362d2f8602f7301f8f2b8544773886f965663",
"sha256:8f5fb8fed503588c10435d2d48e2c3751437f1bdb8116134b05a4591c4899940"
],
"index": "pypi",
"version": "==0.4.6"
},
"pyls-isort": {
"hashes": [
"sha256:a6c292332746d3dc690f2a3dcdb9a01d913b9ee8444defe3cbffcddb7e3874eb"
],
"index": "pypi",
"version": "==0.2.0"
},
"pyls-mypy": {
"hashes": [
"sha256:3fd83028961f0ca9eb3048b7a01cf42a9e3d46d8ea4935c1424c33da22c3eb03"
],
"index": "pypi",
"version": "==0.1.8"
},
"pyparsing": {
"hashes": [
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"pytest": {
"hashes": [
"sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9",
"sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"
],
"index": "pypi",
"version": "==6.2.2"
},
"python-jsonrpc-server": {
"hashes": [
"sha256:62c543e541f101ec5b57dc654efc212d2c2e3ea47ff6f54b2e7dcb36ecf20595",
"sha256:e5a908ff182e620aac07db5f57887eeb0afe33993008f57dc1b85b594cea250c"
],
"version": "==0.4.0"
},
"python-language-server": {
"extras": [
"all"
],
"hashes": [
"sha256:9984c84a67ee2c5102c8e703215f407fcfa5e62b0ae86c9572d0ada8c4b417b0",
"sha256:a0ad0aca03f4a20c1c40f4f230c6773eac82c9b7cdb026cb09ba10237f4815d5"
],
"index": "pypi",
"version": "==0.36.2"
},
"regex": {
"hashes": [
"sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538",
"sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4",
"sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc",
"sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa",
"sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444",
"sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1",
"sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af",
"sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8",
"sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9",
"sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88",
"sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba",
"sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364",
"sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e",
"sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7",
"sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0",
"sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31",
"sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683",
"sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee",
"sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b",
"sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884",
"sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c",
"sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e",
"sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562",
"sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85",
"sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c",
"sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6",
"sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d",
"sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b",
"sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70",
"sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b",
"sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b",
"sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f",
"sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0",
"sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5",
"sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5",
"sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f",
"sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e",
"sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512",
"sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d",
"sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917",
"sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"
],
"version": "==2020.11.13"
},
"rope": {
"hashes": [
"sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04"
],
"version": "==0.18.0"
},
"six": {
"hashes": [
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.15.0"
},
"snowballstemmer": {
"hashes": [
"sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2",
"sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"
],
"version": "==2.1.0"
},
"toml": {
"hashes": [
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"typed-ast": {
"hashes": [
"sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1",
"sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d",
"sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6",
"sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd",
"sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37",
"sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151",
"sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07",
"sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440",
"sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70",
"sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496",
"sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea",
"sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400",
"sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc",
"sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606",
"sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc",
"sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581",
"sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412",
"sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a",
"sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2",
"sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787",
"sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f",
"sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937",
"sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64",
"sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487",
"sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b",
"sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41",
"sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a",
"sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3",
"sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166",
"sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"
],
"markers": "python_version < '3.8' and implementation_name == 'cpython'",
"version": "==1.4.2"
},
"typing-extensions": {
"hashes": [
"sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918",
"sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c",
"sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"
],
"markers": "python_version < '3.8'",
"version": "==3.7.4.3"
},
"ujson": {
"hashes": [
"sha256:0190d26c0e990c17ad072ec8593647218fe1c675d11089cd3d1440175b568967",
"sha256:0ea07fe57f9157118ca689e7f6db72759395b99121c0ff038d2e38649c626fb1",
"sha256:30962467c36ff6de6161d784cd2a6aac1097f0128b522d6e9291678e34fb2b47",
"sha256:4d6d061563470cac889c0a9fd367013a5dbd8efc36ad01ab3e67a57e56cad720",
"sha256:5e1636b94c7f1f59a8ead4c8a7bab1b12cc52d4c21ababa295ffec56b445fd2a",
"sha256:7333e8bc45ea28c74ae26157eacaed5e5629dbada32e0103c23eb368f93af108",
"sha256:84b1dca0d53b0a8d58835f72ea2894e4d6cf7a5dd8f520ab4cbd698c81e49737",
"sha256:91396a585ba51f84dc71c8da60cdc86de6b60ba0272c389b6482020a1fac9394",
"sha256:a214ba5a21dad71a43c0f5aef917cd56a2d70bc974d845be211c66b6742a471c",
"sha256:aad6d92f4d71e37ea70e966500f1951ecd065edca3a70d3861b37b176dd6702c",
"sha256:b3a6dcc660220539aa718bcc9dbd6dedf2a01d19c875d1033f028f212e36d6bb",
"sha256:b5c70704962cf93ec6ea3271a47d952b75ae1980d6c56b8496cec2a722075939",
"sha256:c615a9e9e378a7383b756b7e7a73c38b22aeb8967a8bfbffd4741f7ffd043c4d",
"sha256:d3a87888c40b5bfcf69b4030427cd666893e826e82cc8608d1ba8b4b5e04ea99",
"sha256:e2cadeb0ddc98e3963bea266cc5b884e5d77d73adf807f0bda9eca64d1c509d5",
"sha256:e390df0dcc7897ffb98e17eae1f4c442c39c91814c298ad84d935a3c5c7a32fa",
"sha256:e6e90330670c78e727d6637bb5a215d3e093d8e3570d439fd4922942f88da361",
"sha256:eb6b25a7670c7537a5998e695fa62ff13c7f9c33faf82927adf4daa460d5f62e",
"sha256:f273a875c0b42c2a019c337631bc1907f6fdfbc84210cc0d1fff0e2019bbfaec",
"sha256:f8aded54c2bc554ce20b397f72101737dd61ee7b81c771684a7dd7805e6cca0c",
"sha256:fc51e545d65689c398161f07fd405104956ec27f22453de85898fa088b2cd4bb"
],
"markers": "python_version >= '3.1'",
"version": "==4.0.2"
},
"wrapt": {
"hashes": [
"sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"
],
"version": "==1.12.1"
},
"yapf": {
"hashes": [
"sha256:3000abee4c28daebad55da6c85f3cd07b8062ce48e2e9943c8da1b9667d48427",
"sha256:3abf61ba67cf603069710d30acbc88cfe565d907e16ad81429ae90ce9651e0c9"
],
"version": "==0.30.0"
}
}
}

6229
integration/data/lockfile/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,707 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro=
cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg=
cloud.google.com/go v0.42.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
cloud.google.com/go v0.44.0/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.0/go.mod h1:452BcPOeI9AZfbvDw0Tbo7D32wA+WX9WME8AZwMEDZU=
cloud.google.com/go/bigquery v1.0.0/go.mod h1:W6nZUO55RX1ze8f54muIveLNA7ouiqcTlNELudKtFaM=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
code.gitea.io/gitea v1.9.0-dev/go.mod h1:wWyKwhnrzHgqiqguunHKA6yzZXYsLSC7V6WvI+GlOx8=
code.gitea.io/gitea v1.9.0-rc1/go.mod h1:WJbOBnfoAP54J4mP5ylCEKYxytCh8SMZBeSOBdcZBkw=
code.gitea.io/gitea v1.9.0-rc2/go.mod h1:3yZ+sXUqEshMeUwfr8bB3SvttSBcstgk2zXgePfDx4Y=
code.gitea.io/gitea v1.9.0/go.mod h1:HzXskRRacnLWs4z/B6Bt6gFpCl6cicdHM0GfZMTEmtI=
code.gitea.io/gitea v1.9.1/go.mod h1:HzXskRRacnLWs4z/B6Bt6gFpCl6cicdHM0GfZMTEmtI=
code.gitea.io/gitea v1.9.2/go.mod h1:HzXskRRacnLWs4z/B6Bt6gFpCl6cicdHM0GfZMTEmtI=
code.gitea.io/gitea v1.9.3/go.mod h1:HzXskRRacnLWs4z/B6Bt6gFpCl6cicdHM0GfZMTEmtI=
code.gitea.io/gitea v1.9.4/go.mod h1:nwqMi+nJMcJC7r+SdGt5RdDNLFkWwHZ+GpLKV13WifE=
code.gitea.io/gitea v1.9.5/go.mod h1:nwqMi+nJMcJC7r+SdGt5RdDNLFkWwHZ+GpLKV13WifE=
code.gitea.io/gitea v1.9.6/go.mod h1:mkxMeXN4KE+t6JLCNzKaFrM8SOOWZusNcuG3p5RI+f4=
code.gitea.io/gitea v1.10.0-dev/go.mod h1:WJbOBnfoAP54J4mP5ylCEKYxytCh8SMZBeSOBdcZBkw=
code.gitea.io/gitea v1.10.0-rc1/go.mod h1:Z/ysRJuQTNdT5BysAUhfPcKU7cv4X9h1qFrFN359cgw=
code.gitea.io/gitea v1.10.0-rc2/go.mod h1:Z/ysRJuQTNdT5BysAUhfPcKU7cv4X9h1qFrFN359cgw=
code.gitea.io/gitea v1.10.0/go.mod h1:Z/ysRJuQTNdT5BysAUhfPcKU7cv4X9h1qFrFN359cgw=
code.gitea.io/gitea v1.10.1/go.mod h1:DIJZcrFaYaSmWR2f2eSKO6j2n1mPSD2zVO7A/tdWxbM=
code.gitea.io/gitea v1.10.2/go.mod h1:DIJZcrFaYaSmWR2f2eSKO6j2n1mPSD2zVO7A/tdWxbM=
code.gitea.io/gitea v1.10.3/go.mod h1:DIJZcrFaYaSmWR2f2eSKO6j2n1mPSD2zVO7A/tdWxbM=
gitea.com/lunny/levelqueue v0.1.0/go.mod h1:G7hVb908t0Bl0uk7zGSg14fyzNtxgtD9Shf04wkMK7s=
gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b/go.mod h1:Cxadig6POWpPYYSfg23E7jo35Yf0yvsdC1lifoKWmPo=
gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76/go.mod h1:NFHb9Of+LUnU86bU20CiXXg6ZlgCJ4XytP14UsHOXFs=
gitea.com/macaron/captcha v0.0.0-20190822015246-daa973478bae/go.mod h1:J5h3N+1nKTXtU1x4GxexaQKgAz8UiWecNwi/CfX7CtQ=
gitea.com/macaron/cors v0.0.0-20190821152825-7dcef4a17175/go.mod h1:rtOK4J20kpMD9XcNsnO5YA843YSTe/MUMbDj/TJ/Q7A=
gitea.com/macaron/cors v0.0.0-20190826180238-95aec09ea8b4/go.mod h1:rtOK4J20kpMD9XcNsnO5YA843YSTe/MUMbDj/TJ/Q7A=
gitea.com/macaron/csrf v0.0.0-20190822024205-3dc5a4474439/go.mod h1:IsQPHx73HnnqFBYiVHjg87q4XBZyGXXu77xANukvZuk=
gitea.com/macaron/i18n v0.0.0-20190822004228-474e714e2223/go.mod h1:+qsc10s4hBsHKU/9luGGumFh4m5FFVc7uih+8/mM1NY=
gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM=
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM=
gitea.com/macaron/macaron v1.3.2/go.mod h1:x30d38SbJFBUEO2Mgz7loekCzr87U9UaUDNbSAOxg5k=
gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827/go.mod h1:/rvxMjIkOq4BM8uPUb+VHuU02ZfAO6R4+wD//tiCiRw=
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs=
gitea.com/macaron/macaron v1.4.0/go.mod h1:P7hfDbQjcW22lkYkXlxdRIfWOXxH2+K4EogN4Q0UlLY=
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705/go.mod h1:1ujH0jD6Ca4iK9NL0Q2a7fG2chvXx5hVa7hBfABwpkA=
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d/go.mod h1:FanKy3WjWb5iw/iZBPk4ggoQT9FcM6bkBPvmDmsH6tY=
gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7/go.mod h1:kgsbFPPS4P+acDYDOPDa3N4IWWOuDJt5/INKRUz7aks=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34/go.mod h1:T9ezsOHcCrDCgA8aF1Cqr3sSYbO/xgdy8/R/XiIMAhA=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca/go.mod h1:IRSre9/SEhVuy972TVuJLyaPTS73+8Owhe0Y0l9NXHc=
github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68=
github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966/go.mod h1:SFtfq0zFPsENI7DpE87QM2hcYu5QQ0fRdCgP+P1Hrqo=
github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141/go.mod h1:fw0McLecf/G5NFwddCRmDckU6yovtk1YsgWIoepMbYo=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470/go.mod h1:3I+3V7B6gTBYfdpYgIG2ymALS9H+5VDKUl3lHH7ToM4=
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3/go.mod h1:Y2lmIkzV6mcNfAnAdOd+ZxHkHchhBfU/xroGIp61wfw=
github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3/go.mod h1:WH+MU2F4T0VmSdaPX+Wu5GYoZBrYWdOZWSjzvYcDmqQ=
github.com/blevesearch/go-porterstemmer v0.0.0-20141230013033-23a2c8e5cf1f/go.mod h1:haWQqFT3RdOGz7PJuM3or/pWNJS1pKkoZJWCkWu0DVA=
github.com/blevesearch/segment v0.0.0-20160105220820-db70c57796cc/go.mod h1:IInt5XRvpiGE09KOk9mmCMLjHhydIhNPKPPFLFBB7L8=
github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f/go.mod h1:6QaC0vFoKWYDth94dHFNgRT2YkT5FHdQp/Yx15aAAi0=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/corbym/gocrest v1.0.3/go.mod h1:maVFL5lbdS2PgfOQgGRWDYTeunSWQeiEgoNdTABShCs=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/couchbase/vellum v0.0.0-20190111184608-e91b68ff3efe/go.mod h1:prYTC8EgTu3gwbqJihkud9zRXISvyulAplQ6exdCo1g=
github.com/couchbaselabs/go-couchbase v0.0.0-20190117181324-d904413d884d/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc=
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/denisenkom/go-mssqldb v0.0.0-20190724012636-11b2859924c1/go.mod h1:uU0N10vx1abI4qeVe79CxepBP6PPREVTgMS5Gx6/mOk=
github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a/go.mod h1:MkKY/CB98aVE4VxO63X5vTQKUgcn+3XP15LMASe3lYs=
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9/go.mod h1:uPmAp6Sws4L7+Q/OokbWDAK1ibXYhB3PXFP1kol5hPg=
github.com/facebookgo/grace v0.0.0-20160926231715-5729e484473f/go.mod h1:KigFdumBXUPSwzLDbeuzyt0elrL7+CP7TKuhrhT4bcU=
github.com/facebookgo/httpdown v0.0.0-20160323221027-a3b1354551a2/go.mod h1:TUV/fX3XrTtBQb5+ttSUJzcFgLNpILONFTKmBuk5RSw=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4/go.mod h1:vsJz7uE339KUCpBXx3JAJzSRH7Uk4iGGyJzR529qDIA=
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.1.4/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-gitea/gitea v1.2.3 h1:L0SC8kIr3+UnxNAte9M9bmdQ8Bdrc6I5b4Zuz/T+NCw=
github.com/go-gitea/gitea v1.2.3/go.mod h1:g8iUbfFNyuJp8u7GsSggxI8NQyuxeGTyqxogl3imbQM=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM=
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok=
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
github.com/go-macaron/cors v0.0.0-20190418220122-6fd6a9bfe14e/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E=
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.3/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.2/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/runtime v0.19.3/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/runtime v0.19.5/go.mod h1:WIH6IYPXOrtgTClTV8xzdrD20jBlrK25D0aQbdSlqp8=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-swagger/go-swagger v0.19.0/go.mod h1:fOcXeMI1KPNv3uk4u7cR4VSyq0NyrYx4SS1/ajuTWDg=
github.com/go-swagger/go-swagger v0.20.0/go.mod h1:ylaOr/j+CVsLUsIEhQA49ewFKvVwVSQqVCdDdALNcCw=
github.com/go-swagger/go-swagger v0.20.1/go.mod h1:LoTpv6FHYXUvYnECHNLvi/qYNybk0d9wkJGH1cTANWE=
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0=
github.com/go-xorm/builder v0.3.3/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk=
github.com/go-xorm/core v0.6.2/go.mod h1:bwPIfLdm/FzWgVUH8WPVlr+uJhscvNGFcaZKXsI3n2c=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/go-xorm/xorm v0.7.3/go.mod h1:npNkX0GgFcODSSKHj7nhJPobHwa5E7usBBZUFaxCsXA=
github.com/go-xorm/xorm v0.7.4/go.mod h1:vpza5fydeRgt+stvo9qgMhSNohYqmNt0I1/D6hkCekA=
github.com/go-xorm/xorm v0.7.5/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
github.com/go-xorm/xorm v0.7.6/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
github.com/go-xorm/xorm v0.7.7/go.mod h1:BS8F0smoUxtyUqKnAtvoQecDRNs8SruHci62u9lRAJQ=
github.com/go-xorm/xorm v0.7.8/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ=
github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github/v24 v24.0.1/go.mod h1:CRqaW1Uns1TCkP0wqTpxYyRxRjxwvKU/XSS44u6X74M=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/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-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gophish/gophish v0.1.2 h1:OWsIzbGf+JbkCNOokbY1sS+nkArDs+9G9kPzRBJz4c4=
github.com/gophish/gophish v0.1.2/go.mod h1:3nVgumCxriDReEVZ47/9PK5JtN43TcCE9TXt++zFJe8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.6/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/issue9/assert v1.3.2/go.mod h1:9Ger+iz8X7r1zMYYwEhh++2wMGWcNN2oVI+zIQXxcio=
github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c/go.mod h1:5mTb/PQNkqmq2x3IxlQZE0aSnTksJg7fg/oWmJ5SKXQ=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v0.0.0-20190724205821-6cfae18c12b8/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lafriks/xormstore v1.0.0/go.mod h1:dD8vHNRfEp3Uy+JvX9cMi2SXcRKJ0x4pYKsZuy843Ic=
github.com/lafriks/xormstore v1.1.0/go.mod h1:wqtf8B94a8EtE463Ka1MaUT9ZDRl8FICA0nr65xr2wM=
github.com/lafriks/xormstore v1.2.0/go.mod h1:g47/cl3RfWykO5c4nw/Io3N0R+JuDqiD2YY7NzfWDoU=
github.com/lafriks/xormstore v1.3.0/go.mod h1:RAhtOztWBjK9xeZpXwKq59rhUxoRgo1zfYl0H1mtK7A=
github.com/lafriks/xormstore v1.3.1/go.mod h1:qALRD4Vto2Ic7/A5eplMpu5V62mugtSqFysRwz8FETs=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ=
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ=
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
github.com/markbates/goth v1.56.0/go.mod h1:zZmAw0Es0Dpm7TT/4AdN14QrkiWLMrrU9Xei1o+/mdA=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d/go.mod h1:/M9VLO+lUPmxvoOK2PfWRZ8mTtB4q1Hy9lEGijv9Nr8=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.4/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
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/russross/blackfriday v0.0.0-20180428102519-11635eb403ff/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY=
github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2/go.mod h1:mjqs7N0Q6m5HpR7QfXVBZXZWSqTjQLeTujjA/xUp2uw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tinylib/msgp v0.0.0-20180516164116-c8cf64dff200/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/unknwon/cae v0.0.0-20190822084630-55a0b64484a1/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU=
github.com/unknwon/cae v1.0.0/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU=
github.com/unknwon/com v0.0.0-20181010210213-41959bdd855f/go.mod h1:7l5Mh6tAHnDUu0AqU0g7Sm0dgGkYZLRGxJqMYXXBlok=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6/go.mod h1:+5rDk6sDGpl3azws3O+f+GpFSyN9GVr0K8cvQLQM2ZQ=
github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141/go.mod h1:TBwoao3Q4Eb/cp+dHbXDfRTrZSsj/k7kLr2j1oWRWC0=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53/go.mod h1:f6elajwZV+xceiaqgRL090YzLEDGSbqr3poGL3ZgXYo=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190122013713-64072686203f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE=
golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190814143026-e8b3e6111d02/go.mod h1:z5wpDCy2wbnXyFdvEuY3LhY9gBUL86/IOILm+Hsjx+E=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190820033707-85edb9ef3283/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190910221609-7f5965fd7709/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.3/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/editorconfig/editorconfig-core-go.v1 v1.3.0/go.mod h1:s2mQFI9McjArkyCwyEwU//+luQENTnD/Lfb/7Sj3/kQ=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg=
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk=
gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4=
gopkg.in/src-d/go-git.v4 v4.13.0/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU=
gopkg.in/testfixtures.v2 v2.5.0/go.mod h1:vyAq+MYCgNpR29qitQdLZhdbLFf4mR/2MFJRFoQZZ2M=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-2019.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.0-2019.2.1/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=

2440
integration/data/lockfile/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

1091
integration/data/lockfile/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,131 +0,0 @@
{
"jsonVersion": 4,
"lang": "",
"serverUUID": "",
"serverName": "rails",
"family": "pseudo",
"release": "",
"container": {
"containerID": "",
"name": "",
"image": "",
"type": "",
"uuid": ""
},
"platform": {
"name": "other",
"instanceID": ""
},
"scannedAt": "2021-03-31T12:22:26.428630183+09:00",
"scanMode": "fast mode",
"scannedVersion": "v0.15.9",
"scannedRevision": "build-20210331_121257_1a58c94",
"scannedBy": "dev",
"scannedVia": "pseudo",
"scannedIpv4Addrs": [
"172.19.0.1",
"172.17.0.1",
"172.27.0.1"
],
"reportedAt": "0001-01-01T00:00:00Z",
"reportedVersion": "",
"reportedRevision": "",
"reportedBy": "",
"errors": [],
"warnings": [],
"scannedCves": {},
"runningKernel": {
"release": "",
"version": "",
"rebootRequired": false
},
"packages": {},
"config": {
"scan": {
"logDir": "/var/log/vuls",
"resultsDir": "/home/ubuntu/go/src/github.com/future-architect/vuls/results",
"default": {
"port": "22",
"scanMode": [
"fast"
]
},
"servers": {
"rails": {
"serverName": "rails",
"cpeNames": [
"cpe:/a:rubyonrails:ruby_on_rails:3.0.1"
],
"scanMode": [
"fast"
],
"type": "pseudo",
"wordpress": {}
}
},
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
"Name": "gost",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/future-architect/vuls/gost.sqlite3",
"DebugSQL": false
},
"exploit": {
"Name": "exploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-exploitdb/go-exploitdb.sqlite3",
"DebugSQL": false
},
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},
"report": {
"default": {},
"cveDict": {
"Name": "",
"Type": "",
"SQLite3Path": "",
"DebugSQL": false
},
"ovalDict": {
"Name": "",
"Type": "",
"SQLite3Path": "",
"DebugSQL": false
},
"gost": {
"Name": "",
"Type": "",
"SQLite3Path": "",
"DebugSQL": false
},
"exploit": {
"Name": "",
"Type": "",
"SQLite3Path": "",
"DebugSQL": false
},
"metasploit": {
"Name": "",
"Type": "",
"SQLite3Path": "",
"DebugSQL": false
}
}
}
}

View File

@@ -14,7 +14,7 @@
},
"platform": {
"name": "aws",
"instanceID": "i-048327c9df8186148"
"instanceID": ""
},
"ipv4Addrs": [
"192.168.0.33"
@@ -6459,7 +6459,7 @@
"user": "ec2-user",
"host": "18.183.255.208",
"port": "22",
"keyPath": "/home/ubuntu/.ssh/stg.pem",
"keyPath": "/home/ubuntu/.ssh/hoge.pem",
"scanMode": [
"fast-root"
],
@@ -6469,13 +6469,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -6493,7 +6493,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -14,7 +14,7 @@
},
"platform": {
"name": "aws",
"instanceID": "i-04514844352ecc500"
"instanceID": ""
},
"ipv4Addrs": [
"192.168.0.20"
@@ -5559,7 +5559,7 @@
"user": "centos",
"host": "54.249.18.65",
"port": "22",
"keyPath": "/home/ubuntu/.ssh/stg.pem",
"keyPath": "/home/ubuntu/.ssh/hoge.pem",
"scanMode": [
"fast-root"
],
@@ -5569,13 +5569,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -5593,7 +5593,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -14,7 +14,7 @@
},
"platform": {
"name": "aws",
"instanceID": "i-0545d194b9d8a7a45"
"instanceID": ""
},
"ipv4Addrs": [
"192.168.0.175"
@@ -5556,7 +5556,7 @@
"user": "admin",
"host": "52.199.253.40",
"port": "22",
"keyPath": "/home/ubuntu/.ssh/stg.pem",
"keyPath": "/home/ubuntu/.ssh/hoge.pem",
"scanMode": [
"fast-root"
],
@@ -5566,13 +5566,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -5590,7 +5590,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@
},
"platform": {
"name": "aws",
"instanceID": "i-0521f850531b377ec"
"instanceID": ""
},
"ipv4Addrs": [
"192.168.0.194"
@@ -5083,7 +5083,7 @@
"user": "ec2-user",
"host": "18.179.9.114",
"port": "22",
"keyPath": "/home/ubuntu/.ssh/stg.pem",
"keyPath": "/home/ubuntu/.ssh/hoge.pem",
"scanMode": [
"fast-root"
],
@@ -5093,13 +5093,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -5117,7 +5117,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -14,7 +14,7 @@
},
"platform": {
"name": "aws",
"instanceID": "i-0a73d5d36c9a1c7c5"
"instanceID": ""
},
"ipv4Addrs": [
"192.168.0.231"
@@ -44,6 +44,7 @@
"version": "",
"rebootRequired": false
},
"enabledDnfModules": ["nodejs:12"],
"packages": {
"NetworkManager": {
"name": "NetworkManager",
@@ -5906,6 +5907,15 @@
}
]
},
"nodejs": {
"name": "nodejs",
"version": "1:12.14.1",
"release": "1.module+el8.1.0+5466+30f75628",
"newVersion": "1:12.14.1",
"newRelease": "1.module+el8.1.0+5466+30f75629",
"arch": "x86_64",
"repository": "rhel-8-appstream-rhui-rpms"
},
"sed": {
"name": "sed",
"version": "4.5",
@@ -6851,7 +6861,7 @@
"user": "ec2-user",
"host": "18.183.170.192",
"port": "22",
"keyPath": "/home/ubuntu/.ssh/stg.pem",
"keyPath": "/home/ubuntu/.ssh/hoge.pem",
"scanMode": [
"fast-root"
],
@@ -6861,13 +6871,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -6885,7 +6895,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -14,7 +14,7 @@
},
"platform": {
"name": "aws",
"instanceID": "i-0c9b08532fe475f96"
"instanceID": ""
},
"ipv4Addrs": [
"192.168.0.113"
@@ -8534,7 +8534,7 @@
"user": "ubuntu",
"host": "13.231.130.70",
"port": "22",
"keyPath": "/home/ubuntu/.ssh/stg.pem",
"keyPath": "/home/ubuntu/.ssh/hoge.pem",
"scanMode": [
"fast-root"
],
@@ -8544,13 +8544,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -8568,7 +8568,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -14,7 +14,7 @@
},
"platform": {
"name": "aws",
"instanceID": "i-0fdb2d5d49b36f54d"
"instanceID": ""
},
"ipv4Addrs": [
"192.168.0.25"
@@ -8482,9 +8482,9 @@
"ubuntu_20": {
"serverName": "ubuntu_20",
"user": "ubuntu",
"host": "18.179.206.143",
"host": "18.179.206.100",
"port": "22",
"keyPath": "/home/ubuntu/.ssh/stg.pem",
"keyPath": "/home/ubuntu/.ssh/hoge.pem",
"scanMode": [
"fast-root"
],
@@ -8494,13 +8494,13 @@
"cveDict": {
"Name": "cveDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/go-cve-dictionary/cve.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-cve-dictionary/cve.sqlite3",
"DebugSQL": false
},
"ovalDict": {
"Name": "ovalDict",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/goval-dictionary/oval.sqlite3",
"DebugSQL": false
},
"gost": {
@@ -8518,7 +8518,7 @@
"metasploit": {
"Name": "metasploit",
"Type": "sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/takuzoo3868/go-msfdb/go-msfdb.sqlite3",
"SQLite3Path": "/home/ubuntu/go/src/github.com/vulsio/go-msfdb/go-msfdb.sqlite3",
"DebugSQL": false
}
},

View File

@@ -1,27 +1,80 @@
[cveDict]
Type = "sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/cve.sqlite3"
SQLite3Path = "/data/vulsctl/docker/cve.sqlite3"
[ovalDict]
Type = "sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/oval.sqlite3"
SQLite3Path = "/data/vulsctl/docker/oval.sqlite3"
[gost]
Type = "sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/gost.sqlite3"
SQLite3Path = "/data/vulsctl/docker/gost.sqlite3"
[exploit]
Type = "sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/go-exploitdb.sqlite3"
SQLite3Path = "/data/vulsctl/docker/go-exploitdb.sqlite3"
[metasploit]
type = "sqlite3"
SQLite3Path = "/home/ubuntu/vulsctl/docker/go-msfdb.sqlite3"
SQLite3Path = "/data/vulsctl/docker/go-msfdb.sqlite3"
[default]
[servers]
[servers.rails]
[servers.nvd_exact]
type = "pseudo"
cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:3.0.1" ]
cpeNames = [ "cpe:/a:rubyonrails:rails:3.0.1" ]
[servers.nvd_rough]
type = "pseudo"
cpeNames = [ "cpe:/a:openssl:openssl:1.1.1" ]
[servers.nvd_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:djangoproject:django" ]
[servers.nvd_match_no_jvn]
type = "pseudo"
cpeNames = [ "cpe:/a:apache:tomcat:7.0.27" ]
[servers.jvn_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:hitachi_abb_power_grids:afs660:1.0.0" ]
[servers.jvn_vendor_product_nover]
type = "pseudo"
cpeNames = [ "cpe:/o:nec:aterm_wg2600hp2_firmware"]
[servers.gemfile]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/Gemfile.lock"]
[servers.pipfile]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/Pipfile.lock"]
[servers.poetry]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/poetry.lock"]
[servers.composer]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/composer.lock"]
[servers.packagelock]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/package-lock.json"]
[servers.yarn]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/yarn.lock"]
[servers.cargo]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/Cargo.lock"]
[servers.gomod]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/go.sum"]

View File

@@ -22,6 +22,60 @@ Url = "redis://127.0.0.1/3"
[servers]
[servers.rails]
[servers.nvd_exact]
type = "pseudo"
cpeNames = [ "cpe:/a:rubyonrails:ruby_on_rails:3.0.1" ]
cpeNames = [ "cpe:/a:rubyonrails:rails:3.0.1" ]
#cpeNames = [ "cpe:/a:rubyonrails:rails:4.0.0" ]
[servers.nvd_rough]
type = "pseudo"
cpeNames = [ "cpe:/a:openssl:openssl:1.1.1" ]
[servers.nvd_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:djangoproject:django" ]
[servers.nvd_match_no_jvn]
type = "pseudo"
cpeNames = [ "cpe:/a:apache:tomcat:7.0.27" ]
[servers.jvn_vendor_product]
type = "pseudo"
cpeNames = [ "cpe:/a:hitachi_abb_power_grids:afs660:1.0.0" ]
[servers.jvn_vendor_product_nover]
type = "pseudo"
cpeNames = [ "cpe:/o:nec:aterm_wg2600hp2_firmware"]
[servers.gemfile]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/Gemfile.lock"]
[servers.pipfile]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/Pipfile.lock"]
[servers.poetry]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/poetry.lock"]
[servers.composer]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/composer.lock"]
[servers.packagelock]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/package-lock.json"]
[servers.yarn]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/yarn.lock"]
[servers.cargo]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/Cargo.lock"]
[servers.gomod]
type = "pseudo"
lockfiles = ["./integration/data/lockfile/go.sum"]

View File

@@ -3,6 +3,7 @@ package logging
import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -17,10 +18,11 @@ import (
//LogOpts has options for logging
type LogOpts struct {
Debug bool `json:"debug,omitempty"`
DebugSQL bool `json:"debugSQL,omitempty"`
LogDir string `json:"logDir,omitempty"`
Quiet bool `json:"quiet,omitempty"`
Debug bool `json:"debug,omitempty"`
DebugSQL bool `json:"debugSQL,omitempty"`
LogToFile bool `json:"logToFile,omitempty"`
LogDir string `json:"logDir,omitempty"`
Quiet bool `json:"quiet,omitempty"`
}
// Log for localhost
@@ -44,7 +46,7 @@ func NewNormalLogger() Logger {
}
// NewCustomLogger creates logrus
func NewCustomLogger(debug, quiet bool, logDir, logMsgAnsiColor, serverName string) Logger {
func NewCustomLogger(debug, quiet, logToFile bool, logDir, logMsgAnsiColor, serverName string) Logger {
log := logrus.New()
log.Formatter = &formatter.TextFormatter{MsgAnsiColor: logMsgAnsiColor}
log.Level = logrus.InfoLevel
@@ -57,14 +59,17 @@ func NewCustomLogger(debug, quiet bool, logDir, logMsgAnsiColor, serverName stri
return Logger{Entry: *logrus.NewEntry(log)}
}
// File output
dir := GetDefaultLogDir()
if logDir != "" {
dir = logDir
whereami := "localhost"
if serverName != "" {
whereami = serverName
}
// Only log to a file if quiet mode enabled
if quiet && flag.Lookup("test.v") == nil {
if logToFile {
dir := GetDefaultLogDir()
if logDir != "" {
dir = logDir
}
if _, err := os.Stat(dir); os.IsNotExist(err) {
if err := os.Mkdir(dir, 0700); err != nil {
log.Errorf("Failed to create log directory. path: %s, err: %+v", dir, err)
@@ -73,36 +78,33 @@ func NewCustomLogger(debug, quiet bool, logDir, logMsgAnsiColor, serverName stri
logFile := dir + "/vuls.log"
if file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err == nil {
log.Out = file
log.Out = io.MultiWriter(os.Stderr, file)
} else {
log.Out = os.Stderr
log.Errorf("Failed to create log file. path: %s, err: %+v", logFile, err)
}
if _, err := os.Stat(dir); err == nil {
path := filepath.Join(dir, fmt.Sprintf("%s.log", whereami))
if _, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err == nil {
log.Hooks.Add(lfshook.NewHook(lfshook.PathMap{
logrus.DebugLevel: path,
logrus.InfoLevel: path,
logrus.WarnLevel: path,
logrus.ErrorLevel: path,
logrus.FatalLevel: path,
logrus.PanicLevel: path,
}, nil))
} else {
log.Errorf("Failed to create log file. path: %s, err: %+v", path, err)
}
}
} else if quiet {
log.Out = ioutil.Discard
} else {
log.Out = os.Stderr
}
whereami := "localhost"
if 0 < len(serverName) {
whereami = serverName
}
if _, err := os.Stat(dir); err == nil {
path := filepath.Join(dir, fmt.Sprintf("%s.log", whereami))
if _, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err == nil {
log.Hooks.Add(lfshook.NewHook(lfshook.PathMap{
logrus.DebugLevel: path,
logrus.InfoLevel: path,
logrus.WarnLevel: path,
logrus.ErrorLevel: path,
logrus.FatalLevel: path,
logrus.PanicLevel: path,
}, nil))
} else {
log.Errorf("Failed to create log file. path: %s, err: %+v", path, err)
}
}
entry := log.WithFields(logrus.Fields{"prefix": whereami})
return Logger{Entry: *entry}
}

View File

@@ -1,6 +1,7 @@
package models
import (
"sort"
"strings"
"time"
@@ -8,13 +9,26 @@ import (
)
// CveContents has CveContent
type CveContents map[CveContentType]CveContent
type CveContents map[CveContentType][]CveContent
// NewCveContents create CveContents
func NewCveContents(conts ...CveContent) CveContents {
m := CveContents{}
for _, cont := range conts {
m[cont.Type] = cont
if cont.Type == Jvn {
found := false
for _, cveCont := range m[cont.Type] {
if cont.SourceLink == cveCont.SourceLink {
found = true
break
}
}
if !found {
m[cont.Type] = append(m[cont.Type], cont)
}
} else {
m[cont.Type] = []CveContent{cont}
}
}
return m
}
@@ -44,16 +58,18 @@ func (v CveContents) Except(exceptCtypes ...CveContentType) (values CveContents)
}
// PrimarySrcURLs returns link of source
func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveContentStr) {
func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string, confidences Confidences) (values []CveContentStr) {
if cveID == "" {
return
}
if cont, found := v[Nvd]; found {
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Vendor Advisory" {
values = append(values, CveContentStr{Nvd, r.Link})
if conts, found := v[Nvd]; found {
for _, cont := range conts {
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Vendor Advisory" {
values = append(values, CveContentStr{Nvd, r.Link})
}
}
}
}
@@ -61,17 +77,31 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveC
order := CveContentTypes{Nvd, NewCveContentType(myFamily), GitHub}
for _, ctype := range order {
if cont, found := v[ctype]; found {
if cont.SourceLink == "" {
continue
if conts, found := v[ctype]; found {
for _, cont := range conts {
if cont.SourceLink == "" {
continue
}
values = append(values, CveContentStr{ctype, cont.SourceLink})
}
values = append(values, CveContentStr{ctype, cont.SourceLink})
}
}
if lang == "ja" {
if cont, found := v[Jvn]; found && 0 < len(cont.SourceLink) {
values = append(values, CveContentStr{Jvn, cont.SourceLink})
jvnMatch := false
for _, confidence := range confidences {
if confidence.DetectionMethod == JvnVendorProductMatchStr {
jvnMatch = true
break
}
}
if lang == "ja" || jvnMatch {
if conts, found := v[Jvn]; found {
for _, cont := range conts {
if 0 < len(cont.SourceLink) {
values = append(values, CveContentStr{Jvn, cont.SourceLink})
}
}
}
}
@@ -86,14 +116,17 @@ func (v CveContents) PrimarySrcURLs(lang, myFamily, cveID string) (values []CveC
// PatchURLs returns link of patch
func (v CveContents) PatchURLs() (urls []string) {
cont, found := v[Nvd]
conts, found := v[Nvd]
if !found {
return
}
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Patch" {
urls = append(urls, r.Link)
for _, cont := range conts {
for _, r := range cont.References {
for _, t := range r.Tags {
if t == "Patch" {
urls = append(urls, r.Link)
}
}
}
}
@@ -130,11 +163,15 @@ func (v CveContents) Cpes(myFamily string) (values []CveContentCpes) {
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < len(cont.Cpes) {
values = append(values, CveContentCpes{
Type: ctype,
Value: cont.Cpes,
})
if conts, found := v[ctype]; found {
for _, cont := range conts {
if 0 < len(cont.Cpes) {
values = append(values, CveContentCpes{
Type: ctype,
Value: cont.Cpes,
})
}
}
}
}
return
@@ -152,11 +189,15 @@ func (v CveContents) References(myFamily string) (values []CveContentRefs) {
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < len(cont.References) {
values = append(values, CveContentRefs{
Type: ctype,
Value: cont.References,
})
if conts, found := v[ctype]; found {
for _, cont := range conts {
if 0 < len(cont.References) {
values = append(values, CveContentRefs{
Type: ctype,
Value: cont.References,
})
}
}
}
}
@@ -168,17 +209,21 @@ func (v CveContents) CweIDs(myFamily string) (values []CveContentStr) {
order := CveContentTypes{NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(order...)...)
for _, ctype := range order {
if cont, found := v[ctype]; found && 0 < len(cont.CweIDs) {
for _, cweID := range cont.CweIDs {
for _, val := range values {
if val.Value == cweID {
continue
if conts, found := v[ctype]; found {
for _, cont := range conts {
if 0 < len(cont.CweIDs) {
for _, cweID := range cont.CweIDs {
for _, val := range values {
if val.Value == cweID {
continue
}
}
values = append(values, CveContentStr{
Type: ctype,
Value: cweID,
})
}
}
values = append(values, CveContentStr{
Type: ctype,
Value: cweID,
})
}
}
}
@@ -197,6 +242,47 @@ func (v CveContents) UniqCweIDs(myFamily string) (values []CveContentStr) {
return values
}
// Sort elements for integration-testing
func (v CveContents) Sort() {
for contType, contents := range v {
// CVSS3 desc, CVSS2 desc, SourceLink asc
sort.Slice(contents, func(i, j int) bool {
if contents[i].Cvss3Score > contents[j].Cvss3Score {
return true
} else if contents[i].Cvss3Score == contents[i].Cvss3Score {
if contents[i].Cvss2Score > contents[j].Cvss2Score {
return true
} else if contents[i].Cvss2Score == contents[i].Cvss2Score {
if contents[i].SourceLink < contents[j].SourceLink {
return true
}
}
}
return false
})
v[contType] = contents
}
for contType, contents := range v {
for cveID, cont := range contents {
sort.Slice(cont.References, func(i, j int) bool {
return cont.References[i].Link < cont.References[j].Link
})
sort.Slice(cont.CweIDs, func(i, j int) bool {
return cont.CweIDs[i] < cont.CweIDs[j]
})
for i, ref := range cont.References {
// sort v.CveContents[].References[].Tags
sort.Slice(ref.Tags, func(j, k int) bool {
return ref.Tags[j] < ref.Tags[k]
})
cont.References[i] = ref
}
contents[cveID] = cont
}
v[contType] = contents
}
}
// CveContent has abstraction of various vulnerability information
type CveContent struct {
Type CveContentType `json:"type"`
@@ -233,7 +319,7 @@ func NewCveContentType(name string) CveContentType {
return Nvd
case "jvn":
return Jvn
case "redhat", "centos":
case "redhat", "centos", "alma", "rocky":
return RedHat
case "oracle":
return Oracle
@@ -245,6 +331,8 @@ func NewCveContentType(name string) CveContentType {
return RedHatAPI
case "debian_security_tracker":
return DebianSecurityTracker
case "ubuntu_api":
return UbuntuAPI
case "microsoft":
return Microsoft
case "wordpress":
@@ -282,6 +370,9 @@ const (
// Ubuntu is Ubuntu
Ubuntu CveContentType = "ubuntu"
// UbuntuAPI is Ubuntu
UbuntuAPI CveContentType = "ubuntu_api"
// Oracle is Oracle Linux
Oracle CveContentType = "oracle"
@@ -317,10 +408,11 @@ var AllCveContetTypes = CveContentTypes{
RedHat,
RedHatAPI,
Debian,
DebianSecurityTracker,
Ubuntu,
UbuntuAPI,
Amazon,
SUSE,
DebianSecurityTracker,
WpScan,
Trivy,
GitHub,

View File

@@ -11,12 +11,12 @@ func TestExcept(t *testing.T) {
out CveContents
}{{
in: CveContents{
RedHat: {Type: RedHat},
Ubuntu: {Type: Ubuntu},
Debian: {Type: Debian},
RedHat: []CveContent{{Type: RedHat}},
Ubuntu: []CveContent{{Type: Ubuntu}},
Debian: []CveContent{{Type: Debian}},
},
out: CveContents{
RedHat: {Type: RedHat},
RedHat: []CveContent{{Type: RedHat}},
},
},
}
@@ -30,9 +30,10 @@ func TestExcept(t *testing.T) {
func TestSourceLinks(t *testing.T) {
type in struct {
lang string
cveID string
cont CveContents
lang string
cveID string
cont CveContents
confidences Confidences
}
var tests = []struct {
in in
@@ -44,15 +45,15 @@ func TestSourceLinks(t *testing.T) {
lang: "ja",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
References: []Reference{
{
@@ -69,7 +70,7 @@ func TestSourceLinks(t *testing.T) {
},
},
SourceLink: "https://nvd.nist.gov/vuln/detail/CVE-2017-6074",
},
}},
},
},
out: []CveContentStr{
@@ -97,14 +98,14 @@ func TestSourceLinks(t *testing.T) {
lang: "en",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
SourceLink: "https://access.redhat.com/security/cve/CVE-2017-6074",
},
}},
},
},
out: []CveContentStr{
@@ -128,11 +129,123 @@ func TestSourceLinks(t *testing.T) {
},
},
},
// Confidence: JvnVendorProductMatch
{
in: in{
lang: "en",
cveID: "CVE-2017-6074",
cont: CveContents{
Jvn: []CveContent{{
Type: Jvn,
SourceLink: "https://jvn.jp/vu/JVNVU93610402/",
}},
},
confidences: Confidences{
Confidence{DetectionMethod: JvnVendorProductMatchStr},
},
},
out: []CveContentStr{
{
Type: Jvn,
Value: "https://jvn.jp/vu/JVNVU93610402/",
},
},
},
}
for i, tt := range tests {
actual := tt.in.cont.PrimarySrcURLs(tt.in.lang, "redhat", tt.in.cveID)
actual := tt.in.cont.PrimarySrcURLs(tt.in.lang, "redhat", tt.in.cveID, tt.in.confidences)
if !reflect.DeepEqual(tt.out, actual) {
t.Errorf("\n[%d] expected: %v\n actual: %v\n", i, tt.out, actual)
}
}
}
func TestCveContents_Sort(t *testing.T) {
tests := []struct {
name string
v CveContents
want CveContents
}{
{
name: "sorted",
v: map[CveContentType][]CveContent{
"jvn": {
{Cvss3Score: 3},
{Cvss3Score: 10},
},
},
want: map[CveContentType][]CveContent{
"jvn": {
{Cvss3Score: 10},
{Cvss3Score: 3},
},
},
},
{
name: "sort JVN by cvss3, cvss2, sourceLink",
v: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
},
},
want: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
},
},
},
{
name: "sort JVN by cvss3, cvss2",
v: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 1,
},
{
Cvss3Score: 3,
Cvss2Score: 10,
},
},
},
want: map[CveContentType][]CveContent{
"jvn": {
{
Cvss3Score: 3,
Cvss2Score: 10,
},
{
Cvss3Score: 3,
Cvss2Score: 1,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.v.Sort()
if !reflect.DeepEqual(tt.v, tt.want) {
t.Errorf("\n[%s] expected: %v\n actual: %v\n", tt.name, tt.want, tt.v)
}
})
}
}

View File

@@ -40,13 +40,14 @@ func (lss LibraryScanners) Total() (total int) {
// LibraryScanner has libraries information
type LibraryScanner struct {
Type string
Path string
Libs []types.Library
}
// Scan : scan target library
func (s LibraryScanner) Scan() ([]VulnInfo, error) {
scanner, err := library.DriverFactory{}.NewDriver(filepath.Base(string(s.Path)))
scanner, err := library.NewDriver(s.Type)
if err != nil {
return nil, xerrors.Errorf("Failed to new a library driver: %w", err)
}
@@ -87,35 +88,34 @@ func (s LibraryScanner) getVulnDetail(tvuln types.DetectedVulnerability) (vinfo
vinfo.CveID = tvuln.VulnerabilityID
vinfo.CveContents = getCveContents(tvuln.VulnerabilityID, vul)
if tvuln.FixedVersion != "" {
vinfo.LibraryFixedIns = []LibraryFixedIn{
{
Key: s.GetLibraryKey(),
Name: tvuln.PkgName,
FixedIn: tvuln.FixedVersion,
Path: s.Path,
},
}
vinfo.LibraryFixedIns = []LibraryFixedIn{
{
Key: s.GetLibraryKey(),
Name: tvuln.PkgName,
FixedIn: tvuln.FixedVersion,
Path: s.Path,
},
}
return vinfo, nil
}
func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[CveContentType]CveContent) {
contents = map[CveContentType]CveContent{}
func getCveContents(cveID string, vul trivyDBTypes.Vulnerability) (contents map[CveContentType][]CveContent) {
contents = map[CveContentType][]CveContent{}
refs := []Reference{}
for _, refURL := range vul.References {
refs = append(refs, Reference{Source: "trivy", Link: refURL})
}
content := CveContent{
Type: Trivy,
CveID: cveID,
Title: vul.Title,
Summary: vul.Description,
Cvss3Severity: string(vul.Severity),
References: refs,
contents[Trivy] = []CveContent{
{
Type: Trivy,
CveID: cveID,
Title: vul.Title,
Summary: vul.Description,
Cvss3Severity: string(vul.Severity),
References: refs,
},
}
contents[Trivy] = content
return contents
}
@@ -128,6 +128,7 @@ var LibraryMap = map[string]string{
"composer.lock": "php",
"Pipfile.lock": "python",
"poetry.lock": "python",
"go.sum": "gomod",
}
// GetLibraryKey returns target library key

View File

@@ -382,7 +382,7 @@ func Test_IsRaspbianPackage(t *testing.T) {
}
}
func Test_parseListenPorts(t *testing.T) {
func Test_NewPortStat(t *testing.T) {
tests := []struct {
name string
args string
@@ -423,7 +423,7 @@ func Test_parseListenPorts(t *testing.T) {
if err != nil {
t.Errorf("unexpected error occurred: %s", err)
} else if !reflect.DeepEqual(*listenPort, tt.expect) {
t.Errorf("base.parseListenPorts() = %v, want %v", *listenPort, tt.expect)
t.Errorf("base.NewPortStat() = %v, want %v", *listenPort, tt.expect)
}
})
}

View File

@@ -291,12 +291,11 @@ func (r ScanResult) IsContainer() bool {
}
// RemoveRaspbianPackFromResult is for Raspberry Pi and removes the Raspberry Pi dedicated package from ScanResult.
func (r ScanResult) RemoveRaspbianPackFromResult() ScanResult {
func (r ScanResult) RemoveRaspbianPackFromResult() *ScanResult {
if r.Family != constant.Raspbian {
return r
return &r
}
result := r
packs := make(Packages)
for _, pack := range r.Packages {
if !IsRaspbianPackage(pack.Name, pack.Version) {
@@ -311,10 +310,10 @@ func (r ScanResult) RemoveRaspbianPackFromResult() ScanResult {
}
}
result.Packages = packs
result.SrcPackages = srcPacks
r.Packages = packs
r.SrcPackages = srcPacks
return result
return &r
}
// ClearFields clears a given fields of ScanResult
@@ -375,44 +374,56 @@ func (r *ScanResult) CheckEOL() {
}
}
// SortForJSONOutput sort list elements in the ScanResult to diff in integration-test
func (r *ScanResult) SortForJSONOutput() {
for k, v := range r.Packages {
sort.SliceStable(v.AffectedProcs, func(i, j int) bool {
sort.Slice(v.AffectedProcs, func(i, j int) bool {
return v.AffectedProcs[i].PID < v.AffectedProcs[j].PID
})
sort.SliceStable(v.NeedRestartProcs, func(i, j int) bool {
sort.Slice(v.NeedRestartProcs, func(i, j int) bool {
return v.NeedRestartProcs[i].PID < v.NeedRestartProcs[j].PID
})
r.Packages[k] = v
}
for i, v := range r.LibraryScanners {
sort.Slice(v.Libs, func(i, j int) bool {
switch strings.Compare(v.Libs[i].Name, v.Libs[j].Name) {
case -1:
return true
case 1:
return false
}
return v.Libs[i].Version < v.Libs[j].Version
})
r.LibraryScanners[i] = v
}
for k, v := range r.ScannedCves {
sort.SliceStable(v.AffectedPackages, func(i, j int) bool {
sort.Slice(v.AffectedPackages, func(i, j int) bool {
return v.AffectedPackages[i].Name < v.AffectedPackages[j].Name
})
sort.SliceStable(v.DistroAdvisories, func(i, j int) bool {
sort.Slice(v.DistroAdvisories, func(i, j int) bool {
return v.DistroAdvisories[i].AdvisoryID < v.DistroAdvisories[j].AdvisoryID
})
sort.SliceStable(v.Exploits, func(i, j int) bool {
return v.Exploits[i].ID < v.Exploits[j].ID
sort.Slice(v.Exploits, func(i, j int) bool {
return v.Exploits[i].URL < v.Exploits[j].URL
})
sort.SliceStable(v.Metasploits, func(i, j int) bool {
sort.Slice(v.Metasploits, func(i, j int) bool {
return v.Metasploits[i].Name < v.Metasploits[j].Name
})
for kk, vv := range v.CveContents {
sort.SliceStable(vv.References, func(i, j int) bool {
return vv.References[i].Link < vv.References[j].Link
})
v.CveContents[kk] = vv
}
sort.Slice(v.Mitigations, func(i, j int) bool {
return v.Mitigations[i].URL < v.Mitigations[j].URL
})
sort.SliceStable(v.AlertDict.En, func(i, j int) bool {
v.CveContents.Sort()
sort.Slice(v.AlertDict.En, func(i, j int) bool {
return v.AlertDict.En[i].Title < v.AlertDict.En[j].Title
})
sort.SliceStable(v.AlertDict.Ja, func(i, j int) bool {
sort.Slice(v.AlertDict.Ja, func(i, j int) bool {
return v.AlertDict.Ja[i].Title < v.AlertDict.Ja[j].Title
})
r.ScannedCves[k] = v
}
}

View File

@@ -56,6 +56,16 @@ func TestIsDisplayUpdatableNum(t *testing.T) {
family: constant.CentOS,
expected: true,
},
{
mode: []byte{config.Fast},
family: constant.Alma,
expected: true,
},
{
mode: []byte{config.Fast},
family: constant.Rocky,
expected: true,
},
{
mode: []byte{config.Fast},
family: constant.Amazon,
@@ -94,6 +104,55 @@ func TestIsDisplayUpdatableNum(t *testing.T) {
}
}
func TestRemoveRaspbianPackFromResult(t *testing.T) {
var tests = []struct {
in ScanResult
expected ScanResult
}{
{
in: ScanResult{
Family: constant.Raspbian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
"libraspberrypi-dev": Package{Name: "libraspberrypi-dev", Version: "1.20200811-1"},
},
SrcPackages: SrcPackages{},
},
expected: ScanResult{
Family: constant.Raspbian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
},
SrcPackages: SrcPackages{},
},
},
{
in: ScanResult{
Family: constant.Debian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
},
SrcPackages: SrcPackages{},
},
expected: ScanResult{
Family: constant.Debian,
Packages: Packages{
"apt": Package{Name: "apt", Version: "1.8.2.1"},
},
SrcPackages: SrcPackages{},
},
},
}
for i, tt := range tests {
r := tt.in
r = *r.RemoveRaspbianPackFromResult()
if !reflect.DeepEqual(r, tt.expected) {
t.Errorf("[%d] expected %+v, actual %+v", i, tt.expected, r)
}
}
}
func TestScanResult_Sort(t *testing.T) {
type fields struct {
Packages Packages
@@ -131,25 +190,25 @@ func TestScanResult_Sort(t *testing.T) {
{AdvisoryID: "adv-2"},
},
Exploits: []Exploit{
{ID: "a"},
{ID: "b"},
{URL: "a"},
{URL: "b"},
},
Metasploits: []Metasploit{
{Name: "a"},
{Name: "b"},
},
CveContents: CveContents{
"nvd": CveContent{
"nvd": []CveContent{{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
},
}},
},
"jvn": CveContent{
"jvn": []CveContent{{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
},
}},
},
},
AlertDict: AlertDict{
@@ -190,25 +249,25 @@ func TestScanResult_Sort(t *testing.T) {
{AdvisoryID: "adv-2"},
},
Exploits: []Exploit{
{ID: "a"},
{ID: "b"},
{URL: "a"},
{URL: "b"},
},
Metasploits: []Metasploit{
{Name: "a"},
{Name: "b"},
},
CveContents: CveContents{
"nvd": CveContent{
"nvd": []CveContent{{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
},
}},
},
"jvn": CveContent{
"jvn": []CveContent{{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
},
}},
},
},
AlertDict: AlertDict{
@@ -252,25 +311,25 @@ func TestScanResult_Sort(t *testing.T) {
{AdvisoryID: "adv-1"},
},
Exploits: []Exploit{
{ID: "b"},
{ID: "a"},
{URL: "b"},
{URL: "a"},
},
Metasploits: []Metasploit{
{Name: "b"},
{Name: "a"},
},
CveContents: CveContents{
"nvd": CveContent{
"nvd": []CveContent{{
References: References{
Reference{Link: "b"},
Reference{Link: "a"},
},
}},
},
"jvn": CveContent{
"jvn": []CveContent{{
References: References{
Reference{Link: "b"},
Reference{Link: "a"},
},
}},
},
},
AlertDict: AlertDict{
@@ -311,25 +370,25 @@ func TestScanResult_Sort(t *testing.T) {
{AdvisoryID: "adv-2"},
},
Exploits: []Exploit{
{ID: "a"},
{ID: "b"},
{URL: "a"},
{URL: "b"},
},
Metasploits: []Metasploit{
{Name: "a"},
{Name: "b"},
},
CveContents: CveContents{
"nvd": CveContent{
"nvd": []CveContent{{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
},
}},
},
"jvn": CveContent{
"jvn": []CveContent{{
References: References{
Reference{Link: "a"},
Reference{Link: "b"},
},
}},
},
},
AlertDict: AlertDict{
@@ -346,6 +405,115 @@ func TestScanResult_Sort(t *testing.T) {
},
},
},
{
name: "sort JVN by cvss v3",
fields: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{Cvss3Score: 3},
{Cvss3Score: 10},
},
},
},
},
},
expected: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{Cvss3Score: 10},
{Cvss3Score: 3},
},
},
},
},
},
},
{
name: "sort JVN by cvss3, cvss2, sourceLink",
fields: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
},
},
},
},
},
expected: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2021/JVNDB-2021-001210.html",
},
{
Cvss3Score: 3,
Cvss2Score: 3,
SourceLink: "https://jvndb.jvn.jp/ja/contents/2023/JVNDB-2023-001210.html",
},
},
},
},
},
},
},
{
name: "sort JVN by cvss3, cvss2",
fields: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 1,
},
{
Cvss3Score: 3,
Cvss2Score: 10,
},
},
},
},
},
},
expected: fields{
ScannedCves: VulnInfos{
"CVE-2014-3591": VulnInfo{
CveContents: CveContents{
"jvn": []CveContent{
{
Cvss3Score: 3,
Cvss2Score: 10,
},
{
Cvss3Score: 3,
Cvss2Score: 1,
},
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package models
@@ -5,116 +6,120 @@ package models
import (
"strings"
cvedict "github.com/kotakanbe/go-cve-dictionary/models"
cvedict "github.com/vulsio/go-cve-dictionary/models"
)
// ConvertJvnToModel convert JVN to CveContent
func ConvertJvnToModel(cveID string, jvn *cvedict.Jvn) *CveContent {
if jvn == nil {
return nil
}
// var cpes = []Cpe{}
// for _, c := range jvn.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
func ConvertJvnToModel(cveID string, jvns []cvedict.Jvn) []CveContent {
cves := []CveContent{}
for _, jvn := range jvns {
// cpes := []Cpe{}
// for _, c := range jvn.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
refs := []Reference{}
for _, r := range jvn.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
refs := []Reference{}
for _, r := range jvn.References {
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
})
}
return &CveContent{
Type: Jvn,
CveID: cveID,
Title: jvn.Title,
Summary: jvn.Summary,
Cvss2Score: jvn.Cvss2.BaseScore,
Cvss2Vector: jvn.Cvss2.VectorString,
Cvss2Severity: jvn.Cvss2.Severity,
Cvss3Score: jvn.Cvss3.BaseScore,
Cvss3Vector: jvn.Cvss3.VectorString,
Cvss3Severity: jvn.Cvss3.BaseSeverity,
SourceLink: jvn.JvnLink,
// Cpes: cpes,
References: refs,
Published: jvn.PublishedDate,
LastModified: jvn.LastModifiedDate,
cve := CveContent{
Type: Jvn,
CveID: cveID,
Title: jvn.Title,
Summary: jvn.Summary,
Cvss2Score: jvn.Cvss2.BaseScore,
Cvss2Vector: jvn.Cvss2.VectorString,
Cvss2Severity: jvn.Cvss2.Severity,
Cvss3Score: jvn.Cvss3.BaseScore,
Cvss3Vector: jvn.Cvss3.VectorString,
Cvss3Severity: jvn.Cvss3.BaseSeverity,
SourceLink: jvn.JvnLink,
// Cpes: cpes,
References: refs,
Published: jvn.PublishedDate,
LastModified: jvn.LastModifiedDate,
}
cves = append(cves, cve)
}
return cves
}
// ConvertNvdJSONToModel convert NVD to CveContent
func ConvertNvdJSONToModel(cveID string, nvd *cvedict.NvdJSON) (*CveContent, []Exploit, []Mitigation) {
if nvd == nil {
return nil, nil, nil
}
// var cpes = []Cpe{}
// for _, c := range nvd.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
// ConvertNvdToModel convert NVD to CveContent
func ConvertNvdToModel(cveID string, nvds []cvedict.Nvd) ([]CveContent, []Exploit, []Mitigation) {
cves := []CveContent{}
refs := []Reference{}
exploits := []Exploit{}
mitigations := []Mitigation{}
for _, r := range nvd.References {
var tags []string
if 0 < len(r.Tags) {
tags = strings.Split(r.Tags, ",")
}
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
Tags: tags,
})
if strings.Contains(r.Tags, "Exploit") {
exploits = append(exploits, Exploit{
//TODO Add const to here
// https://github.com/vulsio/go-exploitdb/blob/master/models/exploit.go#L13-L18
ExploitType: "nvd",
URL: r.Link,
for _, nvd := range nvds {
// cpes := []Cpe{}
// for _, c := range nvd.Cpes {
// cpes = append(cpes, Cpe{
// FormattedString: c.FormattedString,
// URI: c.URI,
// })
// }
for _, r := range nvd.References {
var tags []string
if 0 < len(r.Tags) {
tags = strings.Split(r.Tags, ",")
}
refs = append(refs, Reference{
Link: r.Link,
Source: r.Source,
Tags: tags,
})
if strings.Contains(r.Tags, "Exploit") {
exploits = append(exploits, Exploit{
//TODO Add const to here
// https://github.com/vulsio/go-exploitdb/blob/master/models/exploit.go#L13-L18
ExploitType: "nvd",
URL: r.Link,
})
}
if strings.Contains(r.Tags, "Mitigation") {
mitigations = append(mitigations, Mitigation{
CveContentType: Nvd,
URL: r.Link,
})
}
}
if strings.Contains(r.Tags, "Mitigation") {
mitigations = append(mitigations, Mitigation{
CveContentType: Nvd,
URL: r.Link,
})
cweIDs := []string{}
for _, cid := range nvd.Cwes {
cweIDs = append(cweIDs, cid.CweID)
}
}
cweIDs := []string{}
for _, cid := range nvd.Cwes {
cweIDs = append(cweIDs, cid.CweID)
}
desc := []string{}
for _, d := range nvd.Descriptions {
desc = append(desc, d.Value)
}
desc := []string{}
for _, d := range nvd.Descriptions {
desc = append(desc, d.Value)
cve := CveContent{
Type: Nvd,
CveID: cveID,
Summary: strings.Join(desc, "\n"),
Cvss2Score: nvd.Cvss2.BaseScore,
Cvss2Vector: nvd.Cvss2.VectorString,
Cvss2Severity: nvd.Cvss2.Severity,
Cvss3Score: nvd.Cvss3.BaseScore,
Cvss3Vector: nvd.Cvss3.VectorString,
Cvss3Severity: nvd.Cvss3.BaseSeverity,
SourceLink: "https://nvd.nist.gov/vuln/detail/" + cveID,
// Cpes: cpes,
CweIDs: cweIDs,
References: refs,
Published: nvd.PublishedDate,
LastModified: nvd.LastModifiedDate,
}
cves = append(cves, cve)
}
return &CveContent{
Type: Nvd,
CveID: cveID,
Summary: strings.Join(desc, "\n"),
Cvss2Score: nvd.Cvss2.BaseScore,
Cvss2Vector: nvd.Cvss2.VectorString,
Cvss2Severity: nvd.Cvss2.Severity,
Cvss3Score: nvd.Cvss3.BaseScore,
Cvss3Vector: nvd.Cvss3.VectorString,
Cvss3Severity: nvd.Cvss3.BaseSeverity,
SourceLink: "https://nvd.nist.gov/vuln/detail/" + cveID,
// Cpes: cpes,
CweIDs: cweIDs,
References: refs,
Published: nvd.PublishedDate,
LastModified: nvd.LastModifiedDate,
}, exploits, mitigations
return cves, exploits, mitigations
}

View File

@@ -37,6 +37,18 @@ func (v VulnInfos) FilterByCvssOver(over float64) VulnInfos {
})
}
// FilterByConfidenceOver scored vulnerabilities
func (v VulnInfos) FilterByConfidenceOver(over int) VulnInfos {
return v.Find(func(v VulnInfo) bool {
for _, c := range v.Confidences {
if over <= c.Score {
return true
}
}
return false
})
}
// FilterIgnoreCves filter function.
func (v VulnInfos) FilterIgnoreCves(ignoreCveIDs []string) VulnInfos {
return v.Find(func(v VulnInfo) bool {
@@ -75,9 +87,8 @@ func (v VulnInfos) FilterIgnorePkgs(ignorePkgsRegexps []string) VulnInfos {
if err != nil {
logging.Log.Warnf("Failed to parse %s. err: %+v", pkgRegexp, err)
continue
} else {
regexps = append(regexps, re)
}
regexps = append(regexps, re)
}
if len(regexps) == 0 {
return v
@@ -157,7 +168,7 @@ func (v VulnInfos) CountGroupBySeverity() map[string]int {
func (v VulnInfos) FormatCveSummary() string {
m := v.CountGroupBySeverity()
line := fmt.Sprintf("Total: %d (Critical:%d High:%d Medium:%d Low:%d ?:%d)",
m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
m["Critical"]+m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
m["Critical"], m["High"], m["Medium"], m["Low"], m["Unknown"])
nPlus, nMinus := v.CountDiff()
@@ -347,30 +358,46 @@ func (v VulnInfo) CveIDDiffFormat() string {
// Titles returns title (TUI)
func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if cont, found := v.CveContents[Jvn]; found && cont.Title != "" {
values = append(values, CveContentStr{Jvn, cont.Title})
if conts, found := v.CveContents[Jvn]; found {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{Jvn, cont.Title})
}
}
}
}
// RedHat API has one line title.
if cont, found := v.CveContents[RedHatAPI]; found && cont.Title != "" {
values = append(values, CveContentStr{RedHatAPI, cont.Title})
if conts, found := v.CveContents[RedHatAPI]; found {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{RedHatAPI, cont.Title})
}
}
}
// GitHub security alerts has a title.
if cont, found := v.CveContents[GitHub]; found && cont.Title != "" {
values = append(values, CveContentStr{GitHub, cont.Title})
if conts, found := v.CveContents[GitHub]; found {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{GitHub, cont.Title})
}
}
}
order := CveContentTypes{Trivy, Nvd, NewCveContentType(myFamily)}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
}
}
@@ -393,23 +420,31 @@ func (v VulnInfo) Titles(lang, myFamily string) (values []CveContentStr) {
// Summaries returns summaries
func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
if lang == "ja" {
if cont, found := v.CveContents[Jvn]; found && cont.Summary != "" {
summary := cont.Title
summary += "\n" + strings.Replace(
strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1)
values = append(values, CveContentStr{Jvn, summary})
if conts, found := v.CveContents[Jvn]; found {
for _, cont := range conts {
if cont.Summary != "" {
summary := cont.Title
summary += "\n" + strings.Replace(
strings.Replace(cont.Summary, "\n", " ", -1), "\r", " ", -1)
values = append(values, CveContentStr{Jvn, summary})
}
}
}
}
order := CveContentTypes{Trivy, NewCveContentType(myFamily), Nvd, GitHub}
order = append(order, AllCveContetTypes.Except(append(order, Jvn)...)...)
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found && cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Summary != "" {
summary := strings.Replace(cont.Summary, "\n", " ", -1)
values = append(values, CveContentStr{
Type: ctype,
Value: summary,
})
}
}
}
}
@@ -420,11 +455,15 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
})
}
if v, ok := v.CveContents[WpScan]; ok {
values = append(values, CveContentStr{
Type: WpScan,
Value: v.Title,
})
if conts, ok := v.CveContents[WpScan]; ok {
for _, cont := range conts {
if cont.Title != "" {
values = append(values, CveContentStr{
Type: WpScan,
Value: cont.Title,
})
}
}
}
if len(values) == 0 {
@@ -441,20 +480,22 @@ func (v VulnInfo) Summaries(lang, myFamily string) (values []CveContentStr) {
func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) {
order := []CveContentType{RedHatAPI, RedHat, Nvd, Jvn}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found {
if cont.Cvss2Score == 0 && cont.Cvss2Severity == "" {
continue
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Cvss2Score == 0 && cont.Cvss2Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: cont.Cvss2Score,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
})
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS2,
Score: cont.Cvss2Score,
Vector: cont.Cvss2Vector,
Severity: strings.ToUpper(cont.Cvss2Severity),
},
})
}
}
return
@@ -464,34 +505,40 @@ func (v VulnInfo) Cvss2Scores() (values []CveContentCvss) {
func (v VulnInfo) Cvss3Scores() (values []CveContentCvss) {
order := []CveContentType{RedHatAPI, RedHat, Nvd, Jvn}
for _, ctype := range order {
if cont, found := v.CveContents[ctype]; found {
if cont.Cvss3Score == 0 && cont.Cvss3Severity == "" {
continue
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Cvss3Score == 0 && cont.Cvss3Severity == "" {
continue
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: cont.Cvss3Score,
Vector: cont.Cvss3Vector,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
// https://nvd.nist.gov/vuln-metrics/cvss
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: cont.Cvss3Score,
Vector: cont.Cvss3Vector,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
}
for _, ctype := range []CveContentType{Debian, DebianSecurityTracker, Ubuntu, Amazon, Trivy, GitHub, WpScan} {
if cont, found := v.CveContents[ctype]; found && cont.Cvss3Severity != "" {
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: severityToCvssScoreRoughly(cont.Cvss3Severity),
CalculatedBySeverity: true,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
if conts, found := v.CveContents[ctype]; found {
for _, cont := range conts {
if cont.Cvss3Severity != "" {
values = append(values, CveContentCvss{
Type: ctype,
Value: Cvss{
Type: CVSS3,
Score: severityToCvssScoreRoughly(cont.Cvss3Severity),
CalculatedBySeverity: true,
Severity: strings.ToUpper(cont.Cvss3Severity),
},
})
}
}
}
}
@@ -553,24 +600,28 @@ func (v VulnInfo) MaxCvss2Score() CveContentCvss {
// AttackVector returns attack vector string
func (v VulnInfo) AttackVector() string {
for _, cnt := range v.CveContents {
if strings.HasPrefix(cnt.Cvss2Vector, "AV:N") ||
strings.Contains(cnt.Cvss3Vector, "AV:N") {
return "AV:N"
} else if strings.HasPrefix(cnt.Cvss2Vector, "AV:A") ||
strings.Contains(cnt.Cvss3Vector, "AV:A") {
return "AV:A"
} else if strings.HasPrefix(cnt.Cvss2Vector, "AV:L") ||
strings.Contains(cnt.Cvss3Vector, "AV:L") {
return "AV:L"
} else if strings.Contains(cnt.Cvss3Vector, "AV:P") {
// no AV:P in CVSS v2
return "AV:P"
for _, conts := range v.CveContents {
for _, cont := range conts {
if strings.HasPrefix(cont.Cvss2Vector, "AV:N") ||
strings.Contains(cont.Cvss3Vector, "AV:N") {
return "AV:N"
} else if strings.HasPrefix(cont.Cvss2Vector, "AV:A") ||
strings.Contains(cont.Cvss3Vector, "AV:A") {
return "AV:A"
} else if strings.HasPrefix(cont.Cvss2Vector, "AV:L") ||
strings.Contains(cont.Cvss3Vector, "AV:L") {
return "AV:L"
} else if strings.Contains(cont.Cvss3Vector, "AV:P") {
// no AV:P in CVSS v2
return "AV:P"
}
}
}
if cont, found := v.CveContents[DebianSecurityTracker]; found {
if attackRange, found := cont.Optional["attack range"]; found {
return attackRange
if conts, found := v.CveContents[DebianSecurityTracker]; found {
for _, cont := range conts {
if attackRange, found := cont.Optional["attack range"]; found {
return attackRange
}
}
}
return ""
@@ -808,53 +859,56 @@ func (c Confidence) String() string {
type DetectionMethod string
const (
// CpeNameMatchStr is a String representation of CpeNameMatch
CpeNameMatchStr = "CpeNameMatch"
// NvdExactVersionMatchStr :
NvdExactVersionMatchStr = "NvdExactVersionMatch"
// YumUpdateSecurityMatchStr is a String representation of YumUpdateSecurityMatch
YumUpdateSecurityMatchStr = "YumUpdateSecurityMatch"
// NvdRoughVersionMatchStr :
NvdRoughVersionMatchStr = "NvdRoughVersionMatch"
// PkgAuditMatchStr is a String representation of PkgAuditMatch
// NvdVendorProductMatchStr :
NvdVendorProductMatchStr = "NvdVendorProductMatch"
// JvnVendorProductMatchStr :
JvnVendorProductMatchStr = "JvnVendorProductMatch"
// PkgAuditMatchStr :
PkgAuditMatchStr = "PkgAuditMatch"
// OvalMatchStr is a String representation of OvalMatch
// OvalMatchStr :
OvalMatchStr = "OvalMatch"
// RedHatAPIStr is a String representation of RedHatAPIMatch
// RedHatAPIStr is :
RedHatAPIStr = "RedHatAPIMatch"
// DebianSecurityTrackerMatchStr is a String representation of DebianSecurityTrackerMatch
// DebianSecurityTrackerMatchStr :
DebianSecurityTrackerMatchStr = "DebianSecurityTrackerMatch"
// TrivyMatchStr is a String representation of Trivy
// UbuntuAPIMatchStr :
UbuntuAPIMatchStr = "UbuntuAPIMatch"
// TrivyMatchStr :
TrivyMatchStr = "TrivyMatch"
// ChangelogExactMatchStr is a String representation of ChangelogExactMatch
// ChangelogExactMatchStr :
ChangelogExactMatchStr = "ChangelogExactMatch"
// ChangelogLenientMatchStr is a String representation of ChangelogLenientMatch
ChangelogLenientMatchStr = "ChangelogLenientMatch"
// ChangelogRoughMatchStr :
ChangelogRoughMatchStr = "ChangelogRoughMatch"
// GitHubMatchStr is a String representation of GitHubMatch
// GitHubMatchStr :
GitHubMatchStr = "GitHubMatch"
// WpScanMatchStr is a String representation of WordPress VulnDB scanning
// WpScanMatchStr :
WpScanMatchStr = "WpScanMatch"
// FailedToGetChangelog is a String representation of FailedToGetChangelog
// FailedToGetChangelog :
FailedToGetChangelog = "FailedToGetChangelog"
// FailedToFindVersionInChangelog is a String representation of FailedToFindVersionInChangelog
// FailedToFindVersionInChangelog :
FailedToFindVersionInChangelog = "FailedToFindVersionInChangelog"
)
var (
// CpeNameMatch is a ranking how confident the CVE-ID was detected correctly
CpeNameMatch = Confidence{100, CpeNameMatchStr, 1}
// YumUpdateSecurityMatch is a ranking how confident the CVE-ID was detected correctly
YumUpdateSecurityMatch = Confidence{100, YumUpdateSecurityMatchStr, 2}
// PkgAuditMatch is a ranking how confident the CVE-ID was detected correctly
PkgAuditMatch = Confidence{100, PkgAuditMatchStr, 2}
@@ -867,18 +921,33 @@ var (
// DebianSecurityTrackerMatch ranking how confident the CVE-ID was detected correctly
DebianSecurityTrackerMatch = Confidence{100, DebianSecurityTrackerMatchStr, 0}
// UbuntuAPIMatch ranking how confident the CVE-ID was detected correctly
UbuntuAPIMatch = Confidence{100, UbuntuAPIMatchStr, 0}
// TrivyMatch ranking how confident the CVE-ID was detected correctly
TrivyMatch = Confidence{100, TrivyMatchStr, 0}
// ChangelogExactMatch is a ranking how confident the CVE-ID was detected correctly
ChangelogExactMatch = Confidence{95, ChangelogExactMatchStr, 3}
// ChangelogLenientMatch is a ranking how confident the CVE-ID was detected correctly
ChangelogLenientMatch = Confidence{50, ChangelogLenientMatchStr, 4}
// ChangelogRoughMatch is a ranking how confident the CVE-ID was detected correctly
ChangelogRoughMatch = Confidence{50, ChangelogRoughMatchStr, 4}
// GitHubMatch is a ranking how confident the CVE-ID was detected correctly
GitHubMatch = Confidence{97, GitHubMatchStr, 2}
GitHubMatch = Confidence{100, GitHubMatchStr, 2}
// WpScanMatch is a ranking how confident the CVE-ID was detected correctly
WpScanMatch = Confidence{100, WpScanMatchStr, 0}
// NvdExactVersionMatch is a ranking how confident the CVE-ID was detected correctly
NvdExactVersionMatch = Confidence{100, NvdExactVersionMatchStr, 1}
// NvdRoughVersionMatch NvdExactVersionMatch is a ranking how confident the CVE-ID was detected correctly
NvdRoughVersionMatch = Confidence{80, NvdRoughVersionMatchStr, 1}
// NvdVendorProductMatch is a ranking how confident the CVE-ID was detected correctly
NvdVendorProductMatch = Confidence{10, NvdVendorProductMatchStr, 9}
// JvnVendorProductMatch is a ranking how confident the CVE-ID was detected correctly
JvnVendorProductMatch = Confidence{10, JvnVendorProductMatchStr, 10}
)

View File

@@ -21,19 +21,19 @@ func TestTitles(t *testing.T) {
lang: "ja",
cont: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Title: "Title1",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Summary: "Summary RedHat",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
}},
},
},
},
@@ -58,19 +58,19 @@ func TestTitles(t *testing.T) {
lang: "en",
cont: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Title: "Title1",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Summary: "Summary RedHat",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
}},
},
},
},
@@ -122,20 +122,20 @@ func TestSummaries(t *testing.T) {
lang: "ja",
cont: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Title: "Title JVN",
Summary: "Summary JVN",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Summary: "Summary RedHat",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
}},
},
},
},
@@ -160,20 +160,20 @@ func TestSummaries(t *testing.T) {
lang: "en",
cont: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Title: "Title JVN",
Summary: "Summary JVN",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Summary: "Summary RedHat",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Summary: "Summary NVD",
// Severity is NOT included in NVD
},
}},
},
},
},
@@ -220,32 +220,32 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss3Score: 6.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss3Score: 2.0,
},
}},
},
},
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss3Score: 5.0,
},
}},
},
},
"CVE-2017-0005": {
@@ -254,10 +254,10 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0006": {
CveID: "CVE-2017-0005",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss3Score: 10.0,
},
}},
},
},
},
@@ -274,32 +274,32 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 1.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 2.0,
},
}},
},
},
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 5.0,
},
}},
},
},
"CVE-2017-0005": {
@@ -308,10 +308,10 @@ func TestCountGroupBySeverity(t *testing.T) {
"CVE-2017-0006": {
CveID: "CVE-2017-0005",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 10.0,
},
}},
},
},
},
@@ -346,27 +346,27 @@ func TestToSortedSlice(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 7.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 8.0,
},
}},
},
},
},
@@ -374,27 +374,27 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0001",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 7.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 8.0,
},
}},
},
},
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
},
@@ -405,23 +405,23 @@ func TestToSortedSlice(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: CveContents{
RedHat: {
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
},
@@ -429,23 +429,23 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0001",
CveContents: CveContents{
RedHat: {
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 6.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 7.0,
},
}},
},
},
},
@@ -456,19 +456,19 @@ func TestToSortedSlice(t *testing.T) {
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "High",
},
}},
},
},
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "Low",
},
}},
},
},
},
@@ -476,19 +476,19 @@ func TestToSortedSlice(t *testing.T) {
{
CveID: "CVE-2017-0002",
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "High",
},
}},
},
},
{
CveID: "CVE-2017-0001",
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "Low",
},
}},
},
},
},
@@ -510,31 +510,31 @@ func TestCvss2Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.2,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss2Severity: "HIGH",
Cvss2Score: 8.0,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Cvss2Severity: "HIGH",
},
}},
//v3
RedHatAPI: {
RedHatAPI: []CveContent{{
Type: RedHatAPI,
Cvss3Score: 8.1,
Cvss3Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
Cvss3Severity: "HIGH",
},
}},
},
},
out: []CveContentCvss{
@@ -590,24 +590,24 @@ func TestMaxCvss2Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.2,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss2Severity: "HIGH",
Cvss2Score: 8.0,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
// Severity is NOT included in NVD
},
}},
},
},
out: CveContentCvss{
@@ -650,18 +650,18 @@ func TestCvss3Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
RedHat: {
RedHat: []CveContent{{
Type: RedHat,
Cvss3Severity: "HIGH",
Cvss3Score: 8.0,
Cvss3Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 8.1,
Cvss2Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
Cvss2Severity: "HIGH",
},
}},
},
},
out: []CveContentCvss{
@@ -680,10 +680,10 @@ func TestCvss3Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "HIGH",
},
}},
},
},
out: []CveContentCvss{
@@ -720,12 +720,12 @@ func TestMaxCvss3Scores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
RedHat: {
RedHat: []CveContent{{
Type: RedHat,
Cvss3Severity: "HIGH",
Cvss3Score: 8.0,
Cvss3Vector: "AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
},
}},
},
},
out: CveContentCvss{
@@ -768,14 +768,14 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Nvd: {
Nvd: []CveContent{{
Type: Nvd,
Cvss3Score: 7.0,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss2Score: 8.0,
},
}},
},
},
out: CveContentCvss{
@@ -789,10 +789,10 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
RedHat: {
RedHat: []CveContent{{
Type: RedHat,
Cvss3Score: 8.0,
},
}},
},
},
out: CveContentCvss{
@@ -807,10 +807,10 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "HIGH",
},
}},
},
},
out: CveContentCvss{
@@ -827,15 +827,15 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "MEDIUM",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 7.0,
Cvss2Severity: "HIGH",
},
}},
},
},
out: CveContentCvss{
@@ -871,15 +871,15 @@ func TestMaxCvssScores(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Ubuntu: {
Ubuntu: []CveContent{{
Type: Ubuntu,
Cvss3Severity: "MEDIUM",
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 4.0,
Cvss2Severity: "MEDIUM",
},
}},
},
DistroAdvisories: []DistroAdvisory{
{
@@ -925,21 +925,21 @@ func TestFormatMaxCvssScore(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.3,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss3Severity: "HIGH",
Cvss3Score: 8.0,
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 8.1,
// Severity is NOT included in NVD
},
}},
},
},
out: "8.0 HIGH (redhat)",
@@ -947,22 +947,22 @@ func TestFormatMaxCvssScore(t *testing.T) {
{
in: VulnInfo{
CveContents: CveContents{
Jvn: {
Jvn: []CveContent{{
Type: Jvn,
Cvss2Severity: "HIGH",
Cvss2Score: 8.3,
},
RedHat: {
}},
RedHat: []CveContent{{
Type: RedHat,
Cvss2Severity: "HIGH",
Cvss2Score: 8.0,
Cvss3Severity: "HIGH",
Cvss3Score: 9.9,
},
Nvd: {
}},
Nvd: []CveContent{{
Type: Nvd,
Cvss2Score: 8.1,
},
}},
},
},
out: "9.9 HIGH (redhat)",
@@ -1037,20 +1037,20 @@ func TestAppendIfMissing(t *testing.T) {
}{
{
in: Confidences{
CpeNameMatch,
NvdExactVersionMatch,
},
arg: CpeNameMatch,
arg: NvdExactVersionMatch,
out: Confidences{
CpeNameMatch,
NvdExactVersionMatch,
},
},
{
in: Confidences{
CpeNameMatch,
NvdExactVersionMatch,
},
arg: ChangelogExactMatch,
out: Confidences{
CpeNameMatch,
NvdExactVersionMatch,
ChangelogExactMatch,
},
},
@@ -1071,21 +1071,21 @@ func TestSortByConfident(t *testing.T) {
{
in: Confidences{
OvalMatch,
CpeNameMatch,
NvdExactVersionMatch,
},
out: Confidences{
OvalMatch,
CpeNameMatch,
NvdExactVersionMatch,
},
},
{
in: Confidences{
CpeNameMatch,
NvdExactVersionMatch,
OvalMatch,
},
out: Confidences{
OvalMatch,
CpeNameMatch,
NvdExactVersionMatch,
},
},
}
@@ -1610,3 +1610,78 @@ func TestVulnInfos_FilterIgnorePkgs(t *testing.T) {
})
}
}
func TestVulnInfos_FilterByConfidenceOver(t *testing.T) {
type args struct {
over int
}
tests := []struct {
name string
v VulnInfos
args args
want VulnInfos
}{
{
name: "over 0",
v: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{JvnVendorProductMatch},
},
},
args: args{
over: 0,
},
want: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{JvnVendorProductMatch},
},
},
},
{
name: "over 20",
v: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{JvnVendorProductMatch},
},
},
args: args{
over: 20,
},
want: map[string]VulnInfo{},
},
{
name: "over 100",
v: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{
NvdExactVersionMatch,
JvnVendorProductMatch,
},
},
},
args: args{
over: 20,
},
want: map[string]VulnInfo{
"CVE-2021-1111": {
CveID: "CVE-2021-1111",
Confidences: Confidences{
NvdExactVersionMatch,
JvnVendorProductMatch,
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.v.FilterByConfidenceOver(tt.args.over); !reflect.DeepEqual(got, tt.want) {
t.Errorf("VulnInfos.FilterByConfidenceOver() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -53,8 +54,8 @@ func (o Alpine) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
return len(relatedDefs.entries), nil
}
func (o Alpine) update(r *models.ScanResult, defPacks defPacks) {
cveID := defPacks.def.Advisory.Cves[0].CveID
func (o Alpine) update(r *models.ScanResult, defpacks defPacks) {
cveID := defpacks.def.Advisory.Cves[0].CveID
vinfo, ok := r.ScannedCves[cveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", cveID)
@@ -64,7 +65,7 @@ func (o Alpine) update(r *models.ScanResult, defPacks defPacks) {
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages = defpacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cveID] = vinfo
}

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -11,7 +12,7 @@ import (
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
// DebianBase is the base struct of Debian and Ubuntu
@@ -19,73 +20,75 @@ type DebianBase struct {
Base
}
func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) {
ovalContent := *o.convertToModel(&defPacks.def)
ovalContent.Type = models.NewCveContentType(o.family)
vinfo, ok := r.ScannedCves[defPacks.def.Debian.CveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Debian.CveID)
vinfo = models.VulnInfo{
CveID: defPacks.def.Debian.CveID,
Confidences: []models.Confidence{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
func (o DebianBase) update(r *models.ScanResult, defpacks defPacks) {
for _, cve := range defpacks.def.Advisory.Cves {
ovalContent := o.convertToModel(cve.CveID, &defpacks.def)
if ovalContent == nil {
continue
}
} else {
cveContents := vinfo.CveContents
ctype := models.NewCveContentType(o.family)
if _, ok := vinfo.CveContents[ctype]; ok {
logging.Log.Debugf("%s OVAL will be overwritten",
defPacks.def.Debian.CveID)
vinfo, ok := r.ScannedCves[cve.CveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", cve.CveID)
vinfo = models.VulnInfo{
CveID: cve.CveID,
Confidences: []models.Confidence{models.OvalMatch},
CveContents: models.NewCveContents(*ovalContent),
}
} else {
logging.Log.Debugf("%s is also detected by OVAL",
defPacks.def.Debian.CveID)
cveContents = models.CveContents{}
}
if r.Family != constant.Raspbian {
cveContents := vinfo.CveContents
if _, ok := vinfo.CveContents[ovalContent.Type]; ok {
logging.Log.Debugf("%s OVAL will be overwritten", cve.CveID)
} else {
logging.Log.Debugf("%s is also detected by OVAL", cve.CveID)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
} else {
if len(vinfo.Confidences) == 0 {
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ovalContent.Type] = []models.CveContent{*ovalContent}
vinfo.CveContents = cveContents
}
// uniq(vinfo.AffectedPackages[].Name + defPacks.binpkgFixstat(map[string(=package name)]fixStat{}))
collectBinpkgFixstat := defPacks{
binpkgFixstat: map[string]fixStat{},
}
for packName, fixStatus := range defpacks.binpkgFixstat {
collectBinpkgFixstat.binpkgFixstat[packName] = fixStatus
}
for _, pack := range vinfo.AffectedPackages {
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
isSrcPack: false,
}
}
cveContents[ctype] = ovalContent
vinfo.CveContents = cveContents
}
// uniq(vinfo.PackNames + defPacks.binpkgStat)
for _, pack := range vinfo.AffectedPackages {
defPacks.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
isSrcPack: false,
}
}
// Update package status of source packages.
// In the case of Debian based Linux, sometimes source package name is defined as affected package in OVAL.
// To display binary package name showed in apt-get, need to convert source name to binary name.
for binName := range defPacks.binpkgFixstat {
if srcPack, ok := r.SrcPackages.FindByBinName(binName); ok {
for _, p := range defPacks.def.AffectedPacks {
if p.Name == srcPack.Name {
defPacks.binpkgFixstat[binName] = fixStat{
notFixedYet: p.NotFixedYet,
fixedIn: p.Version,
isSrcPack: true,
srcPackName: srcPack.Name,
// Update package status of source packages.
// In the case of Debian based Linux, sometimes source package name is defined as affected package in OVAL.
// To display binary package name showed in apt-get, need to convert source name to binary name.
for binName := range defpacks.binpkgFixstat {
if srcPack, ok := r.SrcPackages.FindByBinName(binName); ok {
for _, p := range defpacks.def.AffectedPacks {
if p.Name == srcPack.Name {
collectBinpkgFixstat.binpkgFixstat[binName] = fixStat{
notFixedYet: p.NotFixedYet,
fixedIn: p.Version,
isSrcPack: true,
srcPackName: srcPack.Name,
}
}
}
}
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[defPacks.def.Debian.CveID] = vinfo
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cve.CveID] = vinfo
}
}
func (o DebianBase) convertToModel(def *ovalmodels.Definition) *models.CveContent {
refs := []models.Reference{}
func (o DebianBase) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
refs := make([]models.Reference, 0, len(def.References))
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
@@ -94,14 +97,23 @@ func (o DebianBase) convertToModel(def *ovalmodels.Definition) *models.CveConten
})
}
return &models.CveContent{
CveID: def.Debian.CveID,
Title: def.Title,
Summary: def.Description,
Cvss2Severity: def.Advisory.Severity,
Cvss3Severity: def.Advisory.Severity,
References: refs,
for _, cve := range def.Advisory.Cves {
if cve.CveID != cveID {
continue
}
return &models.CveContent{
Type: models.NewCveContentType(o.family),
CveID: cve.CveID,
Title: def.Title,
Summary: def.Description,
Cvss2Severity: def.Advisory.Severity,
Cvss3Severity: def.Advisory.Severity,
References: refs,
}
}
return nil
}
// Debian is the interface for Debian OVAL
@@ -142,16 +154,8 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.Cnf.IsFetchViaHTTP() {
if r.Family != constant.Raspbian {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
}
} else {
// OVAL does not support Package for Raspbian, so skip it.
result := r.RemoveRaspbianPackFromResult()
if relatedDefs, err = getDefsByPackNameViaHTTP(&result, o.Cnf.GetURL()); err != nil {
return 0, err
}
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
}
} else {
driver, err := newOvalDB(o.Cnf, r.Family)
@@ -164,16 +168,8 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
}
}()
if r.Family != constant.Raspbian {
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
} else {
// OVAL does not support Package for Raspbian, so skip it.
result := r.RemoveRaspbianPackFromResult()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, &result); err != nil {
return 0, err
}
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
}
}
@@ -197,9 +193,11 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
}
for _, vuln := range r.ScannedCves {
if cont, ok := vuln.CveContents[models.Debian]; ok {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.Debian] = cont
if conts, ok := vuln.CveContents[models.Debian]; ok {
for i, cont := range conts {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.Debian][i] = cont
}
}
}
return len(relatedDefs.entries), nil
@@ -358,6 +356,47 @@ func (o Ubuntu) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
"linux",
}
return o.fillWithOval(r, kernelNamesInOval)
case "21":
kernelNamesInOval := []string{
"linux-aws",
"linux-base-sgx",
"linux-base",
"linux-cloud-tools-common",
"linux-cloud-tools-generic",
"linux-cloud-tools-lowlatency",
"linux-cloud-tools-virtual",
"linux-gcp",
"linux-generic",
"linux-gke",
"linux-headers-aws",
"linux-headers-gcp",
"linux-headers-gke",
"linux-headers-oracle",
"linux-image-aws",
"linux-image-extra-virtual",
"linux-image-gcp",
"linux-image-generic",
"linux-image-gke",
"linux-image-lowlatency",
"linux-image-oracle",
"linux-image-virtual",
"linux-lowlatency",
"linux-modules-extra-aws",
"linux-modules-extra-gcp",
"linux-modules-extra-gke",
"linux-oracle",
"linux-tools-aws",
"linux-tools-common",
"linux-tools-gcp",
"linux-tools-generic",
"linux-tools-gke",
"linux-tools-host",
"linux-tools-lowlatency",
"linux-tools-oracle",
"linux-tools-virtual",
"linux-virtual",
}
return o.fillWithOval(r, kernelNamesInOval)
}
return 0, fmt.Errorf("Ubuntu %s is not support for now", r.Release)
}
@@ -439,7 +478,7 @@ func (o Ubuntu) fillWithOval(r *models.ScanResult, kernelNamesInOval []string) (
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v")
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
@@ -473,9 +512,11 @@ func (o Ubuntu) fillWithOval(r *models.ScanResult, kernelNamesInOval []string) (
}
for _, vuln := range r.ScannedCves {
if cont, ok := vuln.CveContents[models.Ubuntu]; ok {
cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID
vuln.CveContents[models.Ubuntu] = cont
if conts, ok := vuln.CveContents[models.Ubuntu]; ok {
for i, cont := range conts {
cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID
vuln.CveContents[models.Ubuntu][i] = cont
}
}
}
return len(relatedDefs.entries), nil

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -7,7 +8,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
func TestPackNamesOfUpdateDebian(t *testing.T) {
@@ -29,8 +30,8 @@ func TestPackNamesOfUpdateDebian(t *testing.T) {
},
defPacks: defPacks{
def: ovalmodels.Definition{
Debian: ovalmodels.Debian{
CveID: "CVE-2000-1000",
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{{CveID: "CVE-2000-1000"}},
},
},
binpkgFixstat: map[string]fixStat{
@@ -52,15 +53,68 @@ func TestPackNamesOfUpdateDebian(t *testing.T) {
},
},
},
{
in: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packC"},
},
},
},
},
defPacks: defPacks{
def: ovalmodels.Definition{
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{
{
CveID: "CVE-2000-1000",
},
{
CveID: "CVE-2000-1001",
},
},
},
},
binpkgFixstat: map[string]fixStat{
"packB": {
notFixedYet: false,
},
},
},
out: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packB", NotFixedYet: false},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packB", NotFixedYet: false},
{Name: "packC"},
},
},
},
},
},
}
// util.Log = util.NewCustomLogger()
for i, tt := range tests {
Debian{}.update(&tt.in, tt.defPacks)
e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages
a := tt.in.ScannedCves["CVE-2000-1000"].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %#v\n actual: %#v\n", i, e, a)
for cveid := range tt.out.ScannedCves {
e := tt.out.ScannedCves[cveid].AffectedPackages
a := tt.in.ScannedCves[cveid].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %v\n actual: %v\n", i, e, a)
}
}
}
}

View File

@@ -1 +0,0 @@
package oval

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -10,8 +11,8 @@ import (
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/kotakanbe/goval-dictionary/db"
"github.com/parnurzeal/gorequest"
"github.com/vulsio/goval-dictionary/db"
"golang.org/x/xerrors"
)
@@ -41,7 +42,7 @@ func (b Base) CheckIfOvalFetched(osFamily, release string) (fetched bool, err er
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v")
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
@@ -80,10 +81,13 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v")
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
lastModified = driver.GetLastModified(ovalFamily, release)
lastModified, err = driver.GetLastModified(ovalFamily, release)
if err != nil {
return false, xerrors.Errorf("Failed to GetLastModified: %w", err)
}
} else {
url, _ := util.URLPathJoin(config.Conf.OvalDict.URL, "lastmodified", ovalFamily, release)
resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End()
@@ -99,7 +103,7 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
since := time.Now()
since = since.AddDate(0, 0, -3)
if lastModified.Before(since) {
logging.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/kotakanbe/goval-dictionary#usage",
logging.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/vulsio/goval-dictionary#usage",
osFamily, release, lastModified)
return false, nil
}

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -11,10 +12,10 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
// RedHatBase is the base struct for RedHat and CentOS
// RedHatBase is the base struct for RedHat, CentOS, Alma and Rocky
type RedHatBase struct {
Base
}
@@ -33,7 +34,7 @@ func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v")
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
@@ -50,14 +51,18 @@ func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
for _, vuln := range r.ScannedCves {
switch models.NewCveContentType(o.family) {
case models.RedHat:
if cont, ok := vuln.CveContents[models.RedHat]; ok {
cont.SourceLink = "https://access.redhat.com/security/cve/" + cont.CveID
vuln.CveContents[models.RedHat] = cont
if conts, ok := vuln.CveContents[models.RedHat]; ok {
for i, cont := range conts {
cont.SourceLink = "https://access.redhat.com/security/cve/" + cont.CveID
vuln.CveContents[models.RedHat][i] = cont
}
}
case models.Oracle:
if cont, ok := vuln.CveContents[models.Oracle]; ok {
cont.SourceLink = fmt.Sprintf("https://linux.oracle.com/cve/%s.html", cont.CveID)
vuln.CveContents[models.Oracle] = cont
if conts, ok := vuln.CveContents[models.Oracle]; ok {
for i, cont := range conts {
cont.SourceLink = fmt.Sprintf("https://linux.oracle.com/cve/%s.html", cont.CveID)
vuln.CveContents[models.Oracle][i] = cont
}
}
}
}
@@ -92,59 +97,71 @@ var kernelRelatedPackNames = map[string]bool{
"kernel-tools": true,
"kernel-tools-libs": true,
"kernel-tools-libs-devel": true,
"kernel-uek": true,
"perf": true,
"python-perf": true,
}
func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int) {
ctype := models.NewCveContentType(o.family)
for _, cve := range defPacks.def.Advisory.Cves {
ovalContent := *o.convertToModel(cve.CveID, &defPacks.def)
func (o RedHatBase) update(r *models.ScanResult, defpacks defPacks) (nCVEs int) {
for _, cve := range defpacks.def.Advisory.Cves {
ovalContent := o.convertToModel(cve.CveID, &defpacks.def)
if ovalContent == nil {
continue
}
vinfo, ok := r.ScannedCves[cve.CveID]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL: DefID: %s", cve.CveID, defPacks.def.DefinitionID)
logging.Log.Debugf("%s is newly detected by OVAL: DefID: %s", cve.CveID, defpacks.def.DefinitionID)
vinfo = models.VulnInfo{
CveID: cve.CveID,
Confidences: models.Confidences{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
CveContents: models.NewCveContents(*ovalContent),
}
nCVEs++
} else {
cveContents := vinfo.CveContents
if v, ok := vinfo.CveContents[ctype]; ok {
if v.LastModified.After(ovalContent.LastModified) {
logging.Log.Debugf("%s ignored. DefID: %s ", cve.CveID, defPacks.def.DefinitionID)
} else {
logging.Log.Debugf("%s OVAL will be overwritten. DefID: %s", cve.CveID, defPacks.def.DefinitionID)
if v, ok := vinfo.CveContents[ovalContent.Type]; ok {
for _, vv := range v {
if vv.LastModified.After(ovalContent.LastModified) {
logging.Log.Debugf("%s ignored. DefID: %s ", cve.CveID, defpacks.def.DefinitionID)
} else {
logging.Log.Debugf("%s OVAL will be overwritten. DefID: %s", cve.CveID, defpacks.def.DefinitionID)
}
}
} else {
logging.Log.Debugf("%s also detected by OVAL. DefID: %s", cve.CveID, defPacks.def.DefinitionID)
logging.Log.Debugf("%s also detected by OVAL. DefID: %s", cve.CveID, defpacks.def.DefinitionID)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ctype] = ovalContent
cveContents[ovalContent.Type] = []models.CveContent{*ovalContent}
vinfo.CveContents = cveContents
}
vinfo.DistroAdvisories.AppendIfMissing(
o.convertToDistroAdvisory(&defPacks.def))
o.convertToDistroAdvisory(&defpacks.def))
// uniq(vinfo.AffectedPackages[].Name + defPacks.binpkgFixstat(map[string(=package name)]fixStat{}))
collectBinpkgFixstat := defPacks{
binpkgFixstat: map[string]fixStat{},
}
for packName, fixStatus := range defpacks.binpkgFixstat {
collectBinpkgFixstat.binpkgFixstat[packName] = fixStatus
}
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
for _, pack := range vinfo.AffectedPackages {
if stat, ok := defPacks.binpkgFixstat[pack.Name]; !ok {
defPacks.binpkgFixstat[pack.Name] = fixStat{
if stat, ok := collectBinpkgFixstat.binpkgFixstat[pack.Name]; !ok {
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
} else if stat.notFixedYet {
defPacks.binpkgFixstat[pack.Name] = fixStat{
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: true,
fixedIn: pack.FixedIn,
}
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[cve.CveID] = vinfo
}
@@ -153,9 +170,12 @@ func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int)
func (o RedHatBase) convertToDistroAdvisory(def *ovalmodels.Definition) *models.DistroAdvisory {
advisoryID := def.Title
if (o.family == constant.RedHat || o.family == constant.CentOS) && len(advisoryID) > 0 {
ss := strings.Fields(def.Title)
advisoryID = strings.TrimSuffix(ss[0], ":")
switch o.family {
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky, constant.Oracle:
if def.Title != "" {
ss := strings.Fields(def.Title)
advisoryID = strings.TrimSuffix(ss[0], ":")
}
}
return &models.DistroAdvisory{
AdvisoryID: advisoryID,
@@ -167,18 +187,19 @@ func (o RedHatBase) convertToDistroAdvisory(def *ovalmodels.Definition) *models.
}
func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *models.CveContent {
refs := make([]models.Reference, 0, len(def.References))
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
for _, cve := range def.Advisory.Cves {
if cve.CveID != cveID {
continue
}
var refs []models.Reference
for _, r := range def.References {
refs = append(refs, models.Reference{
Link: r.RefURL,
Source: r.Source,
RefID: r.RefID,
})
}
score2, vec2 := o.parseCvss2(cve.Cvss2)
score3, vec3 := o.parseCvss3(cve.Cvss3)
@@ -318,3 +339,39 @@ func NewAmazon(cnf config.VulnDictInterface) Amazon {
},
}
}
// Alma is the interface for RedhatBase OVAL
type Alma struct {
// Base
RedHatBase
}
// NewAlma creates OVAL client for Alma Linux
func NewAlma(cnf config.VulnDictInterface) Alma {
return Alma{
RedHatBase{
Base{
family: constant.Alma,
Cnf: cnf,
},
},
}
}
// Rocky is the interface for RedhatBase OVAL
type Rocky struct {
// Base
RedHatBase
}
// NewRocky creates OVAL client for Rocky Linux
func NewRocky(cnf config.VulnDictInterface) Rocky {
return Rocky{
RedHatBase{
Base{
family: constant.Rocky,
Cnf: cnf,
},
},
}
}

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -7,7 +8,7 @@ import (
"testing"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
func TestParseCvss2(t *testing.T) {
@@ -128,15 +129,68 @@ func TestPackNamesOfUpdate(t *testing.T) {
},
},
},
{
in: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packC"},
},
},
},
},
defPacks: defPacks{
def: ovalmodels.Definition{
Advisory: ovalmodels.Advisory{
Cves: []ovalmodels.Cve{
{
CveID: "CVE-2000-1000",
},
{
CveID: "CVE-2000-1001",
},
},
},
},
binpkgFixstat: map[string]fixStat{
"packB": {
notFixedYet: false,
},
},
},
out: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2000-1000": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packA"},
{Name: "packB", NotFixedYet: false},
},
},
"CVE-2000-1001": models.VulnInfo{
AffectedPackages: models.PackageFixStatuses{
{Name: "packB", NotFixedYet: false},
{Name: "packC"},
},
},
},
},
},
}
// util.Log = util.Logger{}.NewCustomLogger()
for i, tt := range tests {
RedHat{}.update(&tt.in, tt.defPacks)
e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages
a := tt.in.ScannedCves["CVE-2000-1000"].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %v\n actual: %v\n", i, e, a)
for cveid := range tt.out.ScannedCves {
e := tt.out.ScannedCves[cveid].AffectedPackages
a := tt.in.ScannedCves[cveid].AffectedPackages
if !reflect.DeepEqual(a, e) {
t.Errorf("[%d] expected: %v\n actual: %v\n", i, e, a)
}
}
}
}

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -7,7 +8,7 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
// SUSE is the struct of SUSE Linux
@@ -40,7 +41,7 @@ func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v")
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
@@ -53,22 +54,24 @@ func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
}
for _, vuln := range r.ScannedCves {
if cont, ok := vuln.CveContents[models.SUSE]; ok {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.SUSE] = cont
if conts, ok := vuln.CveContents[models.SUSE]; ok {
for i, cont := range conts {
cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
vuln.CveContents[models.SUSE][i] = cont
}
}
}
return len(relatedDefs.entries), nil
}
func (o SUSE) update(r *models.ScanResult, defPacks defPacks) {
ovalContent := *o.convertToModel(&defPacks.def)
func (o SUSE) update(r *models.ScanResult, defpacks defPacks) {
ovalContent := *o.convertToModel(&defpacks.def)
ovalContent.Type = models.NewCveContentType(o.family)
vinfo, ok := r.ScannedCves[defPacks.def.Title]
vinfo, ok := r.ScannedCves[defpacks.def.Title]
if !ok {
logging.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Title)
logging.Log.Debugf("%s is newly detected by OVAL", defpacks.def.Title)
vinfo = models.VulnInfo{
CveID: defPacks.def.Title,
CveID: defpacks.def.Title,
Confidences: models.Confidences{models.OvalMatch},
CveContents: models.NewCveContents(ovalContent),
}
@@ -76,26 +79,33 @@ func (o SUSE) update(r *models.ScanResult, defPacks defPacks) {
cveContents := vinfo.CveContents
ctype := models.NewCveContentType(o.family)
if _, ok := vinfo.CveContents[ctype]; ok {
logging.Log.Debugf("%s OVAL will be overwritten", defPacks.def.Title)
logging.Log.Debugf("%s OVAL will be overwritten", defpacks.def.Title)
} else {
logging.Log.Debugf("%s is also detected by OVAL", defPacks.def.Title)
logging.Log.Debugf("%s is also detected by OVAL", defpacks.def.Title)
cveContents = models.CveContents{}
}
vinfo.Confidences.AppendIfMissing(models.OvalMatch)
cveContents[ctype] = ovalContent
cveContents[ctype] = []models.CveContent{ovalContent}
vinfo.CveContents = cveContents
}
// uniq(vinfo.PackNames + defPacks.actuallyAffectedPackNames)
// uniq(vinfo.AffectedPackages[].Name + defPacks.binpkgFixstat(map[string(=package name)]fixStat{}))
collectBinpkgFixstat := defPacks{
binpkgFixstat: map[string]fixStat{},
}
for packName, fixStatus := range defpacks.binpkgFixstat {
collectBinpkgFixstat.binpkgFixstat[packName] = fixStatus
}
for _, pack := range vinfo.AffectedPackages {
defPacks.binpkgFixstat[pack.Name] = fixStat{
collectBinpkgFixstat.binpkgFixstat[pack.Name] = fixStat{
notFixedYet: pack.NotFixedYet,
fixedIn: pack.FixedIn,
}
}
vinfo.AffectedPackages = defPacks.toPackStatuses()
vinfo.AffectedPackages = collectBinpkgFixstat.toPackStatuses()
vinfo.AffectedPackages.Sort()
r.ScannedCves[defPacks.def.Title] = vinfo
r.ScannedCves[defpacks.def.Title] = vinfo
}
func (o SUSE) convertToModel(def *ovalmodels.Definition) *models.CveContent {

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -7,6 +8,7 @@ import (
"net/http"
"regexp"
"sort"
"strings"
"time"
"github.com/cenkalti/backoff"
@@ -18,9 +20,9 @@ import (
apkver "github.com/knqyf263/go-apk-version"
debver "github.com/knqyf263/go-deb-version"
rpmver "github.com/knqyf263/go-rpm-version"
"github.com/kotakanbe/goval-dictionary/db"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
"github.com/parnurzeal/gorequest"
"github.com/vulsio/goval-dictionary/db"
ovalmodels "github.com/vulsio/goval-dictionary/models"
"golang.org/x/xerrors"
)
@@ -155,7 +157,11 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ova
select {
case res := <-resChan:
for _, def := range res.defs {
affected, notFixedYet, fixedIn := isOvalDefAffected(def, res.request, r.Family, r.RunningKernel, r.EnabledDnfModules)
affected, notFixedYet, fixedIn, err := isOvalDefAffected(def, res.request, r.Family, r.RunningKernel, r.EnabledDnfModules)
if err != nil {
errs = append(errs, err)
continue
}
if !affected {
continue
}
@@ -185,7 +191,7 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ova
}
}
if len(errs) != 0 {
return relatedDefs, xerrors.Errorf("Failed to fetch OVAL. err: %w", errs)
return relatedDefs, xerrors.Errorf("Failed to detect OVAL. err: %w", errs)
}
return
}
@@ -262,7 +268,10 @@ func getDefsByPackNameFromOvalDB(driver db.DB, r *models.ScanResult) (relatedDef
return relatedDefs, xerrors.Errorf("Failed to get %s OVAL info by package: %#v, err: %w", r.Family, req, err)
}
for _, def := range definitions {
affected, notFixedYet, fixedIn := isOvalDefAffected(def, req, ovalFamily, r.RunningKernel, r.EnabledDnfModules)
affected, notFixedYet, fixedIn, err := isOvalDefAffected(def, req, ovalFamily, r.RunningKernel, r.EnabledDnfModules)
if err != nil {
return relatedDefs, xerrors.Errorf("Failed to exec isOvalAffected. err: %w", err)
}
if !affected {
continue
}
@@ -289,12 +298,29 @@ func getDefsByPackNameFromOvalDB(driver db.DB, r *models.ScanResult) (relatedDef
return
}
func isOvalDefAffected(def ovalmodels.Definition, req request, family string, running models.Kernel, enabledMods []string) (affected, notFixedYet bool, fixedIn string) {
func isOvalDefAffected(def ovalmodels.Definition, req request, family string, running models.Kernel, enabledMods []string) (affected, notFixedYet bool, fixedIn string, err error) {
for _, ovalPack := range def.AffectedPacks {
if req.packName != ovalPack.Name {
continue
}
switch family {
case constant.Oracle, constant.Amazon:
if ovalPack.Arch == "" {
logging.Log.Infof("Arch is needed to detect Vulns for Amazon and Oracle Linux, but empty. You need refresh OVAL maybe. oval: %#v, defID: %s", ovalPack, def.DefinitionID)
continue
}
}
if ovalPack.Arch != "" && req.arch != ovalPack.Arch {
continue
}
// https://github.com/aquasecurity/trivy/pull/745
if strings.Contains(req.versionRelease, ".ksplice1.") != strings.Contains(ovalPack.Version, ".ksplice1.") {
continue
}
isModularityLabelEmptyOrSame := false
if ovalPack.ModularityLabel != "" {
for _, mod := range enabledMods {
@@ -312,7 +338,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
if running.Release != "" {
switch family {
case constant.RedHat, constant.CentOS:
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky, constant.Oracle:
// For kernel related packages, ignore OVAL information with different major versions
if _, ok := kernelRelatedPackNames[ovalPack.Name]; ok {
if util.Major(ovalPack.Version) != util.Major(running.Release) {
@@ -323,7 +349,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
}
if ovalPack.NotFixedYet {
return true, true, ovalPack.Version
return true, true, ovalPack.Version, nil
}
// Compare between the installed version vs the version in OVAL
@@ -331,12 +357,12 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
if err != nil {
logging.Log.Debugf("Failed to parse versions: %s, Ver: %#v, OVAL: %#v, DefID: %s",
err, req.versionRelease, ovalPack, def.DefinitionID)
return false, false, ovalPack.Version
return false, false, ovalPack.Version, nil
}
if less {
if req.isSrcPack {
// Unable to judge whether fixed or not-fixed of src package(Ubuntu, Debian)
return true, false, ovalPack.Version
return true, false, ovalPack.Version, nil
}
// If the version of installed is less than in OVAL
@@ -346,12 +372,13 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
constant.SUSEEnterpriseServer,
constant.Debian,
constant.Ubuntu,
constant.Raspbian:
constant.Raspbian,
constant.Oracle:
// Use fixed state in OVAL for these distros.
return true, false, ovalPack.Version
return true, false, ovalPack.Version, nil
}
// But CentOS can't judge whether fixed or unfixed.
// But CentOS/Alma/Rocky can't judge whether fixed or unfixed.
// Because fixed state in RHEL OVAL is different.
// So, it have to be judged version comparison.
@@ -359,7 +386,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
// In these mode, the blow field was set empty.
// Vuls can not judge fixed or unfixed.
if req.newVersionRelease == "" {
return true, false, ovalPack.Version
return true, false, ovalPack.Version, nil
}
// compare version: newVer vs oval
@@ -367,12 +394,12 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
if err != nil {
logging.Log.Debugf("Failed to parse versions: %s, NewVer: %#v, OVAL: %#v, DefID: %s",
err, req.newVersionRelease, ovalPack, def.DefinitionID)
return false, false, ovalPack.Version
return false, false, ovalPack.Version, nil
}
return true, less, ovalPack.Version
return true, less, ovalPack.Version, nil
}
}
return false, false, ""
return false, false, "", nil
}
func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error) {
@@ -409,9 +436,11 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
return vera.LessThan(verb), nil
case constant.RedHat,
constant.CentOS:
vera := rpmver.NewVersion(centOSVersionToRHEL(newVer))
verb := rpmver.NewVersion(centOSVersionToRHEL(packInOVAL.Version))
constant.CentOS,
constant.Alma,
constant.Rocky:
vera := rpmver.NewVersion(rhelDownStreamOSVersionToRHEL(newVer))
verb := rpmver.NewVersion(rhelDownStreamOSVersionToRHEL(packInOVAL.Version))
return vera.LessThan(verb), nil
default:
@@ -419,10 +448,10 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
}
}
var centosVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`)
var rhelDownStreamOSVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.(centos|rocky|alma))?`)
func centOSVersionToRHEL(ver string) string {
return centosVerPattern.ReplaceAllString(ver, ".el$1")
func rhelDownStreamOSVersionToRHEL(ver string) string {
return rhelDownStreamOSVerPattern.ReplaceAllString(ver, ".el$1")
}
// NewOVALClient returns a client for OVAL database
@@ -435,8 +464,11 @@ func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
case constant.RedHat:
return NewRedhat(&cnf), nil
case constant.CentOS:
//use RedHat's OVAL
return NewCentOS(&cnf), nil
case constant.Alma:
return NewAlma(&cnf), nil
case constant.Rocky:
return NewRocky(&cnf), nil
case constant.Oracle:
return NewOracle(&cnf), nil
case constant.SUSEEnterpriseServer:
@@ -459,17 +491,14 @@ func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
}
// GetFamilyInOval returns the OS family name in OVAL
// For example, CentOS uses Red Hat's OVAL, so return 'redhat'
// For example, CentOS/Alma/Rocky uses Red Hat's OVAL, so return 'redhat'
func GetFamilyInOval(familyInScanResult string) (string, error) {
switch familyInScanResult {
case constant.Debian, constant.Raspbian:
return constant.Debian, nil
case constant.Ubuntu:
return constant.Ubuntu, nil
case constant.RedHat:
return constant.RedHat, nil
case constant.CentOS:
//use RedHat's OVAL
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky:
return constant.RedHat, nil
case constant.Oracle:
return constant.Oracle, nil

View File

@@ -1,3 +1,4 @@
//go:build !scanner
// +build !scanner
package oval
@@ -9,7 +10,7 @@ import (
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/models"
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
func TestUpsert(t *testing.T) {
@@ -209,6 +210,7 @@ func TestIsOvalDefAffected(t *testing.T) {
affected bool
notFixedYet bool
fixedIn string
wantErr bool
}{
// 0. Ubuntu ovalpack.NotFixedYet == true
{
@@ -1077,6 +1079,472 @@ func TestIsOvalDefAffected(t *testing.T) {
notFixedYet: false,
fixedIn: "3.1.0",
},
// Rocky Linux
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.7",
newVersionRelease: "",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.9",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.6",
newVersionRelease: "0:1.2.3-45.el6.rocky.7",
},
},
affected: true,
notFixedYet: true,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.6",
newVersionRelease: "0:1.2.3-45.el6.rocky.8",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.rocky.6",
newVersionRelease: "0:1.2.3-45.el6.rocky.9",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6_7.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.7",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.9",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.6",
newVersionRelease: "0:1.2.3-45.sl6.7",
},
},
affected: true,
notFixedYet: true,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.6",
newVersionRelease: "0:1.2.3-45.sl6.8",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.sl6.6",
newVersionRelease: "0:1.2.3-45.sl6.9",
},
},
affected: true,
notFixedYet: false,
fixedIn: "0:1.2.3-45.el6_7.8",
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6_7.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6.8",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: "rocky",
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "a",
NotFixedYet: false,
},
{
Name: "b",
NotFixedYet: false,
Version: "0:1.2.3-45.el6.8",
},
},
},
req: request{
packName: "b",
isSrcPack: false,
versionRelease: "0:1.2.3-45.el6_7.8",
},
},
affected: false,
notFixedYet: false,
},
// For kernel related packages, ignore OVAL with different major versions
{
in: in{
family: constant.Rocky,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "kernel",
Version: "4.1.0",
NotFixedYet: false,
},
},
},
req: request{
packName: "kernel",
versionRelease: "3.0.0",
newVersionRelease: "3.2.0",
},
kernel: models.Kernel{
Release: "3.0.0",
},
},
affected: false,
notFixedYet: false,
},
{
in: in{
family: constant.Rocky,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "kernel",
Version: "3.1.0",
NotFixedYet: false,
},
},
},
req: request{
packName: "kernel",
versionRelease: "3.0.0",
newVersionRelease: "3.2.0",
},
kernel: models.Kernel{
Release: "3.0.0",
},
},
affected: true,
notFixedYet: false,
fixedIn: "3.1.0",
},
// dnf module
{
in: in{
@@ -1153,9 +1621,166 @@ func TestIsOvalDefAffected(t *testing.T) {
affected: false,
notFixedYet: false,
},
// .ksplice1.
{
in: in{
family: constant.Oracle,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "2:2.17-106.0.1.ksplice1.el7_2.4",
Arch: "x86_64",
},
},
},
req: request{
packName: "nginx",
versionRelease: "2:2.17-107",
arch: "x86_64",
},
},
affected: false,
},
// .ksplice1.
{
in: in{
family: constant.Oracle,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "2:2.17-106.0.1.ksplice1.el7_2.4",
Arch: "x86_64",
},
},
},
req: request{
packName: "nginx",
versionRelease: "2:2.17-105.0.1.ksplice1.el7_2.4",
arch: "x86_64",
},
},
affected: true,
fixedIn: "2:2.17-106.0.1.ksplice1.el7_2.4",
},
// same arch
{
in: in{
family: constant.Oracle,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "2.17-106.0.1",
Arch: "x86_64",
},
},
},
req: request{
packName: "nginx",
versionRelease: "2.17-105.0.1",
arch: "x86_64",
},
},
affected: true,
fixedIn: "2.17-106.0.1",
},
// different arch
{
in: in{
family: constant.Oracle,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "2.17-106.0.1",
Arch: "aarch64",
},
},
},
req: request{
packName: "nginx",
versionRelease: "2.17-105.0.1",
arch: "x86_64",
},
},
affected: false,
fixedIn: "",
},
// Arch for RHEL, CentOS is ""
{
in: in{
family: constant.RedHat,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "2.17-106.0.1",
Arch: "",
},
},
},
req: request{
packName: "nginx",
versionRelease: "2.17-105.0.1",
arch: "x86_64",
},
},
affected: true,
fixedIn: "2.17-106.0.1",
},
// arch is empty for Oracle, Amazon linux
{
in: in{
family: constant.Oracle,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "2.17-106.0.1",
Arch: "",
},
},
},
req: request{
packName: "nginx",
versionRelease: "2.17-105.0.1",
arch: "x86_64",
},
},
wantErr: false,
fixedIn: "",
},
// arch is empty for Oracle, Amazon linux
{
in: in{
family: constant.Amazon,
def: ovalmodels.Definition{
AffectedPacks: []ovalmodels.Package{
{
Name: "nginx",
Version: "2.17-106.0.1",
Arch: "",
},
},
},
req: request{
packName: "nginx",
versionRelease: "2.17-105.0.1",
arch: "x86_64",
},
},
wantErr: false,
fixedIn: "",
},
}
for i, tt := range tests {
affected, notFixedYet, fixedIn := isOvalDefAffected(tt.in.def, tt.in.req, tt.in.family, tt.in.kernel, tt.in.mods)
affected, notFixedYet, fixedIn, err := isOvalDefAffected(tt.in.def, tt.in.req, tt.in.family, tt.in.kernel, tt.in.mods)
if tt.wantErr != (err != nil) {
t.Errorf("[%d] err\nexpected: %t\n actual: %s\n", i, tt.wantErr, err)
}
if tt.affected != affected {
t.Errorf("[%d] affected\nexpected: %v\n actual: %v\n", i, tt.affected, affected)
}
@@ -1168,7 +1793,7 @@ func TestIsOvalDefAffected(t *testing.T) {
}
}
func Test_centOSVersionToRHEL(t *testing.T) {
func Test_rhelDownStreamOSVersionToRHEL(t *testing.T) {
type args struct {
ver string
}
@@ -1184,6 +1809,13 @@ func Test_centOSVersionToRHEL(t *testing.T) {
},
want: "grub2-tools-2.02-0.80.el7.x86_64",
},
{
name: "remove rocky.",
args: args{
ver: "platform-python-3.6.8-37.el8.rocky.x86_64",
},
want: "platform-python-3.6.8-37.el8.x86_64",
},
{
name: "noop",
args: args{
@@ -1201,8 +1833,8 @@ func Test_centOSVersionToRHEL(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := centOSVersionToRHEL(tt.args.ver); got != tt.want {
t.Errorf("centOSVersionToRHEL() = %v, want %v", got, tt.want)
if got := rhelDownStreamOSVersionToRHEL(tt.args.ver); got != tt.want {
t.Errorf("rhelDownStreamOSVersionToRHEL() = %v, want %v", got, tt.want)
}
})
}

102
reporter/googlechat.go Normal file
View File

@@ -0,0 +1,102 @@
package reporter
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"time"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"golang.org/x/xerrors"
)
// GoogleChatWriter send report to GoogleChat
type GoogleChatWriter struct {
Cnf config.GoogleChatConf
Proxy string
}
func (w GoogleChatWriter) Write(rs ...models.ScanResult) (err error) {
re := regexp.MustCompile(w.Cnf.ServerNameRegexp)
for _, r := range rs {
if re.Match([]byte(r.FormatServerName())) {
continue
}
msgs := []string{fmt.Sprintf("*%s*\n%s\t%s\t%s",
r.ServerInfo(),
r.ScannedCves.FormatCveSummary(),
r.ScannedCves.FormatFixedStatus(r.Packages),
r.FormatUpdatablePkgsSummary())}
for _, vinfo := range r.ScannedCves.ToSortedSlice() {
max := vinfo.MaxCvssScore().Value.Score
exploits := ""
if 0 < len(vinfo.Exploits) || 0 < len(vinfo.Metasploits) {
exploits = "*PoC*"
}
link := ""
if strings.HasPrefix(vinfo.CveID, "CVE-") {
link = fmt.Sprintf("https://nvd.nist.gov/vuln/detail/%s", vinfo.CveID)
} else if strings.HasPrefix(vinfo.CveID, "WPVDBID-") {
link = fmt.Sprintf("https://wpscan.com/vulnerabilities/%s", strings.TrimPrefix(vinfo.CveID, "WPVDBID-"))
}
msgs = append(msgs, fmt.Sprintf(`%s %s %4.1f %5s %s`,
vinfo.CveIDDiffFormat(),
link,
max,
vinfo.AttackVector(),
exploits))
if len(msgs) == 50 {
msgs = append(msgs, "(The rest is omitted.)")
break
}
}
if len(msgs) == 1 && w.Cnf.SkipIfNoCve {
msgs = []string{}
}
if len(msgs) != 0 {
if err = w.postMessage(strings.Join(msgs, "\n")); err != nil {
return err
}
}
}
return nil
}
func (w GoogleChatWriter) postMessage(message string) error {
uri := fmt.Sprintf("%s", w.Cnf.WebHookURL)
payload := `{"text": "` + message + `" }`
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, bytes.NewBuffer([]byte(payload)))
defer cancel()
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/json; charset=utf-8")
client, err := util.GetHTTPClient(w.Proxy)
if err != nil {
return err
}
resp, err := client.Do(req)
if checkResponse(resp) != nil && err != nil {
return err
}
defer resp.Body.Close()
return nil
}
func (w GoogleChatWriter) checkResponse(r *http.Response) error {
if c := r.StatusCode; 200 <= c && c <= 299 {
return nil
}
return xerrors.Errorf("API call to %s failed: %s", r.Request.URL.String(), r.Status)
}

View File

@@ -11,7 +11,7 @@ import (
// HTTPRequestWriter writes results to HTTP request
type HTTPRequestWriter struct {
Proxy string
URL string
}
// Write sends results as HTTP response
@@ -21,7 +21,7 @@ func (w HTTPRequestWriter) Write(rs ...models.ScanResult) (err error) {
if err := json.NewEncoder(b).Encode(r); err != nil {
return err
}
_, err = http.Post(w.Proxy, "application/json; charset=utf-8", b)
_, err = http.Post(w.URL, "application/json; charset=utf-8", b)
if err != nil {
return err
}

View File

@@ -269,19 +269,20 @@ func (w SlackWriter) attachmentText(vinfo models.VulnInfo, cweDict map[string]mo
vinfo.CveID)
}
if cont, ok := vinfo.CveContents[cvss.Type]; ok {
v := fmt.Sprintf("<%s|%s> %s (<%s|%s>)",
calcURL,
fmt.Sprintf("%3.1f/%s", cvss.Value.Score, cvss.Value.Vector),
cvss.Value.Severity,
cont.SourceLink,
cvss.Type)
vectors = append(vectors, v)
if conts, ok := vinfo.CveContents[cvss.Type]; ok {
for _, cont := range conts {
v := fmt.Sprintf("<%s|%s> %s (<%s|%s>)",
calcURL,
fmt.Sprintf("%3.1f/%s", cvss.Value.Score, cvss.Value.Vector),
cvss.Value.Severity,
cont.SourceLink,
cvss.Type)
vectors = append(vectors, v)
}
} else {
if 0 < len(vinfo.DistroAdvisories) {
links := []string{}
for _, v := range vinfo.CveContents.PrimarySrcURLs(w.lang, w.osFamily, vinfo.CveID) {
for _, v := range vinfo.CveContents.PrimarySrcURLs(w.lang, w.osFamily, vinfo.CveID, vinfo.Confidences) {
links = append(links, fmt.Sprintf("<%s|%s>", v.Value, v.Type))
}

View File

@@ -70,16 +70,20 @@ func (w SyslogWriter) encodeSyslog(result models.ScanResult) (messages []string)
kvPairs = append(kvPairs, fmt.Sprintf(`cvss_vector_%s_v3="%s"`, cvss.Type, cvss.Value.Vector))
}
if content, ok := vinfo.CveContents[models.Nvd]; ok {
cwes := strings.Join(content.CweIDs, ",")
kvPairs = append(kvPairs, fmt.Sprintf(`cwe_ids="%s"`, cwes))
if w.Cnf.Verbose {
kvPairs = append(kvPairs, fmt.Sprintf(`source_link="%s"`, content.SourceLink))
kvPairs = append(kvPairs, fmt.Sprintf(`summary="%s"`, content.Summary))
if conts, ok := vinfo.CveContents[models.Nvd]; ok {
for _, cont := range conts {
cwes := strings.Join(cont.CweIDs, ",")
kvPairs = append(kvPairs, fmt.Sprintf(`cwe_ids="%s"`, cwes))
if w.Cnf.Verbose {
kvPairs = append(kvPairs, fmt.Sprintf(`source_link="%s"`, cont.SourceLink))
kvPairs = append(kvPairs, fmt.Sprintf(`summary="%s"`, cont.Summary))
}
}
}
if content, ok := vinfo.CveContents[models.RedHat]; ok {
kvPairs = append(kvPairs, fmt.Sprintf(`title="%s"`, content.Title))
if conts, ok := vinfo.CveContents[models.RedHat]; ok {
for _, cont := range conts {
kvPairs = append(kvPairs, fmt.Sprintf(`title="%s"`, cont.Title))
}
}
// message: key1="value1" key2="value2"...

View File

@@ -33,7 +33,7 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
models.PackageFixStatus{Name: "pkg4"},
},
CveContents: models.CveContents{
models.Nvd: models.CveContent{
models.Nvd: []models.CveContent{{
Cvss2Score: 5.0,
Cvss2Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
Cvss2Severity: "MEDIUM",
@@ -41,7 +41,7 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
Cvss3Score: 9.8,
Cvss3Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
Cvss3Severity: "HIGH",
},
}},
},
},
},
@@ -65,13 +65,13 @@ func TestSyslogWriterEncodeSyslog(t *testing.T) {
models.PackageFixStatus{Name: "pkg5"},
},
CveContents: models.CveContents{
models.RedHat: models.CveContent{
models.RedHat: []models.CveContent{{
Cvss3Score: 5.0,
Cvss3Severity: "Medium",
Cvss3Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C",
CweIDs: []string{"CWE-284"},
Title: "RHSA-2017:0001: pkg5 security update (Important)",
},
}},
},
},
},

View File

@@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"strings"
@@ -347,7 +348,7 @@ No CVE-IDs are found in updatable packages.
data = append(data, []string{"Mitigation", m.URL})
}
links := vuln.CveContents.PrimarySrcURLs(r.Lang, r.Family, vuln.CveID)
links := vuln.CveContents.PrimarySrcURLs(r.Lang, r.Family, vuln.CveID, vuln.Confidences)
for _, link := range links {
data = append(data, []string{"Primary Src", link.Value})
}
@@ -620,7 +621,7 @@ func getPlusDiffCves(previous, current models.ScanResult) models.VulnInfos {
// TODO commented out because a bug of diff logic when multiple oval defs found for a certain CVE-ID and same updated_at
// if these OVAL defs have different affected packages, this logic detects as updated.
// This logic will be uncomented after integration with gost https://github.com/knqyf263/gost
// This logic will be uncomented after integration with gost https://github.com/vulsio/gost
// } else if isCveFixed(v, previous) {
// updated[v.CveID] = v
// logging.Log.Debugf("fixed: %s", v.CveID)
@@ -673,32 +674,36 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
models.NewCveContentType(current.Family),
}
prevLastModified := map[models.CveContentType]time.Time{}
prevLastModifieds := map[models.CveContentType][]time.Time{}
preVinfo, ok := previous.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if content, ok := preVinfo.CveContents[cType]; ok {
prevLastModified[cType] = content.LastModified
if conts, ok := preVinfo.CveContents[cType]; ok {
for _, cont := range conts {
prevLastModifieds[cType] = append(prevLastModifieds[cType], cont.LastModified)
}
}
}
curLastModified := map[models.CveContentType]time.Time{}
curLastModifieds := map[models.CveContentType][]time.Time{}
curVinfo, ok := current.ScannedCves[cveID]
if !ok {
return true
}
for _, cType := range cTypes {
if content, ok := curVinfo.CveContents[cType]; ok {
curLastModified[cType] = content.LastModified
if conts, ok := curVinfo.CveContents[cType]; ok {
for _, cont := range conts {
curLastModifieds[cType] = append(curLastModifieds[cType], cont.LastModified)
}
}
}
for _, t := range cTypes {
if !curLastModified[t].Equal(prevLastModified[t]) {
if !reflect.DeepEqual(curLastModifieds[t], prevLastModifieds[t]) {
logging.Log.Debugf("%s LastModified not equal: \n%s\n%s",
cveID, curLastModified[t], prevLastModified[t])
cveID, curLastModifieds[t], prevLastModifieds[t])
return true
}
}

View File

@@ -19,7 +19,7 @@ import (
// EnsureUUIDs generate a new UUID of the scan target server if UUID is not assigned yet.
// And then set the generated UUID to config.toml and scan results.
func EnsureUUIDs(servers map[string]config.ServerInfo, path string, scanResults models.ScanResults) (err error) {
needsOverwrite, err := ensure(servers, path, scanResults, uuid.GenerateUUID)
needsOverwrite, err := ensure(servers, scanResults, uuid.GenerateUUID)
if err != nil {
return xerrors.Errorf("Failed to ensure UUIDs. err: %w", err)
}
@@ -30,7 +30,7 @@ func EnsureUUIDs(servers map[string]config.ServerInfo, path string, scanResults
return writeToFile(config.Conf, path)
}
func ensure(servers map[string]config.ServerInfo, path string, scanResults models.ScanResults, generateFunc func() (string, error)) (needsOverwrite bool, err error) {
func ensure(servers map[string]config.ServerInfo, scanResults models.ScanResults, generateFunc func() (string, error)) (needsOverwrite bool, err error) {
for i, r := range scanResults {
serverInfo := servers[r.ServerName]
if serverInfo.UUIDs == nil {

View File

@@ -377,7 +377,7 @@ func Test_ensure(t *testing.T) {
}
for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotNeedsOverwrite, err := ensure(tt.args.servers, tt.args.path, tt.args.scanResults, tt.args.generateFunc)
gotNeedsOverwrite, err := ensure(tt.args.servers, tt.args.scanResults, tt.args.generateFunc)
if (err != nil) != tt.wantErr {
t.Errorf("ensure() error = %v, wantErr %v", err, tt.wantErr)
return

118
scanner/alma.go Normal file
View File

@@ -0,0 +1,118 @@
package scanner
import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
)
// inherit OsTypeInterface
type alma struct {
redhatBase
}
// NewAlma is constructor
func newAlma(c config.ServerInfo) *alma {
r := &alma{
redhatBase{
base: base{
osPackages: osPackages{
Packages: models.Packages{},
VulnInfos: models.VulnInfos{},
},
},
sudo: rootPrivAlma{},
},
}
r.log = logging.NewNormalLogger()
r.setServerInfo(c)
return r
}
func (o *alma) checkScanMode() error {
return nil
}
func (o *alma) checkDeps() error {
if o.getServerInfo().Mode.IsFast() {
return o.execCheckDeps(o.depsFast())
} else if o.getServerInfo().Mode.IsFastRoot() {
return o.execCheckDeps(o.depsFastRoot())
} else {
return o.execCheckDeps(o.depsDeep())
}
}
func (o *alma) depsFast() []string {
if o.getServerInfo().Mode.IsOffline() {
return []string{}
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}
func (o *alma) depsFastRoot() []string {
if o.getServerInfo().Mode.IsOffline() {
return []string{}
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}
func (o *alma) depsDeep() []string {
return o.depsFastRoot()
}
func (o *alma) checkIfSudoNoPasswd() error {
if o.getServerInfo().Mode.IsFast() {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsFast())
} else if o.getServerInfo().Mode.IsFastRoot() {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsFastRoot())
} else {
return o.execCheckIfSudoNoPasswd(o.sudoNoPasswdCmdsDeep())
}
}
func (o *alma) sudoNoPasswdCmdsFast() []cmd {
return []cmd{}
}
func (o *alma) sudoNoPasswdCmdsFastRoot() []cmd {
if !o.ServerInfo.IsContainer() {
return []cmd{
{"repoquery -h", exitStatusZero},
{"needs-restarting", exitStatusZero},
{"which which", exitStatusZero},
{"stat /proc/1/exe", exitStatusZero},
{"ls -l /proc/1/exe", exitStatusZero},
{"cat /proc/1/maps", exitStatusZero},
{"lsof -i -P", exitStatusZero},
}
}
return []cmd{
{"repoquery -h", exitStatusZero},
{"needs-restarting", exitStatusZero},
}
}
func (o *alma) sudoNoPasswdCmdsDeep() []cmd {
return o.sudoNoPasswdCmdsFastRoot()
}
type rootPrivAlma struct{}
func (o rootPrivAlma) repoquery() bool {
return false
}
func (o rootPrivAlma) yumMakeCache() bool {
return false
}
func (o rootPrivAlma) yumPS() bool {
return false
}

View File

@@ -2,13 +2,17 @@ package scanner
import (
"bufio"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/aquasecurity/fanal/analyzer"
@@ -18,16 +22,28 @@ import (
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"golang.org/x/sync/semaphore"
"golang.org/x/xerrors"
// Import library scanner
_ "github.com/aquasecurity/fanal/analyzer/library/bundler"
_ "github.com/aquasecurity/fanal/analyzer/library/cargo"
_ "github.com/aquasecurity/fanal/analyzer/library/composer"
_ "github.com/aquasecurity/fanal/analyzer/library/npm"
_ "github.com/aquasecurity/fanal/analyzer/library/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/library/poetry"
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/dotnet/nuget"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/binary"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/mod"
_ "github.com/aquasecurity/fanal/analyzer/language/java/jar"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/npm"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/php/composer"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pip"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/language/python/poetry"
_ "github.com/aquasecurity/fanal/analyzer/language/ruby/bundler"
_ "github.com/aquasecurity/fanal/analyzer/language/rust/cargo"
// _ "github.com/aquasecurity/fanal/analyzer/language/ruby/gemspec"
// _ "github.com/aquasecurity/fanal/analyzer/language/nodejs/pkg"
// _ "github.com/aquasecurity/fanal/analyzer/language/python/packaging"
nmap "github.com/Ullaakut/nmap/v2"
)
type base struct {
@@ -54,7 +70,7 @@ type osPackages struct {
// enabled dnf modules or packages
EnabledDnfModules []string
// unsecure packages
// Detected Vulnerabilities Key: CVE-ID
VulnInfos models.VulnInfos
// kernel information
@@ -357,15 +373,13 @@ func (l *base) detectDeepSecurity() (string, error) {
return "", xerrors.Errorf("Failed to detect deepsecurity %s", l.ServerInfo.ServerName)
}
const deepSecurity string = "deepsecurity"
func (l *base) detectIPS() {
ips := map[string]string{}
fingerprint, err := l.detectDeepSecurity()
if err != nil {
return
}
ips[deepSecurity] = fingerprint
ips[constant.DeepSecurity] = fingerprint
l.ServerInfo.IPSIdentifiers = ips
}
@@ -581,6 +595,11 @@ func (l *base) scanLibraries() (err error) {
if path == "" {
continue
}
if path, err = filepath.Abs(path); err != nil {
return xerrors.Errorf("Failed to abs the lockfile. err: %w, filepath: %s", err, path)
}
// skip already exist
if _, ok := libFilemap[path]; ok {
continue
@@ -591,7 +610,7 @@ func (l *base) scanLibraries() (err error) {
case constant.ServerTypePseudo:
bytes, err = ioutil.ReadFile(path)
if err != nil {
return xerrors.Errorf("Failed to get target file: %s, filepath: %s", err, path)
return xerrors.Errorf("Failed to get target file. err: %w, filepath: %s", err, path)
}
default:
cmd := fmt.Sprintf("cat %s", path)
@@ -604,22 +623,64 @@ func (l *base) scanLibraries() (err error) {
libFilemap[path] = bytes
}
for path, b := range libFilemap {
res, err := analyzer.AnalyzeFile(path, &DummyFileInfo{}, func() ([]byte, error) {
return b, nil
})
if err != nil {
return xerrors.Errorf("Failed to get libs: %w", err)
}
libscan, err := convertLibWithScanner(res.Applications)
if err != nil {
return xerrors.Errorf("Failed to scan libraries: %w", err)
}
l.LibraryScanners = append(l.LibraryScanners, libscan...)
var libraryScanners []models.LibraryScanner
if libraryScanners, err = AnalyzeLibraries(context.Background(), libFilemap); err != nil {
return err
}
l.LibraryScanners = append(l.LibraryScanners, libraryScanners...)
return nil
}
// AnalyzeLibraries : detects libs defined in lockfile
func AnalyzeLibraries(ctx context.Context, libFilemap map[string][]byte) (libraryScanners []models.LibraryScanner, err error) {
disabledAnalyzers := []analyzer.Type{
analyzer.TypeAlpine,
analyzer.TypeAmazon,
analyzer.TypeDebian,
analyzer.TypePhoton,
analyzer.TypeCentOS,
analyzer.TypeFedora,
analyzer.TypeOracle,
analyzer.TypeRedHatBase,
analyzer.TypeSUSE,
analyzer.TypeUbuntu,
analyzer.TypeApk,
analyzer.TypeDpkg,
analyzer.TypeRpm,
analyzer.TypeApkCommand,
analyzer.TypeYaml,
analyzer.TypeTOML,
analyzer.TypeJSON,
analyzer.TypeDockerfile,
analyzer.TypeHCL,
}
anal := analyzer.NewAnalyzer(disabledAnalyzers)
for path, b := range libFilemap {
var wg sync.WaitGroup
result := new(analyzer.AnalysisResult)
if err := anal.AnalyzeFile(
ctx,
&wg,
semaphore.NewWeighted(1),
result,
"",
path,
&DummyFileInfo{},
func() ([]byte, error) { return b, nil }); err != nil {
return nil, xerrors.Errorf("Failed to get libs. err: %w", err)
}
wg.Wait()
libscan, err := convertLibWithScanner(result.Applications)
if err != nil {
return nil, xerrors.Errorf("Failed to convert libs. err: %w", err)
}
libraryScanners = append(libraryScanners, libscan...)
}
return libraryScanners, nil
}
// DummyFileInfo is a dummy struct for libscan
type DummyFileInfo struct{}
@@ -798,26 +859,196 @@ func (l *base) detectScanDest() map[string][]string {
}
func (l *base) execPortsScan(scanDestIPPorts map[string][]string) ([]string, error) {
if l.getServerInfo().PortScan.IsUseExternalScanner {
listenIPPorts, err := l.execExternalPortScan(scanDestIPPorts)
if err != nil {
return []string{}, err
}
return listenIPPorts, nil
}
listenIPPorts, err := l.execNativePortScan(scanDestIPPorts)
if err != nil {
return []string{}, err
}
return listenIPPorts, nil
}
func (l *base) execNativePortScan(scanDestIPPorts map[string][]string) ([]string, error) {
l.log.Info("Using Port Scanner: Vuls built-in Scanner")
listenIPPorts := []string{}
for ip, ports := range scanDestIPPorts {
if !isLocalExec(l.ServerInfo.Port, l.ServerInfo.Host) && net.ParseIP(ip).IsLoopback() {
continue
}
for _, port := range ports {
scanDest := ip + ":" + port
conn, err := net.DialTimeout("tcp", scanDest, time.Duration(1)*time.Second)
isOpen, err := nativeScanPort(scanDest)
if err != nil {
continue
return []string{}, err
}
if isOpen {
listenIPPorts = append(listenIPPorts, scanDest)
}
conn.Close()
listenIPPorts = append(listenIPPorts, scanDest)
}
}
return listenIPPorts, nil
}
func nativeScanPort(scanDest string) (bool, error) {
conn, err := net.DialTimeout("tcp", scanDest, time.Duration(1)*time.Second)
if err != nil {
if strings.Contains(err.Error(), "i/o timeout") || strings.Contains(err.Error(), "connection refused") {
return false, nil
}
if strings.Contains(err.Error(), "too many open files") {
time.Sleep(time.Duration(1) * time.Second)
return nativeScanPort(scanDest)
}
return false, err
}
conn.Close()
return true, nil
}
func (l *base) execExternalPortScan(scanDestIPPorts map[string][]string) ([]string, error) {
portScanConf := l.getServerInfo().PortScan
l.log.Infof("Using Port Scanner: External Scanner(PATH: %s)", portScanConf.ScannerBinPath)
l.log.Infof("External Scanner Apply Options: Scan Techniques: %s, HasPrivileged: %t, Source Port: %s",
strings.Join(portScanConf.ScanTechniques, ","), portScanConf.HasPrivileged, portScanConf.SourcePort)
baseCmd := formatNmapOptionsToString(portScanConf)
listenIPPorts := []string{}
for ip, ports := range scanDestIPPorts {
if !isLocalExec(l.ServerInfo.Port, l.ServerInfo.Host) && net.ParseIP(ip).IsLoopback() {
continue
}
_, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
scanner, err := nmap.NewScanner(nmap.WithBinaryPath(portScanConf.ScannerBinPath))
if err != nil {
return []string{}, xerrors.Errorf("unable to create nmap scanner: %w", err)
}
scanTechnique, err := l.setScanTechniques()
if err != nil {
return []string{}, err
}
scanner.AddOptions(scanTechnique)
if portScanConf.HasPrivileged {
scanner.AddOptions(nmap.WithPrivileged())
} else {
scanner.AddOptions(nmap.WithUnprivileged())
}
if portScanConf.SourcePort != "" {
port, err := strconv.ParseUint(portScanConf.SourcePort, 10, 16)
if err != nil {
return []string{}, xerrors.Errorf("failed to strconv.ParseUint(%s, 10, 16) = %w", portScanConf.SourcePort, err)
}
scanner.AddOptions(nmap.WithSourcePort(uint16(port)))
}
cmd := []string{baseCmd}
if strings.Contains(ip, ":") {
scanner.AddOptions(nmap.WithTargets(ip[1:len(ip)-1]), nmap.WithPorts(ports...), nmap.WithIPv6Scanning())
cmd = append(cmd, "-p", strings.Join(ports, ","), ip[1:len(ip)-1])
} else {
scanner.AddOptions(nmap.WithTargets(ip), nmap.WithPorts(ports...))
cmd = append(cmd, "-p", strings.Join(ports, ","), ip)
}
l.log.Debugf("Executing... %s", strings.Replace(strings.Join(cmd, " "), "\n", "", -1))
result, warnings, err := scanner.Run()
if err != nil {
return []string{}, xerrors.Errorf("unable to run nmap scan: %w", err)
}
if warnings != nil {
l.log.Warnf("nmap scan warnings: %s", warnings)
}
for _, host := range result.Hosts {
if len(host.Ports) == 0 || len(host.Addresses) == 0 {
continue
}
for _, port := range host.Ports {
if strings.Contains(string(port.Status()), string(nmap.Open)) {
scanDest := fmt.Sprintf("%s:%d", ip, port.ID)
listenIPPorts = append(listenIPPorts, scanDest)
}
}
}
}
return listenIPPorts, nil
}
func formatNmapOptionsToString(conf *config.PortScanConf) string {
cmd := []string{conf.ScannerBinPath}
if len(conf.ScanTechniques) != 0 {
for _, technique := range conf.ScanTechniques {
cmd = append(cmd, "-"+technique)
}
}
if conf.SourcePort != "" {
cmd = append(cmd, "--source-port "+conf.SourcePort)
}
if conf.HasPrivileged {
cmd = append(cmd, "--privileged")
}
return strings.Join(cmd, " ")
}
func (l *base) setScanTechniques() (func(*nmap.Scanner), error) {
scanTechniques := l.getServerInfo().PortScan.GetScanTechniques()
if len(scanTechniques) == 0 {
if l.getServerInfo().PortScan.HasPrivileged {
return nmap.WithSYNScan(), nil
}
return nmap.WithConnectScan(), nil
}
for _, technique := range scanTechniques {
switch technique {
case config.TCPSYN:
return nmap.WithSYNScan(), nil
case config.TCPConnect:
return nmap.WithConnectScan(), nil
case config.TCPACK:
return nmap.WithACKScan(), nil
case config.TCPWindow:
return nmap.WithWindowScan(), nil
case config.TCPMaimon:
return nmap.WithMaimonScan(), nil
case config.TCPNull:
return nmap.WithTCPNullScan(), nil
case config.TCPFIN:
return nmap.WithTCPFINScan(), nil
case config.TCPXmas:
return nmap.WithTCPXmasScan(), nil
}
}
return nil, xerrors.Errorf("Failed to setScanTechniques. There is an unsupported option in ScanTechniques.")
}
func (l *base) updatePortStatus(listenIPPorts []string) {
for name, p := range l.osPackages.Packages {
if p.AffectedProcs == nil {

View File

@@ -4,13 +4,18 @@ import (
"reflect"
"testing"
_ "github.com/aquasecurity/fanal/analyzer/library/bundler"
_ "github.com/aquasecurity/fanal/analyzer/library/cargo"
_ "github.com/aquasecurity/fanal/analyzer/library/composer"
_ "github.com/aquasecurity/fanal/analyzer/library/npm"
_ "github.com/aquasecurity/fanal/analyzer/library/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/library/poetry"
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/dotnet/nuget"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/binary"
_ "github.com/aquasecurity/fanal/analyzer/language/golang/mod"
_ "github.com/aquasecurity/fanal/analyzer/language/java/jar"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/npm"
_ "github.com/aquasecurity/fanal/analyzer/language/nodejs/yarn"
_ "github.com/aquasecurity/fanal/analyzer/language/php/composer"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pip"
_ "github.com/aquasecurity/fanal/analyzer/language/python/pipenv"
_ "github.com/aquasecurity/fanal/analyzer/language/python/poetry"
_ "github.com/aquasecurity/fanal/analyzer/language/ruby/bundler"
_ "github.com/aquasecurity/fanal/analyzer/language/rust/cargo"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)
@@ -467,7 +472,7 @@ func Test_updatePortStatus(t *testing.T) {
}
}
func Test_matchListenPorts(t *testing.T) {
func Test_findPortScanSuccessOn(t *testing.T) {
type args struct {
listenIPPorts []string
searchListenPort models.PortStat

View File

@@ -11,7 +11,7 @@ type centos struct {
redhatBase
}
// NewAmazon is constructor
// NewCentOS is constructor
func newCentOS(c config.ServerInfo) *centos {
r := &centos{
redhatBase{
@@ -49,7 +49,7 @@ func (o *centos) depsFast() []string {
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}
@@ -59,7 +59,7 @@ func (o *centos) depsFastRoot() []string {
}
// repoquery
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8
// `rpm -qa` shows dnf-utils as yum-utils on RHEL8, CentOS8, Alma8, Rocky8
return []string{"yum-utils"}
}

View File

@@ -48,7 +48,8 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
return false, nil, nil
}
if r.ExitStatus == 255 {
return false, nil, xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add the HostKey. %s@%s port: %s\n%s", c.User, c.Host, c.Port, r)
deb := newDebian(c) // Panic occur when return value 2 is nil and 3 is non-nil
return false, deb, xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add the HostKey. %s@%s port: %s\n%s", c.User, c.Host, c.Port, r)
}
logging.Log.Debugf("Not Debian like Linux. %s", r)
return false, nil, nil
@@ -930,7 +931,7 @@ func (o *debian) getCveIDsFromChangelog(
if 1 < len(splittedByColon) {
verAfterColon = splittedByColon[1]
if cveIDs, pack, err := o.parseChangelog(
changelog, name, verAfterColon, models.ChangelogLenientMatch); err == nil {
changelog, name, verAfterColon, models.ChangelogRoughMatch); err == nil {
return cveIDs, pack
}
}
@@ -947,7 +948,7 @@ func (o *debian) getCveIDsFromChangelog(
ss := strings.Split(ver, d)
if 1 < len(ss) {
if cveIDs, pack, err := o.parseChangelog(
changelog, name, ss[0], models.ChangelogLenientMatch); err == nil {
changelog, name, ss[0], models.ChangelogRoughMatch); err == nil {
return cveIDs, pack
}
}
@@ -955,7 +956,7 @@ func (o *debian) getCveIDsFromChangelog(
ss = strings.Split(verAfterColon, d)
if 1 < len(ss) {
if cveIDs, pack, err := o.parseChangelog(
changelog, name, ss[0], models.ChangelogLenientMatch); err == nil {
changelog, name, ss[0], models.ChangelogRoughMatch); err == nil {
return cveIDs, pack
}
}
@@ -1019,7 +1020,7 @@ func (o *debian) parseChangelog(changelog, name, ver string, confidence models.C
pack := o.Packages[name]
pack.Changelog = &models.Changelog{
Contents: strings.Join(buf, "\n"),
Method: models.ChangelogLenientMatchStr,
Method: models.ChangelogRoughMatchStr,
}
cves := []DetectedCveID{}

View File

@@ -144,12 +144,7 @@ systemd (228-5) unstable; urgency=medium`,
util-linux (2.27.1-1) unstable; urgency=medium
util-linux (2.27-3ubuntu1) xenial; urgency=medium`,
},
[]DetectedCveID{
// {"CVE-2015-2325", models.ChangelogLenientMatch},
// {"CVE-2015-2326", models.ChangelogLenientMatch},
// {"CVE-2015-3210", models.ChangelogLenientMatch},
// {"CVE-2016-1000000", models.ChangelogLenientMatch},
},
[]DetectedCveID{},
models.Changelog{
// Contents: `util-linux (2.27.1-3ubuntu1) xenial; urgency=medium
// util-linux (2.27.1-3) unstable; urgency=medium
@@ -180,12 +175,7 @@ systemd (228-5) unstable; urgency=medium`,
util-linux (2.27.1-1) unstable; urgency=medium
util-linux (2.27-3) xenial; urgency=medium`,
},
[]DetectedCveID{
// {"CVE-2015-2325", models.ChangelogLenientMatch},
// {"CVE-2015-2326", models.ChangelogLenientMatch},
// {"CVE-2015-3210", models.ChangelogLenientMatch},
// {"CVE-2016-1000000", models.ChangelogLenientMatch},
},
[]DetectedCveID{},
models.Changelog{
// Contents: `util-linux (2.27.1-3ubuntu1) xenial; urgency=medium
// util-linux (2.27.1-3) unstable; urgency=medium
@@ -845,7 +835,7 @@ vlc (3.0.11-0+deb10u1) buster-security; urgency=high
-- RealVNC <noreply@realvnc.com> Wed, 13 May 2020 19:51:40 +0100
`,
Method: models.ChangelogLenientMatchStr,
Method: models.ChangelogRoughMatchStr,
}},
},
},

View File

@@ -18,6 +18,7 @@ func convertLibWithScanner(apps []types.Application) ([]models.LibraryScanner, e
})
}
scanners = append(scanners, models.LibraryScanner{
Type: app.Type,
Path: app.FilePath,
Libs: libs,
})

View File

@@ -11,7 +11,7 @@ type oracle struct {
redhatBase
}
// NewAmazon is constructor
// NewOracle is constructor
func newOracle(c config.ServerInfo) *oracle {
r := &oracle{
redhatBase{

View File

@@ -58,12 +58,58 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
cent := newCentOS(c)
cent.setDistro(constant.CentOS, release)
return true, cent
case "alma", "almalinux":
alma := newAlma(c)
alma.setDistro(constant.Alma, release)
return true, alma
default:
logging.Log.Warnf("Failed to parse CentOS: %s", r)
}
}
}
if r := exec(c, "ls /etc/almalinux-release", noSudo); r.isSuccess() {
if r := exec(c, "cat /etc/almalinux-release", noSudo); r.isSuccess() {
re := regexp.MustCompile(`(.*) release (\d[\d\.]*)`)
result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout))
if len(result) != 3 {
logging.Log.Warnf("Failed to parse Alma version: %s", r)
return true, newAlma(c)
}
release := result[2]
switch strings.ToLower(result[1]) {
case "alma", "almalinux":
alma := newAlma(c)
alma.setDistro(constant.Alma, release)
return true, alma
default:
logging.Log.Warnf("Failed to parse Alma: %s", r)
}
}
}
if r := exec(c, "ls /etc/rocky-release", noSudo); r.isSuccess() {
if r := exec(c, "cat /etc/rocky-release", noSudo); r.isSuccess() {
re := regexp.MustCompile(`(.*) release (\d[\d\.]*)`)
result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout))
if len(result) != 3 {
logging.Log.Warnf("Failed to parse Rocky version: %s", r)
return true, newRocky(c)
}
release := result[2]
switch strings.ToLower(result[1]) {
case "rocky", "rocky linux":
rocky := newRocky(c)
rocky.setDistro(constant.Rocky, release)
return true, rocky
default:
logging.Log.Warnf("Failed to parse Rocky: %s", r)
}
}
}
if r := exec(c, "ls /etc/redhat-release", noSudo); r.isSuccess() {
// https://www.rackaid.com/blog/how-to-determine-centos-or-red-hat-version/
// e.g.
@@ -79,10 +125,18 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) {
release := result[2]
switch strings.ToLower(result[1]) {
case "centos", "centos linux":
case "centos", "centos linux", "centos stream":
cent := newCentOS(c)
cent.setDistro(constant.CentOS, release)
return true, cent
case "alma", "almalinux":
alma := newAlma(c)
alma.setDistro(constant.Alma, release)
return true, alma
case "rocky", "rocky linux":
rocky := newRocky(c)
rocky.setDistro(constant.Rocky, release)
return true, rocky
default:
// RHEL
rhel := newRHEL(c)
@@ -210,7 +264,8 @@ func (o *redhatBase) scanPackages() (err error) {
return xerrors.Errorf("Failed to detect installed dnf modules: %w", err)
}
o.Kernel.RebootRequired, err = o.rebootRequired()
fn := func(pkgName string) execResult { return o.exec(fmt.Sprintf("rpm -q --last %s", pkgName), noSudo) }
o.Kernel.RebootRequired, err = o.rebootRequired(fn)
if err != nil {
err = xerrors.Errorf("Failed to detect the kernel reboot required: %w", err)
o.log.Warnf("err: %+v", err)
@@ -238,8 +293,13 @@ func (o *redhatBase) scanPackages() (err error) {
return nil
}
func (o *redhatBase) rebootRequired() (bool, error) {
r := o.exec("rpm -q --last kernel", noSudo)
func (o *redhatBase) rebootRequired(fn func(s string) execResult) (bool, error) {
pkgName := "kernel"
if strings.Contains(o.Kernel.Release, "uek.") {
pkgName = "kernel-uek"
}
r := fn(pkgName)
scanner := bufio.NewScanner(strings.NewReader(r.Stdout))
if !r.isSuccess(0, 1) {
return false, xerrors.Errorf("Failed to detect the last installed kernel : %v", r)
@@ -248,7 +308,7 @@ func (o *redhatBase) rebootRequired() (bool, error) {
return false, nil
}
lastInstalledKernelVer := strings.Fields(scanner.Text())[0]
running := fmt.Sprintf("kernel-%s", o.Kernel.Release)
running := fmt.Sprintf("%s-%s", pkgName, o.Kernel.Release)
return running != lastInstalledKernelVer, nil
}
@@ -449,7 +509,7 @@ func (o *redhatBase) isExecNeedsRestarting() bool {
// TODO zypper ps
// https://github.com/future-architect/vuls/issues/696
return false
case constant.RedHat, constant.CentOS, constant.Oracle:
case constant.RedHat, constant.CentOS, constant.Rocky, constant.Oracle:
majorVersion, err := o.Distro.MajorVersion()
if err != nil || majorVersion < 6 {
o.log.Errorf("Not implemented yet: %s, err: %+v", o.Distro, err)
@@ -628,7 +688,7 @@ func (o *redhatBase) rpmQf() string {
func (o *redhatBase) detectEnabledDnfModules() ([]string, error) {
switch o.Distro.Family {
case constant.RedHat, constant.CentOS:
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky:
//TODO OracleLinux
default:
return nil, nil

Some files were not shown because too many files have changed in this diff Show More