diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 60f2ffceb9ae..ca3e635e3a56 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -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 diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 407256add122..b9582f280a6a 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -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 diff --git a/docs/docs/target/container_image.md b/docs/docs/target/container_image.md index 7350a6a933ad..1eeef7b9d34c 100644 --- a/docs/docs/target/container_image.md +++ b/docs/docs/target/container_image.md @@ -482,3 +482,9 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1) +### 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 +``` diff --git a/pkg/commands/app.go b/pkg/commands/app.go index 71cfbe923289..ead3ddbad407 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -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{ diff --git a/pkg/commands/artifact/inject.go b/pkg/commands/artifact/inject.go index 072d044703a7..b6a0cc105cf1 100644 --- a/pkg/commands/artifact/inject.go +++ b/pkg/commands/artifact/inject.go @@ -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 diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index b408f97603f9..10904192a587 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -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, diff --git a/pkg/commands/artifact/scanner.go b/pkg/commands/artifact/scanner.go index 83f1bd9a76c4..73e6e9241c1f 100644 --- a/pkg/commands/artifact/scanner.go +++ b/pkg/commands/artifact/scanner.go @@ -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) } diff --git a/pkg/commands/artifact/wire_gen.go b/pkg/commands/artifact/wire_gen.go index 8b2cd8eaebe5..6adce39be207 100644 --- a/pkg/commands/artifact/wire_gen.go +++ b/pkg/commands/artifact/wire_gen.go @@ -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 } diff --git a/pkg/commands/operation/operation.go b/pkg/commands/operation/operation.go index eb512ef2b06f..597f45843803 100644 --- a/pkg/commands/operation/operation.go +++ b/pkg/commands/operation/operation.go @@ -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() diff --git a/pkg/commands/server/run.go b/pkg/commands/server/run.go index 5d13584ac545..92418fa66392 100644 --- a/pkg/commands/server/run.go +++ b/pkg/commands/server/run.go @@ -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) } diff --git a/pkg/db/db.go b/pkg/db/db.go index bf96f49a9cd9..6b69ccbe7086 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -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 } diff --git a/pkg/db/db_test.go b/pkg/db/db_test.go index 873eba00d723..ef15370879a6 100644 --- a/pkg/db/db_test.go +++ b/pkg/db/db_test.go @@ -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)) diff --git a/pkg/db/mock_operation.go b/pkg/db/mock_operation.go index be87a776cb66..b5a879fb5afc 100644 --- a/pkg/db/mock_operation.go +++ b/pkg/db/mock_operation.go @@ -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 diff --git a/pkg/fanal/artifact/artifact.go b/pkg/fanal/artifact/artifact.go index 1efb0e695dd4..4af51fcff127 100644 --- a/pkg/fanal/artifact/artifact.go +++ b/pkg/fanal/artifact/artifact.go @@ -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 diff --git a/pkg/fanal/artifact/image/remote_sbom.go b/pkg/fanal/artifact/image/remote_sbom.go index 5a69bcf93a5c..eecaf5081e2d 100644 --- a/pkg/fanal/artifact/image/remote_sbom.go +++ b/pkg/fanal/artifact/image/remote_sbom.go @@ -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) } diff --git a/pkg/fanal/image/daemon.go b/pkg/fanal/image/daemon.go index 4be9c361d604..7e78ba59d858 100644 --- a/pkg/fanal/image/daemon.go +++ b/pkg/fanal/image/daemon.go @@ -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 } diff --git a/pkg/fanal/image/daemon/docker.go b/pkg/fanal/image/daemon/docker.go index 26a707390cac..9fc6e1b46357 100644 --- a/pkg/fanal/image/daemon/docker.go +++ b/pkg/fanal/image/daemon/docker.go @@ -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) } diff --git a/pkg/fanal/image/daemon/docker_test.go b/pkg/fanal/image/daemon/docker_test.go index 25c6612c66a9..a68c935289a3 100644 --- a/pkg/fanal/image/daemon/docker_test.go +++ b/pkg/fanal/image/daemon/docker_test.go @@ -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 { diff --git a/pkg/fanal/image/daemon/image_test.go b/pkg/fanal/image/daemon/image_test.go index 543e5ee3b444..ce1f1ff82d70 100644 --- a/pkg/fanal/image/daemon/image_test.go +++ b/pkg/fanal/image/daemon/image_test.go @@ -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{ - "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", - } +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{ - APIVersion: "1.38", - ImagePaths: imagePaths, - } +// for Docker +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() diff --git a/pkg/fanal/image/image.go b/pkg/fanal/image/image.go index c18c9bb50b1c..ee6f494ebbf5 100644 --- a/pkg/fanal/image/image.go +++ b/pkg/fanal/image/image.go @@ -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 diff --git a/pkg/fanal/image/image_test.go b/pkg/fanal/image/image_test.go index 964051ea667a..6005354c4eb4 100644 --- a/pkg/fanal/image/image_test.go +++ b/pkg/fanal/image/image_test.go @@ -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,14 +205,16 @@ 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{ - Credentials: []types.Credential{ - { - Username: "test", - Password: "test", + option: types.ImageOptions{ + RegistryOptions: types.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "test", + Password: "test", + }, }, + Insecure: true, }, - Insecure: true, }, }, wantID: "sha256:af341ccd2df8b0e2d67cf8dd32e087bfda4e5756ebd1c76bbf3efa0dc246590e", @@ -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,14 +345,16 @@ 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{ - Credentials: []types.Credential{ - { - Username: "test", - Password: "testpass", + option: types.ImageOptions{ + RegistryOptions: types.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "test", + Password: "testpass", + }, }, + Insecure: true, }, - Insecure: true, }, }, }, @@ -358,9 +362,11 @@ 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{ - RegistryToken: registryToken, - Insecure: true, + option: types.ImageOptions{ + RegistryOptions: types.RegistryOptions{ + RegistryToken: registryToken, + Insecure: true, + }, }, }, }, @@ -375,9 +381,11 @@ 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{ - RegistryToken: registryToken + "invalid", - Insecure: true, + 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,15 +520,17 @@ func TestDockerPlatformArguments(t *testing.T) { { name: "happy path with valid platform", args: args{ - option: types.RemoteOptions{ - Credentials: []types.Credential{ - { - Username: "test", - Password: "testpass", + option: types.ImageOptions{ + RegistryOptions: types.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "test", + Password: "testpass", + }, }, + Insecure: true, + Platform: "arm/linux", }, - Insecure: true, - Platform: "arm/linux", }, }, }, diff --git a/pkg/fanal/image/registry/azure/azure.go b/pkg/fanal/image/registry/azure/azure.go index 523a39b01d3c..bb574f052c42 100644 --- a/pkg/fanal/image/registry/azure/azure.go +++ b/pkg/fanal/image/registry/azure/azure.go @@ -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) } diff --git a/pkg/fanal/image/registry/azure/azure_test.go b/pkg/fanal/image/registry/azure/azure_test.go index 4fdef97709c6..ae823b82a65a 100644 --- a/pkg/fanal/image/registry/azure/azure_test.go +++ b/pkg/fanal/image/registry/azure/azure_test.go @@ -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 { diff --git a/pkg/fanal/image/registry/ecr/ecr.go b/pkg/fanal/image/registry/ecr/ecr.go index e04b0c9a4f14..9c7a8b8d4bad 100644 --- a/pkg/fanal/image/registry/ecr/ecr.go +++ b/pkg/fanal/image/registry/ecr/ecr.go @@ -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) } diff --git a/pkg/fanal/image/registry/ecr/ecr_test.go b/pkg/fanal/image/registry/ecr/ecr_test.go index 7e8203e50a32..7cb7edc506e1 100644 --- a/pkg/fanal/image/registry/ecr/ecr_test.go +++ b/pkg/fanal/image/registry/ecr/ecr_test.go @@ -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) diff --git a/pkg/fanal/image/registry/google/google.go b/pkg/fanal/image/registry/google/google.go index 821293124ba6..65e0e86cfe8a 100644 --- a/pkg/fanal/image/registry/google/google.go +++ b/pkg/fanal/image/registry/google/google.go @@ -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) } diff --git a/pkg/fanal/image/registry/google/google_test.go b/pkg/fanal/image/registry/google/google_test.go index e8340f1b1eac..62a2b1f57627 100644 --- a/pkg/fanal/image/registry/google/google_test.go +++ b/pkg/fanal/image/registry/google/google_test.go @@ -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"), diff --git a/pkg/fanal/image/registry/token.go b/pkg/fanal/image/registry/token.go index 8f2fa5a30012..1e51b0fd31a4 100644 --- a/pkg/fanal/image/registry/token.go +++ b/pkg/fanal/image/registry/token.go @@ -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) diff --git a/pkg/fanal/image/registry/token_test.go b/pkg/fanal/image/registry/token_test.go index 0459e0c5a205..40ddb9e3d373 100644 --- a/pkg/fanal/image/registry/token_test.go +++ b/pkg/fanal/image/registry/token_test.go @@ -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 diff --git a/pkg/fanal/image/remote.go b/pkg/fanal/image/remote.go index e11585f752a7..6b9519ec5dc1 100644 --- a/pkg/fanal/image/remote.go +++ b/pkg/fanal/image/remote.go @@ -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 diff --git a/pkg/fanal/test/integration/containerd_test.go b/pkg/fanal/test/integration/containerd_test.go index 8e6ad8ada617..dab8e7e999ba 100644 --- a/pkg/fanal/test/integration/containerd_test.go +++ b/pkg/fanal/test/integration/containerd_test.go @@ -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() diff --git a/pkg/fanal/test/integration/library_test.go b/pkg/fanal/test/integration/library_test.go index 6cfccd0a39e7..6e2438f34cfa 100644 --- a/pkg/fanal/test/integration/library_test.go +++ b/pkg/fanal/test/integration/library_test.go @@ -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() diff --git a/pkg/fanal/test/integration/registry_test.go b/pkg/fanal/test/integration/registry_test.go index 825ea32a7ffc..b560cb65c1f7 100644 --- a/pkg/fanal/test/integration/registry_test.go +++ b/pkg/fanal/test/integration/registry_test.go @@ -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,14 +92,16 @@ 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{ - Credentials: []types.Credential{ - { - Username: registryUsername, - Password: registryPassword, + option: types.ImageOptions{ + RegistryOptions: types.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: registryUsername, + Password: registryPassword, + }, }, + Insecure: true, }, - Insecure: true, }, expectedOS: types.OS{ Name: "3.10.2", @@ -116,8 +117,10 @@ 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{ - Insecure: true, + option: types.ImageOptions{ + RegistryOptions: types.RegistryOptions{ + Insecure: true, + }, }, login: true, expectedOS: types.OS{ @@ -134,11 +137,13 @@ 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{ - Credentials: []types.Credential{ - { - Username: registryUsername, - Password: registryPassword, + option: types.ImageOptions{ + RegistryOptions: types.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: registryUsername, + Password: registryPassword, + }, }, }, }, @@ -148,8 +153,10 @@ func TestTLSRegistry(t *testing.T) { 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{ - Insecure: true, + 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 diff --git a/pkg/fanal/types/image.go b/pkg/fanal/types/image.go index 61193900e72a..54ba7ad35df0 100644 --- a/pkg/fanal/types/image.go +++ b/pkg/fanal/types/image.go @@ -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 +} diff --git a/pkg/fanal/types/remote.go b/pkg/fanal/types/remote.go deleted file mode 100644 index 607b768c766f..000000000000 --- a/pkg/fanal/types/remote.go +++ /dev/null @@ -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 -} diff --git a/pkg/flag/image_flags.go b/pkg/flag/image_flags.go index e7f337e99f8c..805449c7dbd9 100644 --- a/pkg/flag/image_flags.go +++ b/pkg/flag/image_flags.go @@ -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 } diff --git a/pkg/flag/options.go b/pkg/flag/options.go index 2818a8d2ab5a..c3b1de968112 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -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, diff --git a/pkg/javadb/client.go b/pkg/javadb/client.go index 0d33c41c3d61..f3951e2e28dd 100644 --- a/pkg/javadb/client.go +++ b/pkg/javadb/client.go @@ -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 { diff --git a/pkg/module/command.go b/pkg/module/command.go index f8f9bfe62dff..9114aea1ced6 100644 --- a/pkg/module/command.go +++ b/pkg/module/command.go @@ -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) diff --git a/pkg/oci/artifact.go b/pkg/oci/artifact.go index 6fbd3dd8af4f..7b2678684d64 100644 --- a/pkg/oci/artifact.go +++ b/pkg/oci/artifact.go @@ -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, + repository: repo, + quiet: quiet, + 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 } diff --git a/pkg/oci/artifact_test.go b/pkg/oci/artifact_test.go index df1f9fa7b99b..d28dbe55bc1e 100644 --- a/pkg/oci/artifact_test.go +++ b/pkg/oci/artifact_test.go @@ -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{ diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 711c95cff3bb..1c9efa19947a 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -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) } diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index 3a55557aa955..2101cb45128d 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -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)) diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index f7ea9932772f..dd67e29903d1 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -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{ diff --git a/pkg/remote/remote_test.go b/pkg/remote/remote_test.go index 205534769c52..0421c74b471b 100644 --- a/pkg/remote/remote_test.go +++ b/pkg/remote/remote_test.go @@ -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, }, }, diff --git a/pkg/rpc/server/listen.go b/pkg/rpc/server/listen.go index a6de3d41ef53..7a6d538a7cae 100644 --- a/pkg/rpc/server/listen.go +++ b/pkg/rpc/server/listen.go @@ -35,19 +35,19 @@ 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, - cacheDir: cacheDir, - token: token, - tokenHeader: tokenHeader, - dbRepository: dbRepository, - RemoteOptions: opt, + appVersion: appVersion, + addr: addr, + cacheDir: cacheDir, + token: token, + tokenHeader: tokenHeader, + dbRepository: dbRepository, + 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) diff --git a/pkg/rpc/server/listen_test.go b/pkg/rpc/server/listen_test.go index 823dfe0016b6..cebc41496962 100644 --- a/pkg/rpc/server/listen_test.go +++ b/pkg/rpc/server/listen_test.go @@ -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)