/
githubmirror
/
trivy
Обзор
Документация
Войти
/
githubmirror
/
trivy
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
pkg/remote/remote_test.go
379 строк
8 KB
Teppei Fukuda
refactor: centralize HTTP transport configuration (#9058)
24 июн 2025, 20:43
Не верифицирован
24 июн 2025, 20:43
3adfd98
Код
Авторство
О чём код?
package remote import ( "encoding/base64" "fmt" "net/http" "net/http/httptest" "os" "path/filepath" "sync" "testing" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/aquasecurity/testdocker/auth" "github.com/aquasecurity/testdocker/registry" "github.com/aquasecurity/testdocker/tarfile" "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/set" "github.com/aquasecurity/trivy/pkg/version/app" ) func setupPrivateRegistry(t *testing.T) *httptest.Server { images := map[string]v1.Image{ "v2/library/alpine:3.10": localImage(t), } tr := registry.NewDockerRegistry(registry.Option{ Images: images, Auth: auth.Auth{ User: "test", Password: "testpass", Secret: "secret", }, }) tr.Config.Handler = newUserAgentsTrackingHandler(tr.Config.Handler) return tr } // setupConfigDir sets up an isolated configDir() for this test. func setupConfigDir(t *testing.T) string { p := t.TempDir() t.Setenv("DOCKER_CONFIG", p) return p } func setupDockerConfig(t *testing.T, content string) { cd := setupConfigDir(t) p := filepath.Join(cd, "config.json") err := os.WriteFile(p, []byte(content), 0o600) require.NoError(t, err) } func encode(user, pass string) string { delimited := fmt.Sprintf("%s:%s", user, pass) return base64.StdEncoding.EncodeToString([]byte(delimited)) } func TestGet(t *testing.T) { tr := setupPrivateRegistry(t) defer tr.Close() serverAddr := tr.Listener.Addr().String() type args struct { imageName string config string option types.RegistryOptions } tests := []struct { name string args args want *Descriptor wantErr string }{ { name: "single credential", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "test", Password: "testpass", }, }, Insecure: true, }, }, }, { name: "mirror", args: args{ imageName: "foo.bar.io/library/alpine:3.10", option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "test", Password: "testpass", }, }, RegistryMirrors: map[string][]string{ "foo.bar.io": { serverAddr, }, }, Insecure: true, }, }, }, { name: "mirror for dockerhub", args: args{ imageName: "alpine:3.10", option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "test", Password: "testpass", }, }, RegistryMirrors: map[string][]string{ "index.docker.io": { serverAddr, }, }, Insecure: true, }, }, }, { name: "non-existent mirror image - use image from host", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "test", Password: "testpass", }, }, RegistryMirrors: map[string][]string{ serverAddr: { "wrong.repository", }, }, Insecure: true, }, }, }, { name: "wrong mirror", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ RegistryMirrors: map[string][]string{ serverAddr: { "wrong.repository:tag@digest", }, }, Insecure: true, }, }, wantErr: "could not parse reference: wrong.repository:tag@digest/library/alpine:3.10", }, { name: "multiple credential", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "foo", Password: "bar", }, { Username: "test", Password: "testpass", }, }, Insecure: true, }, }, }, { name: "keychain", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), config: fmt.Sprintf(`{"auths": {%q: {"auth": %q}}}`, serverAddr, encode("test", "testpass")), option: types.RegistryOptions{ Insecure: true, }, }, }, { name: "platform", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "test", Password: "testpass", }, }, Insecure: true, Platform: types.Platform{ Platform: &v1.Platform{ OS: "", Architecture: "amd64", }, }, }, }, }, { name: "force platform", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "test", Password: "testpass", }, }, Insecure: true, Platform: types.Platform{ Force: true, Platform: &v1.Platform{ OS: "windows", Architecture: "amd64", }, }, }, }, wantErr: "the specified platform not found", }, { name: "bad credential", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "foo", Password: "bar", }, }, Insecure: true, }, }, wantErr: "invalid username/password", }, { name: "bad credential for multiple mirrors", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), option: types.RegistryOptions{ Credentials: []types.Credential{ { Username: "foo", Password: "bar", }, }, Insecure: true, RegistryMirrors: map[string][]string{ serverAddr: { serverAddr, serverAddr, }, }, }, }, wantErr: "6 errors occurred:", // 2 errors for each repository (for 2 mirrors and the original repository) }, { name: "bad keychain", args: args{ imageName: fmt.Sprintf("%s/library/alpine:3.10", serverAddr), config: fmt.Sprintf(`{"auths": {%q: {"auth": %q}}}`, serverAddr, encode("foo", "bar")), option: types.RegistryOptions{ Insecure: true, }, }, wantErr: "invalid username/password", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { n, err := name.ParseReference(tt.args.imageName) require.NoError(t, err) if tt.args.config != "" { setupDockerConfig(t, tt.args.config) } _, err = Get(t.Context(), n, tt.args.option) if tt.wantErr != "" { assert.ErrorContains(t, err, tt.wantErr, err) return } require.NoError(t, err) }) } } type userAgentsTrackingHandler struct { hr http.Handler mu sync.Mutex agents set.Set[string] } func newUserAgentsTrackingHandler(hr http.Handler) *userAgentsTrackingHandler { return &userAgentsTrackingHandler{ hr: hr, agents: set.New[string](), } } func (uh *userAgentsTrackingHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { for _, agent := range r.Header["User-Agent"] { // Skip test framework user agent if agent != "Go-http-client/1.1" { uh.agents.Append(agent) } } uh.hr.ServeHTTP(rw, r) } func setupAgentTrackingRegistry(t *testing.T) (*httptest.Server, *userAgentsTrackingHandler) { images := map[string]v1.Image{ "v2/library/alpine:3.10": localImage(t), } tr := registry.NewDockerRegistry(registry.Option{ Images: images, }) tracker := newUserAgentsTrackingHandler(tr.Config.Handler) tr.Config.Handler = tracker return tr, tracker } func TestUserAgents(t *testing.T) { tr, tracker := setupAgentTrackingRegistry(t) defer tr.Close() serverAddr := tr.Listener.Addr().String() n, err := name.ParseReference(fmt.Sprintf("%s/library/alpine:3.10", serverAddr)) require.NoError(t, err) _, err = Get(t.Context(), n, types.RegistryOptions{ Credentials: []types.Credential{ { Username: "test", Password: "testpass", }, }, Insecure: true, }) require.NoError(t, err) require.Len(t, tracker.agents, 1) ok := tracker.agents.Contains(fmt.Sprintf("trivy/%s", app.Version())) require.True(t, ok, `user-agent header equals to "trivy/dev"`) } func localImage(t *testing.T) v1.Image { img, err := tarfile.ImageFromPath("../fanal/test/testdata/alpine-310.tar.gz") require.NoError(t, err) return img }