diff --git a/main.go b/main.go index 4992643..570d035 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,6 @@ var verbose = flag.Bool("v", false, "Print all details about the image") var filter = flag.Bool("filter", true, "Filters filenames that create noise such as"+ " node_modules. Check ignore.go file for more details") var extractLayers = flag.Bool("x", false, "Save layers to current directory") -var specificVersion = flag.String("sV", "", "Set the docker client ID to a specific version -sV=1.47") var re *regexp.Regexp type Manifest struct { @@ -66,6 +65,7 @@ type dockerHist struct { type DockerClient interface { ImageInspectWithRaw(ctx context.Context, imageID string) (image.InspectResponse, []byte, error) ImageSave(ctx context.Context, imageIDs []string, options ...client.ImageSaveOption) (io.ReadCloser, error) + ImagePull(ctx context.Context, refStr string, options image.PullOptions) (io.ReadCloser, error) Close() error } @@ -172,13 +172,9 @@ func printConfigInfo(config *ImageConfig) { func analyze(cli DockerClient, imageID string) { info, _, err := cli.ImageInspectWithRaw(context.Background(), imageID) if err != nil { - out, err := cli.ImageSave(context.Background(), []string{imageID}) + out, err := cli.ImagePull(context.Background(), imageID, image.PullOptions{}) if err != nil { color.Red(err.Error()) - if strings.Contains(err.Error(), "Maximum supported API version is") { - version := strings.Split(err.Error(), "Maximum supported API version is ")[1] - color.Yellow("Use the -sV flag to change your client version:\n./whaler -sV=%s %s", version, imageID) - } return } defer out.Close() @@ -824,11 +820,7 @@ func main() { } // Existing Docker client logic - if len(*specificVersion) > 0 { - cli, err = client.NewClientWithOpts(client.WithVersion(*specificVersion)) - } else { - cli, err = client.NewClientWithOpts() - } + cli, err = client.NewClientWithOpts(client.WithAPIVersionNegotiation()) if err != nil { color.Red(err.Error()) return diff --git a/main_test.go b/main_test.go index 05aefcf..86ac0d5 100644 --- a/main_test.go +++ b/main_test.go @@ -18,7 +18,8 @@ import ( type MockDockerClient struct { *client.Client imageInspectFunc func(ctx context.Context, imageID string) (image.InspectResponse, []byte, error) - imageSaveFunc func(ctx context.Context, imageIDs []string) (io.ReadCloser, error) + imageSaveFunc func(ctx context.Context, imageIDs []string, options ...client.ImageSaveOption) (io.ReadCloser, error) + imagePullFunc func(ctx context.Context, refStr string, options image.PullOptions) (io.ReadCloser, error) } func (m *MockDockerClient) ImageInspectWithRaw(ctx context.Context, imageID string) (image.InspectResponse, []byte, error) { @@ -28,9 +29,17 @@ func (m *MockDockerClient) ImageInspectWithRaw(ctx context.Context, imageID stri return image.InspectResponse{}, nil, nil } +func (m *MockDockerClient) ImagePull(ctx context.Context, refStr string, options image.PullOptions) (io.ReadCloser, error) { + if m.imagePullFunc != nil { + return m.imagePullFunc(ctx, refStr, options) + } + return nil, nil +} + + func (m *MockDockerClient) ImageSave(ctx context.Context, imageIDs []string, options ...client.ImageSaveOption) (io.ReadCloser, error) { if m.imageSaveFunc != nil { - return m.imageSaveFunc(ctx, imageIDs) + return m.imageSaveFunc(ctx, imageIDs, options...) } return nil, nil } @@ -81,11 +90,13 @@ func TestExtractImageLayers(t *testing.T) { // Create a mock Docker client mockClient := &MockDockerClient{ Client: &client.Client{}, - imageSaveFunc: func(ctx context.Context, imageIDs []string) (io.ReadCloser, error) { + imageSaveFunc: func(ctx context.Context, imageIDs []string, options ...client.ImageSaveOption) (io.ReadCloser, error) { // Create a tar file in memory with our test data pr, pw := io.Pipe() go func() { + defer pw.Close() tw := tar.NewWriter(pw) + defer tw.Close() // Write a layer file layerContent := "test layer content" @@ -94,18 +105,25 @@ func TestExtractImageLayers(t *testing.T) { Size: int64(len(layerContent)), Mode: 0600, } - tw.WriteHeader(header) - tw.Write([]byte(layerContent)) + if err := tw.WriteHeader(header); err != nil { + return + } + if _, err := tw.Write([]byte(layerContent)); err != nil { + return + } - tw.Close() - pw.Close() }() return pr, nil }, } + imageStream, err := mockClient.ImageSave(context.Background(), []string{"test-image"}) + if err != nil { + t.Fatal(err) + } + // Test the extractImageLayers function - err = extractImageLayers(mockClient, "test-image", []dockerHist{ + err = extractImageLayers(imageStream, "test-image", []dockerHist{ { CreatedBy: "ADD file:123 /app", LayerID: "layer1", @@ -138,7 +156,7 @@ func TestAnalyzeImageFilesystem(t *testing.T) { mockClient := &MockDockerClient{ Client: &client.Client{}, - imageSaveFunc: func(ctx context.Context, imageIDs []string) (io.ReadCloser, error) { + imageSaveFunc: func(ctx context.Context, imageIDs []string, options ...client.ImageSaveOption) (io.ReadCloser, error) { // Create a tar file in memory with our test data pr, pw := io.Pipe() go func() { @@ -180,7 +198,7 @@ func TestAnalyzeImageFilesystem(t *testing.T) { }, } - err := analyzeImageFilesystem(mockClient, "test-image") + _, err := analyzeImageFilesystem(mockClient, "test-image") if err != nil { t.Errorf("analyzeImageFilesystem failed: %v", err) } diff --git a/whaler b/whaler index 14924a8..ddf27ea 100755 Binary files a/whaler and b/whaler differ