fix: don't show corrupted trivy-db warning for first run (#8991)

This commit is contained in:
DmitriyLewen
2025-06-05 17:00:16 +06:00
committed by GitHub
parent a61978809b
commit 4ed78e39af
2 changed files with 69 additions and 7 deletions

View File

@@ -110,11 +110,12 @@ func (c *Client) NeedsUpdate(ctx context.Context, cliVersion string, skip bool)
meta = metadata.Metadata{Version: db.SchemaVersion}
}
// There are 2 cases when DownloadAt field is zero:
// There are 3 cases when DownloadAt field is zero:
// - metadata file was not created yet. This is the first run of Trivy.
// - trivy-db was downloaded with `oras`. In this case user can use `--skip-db-update` (like for air-gapped) or re-download trivy-db.
// - trivy-db was corrupted while copying from tmp directory to cache directory. We should update this trivy-db.
// We can't detect these cases, so we will show warning for users who use oras + air-gapped.
if meta.DownloadedAt.IsZero() && !skip {
if !noRequiredFiles && meta.DownloadedAt.IsZero() && !skip {
log.WarnContext(ctx, "Trivy DB may be corrupted and will be re-downloaded. If you manually downloaded DB - use the `--skip-db-update` flag to skip updating DB.")
return true, nil
}
@@ -131,10 +132,11 @@ func (c *Client) NeedsUpdate(ctx context.Context, cliVersion string, skip bool)
}
if skip {
log.DebugContext(ctx, "Skipping DB update...")
if err = c.validate(meta); err != nil {
return false, xerrors.Errorf("validate error: %w", err)
}
log.DebugContext(ctx, "Skipping DB update...")
return false, nil
}

View File

@@ -1,10 +1,13 @@
package db_test
import (
"bytes"
"fmt"
"strings"
"testing"
"time"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -13,6 +16,7 @@ import (
"github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/db"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
)
func TestClient_NeedsUpdate(t *testing.T) {
@@ -27,14 +31,16 @@ func TestClient_NeedsUpdate(t *testing.T) {
dbFileExists bool
metadata metadata.Metadata
want bool
wantLogs []string
wantErr string
}{
{
name: "happy path",
dbFileExists: true,
metadata: metadata.Metadata{
Version: db.SchemaVersion,
NextUpdate: timeNextUpdateDay1,
Version: db.SchemaVersion,
NextUpdate: timeNextUpdateDay1,
DownloadedAt: timeDownloadAt,
},
want: true,
},
@@ -43,20 +49,31 @@ func TestClient_NeedsUpdate(t *testing.T) {
dbFileExists: true,
metadata: metadata.Metadata{},
want: true,
wantLogs: []string{
"There is no valid metadata file",
},
},
{
name: "happy path for first run without trivy.db",
dbFileExists: false,
want: true,
wantLogs: []string{
"There is no db file",
"There is no valid metadata file",
},
},
{
name: "happy path with old schema version",
dbFileExists: true,
metadata: metadata.Metadata{
Version: 0,
NextUpdate: timeNextUpdateDay1,
Version: 0,
NextUpdate: timeNextUpdateDay1,
DownloadedAt: timeDownloadAt,
},
want: true,
wantLogs: []string{
"The local DB schema version does not match with supported version schema.",
},
},
{
name: "happy path with --skip-db-update",
@@ -68,6 +85,9 @@ func TestClient_NeedsUpdate(t *testing.T) {
},
skip: true,
want: false,
wantLogs: []string{
"Skipping DB update...",
},
},
{
name: "skip downloading DB",
@@ -78,6 +98,9 @@ func TestClient_NeedsUpdate(t *testing.T) {
DownloadedAt: timeDownloadAt,
},
want: false,
wantLogs: []string{
"DB update was skipped because the local DB is the latest",
},
},
{
name: "newer schema version",
@@ -89,12 +112,20 @@ func TestClient_NeedsUpdate(t *testing.T) {
},
wantErr: fmt.Sprintf("the version of DB schema doesn't match. Local DB: %d, Expected: %d",
db.SchemaVersion+1, db.SchemaVersion),
wantLogs: []string{
"Trivy version is old. Update to the latest version.",
},
},
{
name: "--skip-db-update without trivy.db on the first run",
dbFileExists: false,
skip: true,
wantErr: "--skip-db-update cannot be specified on the first run",
wantLogs: []string{
"There is no db file",
"There is no valid metadata file",
"The first run cannot skip downloading DB",
},
},
{
name: "--skip-db-update without metadata.json on the first run",
@@ -102,6 +133,10 @@ func TestClient_NeedsUpdate(t *testing.T) {
metadata: metadata.Metadata{},
skip: true,
wantErr: "--skip-db-update cannot be specified on the first run",
wantLogs: []string{
"There is no valid metadata file",
"The first run cannot skip downloading DB",
},
},
{
name: "--skip-db-update with different schema version",
@@ -114,6 +149,9 @@ func TestClient_NeedsUpdate(t *testing.T) {
skip: true,
wantErr: fmt.Sprintf("--skip-db-update cannot be specified with the old DB schema. Local DB: %d, Expected: %d",
0, db.SchemaVersion),
wantLogs: []string{
"The local DB has an old schema version which is not supported by the current version of Trivy CLI. DB needs to be updated.",
},
},
{
name: "happy with old DownloadedAt",
@@ -134,6 +172,9 @@ func TestClient_NeedsUpdate(t *testing.T) {
DownloadedAt: time.Date(2019, 9, 30, 23, 30, 0, 0, time.UTC),
},
want: false,
wantLogs: []string{
"DB update was skipped because the local DB was downloaded during the last hour",
},
},
{
name: "DownloadedAt is zero, skip is false",
@@ -145,6 +186,9 @@ func TestClient_NeedsUpdate(t *testing.T) {
NextUpdate: timeNextUpdateDay1,
},
want: true,
wantLogs: []string{
"Trivy DB may be corrupted and will be re-downloaded. If you manually downloaded DB - use the `--skip-db-update` flag to skip updating DB.",
},
},
{
name: "DownloadedAt is zero, skip is true",
@@ -156,6 +200,9 @@ func TestClient_NeedsUpdate(t *testing.T) {
NextUpdate: timeNextUpdateDay1,
},
want: false,
wantLogs: []string{
"Skipping DB update...",
},
},
{
name: "DownloadedAt is zero, skip is true, old schema version",
@@ -168,11 +215,18 @@ func TestClient_NeedsUpdate(t *testing.T) {
},
wantErr: "--skip-db-update cannot be specified with the old DB schema. Local DB: 0, Expected: 2",
want: false,
wantLogs: []string{
"The local DB has an old schema version which is not supported by the current version of Trivy CLI. DB needs to be updated.",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out := bytes.NewBuffer(nil)
logger := log.New(log.NewHandler(out, &log.Options{Level: log.LevelDebug}))
log.SetDefault(logger)
dbDir := db.Dir(t.TempDir())
if tt.metadata != (metadata.Metadata{}) {
meta := metadata.NewClient(dbDir)
@@ -194,6 +248,12 @@ func TestClient_NeedsUpdate(t *testing.T) {
client := db.NewClient(dbDir, true)
needsUpdate, err := client.NeedsUpdate(ctx, "test", tt.skip)
// Compare log messages
require.Len(t, lo.Compact(strings.Split(out.String(), "\n")), len(tt.wantLogs))
for _, logMsg := range tt.wantLogs {
assert.Contains(t, out.String(), logMsg)
}
switch {
case tt.wantErr != "":
require.ErrorContains(t, err, tt.wantErr, tt.name)