Skip to content

Commit

Permalink
feat(image): customer podman host or socket option (#6256)
Browse files Browse the repository at this point in the history
Co-authored-by: DmitriyLewen <[email protected]>
Co-authored-by: DmitriyLewen <[email protected]>
  • Loading branch information
3 people authored Mar 11, 2024
1 parent 2a9d9bd commit 9d2057a
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 7 deletions.
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 @@ -78,6 +78,7 @@ trivy image [flags] IMAGE_NAME
--parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5)
--password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons.
--platform string set platform in the form os/arch if image is multi-platform capable
--podman-host string unix podman socket path to use for podman scanning
--policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0")
--policy-namespaces strings Rego namespaces
--redis-ca string redis ca file location, if using redis as cache backend
Expand Down
5 changes: 5 additions & 0 deletions docs/docs/references/configuration/config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ image:
# Same as '--docker-host'
# Default is empty
host:

podman:
# Same as '--podman-host'
# Default is empty
host:
```
## Vulnerability Options
Expand Down
7 changes: 7 additions & 0 deletions docs/docs/target/container_image.md
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,10 @@ 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
```

### Configure Podman daemon socket to connect to.
You can configure Podman daemon socket with `--podman-host`.

```shell
$ trivy image --podman-host /run/user/1000/podman/podman.sock YOUR_IMAGE
```
3 changes: 3 additions & 0 deletions pkg/commands/artifact/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,9 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
DockerOptions: ftypes.DockerOptions{
Host: opts.DockerHost,
},
PodmanOptions: ftypes.PodmanOptions{
Host: opts.PodmanHost,
},
ImageSources: opts.ImageSources,
},

Expand Down
4 changes: 2 additions & 2 deletions pkg/fanal/image/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ func tryDockerDaemon(_ context.Context, imageName string, ref name.Reference, op

}

func tryPodmanDaemon(_ context.Context, imageName string, _ name.Reference, _ types.ImageOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.PodmanImage(imageName)
func tryPodmanDaemon(_ context.Context, imageName string, _ name.Reference, opts types.ImageOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.PodmanImage(imageName, opts.PodmanOptions.Host)
if err != nil {
return nil, nil, err
}
Expand Down
40 changes: 40 additions & 0 deletions pkg/fanal/image/daemon/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,46 @@ func Test_image_ConfigNameWithCustomDockerHost(t *testing.T) {
assert.Nil(t, err)
}

func Test_image_ConfigNameWithCustomPodmanHost(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("podman.sock is not available for Windows CI")
}

ref, err := name.ParseReference("alpine:3.11")
require.NoError(t, err)

eo := engine.Option{
APIVersion: opt.APIVersion,
ImagePaths: map[string]string{
"index.docker.io/library/alpine:3.11": "../../test/testdata/alpine-311.tar.gz",
},
}

runtimeDir, err := os.MkdirTemp("", "daemon")
require.NoError(t, err)

dir := filepath.Join(runtimeDir, "image")
err = os.MkdirAll(dir, os.ModePerm)
require.NoError(t, err)

podmanSocket := filepath.Join(dir, "image-test-podman-socket.sock")
eo.UnixDomainSocket = podmanSocket

te := engine.NewDockerEngine(eo)
defer te.Close()

img, cleanup, err := PodmanImage(ref.Name(), podmanSocket)
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
Expand Down
9 changes: 6 additions & 3 deletions pkg/fanal/image/daemon/podman.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ type podmanClient struct {
c http.Client
}

func newPodmanClient() (podmanClient, error) {
func newPodmanClient(host string) (podmanClient, error) {
// Get Podman socket location
sockDir := os.Getenv("XDG_RUNTIME_DIR")
socket := filepath.Join(sockDir, "podman", "podman.sock")
if host != "" {
socket = host
}

if _, err := os.Stat(socket); err != nil {
return podmanClient{}, xerrors.Errorf("no podman socket found: %w", err)
Expand Down Expand Up @@ -109,10 +112,10 @@ func (p podmanClient) imageSave(_ context.Context, imageNames []string) (io.Read

// PodmanImage implements v1.Image by extending daemon.Image.
// The caller must call cleanup() to remove a temporary file.
func PodmanImage(ref string) (Image, func(), error) {
func PodmanImage(ref, host string) (Image, func(), error) {
cleanup := func() {}

c, err := newPodmanClient()
c, err := newPodmanClient(host)
if err != nil {
return nil, cleanup, xerrors.Errorf("unable to initialize Podman client: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/fanal/image/daemon/podman_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func TestPodmanImage(t *testing.T) {
ref, err := name.ParseReference(tt.imageName)
require.NoError(t, err)

img, cleanup, err := PodmanImage(ref.Name())
img, cleanup, err := PodmanImage(ref.Name(), "")
defer cleanup()

if tt.wantErr {
Expand Down
2 changes: 1 addition & 1 deletion pkg/fanal/types/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type DockerOptions struct {
}

type PodmanOptions struct {
// Add Podman-specific options
Host string
}

type ContainerdOptions struct {
Expand Down
11 changes: 11 additions & 0 deletions pkg/flag/image_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ var (
Default: "",
Usage: "unix domain socket path to use for docker scanning",
}
PodmanHostFlag = Flag[string]{
Name: "podman-host",
ConfigName: "image.podman.host",
Default: "",
Usage: "unix podman socket path to use for podman scanning",
}
SourceFlag = Flag[[]string]{
Name: "image-src",
ConfigName: "image.source",
Expand All @@ -60,6 +66,7 @@ type ImageFlagGroup struct {
ScanRemovedPkgs *Flag[bool]
Platform *Flag[string]
DockerHost *Flag[string]
PodmanHost *Flag[string]
ImageSources *Flag[[]string]
}

Expand All @@ -69,6 +76,7 @@ type ImageOptions struct {
ScanRemovedPkgs bool
Platform ftypes.Platform
DockerHost string
PodmanHost string
ImageSources ftypes.ImageSources
}

Expand All @@ -79,6 +87,7 @@ func NewImageFlagGroup() *ImageFlagGroup {
ScanRemovedPkgs: ScanRemovedPkgsFlag.Clone(),
Platform: PlatformFlag.Clone(),
DockerHost: DockerHostFlag.Clone(),
PodmanHost: PodmanHostFlag.Clone(),
ImageSources: SourceFlag.Clone(),
}
}
Expand All @@ -94,6 +103,7 @@ func (f *ImageFlagGroup) Flags() []Flagger {
f.ScanRemovedPkgs,
f.Platform,
f.DockerHost,
f.PodmanHost,
f.ImageSources,
}
}
Expand Down Expand Up @@ -121,6 +131,7 @@ func (f *ImageFlagGroup) ToOptions() (ImageOptions, error) {
ScanRemovedPkgs: f.ScanRemovedPkgs.Value(),
Platform: platform,
DockerHost: f.DockerHost.Value(),
PodmanHost: f.PodmanHost.Value(),
ImageSources: xstrings.ToTSlice[ftypes.ImageSource](f.ImageSources.Value()),
}, nil
}

0 comments on commit 9d2057a

Please sign in to comment.