Expose Trivy and VulnDB version through --version (#435)

* app: Expose Trivy and VulnDB version through --version

Signed-off-by: Simarpreet Singh <simar@linux.com>

* pkg: Use time.Time as value not reference.

Based on: 64db180151

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Use various formatted outputs

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Take value of --cache-dir for cacheDir

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Refactor and test showVersion

Signed-off-by: Simarpreet Singh <simar@linux.com>

* library: lighten names by remove version suffix

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Show types and add parity of table and JSON

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Switch to show using UTC time

Signed-off-by: Simarpreet Singh <simar@linux.com>

* mod: Update to latest trivy-db master.

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Use c.App.Writer for os.Stdout

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Replace table output with docker version style output

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Fix output to show as "Version" for Trivy version.

Signed-off-by: Simarpreet Singh <simar@linux.com>

* app: Move VersionInfo struct out to app.go

Signed-off-by: Simarpreet Singh <simar@linux.com>
This commit is contained in:
Simarpreet Singh
2020-03-20 10:19:44 -07:00
committed by GitHub
parent b847e57991
commit 94eb7cc592
6 changed files with 164 additions and 12 deletions

2
go.mod
View File

@@ -5,7 +5,7 @@ go 1.13
require (
github.com/aquasecurity/fanal v0.0.0-20200317181056-f28b6d21845c
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1
github.com/aquasecurity/trivy-db v0.0.0-20200318223623-7d3e67b057d4
github.com/caarlos0/env/v6 v6.0.0
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/cheggaaa/pb/v3 v3.0.3

4
go.sum
View File

@@ -34,8 +34,8 @@ github.com/aquasecurity/fanal v0.0.0-20200317181056-f28b6d21845c/go.mod h1:yPZqe
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
github.com/aquasecurity/trivy v0.1.6/go.mod h1:5hobyhxLzDtxruHzPxpND2PUKOssvGUdE9BocpJUwo4=
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1 h1:IVXoVH8ejJuBdxgH/+er2WjBxc0tqIGuBCqI5aWW3A0=
github.com/aquasecurity/trivy-db v0.0.0-20191226181755-d6cabf5bc5d1/go.mod h1:Uf9bXd50zTHtWTP7+7u5+OFCPtUVrmsS4v0RXd7E5lw=
github.com/aquasecurity/trivy-db v0.0.0-20200318223623-7d3e67b057d4 h1:DeVT3LzIgKc+5sGhSGusWL+JZ/kiWGjKjQYeshz/gOk=
github.com/aquasecurity/trivy-db v0.0.0-20200318223623-7d3e67b057d4/go.mod h1:Uf9bXd50zTHtWTP7+7u5+OFCPtUVrmsS4v0RXd7E5lw=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2 h1:xbdUfr2KE4THsFx9CFWtWpU91lF+YhgP46moV94nYTA=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=

View File

@@ -1,9 +1,14 @@
package internal
import (
"encoding/json"
"fmt"
"io"
"strings"
"time"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/urfave/cli"
"github.com/aquasecurity/trivy-db/pkg/types"
@@ -14,6 +19,11 @@ import (
"github.com/aquasecurity/trivy/pkg/vulnerability"
)
type VersionInfo struct {
Version string `json:",omitempty"`
VulnerabilityDB db.Metadata `json:",omitempty"`
}
var (
templateFlag = cli.StringFlag{
Name: "template, t",
@@ -174,6 +184,10 @@ OPTIONS:
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{$option}}{{end}}{{end}}
`
cli.VersionPrinter = func(c *cli.Context) {
showVersion(c.String("cache-dir"), c.String("format"), c.App.Version, c.App.Writer)
}
app := cli.NewApp()
app.Name = "trivy"
app.Version = version
@@ -232,6 +246,44 @@ OPTIONS:
return app
}
func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer) {
db.Init(cacheDir)
metadata, err := db.Config{}.GetMetadata()
if err != nil {
fmt.Fprintf(outputWriter, "unable to display current version: %s", err.Error())
return
}
switch outputFormat {
case "json":
b, _ := json.Marshal(VersionInfo{
Version: version,
VulnerabilityDB: db.Metadata{
Version: metadata.Version,
Type: metadata.Type,
NextUpdate: metadata.NextUpdate.UTC(),
UpdatedAt: metadata.UpdatedAt.UTC(),
},
})
fmt.Fprintln(outputWriter, string(b))
default:
var dbType string
switch metadata.Type {
case 0:
dbType = "Full"
case 1:
dbType = "Light"
}
fmt.Fprintf(outputWriter, `Version: %s
Vulnerability DB:
Type: %s
Version: %d
UpdatedAt: %s
NextUpdate: %s
`, version, dbType, metadata.Version, metadata.UpdatedAt.UTC().String(), metadata.NextUpdate.UTC().String())
}
}
func NewClientCommand() cli.Command {
return cli.Command{
Name: "client",

94
internal/app_test.go Normal file
View File

@@ -0,0 +1,94 @@
package internal
import (
"io/ioutil"
"os"
"testing"
"time"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/stretchr/testify/assert"
)
type fakeIOWriter struct {
written []byte
}
func (f *fakeIOWriter) Write(p []byte) (n int, err error) {
f.written = append(f.written, p...)
return len(p), nil
}
func Test_showVersion(t *testing.T) {
type args struct {
cacheDir string
outputFormat string
version string
}
tests := []struct {
name string
args args
createDB bool
expectedOutput string
}{
{
name: "happy path, table output",
args: args{
outputFormat: "table",
version: "v1.2.3",
},
expectedOutput: `Version: v1.2.3
Vulnerability DB:
Type: Light
Version: 42
UpdatedAt: 2020-03-16 23:40:20 +0000 UTC
NextUpdate: 2020-03-16 23:57:00 +0000 UTC
`,
createDB: true,
},
{
name: "happy path, JSON output",
args: args{
outputFormat: "json",
version: "1.2.3",
},
expectedOutput: `{"Version":"1.2.3","VulnerabilityDB":{"Version":42,"Type":1,"NextUpdate":"2020-03-16T23:57:00Z","UpdatedAt":"2020-03-16T23:40:20Z"}}
`,
createDB: true,
},
{
name: "sad path, no DB is available",
args: args{
outputFormat: "table",
version: "1.2.3",
},
expectedOutput: `unable to display current version: unexpected end of JSON input`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d, _ := ioutil.TempDir("", "Test_showVersion-*")
defer func() {
os.RemoveAll(d)
}()
if tt.createDB {
db.Init(d)
db.Config{}.SetMetadata(db.Metadata{
Version: 42,
Type: 1,
NextUpdate: time.Unix(1584403020, 0),
UpdatedAt: time.Unix(1584402020, 0),
})
db.Close()
}
var wb []byte
fw := fakeIOWriter{written: wb}
showVersion(d, tt.args.outputFormat, tt.args.version, &fw)
assert.Equal(t, tt.expectedOutput, string(fw.written), tt.name)
})
}
}

View File

@@ -42,6 +42,9 @@ func (_m *MockConfig) GetMetadata() (db.Metadata, error) {
}
func TestClient_NeedsUpdate(t *testing.T) {
timeNextUpdateDay1 := time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC)
timeNextUpdateDay2 := time.Date(2019, 10, 2, 0, 0, 0, 0, time.UTC)
type getMetadataOutput struct {
metadata db.Metadata
err error
@@ -64,7 +67,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdateDay1,
},
},
expected: true,
@@ -87,7 +90,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdateDay1,
},
},
expected: true,
@@ -100,7 +103,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: db.Metadata{
Version: 0,
Type: db.TypeFull,
NextUpdate: time.Date(2020, 9, 1, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdateDay1,
},
},
expected: true,
@@ -113,7 +116,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdateDay1,
},
},
skip: true,
@@ -127,7 +130,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: time.Date(2019, 10, 2, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdateDay2,
},
},
expected: false,
@@ -140,7 +143,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: db.Metadata{
Version: 2,
Type: db.TypeFull,
NextUpdate: time.Date(2019, 10, 2, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdateDay2,
},
},
expectedError: xerrors.New("the version of DB schema doesn't match. Local DB: 2, Expected: 1"),
@@ -163,7 +166,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: db.Metadata{
Version: 0,
Type: db.TypeFull,
NextUpdate: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdateDay1,
},
},
skip: true,

View File

@@ -25,6 +25,9 @@ func TestMain(m *testing.M) {
}
func Test_dbWorker_update(t *testing.T) {
timeNextUpdate := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)
timeUpdateAt := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)
type needsUpdateInput struct {
appVersion string
skip bool
@@ -67,8 +70,8 @@ func Test_dbWorker_update(t *testing.T) {
want: db.Metadata{
Version: 1,
Type: db.TypeFull,
NextUpdate: time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC),
NextUpdate: timeNextUpdate,
UpdatedAt: timeUpdateAt,
},
},
{