github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/image/daemon/docker.go (about)

     1  package daemon
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  
     7  	"github.com/docker/docker/client"
     8  	"github.com/google/go-containerregistry/pkg/name"
     9  	"golang.org/x/xerrors"
    10  )
    11  
    12  // DockerImage implements v1.Image by extending daemon.Image.
    13  // The caller must call cleanup() to remove a temporary file.
    14  func DockerImage(ref name.Reference, host string) (Image, func(), error) {
    15  	cleanup := func() {}
    16  
    17  	opts := []client.Opt{
    18  		client.FromEnv,
    19  		client.WithAPIVersionNegotiation(),
    20  	}
    21  	if host != "" {
    22  		// adding host parameter to the last assuming it will pick up more preference
    23  		opts = append(opts, client.WithHost(host))
    24  	}
    25  	c, err := client.NewClientWithOpts(opts...)
    26  
    27  	if err != nil {
    28  		return nil, cleanup, xerrors.Errorf("failed to initialize a docker client: %w", err)
    29  	}
    30  	defer func() {
    31  		if err != nil {
    32  			_ = c.Close()
    33  		}
    34  	}()
    35  
    36  	// <image_name>:<tag> pattern like "alpine:3.15"
    37  	// or
    38  	// <image_name>@<digest> pattern like "alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300"
    39  	imageID := ref.Name()
    40  	inspect, _, err := c.ImageInspectWithRaw(context.Background(), imageID)
    41  	if err != nil {
    42  		imageID = ref.String() // <image_id> pattern like `5ac716b05a9c`
    43  		inspect, _, err = c.ImageInspectWithRaw(context.Background(), imageID)
    44  		if err != nil {
    45  			return nil, cleanup, xerrors.Errorf("unable to inspect the image (%s): %w", imageID, err)
    46  		}
    47  	}
    48  
    49  	history, err := c.ImageHistory(context.Background(), imageID)
    50  	if err != nil {
    51  		return nil, cleanup, xerrors.Errorf("unable to get history (%s): %w", imageID, err)
    52  	}
    53  
    54  	f, err := os.CreateTemp("", "fanal-*")
    55  	if err != nil {
    56  		return nil, cleanup, xerrors.Errorf("failed to create a temporary file: %w", err)
    57  	}
    58  
    59  	cleanup = func() {
    60  		_ = c.Close()
    61  		_ = f.Close()
    62  		_ = os.Remove(f.Name())
    63  	}
    64  
    65  	return &image{
    66  		opener:  imageOpener(context.Background(), imageID, f, c.ImageSave),
    67  		inspect: inspect,
    68  		history: configHistory(history),
    69  	}, cleanup, nil
    70  }