feat(image): custom docker host option (#3599)

Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
aswath-s-tw
2023-04-21 00:40:51 +05:30
committed by GitHub
parent cc18f92cf3
commit be47b688c7
47 changed files with 317 additions and 188 deletions

View File

@@ -43,6 +43,7 @@ trivy image [flags] IMAGE_NAME
--custom-headers strings custom headers in client mode
--db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db")
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages
--docker-host string unix domain socket path to use for docker scanning
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
--enable-modules strings [EXPERIMENTAL] module names to enable

View File

@@ -193,6 +193,15 @@ image:
# Same as '--removed-pkgs'
# Default is false
removed-pkgs: false
# Same as '--platform'
# Default is empty
platform:
docker:
# Same as '--docker-host'
# Default is empty
host:
```
## Vulnerability Options

View File

@@ -482,3 +482,9 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)
</details>
### Configure Docker daemon socket to connect to.
You can configure Docker daemon socket with `DOCKER_HOST` or `--docker-host`.
```shell
$ trivy image --docker-host tcp://127.0.0.1:2375 YOUR_IMAGE
```

View File

@@ -760,7 +760,7 @@ func NewModuleCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
if err != nil {
return xerrors.Errorf("flag error: %w", err)
}
return module.Install(cmd.Context(), opts.ModuleDir, repo, opts.Quiet, opts.Remote())
return module.Install(cmd.Context(), opts.ModuleDir, repo, opts.Quiet, opts.Registry())
},
},
&cobra.Command{

View File

@@ -22,7 +22,7 @@ import (
// initializeDockerScanner is for container image scanning in standalone mode
// e.g. dockerd, container registry, podman, etc.
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
localArtifactCache cache.LocalArtifactCache, remoteOpt types.RemoteOptions, artifactOption artifact.Option) (
localArtifactCache cache.LocalArtifactCache, imageOpt types.ImageOptions, artifactOption artifact.Option) (
scanner.Scanner, func(), error) {
wire.Build(scanner.StandaloneDockerSet)
return scanner.Scanner{}, nil, nil
@@ -69,7 +69,7 @@ func initializeVMScanner(ctx context.Context, filePath string, artifactCache cac
// initializeRemoteDockerScanner is for container image scanning in client/server mode
// e.g. dockerd, container registry, podman, etc.
func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache,
remoteScanOptions client.ScannerOption, remoteOpt types.RemoteOptions, artifactOption artifact.Option) (
remoteScanOptions client.ScannerOption, imageOpt types.ImageOptions, artifactOption artifact.Option) (
scanner.Scanner, func(), error) {
wire.Build(scanner.RemoteDockerSet)
return scanner.Scanner{}, nil, nil

View File

@@ -19,6 +19,7 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/config"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/javadb"
"github.com/aquasecurity/trivy/pkg/log"
@@ -314,7 +315,7 @@ func (r *runner) initDB(ctx context.Context, opts flag.Options) error {
// download the database file
noProgress := opts.Quiet || opts.NoProgress
if err := operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository, noProgress, opts.SkipDBUpdate, opts.Remote()); err != nil {
if err := operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository, noProgress, opts.SkipDBUpdate, opts.Registry()); err != nil {
return err
}
@@ -615,8 +616,6 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
fileChecksum = true
}
remoteOpts := opts.Remote()
return ScannerConfig{
Target: target,
ArtifactCache: cacheClient,
@@ -633,18 +632,25 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
FilePatterns: opts.FilePatterns,
Offline: opts.OfflineScan,
NoProgress: opts.NoProgress || opts.Quiet,
Insecure: opts.Insecure,
RepoBranch: opts.RepoBranch,
RepoCommit: opts.RepoCommit,
RepoTag: opts.RepoTag,
SBOMSources: opts.SBOMSources,
RekorURL: opts.RekorURL,
Platform: opts.Platform,
DockerHost: opts.DockerHost,
Slow: opts.Slow,
AWSRegion: opts.Region,
FileChecksum: fileChecksum,
// For OCI registries
RemoteOptions: remoteOpts,
// For image scanning
ImageOption: ftypes.ImageOptions{
RegistryOptions: opts.Registry(),
DockerOptions: ftypes.DockerOptions{
Host: opts.DockerHost,
},
},
// For misconfiguration scanning
MisconfScannerOption: configScannerOptions,

View File

@@ -12,7 +12,7 @@ import (
// $ trivy image alpine:3.15
func imageStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
s, cleanup, err := initializeDockerScanner(ctx, conf.Target, conf.ArtifactCache, conf.LocalArtifactCache,
conf.ArtifactOption.RemoteOptions, conf.ArtifactOption)
conf.ArtifactOption.ImageOption, conf.ArtifactOption)
if err != nil {
return scanner.Scanner{}, func() {}, xerrors.Errorf("unable to initialize a docker scanner: %w", err)
}
@@ -34,7 +34,7 @@ func archiveStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.
func imageRemoteScanner(ctx context.Context, conf ScannerConfig) (
scanner.Scanner, func(), error) {
s, cleanup, err := initializeRemoteDockerScanner(ctx, conf.Target, conf.ArtifactCache, conf.ServerOption,
conf.ArtifactOption.RemoteOptions, conf.ArtifactOption)
conf.ArtifactOption.ImageOption, conf.ArtifactOption)
if err != nil {
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the remote docker scanner: %w", err)
}

View File

@@ -30,14 +30,14 @@ import (
// initializeDockerScanner is for container image scanning in standalone mode
// e.g. dockerd, container registry, podman, etc.
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, remoteOpt types.RemoteOptions, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, localArtifactCache cache.LocalArtifactCache, imageOpt types.ImageOptions, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
applierApplier := applier.NewApplier(localArtifactCache)
detector := ospkg.Detector{}
config := db.Config{}
client := vulnerability.NewClient(config)
localScanner := local.NewScanner(applierApplier, detector, client)
v := _wireValue
typesImage, cleanup, err := image.NewContainerImage(ctx, imageName, remoteOpt, v...)
typesImage, cleanup, err := image.NewContainerImage(ctx, imageName, imageOpt, v...)
if err != nil {
return scanner.Scanner{}, nil, err
}
@@ -140,11 +140,11 @@ func initializeVMScanner(ctx context.Context, filePath string, artifactCache cac
// initializeRemoteDockerScanner is for container image scanning in client/server mode
// e.g. dockerd, container registry, podman, etc.
func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, remoteOpt types.RemoteOptions, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
func initializeRemoteDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, remoteScanOptions client.ScannerOption, imageOpt types.ImageOptions, artifactOption artifact.Option) (scanner.Scanner, func(), error) {
v := _wireValue2
clientScanner := client.NewScanner(remoteScanOptions, v...)
v2 := _wireValue3
typesImage, cleanup, err := image.NewContainerImage(ctx, imageName, remoteOpt, v2...)
typesImage, cleanup, err := image.NewContainerImage(ctx, imageName, imageOpt, v2...)
if err != nil {
return scanner.Scanner{}, nil, err
}

View File

@@ -109,7 +109,7 @@ func (c Cache) ClearArtifacts() error {
}
// DownloadDB downloads the DB
func DownloadDB(ctx context.Context, appVersion, cacheDir, dbRepository string, quiet, skipUpdate bool, opt types.RemoteOptions) error {
func DownloadDB(ctx context.Context, appVersion, cacheDir, dbRepository string, quiet, skipUpdate bool, opt types.RegistryOptions) error {
mu.Lock()
defer mu.Unlock()

View File

@@ -35,7 +35,7 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
// download the database file
if err = operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository,
true, opts.SkipDBUpdate, opts.Remote()); err != nil {
true, opts.SkipDBUpdate, opts.Registry()); err != nil {
return err
}
@@ -58,6 +58,6 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
m.Register()
server := rpcServer.NewServer(opts.AppVersion, opts.Listen, opts.CacheDir, opts.Token, opts.TokenHeader,
opts.DBRepository, opts.Remote())
opts.DBRepository, opts.Registry())
return server.ListenAndServe(cache, opts.SkipDBUpdate)
}

View File

@@ -25,7 +25,7 @@ const (
// Operation defines the DB operations
type Operation interface {
NeedsUpdate(cliVersion string, skip bool) (need bool, err error)
Download(ctx context.Context, dst string, opt types.RemoteOptions) (err error)
Download(ctx context.Context, dst string, opt types.RegistryOptions) (err error)
}
type options struct {
@@ -143,7 +143,7 @@ func (c *Client) isNewDB(meta metadata.Metadata) bool {
}
// Download downloads the DB file
func (c *Client) Download(ctx context.Context, dst string, opt types.RemoteOptions) error {
func (c *Client) Download(ctx context.Context, dst string, opt types.RegistryOptions) error {
// Remove the metadata file under the cache directory before downloading DB
if err := c.metadata.Delete(); err != nil {
log.Logger.Debug("no metadata file")
@@ -183,7 +183,7 @@ func (c *Client) updateDownloadedAt(dst string) error {
return nil
}
func (c *Client) initOCIArtifact(opt types.RemoteOptions) (*oci.Artifact, error) {
func (c *Client) initOCIArtifact(opt types.RegistryOptions) (*oci.Artifact, error) {
if c.artifact != nil {
return c.artifact, nil
}

View File

@@ -219,7 +219,7 @@ func TestClient_Download(t *testing.T) {
}, nil)
// Mock OCI artifact
opt := ftypes.RemoteOptions{
opt := ftypes.RegistryOptions{
Insecure: false,
}
art, err := oci.NewArtifact("db", true, opt, oci.WithImage(img))

View File

@@ -53,7 +53,7 @@ func (_m *MockOperation) ApplyDownloadExpectations(expectations []OperationDownl
}
// Download provides a mock function with given fields: ctx, dst
func (_m *MockOperation) Download(ctx context.Context, dst string, opt types.RemoteOptions) error {
func (_m *MockOperation) Download(ctx context.Context, dst string, opt types.RegistryOptions) error {
ret := _m.Called(ctx, dst, opt)
var r0 error

View File

@@ -18,11 +18,13 @@ type Option struct {
SkipDirs []string
FilePatterns []string
NoProgress bool
Insecure bool
Offline bool
AppDirs []string
SBOMSources []string
RekorURL string
Platform string
DockerHost string
Slow bool // Lower CPU and memory
AWSRegion string
FileChecksum bool // For SPDX
@@ -32,8 +34,8 @@ type Option struct {
RepoCommit string
RepoTag string
// For OCI registries
types.RemoteOptions
// For image scanning
ImageOption types.ImageOptions
MisconfScannerOption misconf.ScannerOption
SecretScannerOption analyzer.SecretScannerOption

View File

@@ -59,7 +59,7 @@ func (a Artifact) inspectOCIReferrerSBOM(ctx context.Context) (ftypes.ArtifactRe
}
// Fetch referrers
index, err := remote.Referrers(ctx, digest, a.artifactOption.RemoteOptions)
index, err := remote.Referrers(ctx, digest, a.artifactOption.ImageOption.RegistryOptions)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("unable to fetch referrers: %w", err)
}
@@ -81,7 +81,7 @@ func (a Artifact) inspectOCIReferrerSBOM(ctx context.Context) (ftypes.ArtifactRe
func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descriptor) (ftypes.ArtifactReference, error) {
const fileName string = "referrer.sbom"
repoName := fmt.Sprintf("%s@%s", repo, desc.Digest)
referrer, err := oci.NewArtifact(repoName, true, a.artifactOption.RemoteOptions)
referrer, err := oci.NewArtifact(repoName, true, a.artifactOption.ImageOption.RegistryOptions)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("OCI error: %w", err)
}

View File

@@ -9,8 +9,8 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/types"
)
func tryDockerDaemon(imageName string, ref name.Reference) (types.Image, func(), error) {
img, cleanup, err := daemon.DockerImage(ref)
func tryDockerDaemon(imageName string, ref name.Reference, opt types.DockerOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.DockerImage(ref, opt.Host)
if err != nil {
return nil, nil, err
}

View File

@@ -11,10 +11,19 @@ import (
// DockerImage implements v1.Image by extending daemon.Image.
// The caller must call cleanup() to remove a temporary file.
func DockerImage(ref name.Reference) (Image, func(), error) {
func DockerImage(ref name.Reference, host string) (Image, func(), error) {
cleanup := func() {}
c, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
opts := []client.Opt{
client.FromEnv,
client.WithAPIVersionNegotiation(),
}
if host != "" {
// adding host parameter to the last assuming it will pick up more preference
opts = append(opts, client.WithHost(host))
}
c, err := client.NewClientWithOpts(opts...)
if err != nil {
return nil, cleanup, xerrors.Errorf("failed to initialize a docker client: %w", err)
}

View File

@@ -40,7 +40,7 @@ func TestDockerImage(t *testing.T) {
ref, err := name.ParseReference(tt.imageName)
require.NoError(t, err)
_, cleanup, err := DockerImage(ref)
_, cleanup, err := DockerImage(ref, "")
assert.Equal(t, tt.wantErr, err != nil, err)
defer func() {
if cleanup != nil {

View File

@@ -4,6 +4,8 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"testing"
"time"
@@ -17,18 +19,19 @@ import (
"github.com/aquasecurity/testdocker/engine"
)
func TestMain(m *testing.M) {
imagePaths := map[string]string{
var imagePaths = map[string]string{
"alpine:3.10": "../../test/testdata/alpine-310.tar.gz",
"alpine:3.11": "../../test/testdata/alpine-311.tar.gz",
"gcr.io/distroless/base": "../../test/testdata/distroless.tar.gz",
}
// for Docker
opt := engine.Option{
var opt = engine.Option{
APIVersion: "1.38",
ImagePaths: imagePaths,
}
func TestMain(m *testing.M) {
te := engine.NewDockerEngine(opt)
defer te.Close()
@@ -59,7 +62,7 @@ func Test_image_ConfigName(t *testing.T) {
ref, err := name.ParseReference(tt.imageName)
require.NoError(t, err)
img, cleanup, err := DockerImage(ref)
img, cleanup, err := DockerImage(ref, "")
require.NoError(t, err)
defer cleanup()
@@ -70,6 +73,50 @@ func Test_image_ConfigName(t *testing.T) {
}
}
func Test_image_ConfigNameWithCustomDockerHost(t *testing.T) {
ref, err := name.ParseReference("alpine:3.11")
require.NoError(t, err)
eo := engine.Option{
APIVersion: opt.APIVersion,
ImagePaths: opt.ImagePaths,
}
var dockerHostParam string
if runtime.GOOS != "windows" {
runtimeDir, err := ioutil.TempDir("", "daemon")
require.NoError(t, err)
dir := filepath.Join(runtimeDir, "image")
err = os.MkdirAll(dir, os.ModePerm)
require.NoError(t, err)
customDockerHost := filepath.Join(dir, "image-test-unix-socket.sock")
eo.UnixDomainSocket = customDockerHost
dockerHostParam = "unix://" + customDockerHost
}
te := engine.NewDockerEngine(eo)
defer te.Close()
if runtime.GOOS == "windows" {
dockerHostParam = te.Listener.Addr().Network() + "://" + te.Listener.Addr().String()
}
img, cleanup, err := DockerImage(ref, dockerHostParam)
require.NoError(t, err)
defer cleanup()
conf, err := img.ConfigName()
assert.Equal(t, v1.Hash{
Algorithm: "sha256",
Hex: "a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
}, conf)
assert.Nil(t, err)
}
func Test_image_ConfigFile(t *testing.T) {
tests := []struct {
name string
@@ -156,7 +203,7 @@ func Test_image_ConfigFile(t *testing.T) {
ref, err := name.ParseReference(tt.imageName)
require.NoError(t, err)
img, cleanup, err := DockerImage(ref)
img, cleanup, err := DockerImage(ref, "")
require.NoError(t, err)
defer cleanup()
@@ -201,7 +248,7 @@ func Test_image_LayerByDiffID(t *testing.T) {
ref, err := name.ParseReference(tt.imageName)
require.NoError(t, err)
img, cleanup, err := DockerImage(ref)
img, cleanup, err := DockerImage(ref, "")
require.NoError(t, err)
defer cleanup()
@@ -230,7 +277,7 @@ func Test_image_RawConfigFile(t *testing.T) {
ref, err := name.ParseReference(tt.imageName)
require.NoError(t, err)
img, cleanup, err := DockerImage(ref)
img, cleanup, err := DockerImage(ref, "")
require.NoError(t, err)
defer cleanup()

View File

@@ -44,7 +44,7 @@ func DisableRemote() Option {
}
}
func NewContainerImage(ctx context.Context, imageName string, opt types.RemoteOptions, opts ...Option) (types.Image, func(), error) {
func NewContainerImage(ctx context.Context, imageName string, opt types.ImageOptions, opts ...Option) (types.Image, func(), error) {
o := &options{
dockerd: true,
podman: true,
@@ -57,7 +57,7 @@ func NewContainerImage(ctx context.Context, imageName string, opt types.RemoteOp
var errs error
var nameOpts []name.Option
if opt.Insecure {
if opt.RegistryOptions.Insecure {
nameOpts = append(nameOpts, name.Insecure)
}
ref, err := name.ParseReference(imageName, nameOpts...)
@@ -67,7 +67,7 @@ func NewContainerImage(ctx context.Context, imageName string, opt types.RemoteOp
// Try accessing Docker Daemon
if o.dockerd {
img, cleanup, err := tryDockerDaemon(imageName, ref)
img, cleanup, err := tryDockerDaemon(imageName, ref, opt.DockerOptions)
if err == nil {
// Return v1.Image if the image is found in Docker Engine
return img, cleanup, nil
@@ -97,7 +97,7 @@ func NewContainerImage(ctx context.Context, imageName string, opt types.RemoteOp
// Try accessing Docker Registry
if o.remote {
img, err := tryRemote(ctx, imageName, ref, opt)
img, err := tryRemote(ctx, imageName, ref, opt.RegistryOptions)
if err == nil {
// Return v1.Image if the image is found in a remote registry
return img, func() {}, nil

View File

@@ -54,7 +54,7 @@ func TestNewDockerImage(t *testing.T) {
type args struct {
imageName string
option types.RemoteOptions
option types.ImageOptions
}
tests := []struct {
name string
@@ -205,7 +205,8 @@ func TestNewDockerImage(t *testing.T) {
name: "happy path with insecure Docker Registry",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: "test",
@@ -215,6 +216,7 @@ func TestNewDockerImage(t *testing.T) {
Insecure: true,
},
},
},
wantID: "sha256:af341ccd2df8b0e2d67cf8dd32e087bfda4e5756ebd1c76bbf3efa0dc246590e",
wantRepoTags: []string{serverAddr + "/library/alpine:3.10"},
wantRepoDigests: []string{
@@ -331,7 +333,7 @@ func TestNewDockerImageWithPrivateRegistry(t *testing.T) {
type args struct {
imageName string
option types.RemoteOptions
option types.ImageOptions
}
tests := []struct {
name string
@@ -343,7 +345,8 @@ func TestNewDockerImageWithPrivateRegistry(t *testing.T) {
name: "happy path with private Docker Registry",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: "test",
@@ -354,16 +357,19 @@ func TestNewDockerImageWithPrivateRegistry(t *testing.T) {
},
},
},
},
{
name: "happy path with registry token",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
RegistryToken: registryToken,
Insecure: true,
},
},
},
},
{
name: "sad path without a credential",
args: args{
@@ -375,11 +381,13 @@ func TestNewDockerImageWithPrivateRegistry(t *testing.T) {
name: "sad path with invalid registry token",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.11", serverAddr),
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
RegistryToken: registryToken + "invalid",
Insecure: true,
},
},
},
wantErr: "signature is invalid",
},
}
@@ -501,7 +509,7 @@ func TestDockerPlatformArguments(t *testing.T) {
serverAddr := tr.Listener.Addr().String()
type args struct {
option types.RemoteOptions
option types.ImageOptions
}
tests := []struct {
name string
@@ -512,7 +520,8 @@ func TestDockerPlatformArguments(t *testing.T) {
{
name: "happy path with valid platform",
args: args{
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: "test",
@@ -524,6 +533,7 @@ func TestDockerPlatformArguments(t *testing.T) {
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -15,7 +15,7 @@ type Registry struct {
const azureURL = "azurecr.io"
func (r *Registry) CheckOptions(domain string, _ types.RemoteOptions) error {
func (r *Registry) CheckOptions(domain string, _ types.RegistryOptions) error {
if !strings.HasSuffix(domain, azureURL) {
return xerrors.Errorf("Azure registry: %w", types.InvalidURLPattern)
}

View File

@@ -28,7 +28,7 @@ func TestRegistry_CheckOptions(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := azure.Registry{}
err := r.CheckOptions(tt.domain, types.RemoteOptions{})
err := r.CheckOptions(tt.domain, types.RegistryOptions{})
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {

View File

@@ -22,7 +22,7 @@ type ECR struct {
Client ecriface.ECRAPI
}
func getSession(option types.RemoteOptions) (*session.Session, error) {
func getSession(option types.RegistryOptions) (*session.Session, error) {
// create custom credential information if option is valid
if option.AWSSecretKey != "" && option.AWSAccessKey != "" && option.AWSRegion != "" {
return session.NewSessionWithOptions(
@@ -45,7 +45,7 @@ func getSession(option types.RemoteOptions) (*session.Session, error) {
})
}
func (e *ECR) CheckOptions(domain string, option types.RemoteOptions) error {
func (e *ECR) CheckOptions(domain string, option types.RegistryOptions) error {
if !strings.HasSuffix(domain, ecrURL) {
return xerrors.Errorf("ECR : %w", types.InvalidURLPattern)
}

View File

@@ -30,7 +30,7 @@ func TestCheckOptions(t *testing.T) {
for testname, v := range tests {
a := &ECR{}
err := a.CheckOptions(v.domain, types.RemoteOptions{})
err := a.CheckOptions(v.domain, types.RegistryOptions{})
if err != nil {
if !errors.Is(err, v.wantErr) {
t.Errorf("[%s]\nexpected error based on %v\nactual : %v", testname, v.wantErr, err)

View File

@@ -24,7 +24,7 @@ const gcrURL = "gcr.io"
// Google artifact registry
const garURL = "docker.pkg.dev"
func (g *Registry) CheckOptions(domain string, option types.RemoteOptions) error {
func (g *Registry) CheckOptions(domain string, option types.RegistryOptions) error {
if !strings.HasSuffix(domain, gcrURL) && !strings.HasSuffix(domain, garURL) {
return xerrors.Errorf("Google registry: %w", types.InvalidURLPattern)
}

View File

@@ -13,23 +13,21 @@ import (
func TestCheckOptions(t *testing.T) {
var tests = map[string]struct {
domain string
opt types.RemoteOptions
opt types.RegistryOptions
gcr *Registry
wantErr error
}{
"InvalidURL": {
domain: "alpine:3.9",
opt: types.RemoteOptions{},
wantErr: types.InvalidURLPattern,
},
"NoOption": {
domain: "gcr.io",
opt: types.RemoteOptions{},
gcr: &Registry{domain: "gcr.io"},
},
"CredOption": {
domain: "gcr.io",
opt: types.RemoteOptions{GCPCredPath: "/path/to/file.json"},
opt: types.RegistryOptions{GCPCredPath: "/path/to/file.json"},
gcr: &Registry{
domain: "gcr.io",
Store: store.NewGCRCredStore("/path/to/file.json"),

View File

@@ -23,7 +23,7 @@ func init() {
}
type Registry interface {
CheckOptions(domain string, option types.RemoteOptions) error
CheckOptions(domain string, option types.RegistryOptions) error
GetCredential(ctx context.Context) (string, string, error)
}
@@ -31,7 +31,7 @@ func RegisterRegistry(registry Registry) {
registries = append(registries, registry)
}
func GetToken(ctx context.Context, domain string, opt types.RemoteOptions) (auth authn.Basic) {
func GetToken(ctx context.Context, domain string, opt types.RegistryOptions) (auth authn.Basic) {
// check registry which particular to get credential
for _, registry := range registries {
err := registry.CheckOptions(domain, opt)

View File

@@ -14,7 +14,7 @@ import (
func TestGetToken(t *testing.T) {
type args struct {
domain string
opt types.RemoteOptions
opt types.RegistryOptions
}
tests := []struct {
name string

View File

@@ -12,7 +12,7 @@ import (
"github.com/aquasecurity/trivy/pkg/remote"
)
func tryRemote(ctx context.Context, imageName string, ref name.Reference, option types.RemoteOptions) (types.Image, error) {
func tryRemote(ctx context.Context, imageName string, ref name.Reference, option types.RegistryOptions) (types.Image, error) {
desc, err := remote.Get(ctx, ref, option)
if err != nil {
return nil, err

View File

@@ -233,7 +233,7 @@ func TestContainerd_SearchLocalStoreByNameOrDigest(t *testing.T) {
}
})
img, cleanup, err := image.NewContainerImage(ctx, tt.searchName, types.RemoteOptions{},
img, cleanup, err := image.NewContainerImage(ctx, tt.searchName, types.ImageOptions{},
image.DisableDockerd(), image.DisablePodman(), image.DisableRemote())
defer cleanup()
if tt.expectErr {
@@ -679,7 +679,7 @@ func localImageTestWithNamespace(t *testing.T, namespace string) {
require.NoError(t, err)
// Enable only containerd
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.RemoteOptions{},
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.ImageOptions{},
image.DisableDockerd(), image.DisablePodman(), image.DisableRemote())
require.NoError(t, err)
defer cleanup()
@@ -814,7 +814,7 @@ func TestContainerd_PullImage(t *testing.T) {
require.NoError(t, err)
// Enable only containerd
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.RemoteOptions{},
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.ImageOptions{},
image.DisableDockerd(), image.DisablePodman(), image.DisableRemote())
require.NoError(t, err)
defer cleanup()

View File

@@ -151,7 +151,7 @@ func TestFanal_Library_DockerLessMode(t *testing.T) {
})
// Enable only registry scanning
img, cleanup, err := image.NewContainerImage(ctx, tt.remoteImageName, types.RemoteOptions{},
img, cleanup, err := image.NewContainerImage(ctx, tt.remoteImageName, types.ImageOptions{},
image.DisableDockerd(), image.DisablePodman(), image.DisableContainerd())
require.NoError(t, err)
defer cleanup()
@@ -200,7 +200,7 @@ func TestFanal_Library_DockerMode(t *testing.T) {
require.NoError(t, err, tt.name)
// Enable only dockerd scanning
img, cleanup, err := image.NewContainerImage(ctx, tt.remoteImageName, types.RemoteOptions{},
img, cleanup, err := image.NewContainerImage(ctx, tt.remoteImageName, types.ImageOptions{},
image.DisablePodman(), image.DisableContainerd(), image.DisableRemote())
require.NoError(t, err, tt.name)
defer cleanup()

View File

@@ -12,8 +12,6 @@ import (
"path/filepath"
"testing"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/stretchr/testify/assert"
@@ -21,6 +19,7 @@ import (
testcontainers "github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/all"
"github.com/aquasecurity/trivy/pkg/fanal/applier"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
@@ -83,7 +82,7 @@ func TestTLSRegistry(t *testing.T) {
name string
imageName string
imageFile string
option types.RemoteOptions
option types.ImageOptions
login bool
expectedOS types.OS
expectedRepo types.Repository
@@ -93,7 +92,8 @@ func TestTLSRegistry(t *testing.T) {
name: "happy path",
imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310",
imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz",
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: registryUsername,
@@ -102,6 +102,7 @@ func TestTLSRegistry(t *testing.T) {
},
Insecure: true,
},
},
expectedOS: types.OS{
Name: "3.10.2",
Family: "alpine",
@@ -116,9 +117,11 @@ func TestTLSRegistry(t *testing.T) {
name: "happy path with docker login",
imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310",
imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz",
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
Insecure: true,
},
},
login: true,
expectedOS: types.OS{
Name: "3.10.2",
@@ -134,7 +137,8 @@ func TestTLSRegistry(t *testing.T) {
name: "sad path: tls verify",
imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310",
imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz",
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: registryUsername,
@@ -142,15 +146,18 @@ func TestTLSRegistry(t *testing.T) {
},
},
},
},
wantErr: true,
},
{
name: "sad path: no credential",
imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310",
imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz",
option: types.RemoteOptions{
option: types.ImageOptions{
RegistryOptions: types.RegistryOptions{
Insecure: true,
},
},
wantErr: true,
},
}
@@ -200,7 +207,7 @@ func getRegistryURL(ctx context.Context, registryC testcontainers.Container, exp
return url.Parse(urlStr)
}
func analyze(ctx context.Context, imageRef string, opt types.RemoteOptions) (*types.ArtifactDetail, error) {
func analyze(ctx context.Context, imageRef string, opt types.ImageOptions) (*types.ArtifactDetail, error) {
d, err := ioutil.TempDir("", "TestRegistry-*")
if err != nil {
return nil, err

View File

@@ -13,3 +13,50 @@ type ImageExtension interface {
RepoTags() []string
RepoDigests() []string
}
type ImageOptions struct {
RegistryOptions RegistryOptions
DockerOptions DockerOptions
PodmanOptions PodmanOptions
ContainerdOptions ContainerdOptions
}
type DockerOptions struct {
Host string
}
type PodmanOptions struct {
// TODO
}
type ContainerdOptions struct {
// TODO
}
type RegistryOptions struct {
// Auth for registries
Credentials []Credential
// RegistryToken is a bearer token to be sent to a registry
RegistryToken string
// SSL/TLS
Insecure bool
// Architecture
Platform string
// ECR
AWSAccessKey string
AWSSecretKey string
AWSSessionToken string
AWSRegion string
// GCP
GCPCredPath string
}
type Credential struct {
Username string
Password string
}

View File

@@ -1,29 +0,0 @@
package types
type RemoteOptions struct {
// Auth for registries
Credentials []Credential
// RegistryToken is a bearer token to be sent to a registry
RegistryToken string
// SSL/TLS
Insecure bool
// Architecture
Platform string
// ECR
AWSAccessKey string
AWSSecretKey string
AWSSessionToken string
AWSRegion string
// GCP
GCPCredPath string
}
type Credential struct {
Username string
Password string
}

View File

@@ -36,6 +36,12 @@ var (
Value: "",
Usage: "set platform in the form os/arch if image is multi-platform capable",
}
DockerHostFlag = Flag{
Name: "docker-host",
ConfigName: "image.docker.host",
Value: "",
Usage: "unix domain socket path to use for docker scanning",
}
)
type ImageFlagGroup struct {
@@ -43,6 +49,7 @@ type ImageFlagGroup struct {
ImageConfigScanners *Flag
ScanRemovedPkgs *Flag
Platform *Flag
DockerHost *Flag
}
type ImageOptions struct {
@@ -50,6 +57,7 @@ type ImageOptions struct {
ImageConfigScanners types.Scanners
ScanRemovedPkgs bool
Platform string
DockerHost string
}
func NewImageFlagGroup() *ImageFlagGroup {
@@ -58,6 +66,7 @@ func NewImageFlagGroup() *ImageFlagGroup {
ImageConfigScanners: &ImageConfigScannersFlag,
ScanRemovedPkgs: &ScanRemovedPkgsFlag,
Platform: &PlatformFlag,
DockerHost: &DockerHostFlag,
}
}
@@ -66,7 +75,13 @@ func (f *ImageFlagGroup) Name() string {
}
func (f *ImageFlagGroup) Flags() []*Flag {
return []*Flag{f.Input, f.ImageConfigScanners, f.ScanRemovedPkgs, f.Platform}
return []*Flag{
f.Input,
f.ImageConfigScanners,
f.ScanRemovedPkgs,
f.Platform,
f.DockerHost,
}
}
func (f *ImageFlagGroup) ToOptions() (ImageOptions, error) {
@@ -79,5 +94,6 @@ func (f *ImageFlagGroup) ToOptions() (ImageOptions, error) {
ImageConfigScanners: scanners,
ScanRemovedPkgs: getBool(f.ScanRemovedPkgs),
Platform: getString(f.Platform),
DockerHost: getString(f.DockerHost),
}, nil
}

View File

@@ -122,9 +122,9 @@ func (o *Options) Align() {
}
}
// Remote returns options for OCI registries
func (o *Options) Remote() ftypes.RemoteOptions {
return ftypes.RemoteOptions{
// Registry returns options for OCI registries
func (o *Options) Registry() ftypes.RegistryOptions {
return ftypes.RegistryOptions{
Credentials: o.Credentials,
RegistryToken: o.RegistryToken,
Insecure: o.Insecure,

View File

@@ -54,7 +54,7 @@ func (u *Updater) Update() error {
// TODO: support remote options
var a *oci.Artifact
if a, err = oci.NewArtifact(u.repo, u.quiet, ftypes.RemoteOptions{Insecure: u.insecure}); err != nil {
if a, err = oci.NewArtifact(u.repo, u.quiet, ftypes.RegistryOptions{Insecure: u.insecure}); err != nil {
return xerrors.Errorf("oci error: %w", err)
}
if err = a.Download(context.Background(), dbDir, oci.DownloadOption{MediaType: mediaType}); err != nil {

View File

@@ -16,7 +16,7 @@ import (
const mediaType = "application/vnd.module.wasm.content.layer.v1+wasm"
// Install installs a module
func Install(ctx context.Context, dir, repo string, quiet bool, opt types.RemoteOptions) error {
func Install(ctx context.Context, dir, repo string, quiet bool, opt types.RegistryOptions) error {
ref, err := name.ParseReference(repo)
if err != nil {
return xerrors.Errorf("repository parse error: %w", err)

View File

@@ -51,17 +51,17 @@ type Artifact struct {
quiet bool
// For OCI registries
types.RemoteOptions
types.RegistryOptions
image v1.Image // For testing
}
// NewArtifact returns a new artifact
func NewArtifact(repo string, quiet bool, remoteOpt types.RemoteOptions, opts ...Option) (*Artifact, error) {
func NewArtifact(repo string, quiet bool, registryOpt types.RegistryOptions, opts ...Option) (*Artifact, error) {
art := &Artifact{
repository: repo,
quiet: quiet,
RemoteOptions: remoteOpt,
RegistryOptions: registryOpt,
}
for _, o := range opts {
@@ -70,7 +70,7 @@ func NewArtifact(repo string, quiet bool, remoteOpt types.RemoteOptions, opts ..
return art, nil
}
func (a *Artifact) populate(ctx context.Context, opt types.RemoteOptions) error {
func (a *Artifact) populate(ctx context.Context, opt types.RegistryOptions) error {
if a.image != nil {
return nil
}
@@ -96,7 +96,7 @@ type DownloadOption struct {
}
func (a *Artifact) Download(ctx context.Context, dir string, opt DownloadOption) error {
if err := a.populate(ctx, a.RemoteOptions); err != nil {
if err := a.populate(ctx, a.RegistryOptions); err != nil {
return err
}
@@ -191,7 +191,7 @@ func (a *Artifact) download(ctx context.Context, layer v1.Layer, fileName, dir s
}
func (a *Artifact) Digest(ctx context.Context) (string, error) {
if err := a.populate(ctx, a.RemoteOptions); err != nil {
if err := a.populate(ctx, a.RegistryOptions); err != nil {
return "", err
}

View File

@@ -118,7 +118,7 @@ func TestArtifact_Download(t *testing.T) {
},
}, nil)
artifact, err := oci.NewArtifact("repo", true, ftypes.RemoteOptions{}, oci.WithImage(img))
artifact, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img))
require.NoError(t, err)
err = artifact.Download(context.Background(), tempDir, oci.DownloadOption{

View File

@@ -79,7 +79,7 @@ func NewClient(cacheDir string, quiet bool, opts ...Option) (*Client, error) {
func (c *Client) populateOCIArtifact() error {
if c.artifact == nil {
repo := fmt.Sprintf("%s:%d", bundleRepository, bundleVersion)
art, err := oci.NewArtifact(repo, c.quiet, types.RemoteOptions{})
art, err := oci.NewArtifact(repo, c.quiet, types.RegistryOptions{})
if err != nil {
return xerrors.Errorf("OCI artifact error: %w", err)
}

View File

@@ -116,7 +116,7 @@ func TestClient_LoadBuiltinPolicies(t *testing.T) {
}, nil)
// Mock OCI artifact
art, err := oci.NewArtifact("repo", true, ftypes.RemoteOptions{}, oci.WithImage(img))
art, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img))
require.NoError(t, err)
c, err := policy.NewClient(tt.cacheDir, true, policy.WithOCIArtifact(art))
@@ -257,7 +257,7 @@ func TestClient_NeedsUpdate(t *testing.T) {
require.NoError(t, err)
}
art, err := oci.NewArtifact("repo", true, ftypes.RemoteOptions{}, oci.WithImage(img))
art, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img))
require.NoError(t, err)
c, err := policy.NewClient(tmpDir, true, policy.WithOCIArtifact(art), policy.WithClock(tt.clock))
@@ -361,7 +361,7 @@ func TestClient_DownloadBuiltinPolicies(t *testing.T) {
}, nil)
// Mock OCI artifact
art, err := oci.NewArtifact("repo", true, ftypes.RemoteOptions{}, oci.WithImage(img))
art, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img))
require.NoError(t, err)
c, err := policy.NewClient(tempDir, true, policy.WithClock(tt.clock), policy.WithOCIArtifact(art))

View File

@@ -26,7 +26,7 @@ type Descriptor = remote.Descriptor
// Get is a wrapper of google/go-containerregistry/pkg/v1/remote.Get
// so that it can try multiple authentication methods.
func Get(ctx context.Context, ref name.Reference, option types.RemoteOptions) (*Descriptor, error) {
func Get(ctx context.Context, ref name.Reference, option types.RegistryOptions) (*Descriptor, error) {
transport := httpTransport(option.Insecure)
var errs error
@@ -63,7 +63,7 @@ func Get(ctx context.Context, ref name.Reference, option types.RemoteOptions) (*
// Image is a wrapper of google/go-containerregistry/pkg/v1/remote.Image
// so that it can try multiple authentication methods.
func Image(ctx context.Context, ref name.Reference, option types.RemoteOptions) (v1.Image, error) {
func Image(ctx context.Context, ref name.Reference, option types.RegistryOptions) (v1.Image, error) {
transport := httpTransport(option.Insecure)
var errs error
@@ -87,7 +87,7 @@ func Image(ctx context.Context, ref name.Reference, option types.RemoteOptions)
// Referrers is a wrapper of google/go-containerregistry/pkg/v1/remote.Referrers
// so that it can try multiple authentication methods.
func Referrers(ctx context.Context, d name.Digest, option types.RemoteOptions) (*v1.IndexManifest, error) {
func Referrers(ctx context.Context, d name.Digest, option types.RegistryOptions) (*v1.IndexManifest, error) {
transport := httpTransport(option.Insecure)
var errs error
@@ -121,7 +121,7 @@ func httpTransport(insecure bool) *http.Transport {
}
}
func authOptions(ctx context.Context, ref name.Reference, option types.RemoteOptions) []remote.Option {
func authOptions(ctx context.Context, ref name.Reference, option types.RegistryOptions) []remote.Option {
var opts []remote.Option
for _, cred := range option.Credentials {
opts = append(opts, remote.WithAuth(&authn.Basic{

View File

@@ -62,7 +62,7 @@ func TestGet(t *testing.T) {
type args struct {
imageName string
config string
option types.RemoteOptions
option types.RegistryOptions
}
tests := []struct {
name string
@@ -74,7 +74,7 @@ func TestGet(t *testing.T) {
name: "single credential",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
option: types.RemoteOptions{
option: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: "test",
@@ -89,7 +89,7 @@ func TestGet(t *testing.T) {
name: "multiple credential",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
option: types.RemoteOptions{
option: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: "foo",
@@ -109,7 +109,7 @@ func TestGet(t *testing.T) {
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
config: fmt.Sprintf(`{"auths": {"%s": {"auth": %q}}}`, serverAddr, encode("test", "testpass")),
option: types.RemoteOptions{
option: types.RegistryOptions{
Insecure: true,
},
},
@@ -118,7 +118,7 @@ func TestGet(t *testing.T) {
name: "platform",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
option: types.RemoteOptions{
option: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: "test",
@@ -134,7 +134,7 @@ func TestGet(t *testing.T) {
name: "bad credential",
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
option: types.RemoteOptions{
option: types.RegistryOptions{
Credentials: []types.Credential{
{
Username: "foo",
@@ -151,7 +151,7 @@ func TestGet(t *testing.T) {
args: args{
imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
config: fmt.Sprintf(`{"auths": {"%s": {"auth": %q}}}`, serverAddr, encode("foo", "bar")),
option: types.RemoteOptions{
option: types.RegistryOptions{
Insecure: true,
},
},

View File

@@ -35,11 +35,11 @@ type Server struct {
dbRepository string
// For OCI registries
types.RemoteOptions
types.RegistryOptions
}
// NewServer returns an instance of Server
func NewServer(appVersion, addr, cacheDir, token, tokenHeader, dbRepository string, opt types.RemoteOptions) Server {
func NewServer(appVersion, addr, cacheDir, token, tokenHeader, dbRepository string, opt types.RegistryOptions) Server {
return Server{
appVersion: appVersion,
addr: addr,
@@ -47,7 +47,7 @@ func NewServer(appVersion, addr, cacheDir, token, tokenHeader, dbRepository stri
token: token,
tokenHeader: tokenHeader,
dbRepository: dbRepository,
RemoteOptions: opt,
RegistryOptions: opt,
}
}
@@ -61,7 +61,7 @@ func (s Server) ListenAndServe(serverCache cache.Cache, skipDBUpdate bool) error
ctx := context.Background()
for {
time.Sleep(updateInterval)
if err := worker.update(ctx, s.appVersion, s.cacheDir, skipDBUpdate, dbUpdateWg, requestWg, s.RemoteOptions); err != nil {
if err := worker.update(ctx, s.appVersion, s.cacheDir, skipDBUpdate, dbUpdateWg, requestWg, s.RegistryOptions); err != nil {
log.Logger.Errorf("%+v\n", err)
}
}
@@ -126,7 +126,7 @@ func newDBWorker(dbClient dbFile.Operation) dbWorker {
}
func (w dbWorker) update(ctx context.Context, appVersion, cacheDir string,
skipDBUpdate bool, dbUpdateWg, requestWg *sync.WaitGroup, opt types.RemoteOptions) error {
skipDBUpdate bool, dbUpdateWg, requestWg *sync.WaitGroup, opt types.RegistryOptions) error {
log.Logger.Debug("Check for DB update...")
needsUpdate, err := w.dbClient.NeedsUpdate(appVersion, skipDBUpdate)
if err != nil {
@@ -142,7 +142,7 @@ func (w dbWorker) update(ctx context.Context, appVersion, cacheDir string,
return nil
}
func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, requestWg *sync.WaitGroup, opt types.RemoteOptions) error {
func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, requestWg *sync.WaitGroup, opt types.RegistryOptions) error {
tmpDir, err := os.MkdirTemp("", "db")
if err != nil {
return xerrors.Errorf("failed to create a temp dir: %w", err)

View File

@@ -161,7 +161,7 @@ func Test_dbWorker_update(t *testing.T) {
var dbUpdateWg, requestWg sync.WaitGroup
err := w.update(context.Background(), tt.args.appVersion, cacheDir,
tt.needsUpdate.input.skip, &dbUpdateWg, &requestWg, ftypes.RemoteOptions{})
tt.needsUpdate.input.skip, &dbUpdateWg, &requestWg, ftypes.RegistryOptions{})
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
assert.Contains(t, err.Error(), tt.wantErr, tt.name)