github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/remote/remote_test.go (about)

     1  package remote
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"net/http/httptest"
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"github.com/google/go-containerregistry/pkg/name"
    13  	v1 "github.com/google/go-containerregistry/pkg/v1"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/aquasecurity/testdocker/auth"
    18  	"github.com/aquasecurity/testdocker/registry"
    19  	"github.com/devseccon/trivy/pkg/fanal/types"
    20  )
    21  
    22  func setupPrivateRegistry() *httptest.Server {
    23  	imagePaths := map[string]string{
    24  		"v2/library/alpine:3.10": "../fanal/test/testdata/alpine-310.tar.gz",
    25  	}
    26  	tr := registry.NewDockerRegistry(registry.Option{
    27  		Images: imagePaths,
    28  		Auth: auth.Auth{
    29  			User:     "test",
    30  			Password: "testpass",
    31  			Secret:   "secret",
    32  		},
    33  	})
    34  
    35  	return tr
    36  }
    37  
    38  // setupConfigDir sets up an isolated configDir() for this test.
    39  func setupConfigDir(t *testing.T) string {
    40  	p := t.TempDir()
    41  	t.Setenv("DOCKER_CONFIG", p)
    42  	return p
    43  }
    44  
    45  func setupDockerConfig(t *testing.T, content string) {
    46  	cd := setupConfigDir(t)
    47  	p := filepath.Join(cd, "config.json")
    48  
    49  	err := os.WriteFile(p, []byte(content), 0600)
    50  	require.NoError(t, err)
    51  }
    52  
    53  func encode(user, pass string) string {
    54  	delimited := fmt.Sprintf("%s:%s", user, pass)
    55  	return base64.StdEncoding.EncodeToString([]byte(delimited))
    56  }
    57  
    58  func TestGet(t *testing.T) {
    59  	tr := setupPrivateRegistry()
    60  	defer tr.Close()
    61  
    62  	serverAddr := tr.Listener.Addr().String()
    63  
    64  	type args struct {
    65  		imageName string
    66  		config    string
    67  		option    types.RegistryOptions
    68  	}
    69  	tests := []struct {
    70  		name    string
    71  		args    args
    72  		want    *Descriptor
    73  		wantErr string
    74  	}{
    75  		{
    76  			name: "single credential",
    77  			args: args{
    78  				imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
    79  				option: types.RegistryOptions{
    80  					Credentials: []types.Credential{
    81  						{
    82  							Username: "test",
    83  							Password: "testpass",
    84  						},
    85  					},
    86  					Insecure: true,
    87  				},
    88  			},
    89  		},
    90  		{
    91  			name: "multiple credential",
    92  			args: args{
    93  				imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
    94  				option: types.RegistryOptions{
    95  					Credentials: []types.Credential{
    96  						{
    97  							Username: "foo",
    98  							Password: "bar",
    99  						},
   100  						{
   101  							Username: "test",
   102  							Password: "testpass",
   103  						},
   104  					},
   105  					Insecure: true,
   106  				},
   107  			},
   108  		},
   109  		{
   110  			name: "keychain",
   111  			args: args{
   112  				imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
   113  				config:    fmt.Sprintf(`{"auths": {"%s": {"auth": %q}}}`, serverAddr, encode("test", "testpass")),
   114  				option: types.RegistryOptions{
   115  					Insecure: true,
   116  				},
   117  			},
   118  		},
   119  		{
   120  			name: "platform",
   121  			args: args{
   122  				imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
   123  				option: types.RegistryOptions{
   124  					Credentials: []types.Credential{
   125  						{
   126  							Username: "test",
   127  							Password: "testpass",
   128  						},
   129  					},
   130  					Insecure: true,
   131  					Platform: types.Platform{
   132  						Platform: &v1.Platform{
   133  							OS:           "",
   134  							Architecture: "amd64",
   135  						},
   136  					},
   137  				},
   138  			},
   139  		},
   140  		{
   141  			name: "force platform",
   142  			args: args{
   143  				imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
   144  				option: types.RegistryOptions{
   145  					Credentials: []types.Credential{
   146  						{
   147  							Username: "test",
   148  							Password: "testpass",
   149  						},
   150  					},
   151  					Insecure: true,
   152  					Platform: types.Platform{
   153  						Force: true,
   154  						Platform: &v1.Platform{
   155  							OS:           "windows",
   156  							Architecture: "amd64",
   157  						},
   158  					},
   159  				},
   160  			},
   161  			wantErr: "the specified platform not found",
   162  		},
   163  		{
   164  			name: "bad credential",
   165  			args: args{
   166  				imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
   167  				option: types.RegistryOptions{
   168  					Credentials: []types.Credential{
   169  						{
   170  							Username: "foo",
   171  							Password: "bar",
   172  						},
   173  					},
   174  					Insecure: true,
   175  				},
   176  			},
   177  			wantErr: "invalid username/password",
   178  		},
   179  		{
   180  			name: "bad keychain",
   181  			args: args{
   182  				imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr),
   183  				config:    fmt.Sprintf(`{"auths": {"%s": {"auth": %q}}}`, serverAddr, encode("foo", "bar")),
   184  				option: types.RegistryOptions{
   185  					Insecure: true,
   186  				},
   187  			},
   188  			wantErr: "invalid username/password",
   189  		},
   190  	}
   191  	for _, tt := range tests {
   192  		t.Run(tt.name, func(t *testing.T) {
   193  			n, err := name.ParseReference(tt.args.imageName)
   194  			require.NoError(t, err)
   195  
   196  			if tt.args.config != "" {
   197  				setupDockerConfig(t, tt.args.config)
   198  			}
   199  
   200  			_, err = Get(context.Background(), n, tt.args.option)
   201  			if tt.wantErr != "" {
   202  				assert.ErrorContains(t, err, tt.wantErr, err)
   203  				return
   204  			}
   205  			assert.NoError(t, err)
   206  		})
   207  	}
   208  }