Skip to content

Commit

Permalink
fix(db): check schema version for image name only (#6410)
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <[email protected]>
Co-authored-by: knqyf263 <[email protected]>
  • Loading branch information
DmitriyLewen and knqyf263 authored Apr 2, 2024
1 parent e75a90f commit 8baccd7
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 62 deletions.
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
47 changes: 38 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,32 @@ 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")
}

var dbRepository, javaDBRepository name.Reference
var err error
if f.DBRepository != nil {
if dbRepository, err = name.ParseReference(f.DBRepository.Value(), name.WithDefaultTag("")); 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()))
}
}

if f.JavaDBRepository != nil {
if javaDBRepository, err = name.ParseReference(f.JavaDBRepository.Value(), name.WithDefaultTag("")); 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 +182,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

0 comments on commit 8baccd7

Please sign in to comment.