diff --git a/docs/vulnerability/examples/db.md b/docs/vulnerability/examples/db.md index ec88099bb0e1..ad35020d7162 100644 --- a/docs/vulnerability/examples/db.md +++ b/docs/vulnerability/examples/db.md @@ -36,3 +36,10 @@ This is useful to initialize workers in Continuous Integration systems. ``` $ trivy image --download-db-only ``` + +## DB Repository +`Trivy` could also download the vulnerability database from an external OCI registry by using `--db-repository` option. + +``` +$ trivy image --db-repository registry.gitlab.com/gitlab-org/security-products/dependencies/trivy-db +``` diff --git a/pkg/commands/app.go b/pkg/commands/app.go index e470f80ef11c..d4105e7e8959 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -325,6 +325,13 @@ var ( EnvVars: []string{"TRIVY_CUSTOM_HEADERS"}, } + dbRepositoryFlag = cli.StringFlag{ + Name: "db-repository", + Usage: "OCI repository to retrieve trivy-db from", + Value: "ghcr.io/aquasecurity/trivy-db", + EnvVars: []string{"TRIVY_DB_REPOSITORY"}, + } + // Global flags globalFlags = []cli.Flag{ &quietFlag, @@ -448,6 +455,7 @@ func NewImageCommand() *cli.Command { &redisBackendKey, &offlineScan, &insecureFlag, + &dbRepositoryFlag, stringSliceFlag(skipFiles), stringSliceFlag(skipDirs), }, @@ -484,6 +492,7 @@ func NewFilesystemCommand() *cli.Command { &ignorePolicy, &listAllPackages, &offlineScan, + &dbRepositoryFlag, stringSliceFlag(skipFiles), stringSliceFlag(skipDirs), diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index b02df76c8886..cb7795203c47 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -151,7 +151,7 @@ func initCache(c Option) (cache.Cache, error) { func initDB(c Option) error { // download the database file noProgress := c.Quiet || c.NoProgress - if err := operation.DownloadDB(c.AppVersion, c.CacheDir, noProgress, c.SkipDBUpdate); err != nil { + if err := operation.DownloadDB(c.AppVersion, c.CacheDir, c.DBRepository, noProgress, c.SkipDBUpdate); err != nil { return err } diff --git a/pkg/commands/operation/operation.go b/pkg/commands/operation/operation.go index 06ac1d8a5e64..6b63048ede36 100644 --- a/pkg/commands/operation/operation.go +++ b/pkg/commands/operation/operation.go @@ -95,8 +95,8 @@ func (c Cache) ClearArtifacts() error { } // DownloadDB downloads the DB -func DownloadDB(appVersion, cacheDir string, quiet, skipUpdate bool) error { - client := db.NewClient(cacheDir, quiet) +func DownloadDB(appVersion, cacheDir, dbRepository string, quiet, skipUpdate bool) error { + client := db.NewClient(cacheDir, quiet, db.WithDBRepository(dbRepository)) ctx := context.Background() needsUpdate, err := client.NeedsUpdate(appVersion, skipUpdate) if err != nil { @@ -105,6 +105,7 @@ func DownloadDB(appVersion, cacheDir string, quiet, skipUpdate bool) error { if needsUpdate { log.Logger.Info("Need to update DB") + log.Logger.Infof("DB Repository: %s", dbRepository) log.Logger.Info("Downloading DB...") if err = client.Download(ctx, cacheDir); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) diff --git a/pkg/commands/option/db.go b/pkg/commands/option/db.go index ec4889357701..902b0c958044 100644 --- a/pkg/commands/option/db.go +++ b/pkg/commands/option/db.go @@ -14,6 +14,7 @@ type DBOption struct { SkipDBUpdate bool Light bool NoProgress bool + DBRepository string } // NewDBOption is the factory method to return the DBOption @@ -24,6 +25,7 @@ func NewDBOption(c *cli.Context) DBOption { SkipDBUpdate: c.Bool("skip-db-update"), Light: c.Bool("light"), NoProgress: c.Bool("no-progress"), + DBRepository: c.String("db-repository"), } } diff --git a/pkg/commands/server/run.go b/pkg/commands/server/run.go index 430a0c57aba9..de5b94c2a50a 100644 --- a/pkg/commands/server/run.go +++ b/pkg/commands/server/run.go @@ -40,7 +40,7 @@ func run(c Config) (err error) { } // download the database file - if err = operation.DownloadDB(c.AppVersion, c.CacheDir, true, c.SkipDBUpdate); err != nil { + if err = operation.DownloadDB(c.AppVersion, c.CacheDir, c.DBRepository, true, c.SkipDBUpdate); err != nil { return err } diff --git a/pkg/db/db.go b/pkg/db/db.go index 500383270d2c..e33aa11f2f75 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -16,8 +16,8 @@ import ( ) const ( - dbRepository = "ghcr.io/aquasecurity/trivy-db" - dbMediaType = "application/vnd.aquasec.trivy.db.layer.v1.tar+gzip" + dbMediaType = "application/vnd.aquasec.trivy.db.layer.v1.tar+gzip" + defaultDBRepository = "ghcr.io/aquasecurity/trivy-db" ) // Operation defines the DB operations @@ -27,8 +27,9 @@ type Operation interface { } type options struct { - artifact *oci.Artifact - clock clock.Clock + artifact *oci.Artifact + clock clock.Clock + dbRepository string } // Option is a functional option @@ -41,6 +42,13 @@ func WithOCIArtifact(art *oci.Artifact) Option { } } +// WithDBRepository takes a dbRepository +func WithDBRepository(dbRepository string) Option { + return func(opts *options) { + opts.dbRepository = dbRepository + } +} + // WithClock takes a clock func WithClock(clock clock.Clock) Option { return func(opts *options) { @@ -60,7 +68,8 @@ type Client struct { // NewClient is the factory method for DB client func NewClient(cacheDir string, quiet bool, opts ...Option) *Client { o := &options{ - clock: clock.RealClock{}, + clock: clock.RealClock{}, + dbRepository: defaultDBRepository, } for _, opt := range opts { @@ -173,7 +182,7 @@ func (c *Client) updateDownloadedAt(dst string) error { func (c *Client) populateOCIArtifact() error { if c.artifact == nil { - repo := fmt.Sprintf("%s:%d", dbRepository, db.SchemaVersion) + repo := fmt.Sprintf("%s:%d", c.dbRepository, db.SchemaVersion) art, err := oci.NewArtifact(repo, dbMediaType, c.quiet) if err != nil { return xerrors.Errorf("OCI artifact error: %w", err)