Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(db): check schema version for image name only #6410

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pkg/commands/operation/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sync"

"github.com/go-redis/redis/v8"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/wire"
"github.com/samber/lo"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -110,7 +111,8 @@ func (c Cache) ClearArtifacts() error {
}

// DownloadDB downloads the DB
func DownloadDB(ctx context.Context, appVersion, cacheDir, dbRepository string, quiet, skipUpdate bool, opt ftypes.RegistryOptions) error {
func DownloadDB(ctx context.Context, appVersion, cacheDir string, dbRepository name.Reference, quiet, skipUpdate bool,
opt ftypes.RegistryOptions) error {
mu.Lock()
defer mu.Unlock()

Expand Down
25 changes: 12 additions & 13 deletions pkg/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"

"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"golang.org/x/xerrors"
"k8s.io/utils/clock"
Expand All @@ -19,8 +19,13 @@ import (
)

const (
dbMediaType = "application/vnd.aquasec.trivy.db.layer.v1.tar+gzip"
defaultDBRepository = "ghcr.io/aquasecurity/trivy-db"
SchemaVersion = db.SchemaVersion
dbMediaType = "application/vnd.aquasec.trivy.db.layer.v1.tar+gzip"
)

var (
DefaultRepository = fmt.Sprintf("%s:%d", "ghcr.io/aquasecurity/trivy-db", db.SchemaVersion)
defaultRepository, _ = name.NewTag(DefaultRepository)
)

// Operation defines the DB operations
Expand All @@ -32,7 +37,7 @@ type Operation interface {
type options struct {
artifact *oci.Artifact
clock clock.Clock
dbRepository string
dbRepository name.Reference
}

// Option is a functional option
Expand All @@ -46,7 +51,7 @@ func WithOCIArtifact(art *oci.Artifact) Option {
}

// WithDBRepository takes a dbRepository
func WithDBRepository(dbRepository string) Option {
func WithDBRepository(dbRepository name.Reference) Option {
return func(opts *options) {
opts.dbRepository = dbRepository
}
Expand All @@ -72,19 +77,13 @@ type Client struct {
func NewClient(cacheDir string, quiet bool, opts ...Option) *Client {
o := &options{
clock: clock.RealClock{},
dbRepository: defaultDBRepository,
dbRepository: defaultRepository,
}

for _, opt := range opts {
opt(o)
}

// Add the schema version as a tag if the tag doesn't exist.
// This is required for backward compatibility.
if !strings.Contains(o.dbRepository, ":") {
o.dbRepository = fmt.Sprintf("%s:%d", o.dbRepository, db.SchemaVersion)
}

return &Client{
options: o,
cacheDir: cacheDir,
Expand Down Expand Up @@ -195,7 +194,7 @@ func (c *Client) initOCIArtifact(opt types.RegistryOptions) (*oci.Artifact, erro
return c.artifact, nil
}

art, err := oci.NewArtifact(c.dbRepository, c.quiet, opt)
art, err := oci.NewArtifact(c.dbRepository.String(), c.quiet, opt)
if err != nil {
var terr *transport.Error
if errors.As(err, &terr) {
Expand Down
28 changes: 17 additions & 11 deletions pkg/fanal/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package analyzer_test
import (
"context"
"fmt"
"github.com/google/go-containerregistry/pkg/name"
"os"
"sync"
"testing"
Expand All @@ -12,11 +13,11 @@ import (
"golang.org/x/sync/semaphore"
"golang.org/x/xerrors"

xio "github.com/aquasecurity/trivy/pkg/x/io"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/javadb"
"github.com/aquasecurity/trivy/pkg/mapfs"
xio "github.com/aquasecurity/trivy/pkg/x/io"

_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/imgconf/apk"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/java/jar"
Expand Down Expand Up @@ -335,15 +336,18 @@ func TestAnalyzerGroup_AnalyzeFile(t *testing.T) {
FilePath: "/lib/apk/db/installed",
Packages: types.Packages{
{
ID: "[email protected]",
Name: "musl",
Version: "1.1.24-r2",
SrcName: "musl",
SrcVersion: "1.1.24-r2",
Licenses: []string{"MIT"},
Arch: "x86_64",
Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6",
InstalledFiles: []string{"lib/libc.musl-x86_64.so.1", "lib/ld-musl-x86_64.so.1"},
ID: "[email protected]",
Name: "musl",
Version: "1.1.24-r2",
SrcName: "musl",
SrcVersion: "1.1.24-r2",
Licenses: []string{"MIT"},
Arch: "x86_64",
Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6",
InstalledFiles: []string{
"lib/libc.musl-x86_64.so.1",
"lib/ld-musl-x86_64.so.1",
},
},
},
},
Expand Down Expand Up @@ -615,7 +619,9 @@ func TestAnalyzerGroup_PostAnalyze(t *testing.T) {

if tt.analyzerType == analyzer.TypeJar {
// init java-trivy-db with skip update
javadb.Init("./language/java/jar/testdata", "ghcr.io/aquasecurity/trivy-java-db", true, false, types.RegistryOptions{Insecure: false})
repo, err := name.NewTag(javadb.DefaultRepository)
require.NoError(t, err)
javadb.Init("./language/java/jar/testdata", repo, true, false, types.RegistryOptions{Insecure: false})
}

ctx := context.Background()
Expand Down
8 changes: 6 additions & 2 deletions pkg/fanal/analyzer/language/java/jar/jar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package jar

import (
"context"
"github.com/google/go-containerregistry/pkg/name"
"github.com/stretchr/testify/require"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -130,13 +132,15 @@ func Test_javaLibraryAnalyzer_Analyze(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// init java-trivy-db with skip update
javadb.Init("testdata", defaultJavaDBRepository, true, false, types.RegistryOptions{Insecure: false})
repo, err := name.NewTag(javadb.DefaultRepository)
require.NoError(t, err)
javadb.Init("testdata", repo, true, false, types.RegistryOptions{Insecure: false})

a := javaLibraryAnalyzer{}
ctx := context.Background()

mfs := mapfs.New()
err := mfs.MkdirAll(filepath.Dir(tt.inputFile), os.ModePerm)
err = mfs.MkdirAll(filepath.Dir(tt.inputFile), os.ModePerm)
assert.NoError(t, err)
err = mfs.WriteFile(tt.inputFile, tt.inputFile)
assert.NoError(t, err)
Expand Down
43 changes: 34 additions & 9 deletions pkg/flag/db_flags.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package flag

import (
"fmt"

"github.com/google/go-containerregistry/pkg/name"
"go.uber.org/zap"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/db"
"github.com/aquasecurity/trivy/pkg/javadb"
"github.com/aquasecurity/trivy/pkg/log"
)

const defaultDBRepository = "ghcr.io/aquasecurity/trivy-db:2"
const defaultJavaDBRepository = "ghcr.io/aquasecurity/trivy-java-db:1"

var (
ResetFlag = Flag[bool]{
Name: "reset",
Expand Down Expand Up @@ -49,13 +52,13 @@ var (
DBRepositoryFlag = Flag[string]{
Name: "db-repository",
ConfigName: "db.repository",
Default: defaultDBRepository,
Default: db.DefaultRepository,
Usage: "OCI repository to retrieve trivy-db from",
}
JavaDBRepositoryFlag = Flag[string]{
Name: "java-db-repository",
ConfigName: "db.java-repository",
Default: defaultJavaDBRepository,
Default: javadb.DefaultRepository,
Usage: "OCI repository to retrieve trivy-java-db from",
}
LightFlag = Flag[bool]{
Expand Down Expand Up @@ -86,8 +89,8 @@ type DBOptions struct {
DownloadJavaDBOnly bool
SkipJavaDBUpdate bool
NoProgress bool
DBRepository string
JavaDBRepository string
DBRepository name.Reference
JavaDBRepository name.Reference
Light bool // deprecated
}

Expand Down Expand Up @@ -145,6 +148,28 @@ func (f *DBFlagGroup) ToOptions() (DBOptions, error) {
log.Logger.Warn("'--light' option is deprecated and will be removed. See also: https://github.com/aquasecurity/trivy/discussions/1649")
}

dbRepository, err := name.ParseReference(f.DBRepository.Value(), name.WithDefaultTag(""))
if err != nil {
return DBOptions{}, xerrors.Errorf("invalid db repository: %w", err)
}
// Add the schema version if the tag is not specified for backward compatibility.
if t, ok := dbRepository.(name.Tag); ok && t.TagStr() == "" {
dbRepository = t.Tag(fmt.Sprint(db.SchemaVersion))
log.Logger.Infow("Adding schema version to the DB repository for backward compatibility",
zap.String("repository", dbRepository.String()))
}

javaDBRepository, err := name.ParseReference(f.JavaDBRepository.Value(), name.WithDefaultTag(""))
if err != nil {
return DBOptions{}, xerrors.Errorf("invalid javadb repository: %w", err)
}
// Add the schema version if the tag is not specified for backward compatibility.
if t, ok := javaDBRepository.(name.Tag); ok && t.TagStr() == "" {
javaDBRepository = t.Tag(fmt.Sprint(javadb.SchemaVersion))
log.Logger.Infow("Adding schema version to the Java DB repository for backward compatibility",
zap.String("repository", javaDBRepository.String()))
}

return DBOptions{
Reset: f.Reset.Value(),
DownloadDBOnly: downloadDBOnly,
Expand All @@ -153,7 +178,7 @@ func (f *DBFlagGroup) ToOptions() (DBOptions, error) {
SkipJavaDBUpdate: skipJavaDBUpdate,
Light: light,
NoProgress: f.NoProgress.Value(),
DBRepository: f.DBRepository.Value(),
JavaDBRepository: f.JavaDBRepository.Value(),
DBRepository: dbRepository,
JavaDBRepository: javaDBRepository,
}, nil
}
52 changes: 39 additions & 13 deletions pkg/flag/db_flags_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package flag_test

import (
"github.com/google/go-containerregistry/pkg/name"
"testing"

"github.com/spf13/viper"
Expand All @@ -15,9 +16,11 @@ import (

func TestDBFlagGroup_ToOptions(t *testing.T) {
type fields struct {
SkipDBUpdate bool
DownloadDBOnly bool
Light bool
SkipDBUpdate bool
DownloadDBOnly bool
Light bool
DBRepository string
JavaDBRepository string
}
tests := []struct {
name string
Expand All @@ -29,22 +32,30 @@ func TestDBFlagGroup_ToOptions(t *testing.T) {
{
name: "happy",
fields: fields{
SkipDBUpdate: true,
DownloadDBOnly: false,
SkipDBUpdate: true,
DownloadDBOnly: false,
DBRepository: "ghcr.io/aquasecurity/trivy-db",
JavaDBRepository: "ghcr.io/aquasecurity/trivy-java-db",
},
want: flag.DBOptions{
SkipDBUpdate: true,
DownloadDBOnly: false,
SkipDBUpdate: true,
DownloadDBOnly: false,
DBRepository: name.Tag{}, // All fields are unexported
JavaDBRepository: name.Tag{}, // All fields are unexported
},
assertion: require.NoError,
},
{
name: "light",
fields: fields{
Light: true,
Light: true,
DBRepository: "ghcr.io/aquasecurity/trivy-db",
JavaDBRepository: "ghcr.io/aquasecurity/trivy-java-db",
},
want: flag.DBOptions{
Light: true,
Light: true,
DBRepository: name.Tag{}, // All fields are unexported
JavaDBRepository: name.Tag{}, // All fields are unexported
},
wantLogs: []string{
"'--light' option is deprecated and will be removed. See also: https://github.com/aquasecurity/trivy/discussions/1649",
Expand All @@ -61,6 +72,17 @@ func TestDBFlagGroup_ToOptions(t *testing.T) {
require.ErrorContains(t, err, "--skip-db-update and --download-db-only options can not be specified both")
},
},
{
name: "invalid repo",
fields: fields{
SkipDBUpdate: true,
DownloadDBOnly: false,
DBRepository: "foo:bar:baz",
},
assertion: func(t require.TestingT, err error, msgs ...interface{}) {
require.ErrorContains(t, err, "invalid db repository")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -71,16 +93,20 @@ func TestDBFlagGroup_ToOptions(t *testing.T) {
viper.Set(flag.SkipDBUpdateFlag.ConfigName, tt.fields.SkipDBUpdate)
viper.Set(flag.DownloadDBOnlyFlag.ConfigName, tt.fields.DownloadDBOnly)
viper.Set(flag.LightFlag.ConfigName, tt.fields.Light)
viper.Set(flag.DBRepositoryFlag.ConfigName, tt.fields.DBRepository)
viper.Set(flag.JavaDBRepositoryFlag.ConfigName, tt.fields.JavaDBRepository)

// Assert options
f := &flag.DBFlagGroup{
DownloadDBOnly: flag.DownloadDBOnlyFlag.Clone(),
SkipDBUpdate: flag.SkipDBUpdateFlag.Clone(),
Light: flag.LightFlag.Clone(),
DownloadDBOnly: flag.DownloadDBOnlyFlag.Clone(),
SkipDBUpdate: flag.SkipDBUpdateFlag.Clone(),
Light: flag.LightFlag.Clone(),
DBRepository: flag.DBRepositoryFlag.Clone(),
JavaDBRepository: flag.JavaDBRepositoryFlag.Clone(),
}
got, err := f.ToOptions()
tt.assertion(t, err)
assert.Equalf(t, tt.want, got, "ToOptions()")
assert.EqualExportedValues(t, tt.want, got)

// Assert log messages
var gotMessages []string
Expand Down
Loading
Loading