Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(image): Add image-src flag to specify which runtime(s) to use #4047

Merged
merged 40 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f7f1051
Add runtime flag to specify which runtime(s) to use
pmengelbert Apr 12, 2023
1bde8ac
Go mod tidy
pmengelbert Apr 17, 2023
19840a5
Allow ordering of selected runtimes
pmengelbert Apr 18, 2023
a8c0266
Restore tests to working order
pmengelbert Apr 18, 2023
563bd8b
Go mod tidy
pmengelbert Apr 18, 2023
4002851
Add doc references for new flag
pmengelbert Apr 18, 2023
bebbe83
Fix broken unit test
pmengelbert Apr 18, 2023
6633752
Fix imports
pmengelbert Apr 19, 2023
1d10fec
Move --runtimes flag to image subcommand only
pmengelbert Apr 20, 2023
b0a9d31
Restore build tag to integration test
pmengelbert Apr 20, 2023
8a24085
Parameter renaming; return error un unrecognized runtime
pmengelbert Apr 20, 2023
e7729f3
Update continer_image.md with docs for the --runtimes flag
pmengelbert Apr 20, 2023
b5c82bb
Restore integration tests to working order
pmengelbert Apr 20, 2023
bfb6df5
Revert "Restore integration tests to working order"
pmengelbert Apr 20, 2023
2dfe326
Fix copy/paste error. Integration tests should work
pmengelbert Apr 20, 2023
34557df
Add runtime flag to specify which runtime(s) to use
pmengelbert Apr 12, 2023
8c75e67
Resolve merge conflicts
pmengelbert Apr 24, 2023
a730332
Resolve merge conflicts
pmengelbert Apr 24, 2023
d95163a
Rebase and resolve merge conflicts
pmengelbert Apr 24, 2023
39fd3cb
Restore unit test to working order
pmengelbert Apr 24, 2023
4bf7078
Move `Runtimes` to `ImageOptions`
pmengelbert Apr 25, 2023
a4342d1
Restore integration/unit tests to working order
pmengelbert Apr 25, 2023
580e029
Remove unused provider
pmengelbert Apr 25, 2023
3c1dc00
Make `WithRuntimes` private and rename
pmengelbert Apr 25, 2023
f6306b7
Rename Runtime to ImageSource everywhere
pmengelbert Apr 25, 2023
53876f2
Merge remote-tracking branch 'upstream/main' into feat/runtime-flag
pmengelbert Apr 25, 2023
6dbc71b
Update docs to reflect name change
pmengelbert Apr 25, 2023
7caa7bf
Merge remote-tracking branch 'upstream/main' into rebase
pmengelbert May 1, 2023
d69fa2a
Trigger tests
pmengelbert May 1, 2023
80fcb2c
Trigger tests
pmengelbert May 2, 2023
ddae094
Merge remote-tracking branch 'upstream/main' into feat/runtime-flag
pmengelbert May 4, 2023
29d6bb6
Merge remote-tracking branch 'upstream/main' into feat/runtime-flag
pmengelbert May 10, 2023
88ae35a
Trigger tests
pmengelbert May 10, 2023
865c2f4
Merge remote-tracking branch 'upstream/main' into feat/runtime-flag
pmengelbert May 11, 2023
dfa8a55
Re-trigger tests
pmengelbert May 11, 2023
e117f83
Merge remote-tracking branch 'upstream/main' into feat/runtime-flag
pmengelbert May 12, 2023
4172f45
refactor: replace runtime with image sources
knqyf263 May 15, 2023
4c4b2c0
refactor: revert import alias
knqyf263 May 15, 2023
6a712a9
fix: change error to warning
knqyf263 May 15, 2023
db0c46e
style: format
knqyf263 May 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/docs/references/configuration/cli/trivy_image.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ trivy image [flags] IMAGE_NAME
--ignored-licenses strings specify a list of license to ignore
--ignorefile string specify .trivyignore file (default ".trivyignore")
--image-config-scanners string comma-separated list of what security issues to detect on container image configurations (config,secret)
--image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote])
--include-non-failures include successes and exceptions, available with '--scanners config'
--input string input file path instead of image name
--java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db")
Expand Down
17 changes: 17 additions & 0 deletions docs/docs/target/container_image.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,23 @@ GitHub Personal Access Token
You can see environment variables with `docker inspect`.

## Supported

Trivy will look for the specified image in a series of locations. By default, it
will first look in the local Docker Engine, then Containerd, Podman, and
finally container registry.

This behavior can be modified with the `--image-src` flag. For example, the
command

```bash
trivy image --image-src podman,containerd alpine:3.7.3
```

Will first search in Podman. If the image is found there, it will be scanned
and the results returned. If the image is not found in Podman, then Trivy will
search in Containerd. If the image is not found there either, the scan will
fail and no more image sources will be searched.

### Docker Engine
Trivy tries to looks for the specified image in your local Docker Engine.
It will be skipped if Docker Engine is not running locally.
Expand Down
1 change: 1 addition & 0 deletions pkg/commands/artifact/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
DockerOptions: ftypes.DockerOptions{
Host: opts.DockerHost,
},
ImageSources: opts.ImageSources,
},

// For misconfiguration scanning
Expand Down
25 changes: 9 additions & 16 deletions pkg/commands/artifact/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions pkg/compliance/spec/compliance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import (
"os"
"strings"

defsecTypes "github.com/aquasecurity/defsec/pkg/types"

"golang.org/x/exp/maps"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"

sp "github.com/aquasecurity/defsec/pkg/spec"
defsecTypes "github.com/aquasecurity/defsec/pkg/types"
"github.com/aquasecurity/trivy/pkg/types"
)

Expand Down
12 changes: 6 additions & 6 deletions pkg/fanal/image/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/types"
)

func tryDockerDaemon(imageName string, ref name.Reference, opt types.DockerOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.DockerImage(ref, opt.Host)
func tryDockerDaemon(_ context.Context, imageName string, ref name.Reference, opt types.ImageOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.DockerImage(ref, opt.DockerOptions.Host)
if err != nil {
return nil, nil, err
}
Expand All @@ -21,18 +21,18 @@ func tryDockerDaemon(imageName string, ref name.Reference, opt types.DockerOptio

}

func tryPodmanDaemon(ref string) (types.Image, func(), error) {
img, cleanup, err := daemon.PodmanImage(ref)
func tryPodmanDaemon(_ context.Context, imageName string, _ name.Reference, _ types.ImageOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.PodmanImage(imageName)
if err != nil {
return nil, nil, err
}
return daemonImage{
Image: img,
name: ref,
name: imageName,
}, cleanup, nil
}

func tryContainerdDaemon(ctx context.Context, imageName string) (types.Image, func(), error) {
func tryContainerdDaemon(ctx context.Context, imageName string, _ name.Reference, _ types.ImageOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.ContainerdImage(ctx, imageName)
if err != nil {
return nil, cleanup, err
Expand Down
89 changes: 18 additions & 71 deletions pkg/fanal/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,102 +9,49 @@ import (
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
)

type options struct {
dockerd bool
podman bool
containerd bool
remote bool
}

type Option func(*options)

func DisableDockerd() Option {
return func(opts *options) {
opts.dockerd = false
}
}
type imageSourceFunc func(ctx context.Context, imageName string, ref name.Reference, option types.ImageOptions) (types.Image, func(), error)

func DisablePodman() Option {
return func(opts *options) {
opts.podman = false
}
var imageSourceFuncs = map[types.ImageSource]imageSourceFunc{
types.ContainerdImageSource: tryContainerdDaemon,
types.PodmanImageSource: tryPodmanDaemon,
types.DockerImageSource: tryDockerDaemon,
types.RemoteImageSource: tryRemote,
}

func DisableContainerd() Option {
return func(opts *options) {
opts.containerd = false
}
}

func DisableRemote() Option {
return func(opts *options) {
opts.remote = false
}
}

func NewContainerImage(ctx context.Context, imageName string, opt types.ImageOptions, opts ...Option) (types.Image, func(), error) {
o := &options{
dockerd: true,
podman: true,
containerd: true,
remote: true,
}
for _, opt := range opts {
opt(o)
func NewContainerImage(ctx context.Context, imageName string, opt types.ImageOptions) (types.Image, func(), error) {
if len(opt.ImageSources) == 0 {
return nil, func() {}, xerrors.New("no image sources supplied")
}

var errs error
var nameOpts []name.Option
if opt.RegistryOptions.Insecure {
nameOpts = append(nameOpts, name.Insecure)
}

ref, err := name.ParseReference(imageName, nameOpts...)
if err != nil {
return nil, func() {}, xerrors.Errorf("failed to parse the image name: %w", err)
}

// Try accessing Docker Daemon
if o.dockerd {
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
}
errs = multierror.Append(errs, err)
}

// Try accessing Podman
if o.podman {
img, cleanup, err := tryPodmanDaemon(imageName)
if err == nil {
// Return v1.Image if the image is found in Podman
return img, cleanup, nil
for _, src := range opt.ImageSources {
trySrc, ok := imageSourceFuncs[src]
if !ok {
log.Logger.Warnf("Unknown image source: '%s'", src)
continue
}
errs = multierror.Append(errs, err)
}

// Try containerd
if o.containerd {
img, cleanup, err := tryContainerdDaemon(ctx, imageName)
img, cleanup, err := trySrc(ctx, imageName, ref, opt)
if err == nil {
// Return v1.Image if the image is found in containerd
// Return v1.Image if the image is found
return img, cleanup, nil
}
errs = multierror.Append(errs, err)
}

// Try accessing Docker Registry
if o.remote {
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
}
errs = multierror.Append(errs, err)
}

return nil, func() {}, errs
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/fanal/image/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ func TestNewDockerImage(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.option.ImageSources = types.AllImageSources
img, cleanup, err := NewContainerImage(context.Background(), tt.args.imageName, tt.args.option)
defer cleanup()

Expand Down Expand Up @@ -393,6 +394,7 @@ func TestNewDockerImageWithPrivateRegistry(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.option.ImageSources = types.AllImageSources
_, cleanup, err := NewContainerImage(context.Background(), tt.args.imageName, tt.args.option)
defer cleanup()

Expand Down Expand Up @@ -543,7 +545,7 @@ func TestDockerPlatformArguments(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
imageName := fmt.Sprintf("%s/library/alpine:3.10", serverAddr)

tt.args.option.ImageSources = types.AllImageSources
_, cleanup, err := NewContainerImage(context.Background(), imageName, tt.args.option)
defer cleanup()

Expand Down
13 changes: 8 additions & 5 deletions pkg/fanal/image/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ import (
"github.com/aquasecurity/trivy/pkg/remote"
)

func tryRemote(ctx context.Context, imageName string, ref name.Reference, option types.RegistryOptions) (types.Image, error) {
desc, err := remote.Get(ctx, ref, option)
func tryRemote(ctx context.Context, imageName string, ref name.Reference, option types.ImageOptions) (types.Image, func(), error) {
// This function doesn't need cleanup
cleanup := func() {}

desc, err := remote.Get(ctx, ref, option.RegistryOptions)
if err != nil {
return nil, err
return nil, cleanup, err
}
img, err := desc.Image()
if err != nil {
return nil, err
return nil, cleanup, err
}

// Return v1.Image if the image is found in Docker Registry
Expand All @@ -28,7 +31,7 @@ func tryRemote(ctx context.Context, imageName string, ref name.Reference, option
Image: img,
ref: implicitReference{ref: ref},
descriptor: desc,
}, nil
}, cleanup, nil

}

Expand Down
15 changes: 9 additions & 6 deletions pkg/fanal/test/integration/containerd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,9 @@ func TestContainerd_SearchLocalStoreByNameOrDigest(t *testing.T) {
}
})

img, cleanup, err := image.NewContainerImage(ctx, tt.searchName, types.ImageOptions{},
image.DisableDockerd(), image.DisablePodman(), image.DisableRemote())
// enable only containerd
img, cleanup, err := image.NewContainerImage(ctx, tt.searchName,
types.ImageOptions{ImageSources: types.ImageSources{types.ContainerdImageSource}})
defer cleanup()
if tt.expectErr {
require.Error(t, err)
Expand Down Expand Up @@ -679,8 +680,9 @@ func localImageTestWithNamespace(t *testing.T, namespace string) {
require.NoError(t, err)

// Enable only containerd
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.ImageOptions{},
image.DisableDockerd(), image.DisablePodman(), image.DisableRemote())
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.ImageOptions{
ImageSources: types.ImageSources{types.ContainerdImageSource},
})
require.NoError(t, err)
defer cleanup()

Expand Down Expand Up @@ -814,8 +816,9 @@ func TestContainerd_PullImage(t *testing.T) {
require.NoError(t, err)

// Enable only containerd
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.ImageOptions{},
image.DisableDockerd(), image.DisablePodman(), image.DisableRemote())
img, cleanup, err := image.NewContainerImage(ctx, tt.imageName, types.ImageOptions{
ImageSources: types.ImageSources{types.ContainerdImageSource},
})
require.NoError(t, err)
defer cleanup()

Expand Down
Loading