diff --git a/container.go b/container.go index c2a7c9f35e..9f01f033ce 100644 --- a/container.go +++ b/container.go @@ -15,6 +15,7 @@ import ( "github.com/docker/go-connections/nat" tcexec "github.com/testcontainers/testcontainers-go/exec" + "github.com/testcontainers/testcontainers-go/internal/testcontainersdocker" "github.com/testcontainers/testcontainers-go/wait" ) @@ -84,7 +85,7 @@ type FromDockerfile struct { Dockerfile string // the path from the context to the Dockerfile for the image, defaults to "Dockerfile" BuildArgs map[string]*string // enable user to pass build args to docker daemon PrintBuildLog bool // enable user to print build log - AuthConfigs map[string]types.AuthConfig // enable auth configs to be able to pull from an authenticated docker registry + AuthConfigs map[string]types.AuthConfig // Deprecated. Testcontainers will detect registry credentials automatically. Enable auth configs to be able to pull from an authenticated docker registry } type ContainerFile struct { @@ -104,7 +105,7 @@ type ContainerRequest struct { Labels map[string]string Mounts ContainerMounts Tmpfs map[string]string - RegistryCred string + RegistryCred string // Deprecated: Testcontainers will detect registry credentials automatically WaitingFor wait.Strategy Name string // for specifying container name Hostname string @@ -158,7 +159,7 @@ func (f GenericProviderOptionFunc) ApplyGenericTo(opts *GenericProviderOptions) // containerOptions functional options for a container type containerOptions struct { ImageName string - RegistryCredentials string + RegistryCredentials string // Deprecated: Testcontainers will detect registry credentials automatically } // functional option for setting the reaper image @@ -171,6 +172,7 @@ func WithImageName(imageName string) ContainerOption { } } +// Deprecated: Testcontainers will detect registry credentials automatically // WithRegistryCredentials sets the reaper registry credentials func WithRegistryCredentials(registryCredentials string) ContainerOption { return func(o *containerOptions) { @@ -271,7 +273,22 @@ func (c *ContainerRequest) GetDockerfile() string { // GetAuthConfigs returns the auth configs to be able to pull from an authenticated docker registry func (c *ContainerRequest) GetAuthConfigs() map[string]types.AuthConfig { - return c.FromDockerfile.AuthConfigs + images, err := testcontainersdocker.ExtractImagesFromDockerfile(filepath.Join(c.Context, c.GetDockerfile()), c.GetBuildArgs()) + if err != nil { + return map[string]types.AuthConfig{} + } + + authConfigs := map[string]types.AuthConfig{} + for _, image := range images { + registry, authConfig, err := DockerImageAuth(context.Background(), image) + if err != nil { + continue + } + + authConfigs[registry] = authConfig + } + + return authConfigs } func (c *ContainerRequest) ShouldBuildImage() bool { diff --git a/container_test.go b/container_test.go index 383a913327..033a13d3c7 100644 --- a/container_test.go +++ b/container_test.go @@ -11,7 +11,6 @@ import ( "testing" "time" - "github.com/docker/docker/api/types" "github.com/stretchr/testify/assert" "github.com/testcontainers/testcontainers-go/wait" @@ -127,50 +126,6 @@ func Test_GetDockerfile(t *testing.T) { } } -func Test_GetAuthConfigs(t *testing.T) { - type TestCase struct { - name string - ExpectedAuthConfigs map[string]types.AuthConfig - ContainerRequest ContainerRequest - } - - testTable := []TestCase{ - { - name: "defaults to no auth", - ExpectedAuthConfigs: nil, - ContainerRequest: ContainerRequest{ - FromDockerfile: FromDockerfile{}, - }, - }, - { - name: "will specify credentials", - ExpectedAuthConfigs: map[string]types.AuthConfig{ - "https://myregistry.com/": { - Username: "username", - Password: "password", - }, - }, - ContainerRequest: ContainerRequest{ - FromDockerfile: FromDockerfile{ - AuthConfigs: map[string]types.AuthConfig{ - "https://myregistry.com/": { - Username: "username", - Password: "password", - }, - }, - }, - }, - }, - } - - for _, testCase := range testTable { - t.Run(testCase.name, func(t *testing.T) { - cfgs := testCase.ContainerRequest.GetAuthConfigs() - assert.Equal(t, testCase.ExpectedAuthConfigs, cfgs) - }) - } -} - func Test_BuildImageWithContexts(t *testing.T) { type TestCase struct { Name string diff --git a/docker.go b/docker.go index 436c72a2cc..7ae381246d 100644 --- a/docker.go +++ b/docker.go @@ -5,7 +5,9 @@ import ( "bufio" "bytes" "context" + "encoding/base64" "encoding/binary" + "encoding/json" "errors" "fmt" "io" @@ -1046,8 +1048,17 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque Platform: req.ImagePlatform, // may be empty } - if req.RegistryCred != "" { - pullOpt.RegistryAuth = req.RegistryCred + registry, imageAuth, err := DockerImageAuth(ctx, req.Image) + if err != nil { + p.Logger.Printf("Failed to get image auth for %s. Setting empty credentials for the image: %s. Error is:%s", registry, req.Image, err) + } else { + // see https://github.com/docker/docs/blob/e8e1204f914767128814dca0ea008644709c117f/engine/api/sdk/examples.md?plain=1#L649-L657 + encodedJSON, err := json.Marshal(imageAuth) + if err != nil { + p.Logger.Printf("Failed to marshal image auth. Setting empty credentials for the image: %s. Error is:%s", req.Image, err) + } else { + pullOpt.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON) + } } if err := p.attemptToPullImage(ctx, tag, pullOpt); err != nil { diff --git a/docker_auth.go b/docker_auth.go new file mode 100644 index 0000000000..c04477f8c2 --- /dev/null +++ b/docker_auth.go @@ -0,0 +1,107 @@ +package testcontainers + +import ( + "context" + "encoding/base64" + "encoding/json" + "os" + + "github.com/cpuguy83/dockercfg" + "github.com/docker/docker/api/types" + "github.com/testcontainers/testcontainers-go/internal/testcontainersdocker" +) + +// DockerImageAuth returns the auth config for the given Docker image, extracting first its Docker registry. +// Finally, it will use the credential helpers to extract the information from the docker config file +// for that registry, if it exists. +func DockerImageAuth(ctx context.Context, image string) (string, types.AuthConfig, error) { + defaultRegistry := defaultRegistry(ctx) + registry := testcontainersdocker.ExtractRegistry(image, defaultRegistry) + + cfgs, err := getDockerAuthConfigs() + if err != nil { + return registry, types.AuthConfig{}, err + } + + if cfg, ok := cfgs[registry]; ok { + return registry, cfg, nil + } + + return registry, types.AuthConfig{}, dockercfg.ErrCredentialsNotFound +} + +// defaultRegistry returns the default registry to use when pulling images +// It will use the docker daemon to get the default registry, returning "https://index.docker.io/v1/" if +// it fails to get the information from the daemon +func defaultRegistry(ctx context.Context) string { + p, err := NewDockerProvider() + if err != nil { + return testcontainersdocker.IndexDockerIO + } + + info, err := p.client.Info(ctx) + if err != nil { + return testcontainersdocker.IndexDockerIO + } + + return info.IndexServerAddress +} + +// getDockerAuthConfigs returns a map with the auth configs from the docker config file +// using the registry as the key +func getDockerAuthConfigs() (map[string]types.AuthConfig, error) { + cfg, err := getDockerConfig() + if err != nil { + return nil, err + } + + cfgs := map[string]types.AuthConfig{} + for k, v := range cfg.AuthConfigs { + ac := types.AuthConfig{ + Auth: v.Auth, + Email: v.Email, + IdentityToken: v.IdentityToken, + Password: v.Password, + RegistryToken: v.RegistryToken, + ServerAddress: v.ServerAddress, + Username: v.Username, + } + + if v.Username == "" && v.Password == "" { + u, p, _ := dockercfg.GetRegistryCredentials(k) + ac.Username = u + ac.Password = p + } + + if v.Auth == "" { + ac.Auth = base64.StdEncoding.EncodeToString([]byte(ac.Username + ":" + ac.Password)) + } + + cfgs[k] = ac + } + + return cfgs, nil +} + +// getDockerConfig returns the docker config file. It will internally check, in this particular order: +// 1. the DOCKER_AUTH_CONFIG environment variable, unmarshalling it into a dockercfg.Config +// 2. the DOCKER_CONFIG environment variable, as the path to the config file +// 3. else it will load the default config file, which is ~/.docker/config.json +func getDockerConfig() (dockercfg.Config, error) { + dockerAuthConfig := os.Getenv("DOCKER_AUTH_CONFIG") + if dockerAuthConfig != "" { + cfg := dockercfg.Config{} + err := json.Unmarshal([]byte(dockerAuthConfig), &cfg) + if err == nil { + return cfg, nil + } + + } + + cfg, err := dockercfg.LoadDefaultConfig() + if err != nil { + return cfg, err + } + + return cfg, nil +} diff --git a/docker_auth_test.go b/docker_auth_test.go new file mode 100644 index 0000000000..e1ee9af029 --- /dev/null +++ b/docker_auth_test.go @@ -0,0 +1,297 @@ +package testcontainers + +import ( + "context" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/cpuguy83/dockercfg" + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go/internal/testcontainersdocker" + "github.com/testcontainers/testcontainers-go/wait" +) + +const exampleAuth = "https://example-auth.com" + +var testDockerConfigDirPath = filepath.Join("testresources", ".docker") + +var indexDockerIO = testcontainersdocker.IndexDockerIO + +func TestGetDockerConfig(t *testing.T) { + const expectedErrorMessage = "Expected to find %s in auth configs" + + // Verify that the default docker config file exists before any test in this suite runs. + // Then, we can safely run the tests that rely on it. + cfg, err := dockercfg.LoadDefaultConfig() + require.Nil(t, err) + require.NotNil(t, cfg) + + t.Run("without DOCKER_CONFIG env var retrieves default", func(t *testing.T) { + cfg, err := getDockerConfig() + require.Nil(t, err) + require.NotNil(t, cfg) + + assert.Equal(t, 1, len(cfg.AuthConfigs)) + + authCfgs := cfg.AuthConfigs + + if _, ok := authCfgs[indexDockerIO]; !ok { + t.Errorf(expectedErrorMessage, indexDockerIO) + } + }) + + t.Run("with DOCKER_CONFIG env var pointing to a non-existing file raises error", func(t *testing.T) { + t.Setenv("DOCKER_CONFIG", filepath.Join(testDockerConfigDirPath, "non-existing")) + + cfg, err := getDockerConfig() + require.NotNil(t, err) + require.Empty(t, cfg) + }) + + t.Run("with DOCKER_CONFIG env var", func(t *testing.T) { + t.Setenv("DOCKER_CONFIG", testDockerConfigDirPath) + + cfg, err := getDockerConfig() + require.Nil(t, err) + require.NotNil(t, cfg) + + assert.Equal(t, 3, len(cfg.AuthConfigs)) + + authCfgs := cfg.AuthConfigs + + if _, ok := authCfgs[indexDockerIO]; !ok { + t.Errorf(expectedErrorMessage, indexDockerIO) + } + if _, ok := authCfgs["https://example.com"]; !ok { + t.Errorf(expectedErrorMessage, "https://example.com") + } + if _, ok := authCfgs["https://my.private.registry"]; !ok { + t.Errorf(expectedErrorMessage, "https://my.private.registry") + } + }) + + t.Run("DOCKER_AUTH_CONFIG env var takes precedence", func(t *testing.T) { + t.Setenv("DOCKER_AUTH_CONFIG", `{ + "auths": { + "`+exampleAuth+`": {} + }, + "credsStore": "desktop" + }`) + t.Setenv("DOCKER_CONFIG", testDockerConfigDirPath) + + cfg, err := getDockerConfig() + require.Nil(t, err) + require.NotNil(t, cfg) + + assert.Equal(t, 1, len(cfg.AuthConfigs)) + + authCfgs := cfg.AuthConfigs + + if _, ok := authCfgs[indexDockerIO]; ok { + t.Errorf("Not expected to find %s in auth configs", indexDockerIO) + } + if _, ok := authCfgs[exampleAuth]; !ok { + t.Errorf(expectedErrorMessage, exampleAuth) + } + }) + + t.Run("retrieve auth with DOCKER_AUTH_CONFIG env var", func(t *testing.T) { + base64 := "Z29waGVyOnNlY3JldA==" // gopher:secret + + t.Setenv("DOCKER_AUTH_CONFIG", `{ + "auths": { + "`+exampleAuth+`": { "username": "gopher", "password": "secret", "auth": "`+base64+`" } + }, + "credsStore": "desktop" + }`) + + registry, cfg, err := DockerImageAuth(context.Background(), exampleAuth+"/my/image:latest") + require.Nil(t, err) + require.NotNil(t, cfg) + + assert.Equal(t, exampleAuth, registry) + assert.Equal(t, "gopher", cfg.Username) + assert.Equal(t, "secret", cfg.Password) + assert.Equal(t, base64, cfg.Auth) + }) +} + +func TestBuildContainerFromDockerfile(t *testing.T) { + ctx := context.Background() + req := ContainerRequest{ + FromDockerfile: FromDockerfile{ + Context: "./testresources", + }, + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("Ready to accept connections"), + } + + redisC, err := prepareRedisImage(ctx, req, t) + require.NoError(t, err) + terminateContainerOnEnd(t, ctx, redisC) +} + +func TestBuildContainerFromDockerfileWithDockerAuthConfig(t *testing.T) { + // using the same credentials as in the Docker Registry + base64 := "dGVzdHVzZXI6dGVzdHBhc3N3b3Jk" // testuser:testpassword + t.Setenv("DOCKER_AUTH_CONFIG", `{ + "auths": { + "localhost:5000": { "username": "testuser", "password": "testpassword", "auth": "`+base64+`" } + }, + "credsStore": "desktop" + }`) + + prepareLocalRegistryWithAuth(t) + defer func() { + ctx := context.Background() + testcontainersClient, err := client.NewClientWithOpts(client.WithVersion(daemonMaxVersion)) + if err != nil { + t.Log("could not create client to cleanup registry: ", err) + } + + _, err = testcontainersClient.ImageRemove(ctx, "localhost:5000/redis:5.0-alpine", types.ImageRemoveOptions{ + Force: true, + PruneChildren: true, + }) + if err != nil { + t.Log("could not remove image: ", err) + } + + }() + + ctx := context.Background() + + req := ContainerRequest{ + FromDockerfile: FromDockerfile{ + Context: "./testresources", + Dockerfile: "auth.Dockerfile", + }, + + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("Ready to accept connections"), + } + + redisC, err := prepareRedisImage(ctx, req, t) + require.NoError(t, err) + terminateContainerOnEnd(t, ctx, redisC) +} + +func TestBuildContainerFromDockerfileShouldFailWithWrongDockerAuthConfig(t *testing.T) { + // using different credentials than in the Docker Registry + base64 := "Zm9vOmJhcg==" // foo:bar + t.Setenv("DOCKER_AUTH_CONFIG", `{ + "auths": { + "localhost:5000": { "username": "foo", "password": "bar", "auth": "`+base64+`" } + }, + "credsStore": "desktop" + }`) + + prepareLocalRegistryWithAuth(t) + + ctx := context.Background() + + req := ContainerRequest{ + FromDockerfile: FromDockerfile{ + Context: "./testresources", + Dockerfile: "auth.Dockerfile", + }, + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("Ready to accept connections"), + } + + redisC, err := prepareRedisImage(ctx, req, t) + require.Error(t, err) + terminateContainerOnEnd(t, ctx, redisC) +} + +func TestCreateContainerFromPrivateRegistry(t *testing.T) { + // using the same credentials as in the Docker Registry + base64 := "dGVzdHVzZXI6dGVzdHBhc3N3b3Jk" // testuser:testpassword + t.Setenv("DOCKER_AUTH_CONFIG", `{ + "auths": { + "localhost:5000": { "username": "testuser", "password": "testpassword", "auth": "`+base64+`" } + }, + "credsStore": "desktop" + }`) + + prepareLocalRegistryWithAuth(t) + + ctx := context.Background() + req := ContainerRequest{ + Image: "localhost:5000/redis:5.0-alpine", + AlwaysPullImage: true, // make sure the authentication takes place + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("Ready to accept connections"), + } + + redisContainer, err := GenericContainer(ctx, GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + require.Nil(t, err) + terminateContainerOnEnd(t, ctx, redisContainer) +} + +func prepareLocalRegistryWithAuth(t *testing.T) { + ctx := context.Background() + wd, err := os.Getwd() + assert.NoError(t, err) + req := ContainerRequest{ + Image: "registry:2", + ExposedPorts: []string{"5000:5000/tcp"}, + Env: map[string]string{ + "REGISTRY_AUTH": "htpasswd", + "REGISTRY_AUTH_HTPASSWD_REALM": "Registry", + "REGISTRY_AUTH_HTPASSWD_PATH": "/auth/htpasswd", + "REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY": "/data", + }, + Mounts: ContainerMounts{ + ContainerMount{ + Source: GenericBindMountSource{ + HostPath: fmt.Sprintf("%s/testresources/auth", wd), + }, + Target: "/auth", + }, + ContainerMount{ + Source: GenericBindMountSource{ + HostPath: fmt.Sprintf("%s/testresources/data", wd), + }, + Target: "/data", + }, + }, + WaitingFor: wait.ForExposedPort(), + } + + genContainerReq := GenericContainerRequest{ + ProviderType: providerType, + ContainerRequest: req, + Started: true, + } + + registryC, err := GenericContainer(ctx, genContainerReq) + assert.NoError(t, err) + + t.Cleanup(func() { + assert.NoError(t, registryC.Terminate(context.Background())) + }) + + _, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) +} + +func prepareRedisImage(ctx context.Context, req ContainerRequest, t *testing.T) (Container, error) { + genContainerReq := GenericContainerRequest{ + ProviderType: providerType, + ContainerRequest: req, + Started: true, + } + + redisC, err := GenericContainer(ctx, genContainerReq) + + return redisC, err +} diff --git a/docker_test.go b/docker_test.go index 6dd72a0005..f2074c5ef9 100644 --- a/docker_test.go +++ b/docker_test.go @@ -1073,151 +1073,6 @@ func TestContainerCreationWaitsForLog(t *testing.T) { terminateContainerOnEnd(t, ctx, mysqlC) } -func Test_BuildContainerFromDockerfile(t *testing.T) { - t.Log("getting context") - ctx := context.Background() - t.Log("got context, creating container request") - req := ContainerRequest{ - FromDockerfile: FromDockerfile{ - Context: "./testresources", - }, - ExposedPorts: []string{"6379/tcp"}, - WaitingFor: wait.ForLog("Ready to accept connections"), - } - - redisC, err := prepareRedisImage(ctx, req, t) - require.NoError(t, err) - terminateContainerOnEnd(t, ctx, redisC) -} - -func Test_BuildContainerFromDockerfileWithAuthConfig_ShouldSucceedWithAuthConfigs(t *testing.T) { - prepareLocalRegistryWithAuth(t) - defer func() { - ctx := context.Background() - testcontainersClient, err := client.NewClientWithOpts(client.WithVersion(daemonMaxVersion)) - if err != nil { - t.Log("could not create client to cleanup registry: ", err) - } - - _, err = testcontainersClient.ImageRemove(ctx, "localhost:5000/redis:5.0-alpine", types.ImageRemoveOptions{ - Force: true, - PruneChildren: true, - }) - if err != nil { - t.Log("could not remove image: ", err) - } - - }() - - t.Log("getting context") - ctx := context.Background() - t.Log("got context, creating container request") - req := ContainerRequest{ - FromDockerfile: FromDockerfile{ - Context: "./testresources", - Dockerfile: "auth.Dockerfile", - AuthConfigs: map[string]types.AuthConfig{ - "localhost:5000": { - Username: "testuser", - Password: "testpassword", - }, - }, - }, - - ExposedPorts: []string{"6379/tcp"}, - WaitingFor: wait.ForLog("Ready to accept connections"), - } - - redisC, err := prepareRedisImage(ctx, req, t) - require.NoError(t, err) - terminateContainerOnEnd(t, ctx, redisC) -} - -func Test_BuildContainerFromDockerfileWithAuthConfig_ShouldFailWithoutAuthConfigs(t *testing.T) { - prepareLocalRegistryWithAuth(t) - - t.Log("getting context") - ctx := context.Background() - t.Log("got context, creating container request") - req := ContainerRequest{ - FromDockerfile: FromDockerfile{ - Context: "./testresources", - Dockerfile: "auth.Dockerfile", - }, - ExposedPorts: []string{"6379/tcp"}, - WaitingFor: wait.ForLog("Ready to accept connections"), - } - - redisC, err := prepareRedisImage(ctx, req, t) - require.Error(t, err) - terminateContainerOnEnd(t, ctx, redisC) -} - -func prepareLocalRegistryWithAuth(t *testing.T) { - ctx := context.Background() - wd, err := os.Getwd() - assert.NoError(t, err) - req := ContainerRequest{ - Image: "registry:2", - ExposedPorts: []string{"5000:5000/tcp"}, - Env: map[string]string{ - "REGISTRY_AUTH": "htpasswd", - "REGISTRY_AUTH_HTPASSWD_REALM": "Registry", - "REGISTRY_AUTH_HTPASSWD_PATH": "/auth/htpasswd", - "REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY": "/data", - }, - Mounts: ContainerMounts{ - ContainerMount{ - Source: GenericBindMountSource{ - HostPath: fmt.Sprintf("%s/testresources/auth", wd), - }, - Target: "/auth", - }, - ContainerMount{ - Source: GenericBindMountSource{ - HostPath: fmt.Sprintf("%s/testresources/data", wd), - }, - Target: "/data", - }, - }, - WaitingFor: wait.ForExposedPort(), - } - - genContainerReq := GenericContainerRequest{ - ProviderType: providerType, - ContainerRequest: req, - Started: true, - } - - t.Log("creating registry container") - - registryC, err := GenericContainer(ctx, genContainerReq) - assert.NoError(t, err) - - t.Cleanup(func() { - assert.NoError(t, registryC.Terminate(context.Background())) - }) - - _, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) -} - -func prepareRedisImage(ctx context.Context, req ContainerRequest, t *testing.T) (Container, error) { - genContainerReq := GenericContainerRequest{ - ProviderType: providerType, - ContainerRequest: req, - Started: true, - } - - t.Log("creating redis container") - - redisC, err := GenericContainer(ctx, genContainerReq) - - t.Log("created redis container") - - return redisC, err -} - func Test_BuildContainerFromDockerfileWithBuildArgs(t *testing.T) { t.Log("getting ctx") ctx := context.Background() diff --git a/docs/features/build_from_dockerfile.md b/docs/features/build_from_dockerfile.md index bd146c0a30..c395d7a2ce 100644 --- a/docs/features/build_from_dockerfile.md +++ b/docs/features/build_from_dockerfile.md @@ -64,20 +64,14 @@ in to `Context`. ## Images requiring auth If you are building a local Docker image that is fetched from a Docker image in a registry requiring authentication -(e.g., assuming you are fetching from a custom registry such as `myregistry.com`), you will need to specify the -credentials to succeed, as follows: +(e.g., assuming you are fetching from a custom registry such as `myregistry.com`), _Testcontainers for Go_ will automatically +discover the credentials for the given Docker image from the Docker config, as described [here](./docker_auth.md). ```go req := ContainerRequest{ FromDockerfile: testcontainers.FromDockerfile{ Context: "/path/to/build/context", Dockerfile: "CustomDockerfile", - AuthConfigs: map[string]types.AuthConfig{ - "https://myregistry.com": { - Username: "myusername", - Password: "mypassword", - }, - }, }, } -``` \ No newline at end of file +``` diff --git a/docs/features/docker_auth.md b/docs/features/docker_auth.md new file mode 100644 index 0000000000..d6f1ed5a25 --- /dev/null +++ b/docs/features/docker_auth.md @@ -0,0 +1,38 @@ +# Authentication with Docker + +Sometimes the Docker images you use live in a private Docker registry. For that reason, _Testcontainers for Go_ gives you the ability to read the Docker configuration +and retrieve the authentication for a given registry. To achieve it, _Testcontainers for Go_ will internally check, in this particular order: + +1. the `DOCKER_AUTH_CONFIG` environment variable, unmarshalling the string value from its JSON representation and using it as the Docker config. +2. the `DOCKER_CONFIG` environment variable, as an alternative path to the Docker config file. +3. else it will load the default Docker config file, which lives in the user's home, e.g. `~/.docker/config.json` +4. it will use the right Docker credential helper to retrieve the authentication (user, password and base64 representation) for the given registry. + +To understand how the Docker credential helpers work, please refer to the [official documentation](https://docs.docker.com/engine/reference/commandline/login/#credential-helpers). + +!!! info + _Testcontainers for Go_ uses [https://github.com/cpuguy83/dockercfg](https://github.com/cpuguy83/dockercfg) to retrieve the authentication from the credential helpers. + +_Testcontainers for Go_ will automatically discover the credentials for a given Docker image from the Docker config, as described above. For that, it will extract the Docker registry from the image name, and for that registry will try to locate the authentication in the Docker config, returning an empty string if the registry is not found. As a consequence, all the fields to pass credentials to the container request will be deprecated. + +```go +req := ContainerRequest{ + FromDockerfile: testcontainers.FromDockerfile{ + Image: "myregistry.com/myimage:latest", + }, +} +``` + +In the case you are building an image from the Dockerfile, the authentication will be automatically retrieved from the Docker config, so you don't need to pass it explicitly: + +```go +req := ContainerRequest{ + FromDockerfile: testcontainers.FromDockerfile{ + Context: "/path/to/build/context", + Dockerfile: "CustomDockerfile", + BuildArgs: map[string]*string { + "FOO": "BAR", + }, + }, +} +``` diff --git a/examples/bigtable/go.mod b/examples/bigtable/go.mod index 82f5c2a207..8c7cfa7e85 100644 --- a/examples/bigtable/go.mod +++ b/examples/bigtable/go.mod @@ -59,7 +59,7 @@ require ( golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/tools v0.3.0 // indirect diff --git a/examples/bigtable/go.sum b/examples/bigtable/go.sum index fc5641deaf..8ff7053b41 100644 --- a/examples/bigtable/go.sum +++ b/examples/bigtable/go.sum @@ -441,8 +441,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/cockroachdb/go.mod b/examples/cockroachdb/go.mod index 796b69f803..4ca698e0cb 100644 --- a/examples/cockroachdb/go.mod +++ b/examples/cockroachdb/go.mod @@ -54,7 +54,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/examples/cockroachdb/go.sum b/examples/cockroachdb/go.sum index 27bbf4337d..0948658d81 100644 --- a/examples/cockroachdb/go.sum +++ b/examples/cockroachdb/go.sum @@ -353,8 +353,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/examples/consul/go.mod b/examples/consul/go.mod index 97a974d2d6..80a68cb822 100644 --- a/examples/consul/go.mod +++ b/examples/consul/go.mod @@ -49,7 +49,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect diff --git a/examples/consul/go.sum b/examples/consul/go.sum index 0b2e116a2b..bf1c13e0ce 100644 --- a/examples/consul/go.sum +++ b/examples/consul/go.sum @@ -297,8 +297,8 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/datastore/go.mod b/examples/datastore/go.mod index 41be3adec1..fe829f237a 100644 --- a/examples/datastore/go.mod +++ b/examples/datastore/go.mod @@ -51,7 +51,7 @@ require ( golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/examples/datastore/go.sum b/examples/datastore/go.sum index e7972e3964..02ef18dd42 100644 --- a/examples/datastore/go.sum +++ b/examples/datastore/go.sum @@ -222,8 +222,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/firestore/go.mod b/examples/firestore/go.mod index 8987583210..d4fbe272c5 100644 --- a/examples/firestore/go.mod +++ b/examples/firestore/go.mod @@ -52,7 +52,7 @@ require ( golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.1.0 // indirect diff --git a/examples/firestore/go.sum b/examples/firestore/go.sum index 403160d7fa..72edf19531 100644 --- a/examples/firestore/go.sum +++ b/examples/firestore/go.sum @@ -223,8 +223,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/mongodb/go.mod b/examples/mongodb/go.mod index 59386928fc..ce6aa676a0 100644 --- a/examples/mongodb/go.mod +++ b/examples/mongodb/go.mod @@ -47,7 +47,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/examples/mongodb/go.sum b/examples/mongodb/go.sum index b05c1ddfdc..713500b0ed 100644 --- a/examples/mongodb/go.sum +++ b/examples/mongodb/go.sum @@ -244,8 +244,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/mysql/go.mod b/examples/mysql/go.mod index eb8654fdaf..96e1718679 100644 --- a/examples/mysql/go.mod +++ b/examples/mysql/go.mod @@ -40,7 +40,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect diff --git a/examples/mysql/go.sum b/examples/mysql/go.sum index 2bb01c955a..71830068d1 100644 --- a/examples/mysql/go.sum +++ b/examples/mysql/go.sum @@ -220,8 +220,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/nginx/go.mod b/examples/nginx/go.mod index 68e00cff87..9354ff0f5b 100644 --- a/examples/nginx/go.mod +++ b/examples/nginx/go.mod @@ -41,7 +41,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect diff --git a/examples/nginx/go.sum b/examples/nginx/go.sum index a597158a27..400a22bbe2 100644 --- a/examples/nginx/go.sum +++ b/examples/nginx/go.sum @@ -218,8 +218,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/postgres/go.mod b/examples/postgres/go.mod index 90d5863969..54b9431e95 100644 --- a/examples/postgres/go.mod +++ b/examples/postgres/go.mod @@ -44,7 +44,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect diff --git a/examples/postgres/go.sum b/examples/postgres/go.sum index 6a70771db1..d31ab1d940 100644 --- a/examples/postgres/go.sum +++ b/examples/postgres/go.sum @@ -230,8 +230,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/pubsub/go.mod b/examples/pubsub/go.mod index d22dd3e5b8..11fd5b203a 100644 --- a/examples/pubsub/go.mod +++ b/examples/pubsub/go.mod @@ -52,7 +52,7 @@ require ( golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/examples/pubsub/go.sum b/examples/pubsub/go.sum index 67c7142971..e8d78df2ab 100644 --- a/examples/pubsub/go.sum +++ b/examples/pubsub/go.sum @@ -225,8 +225,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/redis/go.mod b/examples/redis/go.mod index 2617132ff5..98235088d3 100644 --- a/examples/redis/go.mod +++ b/examples/redis/go.mod @@ -47,7 +47,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect diff --git a/examples/redis/go.sum b/examples/redis/go.sum index fc7c78de48..92488a23c3 100644 --- a/examples/redis/go.sum +++ b/examples/redis/go.sum @@ -235,8 +235,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/spanner/go.mod b/examples/spanner/go.mod index 5219a29ee3..f4bd0a694a 100644 --- a/examples/spanner/go.mod +++ b/examples/spanner/go.mod @@ -60,7 +60,7 @@ require ( golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/tools v0.3.0 // indirect diff --git a/examples/spanner/go.sum b/examples/spanner/go.sum index ddec6d3bde..78eeba28c3 100644 --- a/examples/spanner/go.sum +++ b/examples/spanner/go.sum @@ -440,8 +440,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/examples/toxiproxy/go.mod b/examples/toxiproxy/go.mod index 98dda05bb2..46f4a34f4d 100644 --- a/examples/toxiproxy/go.mod +++ b/examples/toxiproxy/go.mod @@ -43,7 +43,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect diff --git a/examples/toxiproxy/go.sum b/examples/toxiproxy/go.sum index 2759de8b73..8cfb45f2a9 100644 --- a/examples/toxiproxy/go.sum +++ b/examples/toxiproxy/go.sum @@ -230,8 +230,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/go.mod b/go.mod index 62a18b5f84..2750120f2f 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/cenkalti/backoff/v4 v4.2.0 github.com/containerd/containerd v1.6.19 + github.com/cpuguy83/dockercfg v0.3.1 github.com/docker/docker v23.0.1+incompatible github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.5.0 @@ -13,7 +14,7 @@ require ( github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f github.com/opencontainers/image-spec v1.1.0-rc2 github.com/stretchr/testify v1.8.2 - golang.org/x/sys v0.5.0 + golang.org/x/sys v0.6.0 gotest.tools/gotestsum v1.9.0 ) diff --git a/go.sum b/go.sum index 7a4f448bcc..af84b87028 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= @@ -235,8 +237,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/internal/testcontainersdocker/images.go b/internal/testcontainersdocker/images.go new file mode 100644 index 0000000000..3dc10c2a45 --- /dev/null +++ b/internal/testcontainersdocker/images.go @@ -0,0 +1,126 @@ +package testcontainersdocker + +import ( + "bufio" + "net/url" + "os" + "regexp" + "strings" + "unicode/utf8" +) + +const ( + IndexDockerIO = "https://index.docker.io/v1/" + maxURLRuneCount = 2083 + minURLRuneCount = 3 + URLSchema = `((ftp|tcp|udp|wss?|https?):\/\/)` + URLUsername = `(\S+(:\S*)?@)` + URLIP = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))` + IP = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` + URLSubdomain = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))` + URLPath = `((\/|\?|#)[^\s]*)` + URLPort = `(:(\d{1,5}))` + URL = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$` +) + +var rxURL = regexp.MustCompile(URL) + +func ExtractImagesFromDockerfile(dockerfile string, buildArgs map[string]*string) ([]string, error) { + var images []string + + file, err := os.Open(dockerfile) + if err != nil { + return nil, err + } + defer file.Close() + + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + if scanner.Err() != nil { + return nil, scanner.Err() + } + + // extract images from dockerfile + for _, line := range lines { + line = strings.TrimSpace(line) + if !strings.HasPrefix(strings.ToUpper(line), "FROM") { + continue + } + + // remove FROM + line = strings.TrimPrefix(line, "FROM") + parts := strings.Split(strings.TrimSpace(line), " ") + if len(parts) == 0 { + continue + } + + // interpolate build args + for k, v := range buildArgs { + if v != nil { + parts[0] = strings.Replace(parts[0], "${"+k+"}", *v, -1) + } + } + images = append(images, parts[0]) + } + + return images, nil +} + +// ExtractRegistry extracts the registry from the image name, using a regular expression to extract the registry from the image name. +// regular expression to extract the registry from the image name +// the regular expression is based on the grammar defined in +// - image:tag +// - image +// - repository/image:tag +// - repository/image +// - registry/image:tag +// - registry/image +// - registry/repository/image:tag +// - registry/repository/image +// - registry:port/repository/image:tag +// - registry:port/repository/image +// - registry:port/image:tag +// - registry:port/image +// Once extracted the registry, it is validated to check if it is a valid URL or an IP address. +func ExtractRegistry(image string, fallback string) string { + exp := regexp.MustCompile(`^(?:(?P(https?://)?[^/]+)(?::(?P\d+))?/)?(?:(?P[^/]+)/)?(?P[^:]+)(?::(?P.+))?$`).FindStringSubmatch(image) + if len(exp) == 0 { + return "" + } + + registry := exp[1] + + if IsURL(registry) { + return registry + } + + return fallback +} + +// IsURL checks if the string is an URL. +// Extracted from https://github.com/asaskevich/govalidator/blob/f21760c49a8d/validator.go#L104 +func IsURL(str string) bool { + if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") { + return false + } + strTemp := str + if strings.Contains(str, ":") && !strings.Contains(str, "://") { + // support no indicated urlscheme but with colon for port number + // http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString + strTemp = "http://" + str + } + u, err := url.Parse(strTemp) + if err != nil { + return false + } + if strings.HasPrefix(u.Host, ".") { + return false + } + if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) { + return false + } + return rxURL.MatchString(str) +} diff --git a/internal/testcontainersdocker/images_test.go b/internal/testcontainersdocker/images_test.go new file mode 100644 index 0000000000..56f01f4056 --- /dev/null +++ b/internal/testcontainersdocker/images_test.go @@ -0,0 +1,228 @@ +package testcontainersdocker + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + localhost5000 = "localhost:5000" + httpLocalhost5000 = "http://" + localhost5000 + loopback5000 = "127.0.0.1:5000" + httpLoopback5000 = "http://" + loopback5000 + dockerElasticCo = "docker.elastic.co" +) + +func TestExtractImagesFromDockerfile(t *testing.T) { + var baseImage string = "scratch" + var registryHost string = "localhost" + var registryPort string = "5000" + var nginxImage string = "nginx:latest" + + tests := []struct { + name string + dockerfile string + buildArgs map[string]*string + expected []string + expectedError bool + }{ + { + name: "Wrong file", + dockerfile: "", + buildArgs: nil, + expected: []string{}, + expectedError: true, + }, + { + name: "Single Image", + dockerfile: filepath.Join("testresources", "Dockerfile"), + buildArgs: nil, + expected: []string{"nginx:${tag}"}, + }, + { + name: "Multiple Images", + dockerfile: filepath.Join("testresources", "Dockerfile.multistage"), + buildArgs: nil, + expected: []string{"nginx:a", "nginx:b", "nginx:c", "scratch"}, + }, + { + name: "Multiple Images with one build arg", + dockerfile: filepath.Join("testresources", "Dockerfile.multistage.singleBuildArgs"), + buildArgs: map[string]*string{"BASE_IMAGE": &baseImage}, + expected: []string{"nginx:a", "nginx:b", "nginx:c", "scratch"}, + }, + { + name: "Multiple Images with multiple build args", + dockerfile: filepath.Join("testresources", "Dockerfile.multistage.multiBuildArgs"), + buildArgs: map[string]*string{"BASE_IMAGE": &baseImage, "REGISTRY_HOST": ®istryHost, "REGISTRY_PORT": ®istryPort, "NGINX_IMAGE": &nginxImage}, + expected: []string{"nginx:latest", "localhost:5000/nginx:latest", "scratch"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + images, err := ExtractImagesFromDockerfile(tt.dockerfile, tt.buildArgs) + if tt.expectedError { + require.Error(t, err) + assert.Empty(t, images) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected, images) + } + }) + } +} + +func TestExtractRegistry(t *testing.T) { + tests := []struct { + name string + image string + expected string + }{ + { + name: "Empty", + image: "", + expected: "", + }, + { + name: "Numbers", + image: "1234567890", + expected: IndexDockerIO, + }, + { + name: "Malformed Image", + image: "--malformed--", + expected: IndexDockerIO, + }, + { + name: "Repository + Image + Tag", + image: "testcontainers/ryuk:latest", + expected: IndexDockerIO, + }, + { + name: "Repository + Image", + image: "testcontainers/ryuk", + expected: IndexDockerIO, + }, + { + name: "Image + Tag", + image: "nginx:latest", + expected: IndexDockerIO, + }, + { + name: "Image", + image: "nginx", + expected: IndexDockerIO, + }, + { + name: "Local Registry with Port + Repository + Image + Tag", + image: "localhost:5000/testcontainers/ryuk:latest", + expected: localhost5000, + }, + { + name: "Local Registry with Port + Repository + Image", + image: "localhost:5000/testcontainers/ryuk", + expected: localhost5000, + }, + { + name: "Local Registry with Port + Image + Tag", + image: "localhost:5000/ryuk:latest", + expected: localhost5000, + }, + { + name: "Local Registry with Port + Image", + image: "localhost:5000/nginx", + expected: localhost5000, + }, + { + name: "Local Registry with Protocol and Port + Repository + Image + Tag", + image: "http://localhost:5000/testcontainers/ryuk:latest", + expected: httpLocalhost5000, + }, + { + name: "Local Registry with Protocol and Port + Repository + Image", + image: "http://localhost:5000/testcontainers/ryuk", + expected: httpLocalhost5000, + }, + { + name: "Local Registry with Protocol and Port + Image + Tag", + image: "http://localhost:5000/ryuk:latest", + expected: httpLocalhost5000, + }, + { + name: "Local Registry with Protocol and Port + Image", + image: "http://localhost:5000/nginx", + expected: httpLocalhost5000, + }, + { + name: "IP Registry with Port + Repository + Image + Tag", + image: "127.0.0.1:5000/testcontainers/ryuk:latest", + expected: loopback5000, + }, + { + name: "IP Registry with Port + Repository + Image", + image: "127.0.0.1:5000/testcontainers/ryuk", + expected: loopback5000, + }, + { + name: "IP Registry with Port + Image + Tag", + image: "127.0.0.1:5000/ryuk:latest", + expected: loopback5000, + }, + { + name: "IP Registry with Port + Image", + image: "127.0.0.1:5000/nginx", + expected: loopback5000, + }, + { + name: "IP Registry with Protocol and Port + Repository + Image + Tag", + image: "http://127.0.0.1:5000/testcontainers/ryuk:latest", + expected: httpLoopback5000, + }, + { + name: "IP Registry with Protocol and Port + Repository + Image", + image: "http://127.0.0.1:5000/testcontainers/ryuk", + expected: httpLoopback5000, + }, + { + name: "IP Registry with Protocol and Port + Image + Tag", + image: "http://127.0.0.1:5000/ryuk:latest", + expected: httpLoopback5000, + }, + { + name: "IP Registry with Protocol and Port + Image", + image: "http://127.0.0.1:5000/nginx", + expected: httpLoopback5000, + }, + { + name: "DNS Registry + Repository + Image + Tag", + image: "docker.elastic.co/elasticsearch/elasticsearch:8.6.2", + expected: dockerElasticCo, + }, + { + name: "DNS Registry + Repository + Image", + image: "docker.elastic.co/elasticsearch/elasticsearch", + expected: dockerElasticCo, + }, + { + name: "DNS Registry + Image + Tag", + image: "docker.elastic.co/elasticsearch:latest", + expected: dockerElasticCo, + }, + { + name: "DNS Registry + Image", + image: "docker.elastic.co/elasticsearch", + expected: dockerElasticCo, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual := ExtractRegistry(test.image, IndexDockerIO) + assert.Equal(t, test.expected, actual, "expected %s, got %s", test.expected, actual) + }) + } +} diff --git a/internal/testcontainersdocker/testresources/Dockerfile b/internal/testcontainersdocker/testresources/Dockerfile new file mode 100644 index 0000000000..23b462126d --- /dev/null +++ b/internal/testcontainersdocker/testresources/Dockerfile @@ -0,0 +1,4 @@ +ARG tag=latest + FROM nginx:${tag} +COPY . . +CMD ["pwd"] diff --git a/internal/testcontainersdocker/testresources/Dockerfile.multistage b/internal/testcontainersdocker/testresources/Dockerfile.multistage new file mode 100644 index 0000000000..168c1b85b6 --- /dev/null +++ b/internal/testcontainersdocker/testresources/Dockerfile.multistage @@ -0,0 +1,4 @@ +FROM nginx:a as builderA +FROM nginx:b as builderB +FROM nginx:c as builderC +FROM scratch diff --git a/internal/testcontainersdocker/testresources/Dockerfile.multistage.multiBuildArgs b/internal/testcontainersdocker/testresources/Dockerfile.multistage.multiBuildArgs new file mode 100644 index 0000000000..0260630bdc --- /dev/null +++ b/internal/testcontainersdocker/testresources/Dockerfile.multistage.multiBuildArgs @@ -0,0 +1,7 @@ +ARG BASE_IMAGE=scratch +ARG NGINX_IMAGE=nginx:latest +ARG REGISTRY_HOST=localhost +ARG REGISTRY_PORT=5000 +FROM ${NGINX_IMAGE} as builderA +FROM ${REGISTRY_HOST}:${REGISTRY_PORT}/${NGINX_IMAGE} as builderB +FROM ${BASE_IMAGE} diff --git a/internal/testcontainersdocker/testresources/Dockerfile.multistage.singleBuildArgs b/internal/testcontainersdocker/testresources/Dockerfile.multistage.singleBuildArgs new file mode 100644 index 0000000000..06820189a6 --- /dev/null +++ b/internal/testcontainersdocker/testresources/Dockerfile.multistage.singleBuildArgs @@ -0,0 +1,5 @@ +ARG BASE_IMAGE=scratch +FROM nginx:a as builderA +FROM nginx:b as builderB +FROM nginx:c as builderC +FROM ${BASE_IMAGE} diff --git a/mkdocs.yml b/mkdocs.yml index 15158c1591..1df1f1851e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -33,6 +33,7 @@ nav: - features/networking.md - features/garbage_collector.md - features/build_from_dockerfile.md + - features/docker_auth.md - features/docker_compose.md - features/follow_logs.md - features/override_container_command.md diff --git a/modulegen/go.mod b/modulegen/go.mod index e4c8564cd0..9a47c699ab 100644 --- a/modulegen/go.mod +++ b/modulegen/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/stretchr/testify v1.8.2 - golang.org/x/text v0.7.0 + golang.org/x/text v0.8.0 gopkg.in/yaml.v3 v3.0.1 gotest.tools/gotestsum v1.9.0 ) @@ -18,9 +18,9 @@ require ( github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.5.0 // indirect golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect - golang.org/x/tools v0.1.12 // indirect + golang.org/x/tools v0.6.0 // indirect ) diff --git a/modulegen/go.sum b/modulegen/go.sum index 344c556f7c..f7eb3a4d39 100644 --- a/modulegen/go.sum +++ b/modulegen/go.sum @@ -35,8 +35,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -46,8 +47,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -62,8 +63,8 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -71,14 +72,14 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/modules/localstack/go.mod b/modules/localstack/go.mod index 00f89c334d..d04aad1eff 100644 --- a/modules/localstack/go.mod +++ b/modules/localstack/go.mod @@ -5,14 +5,14 @@ go 1.18 require ( github.com/aws/aws-sdk-go v1.44.211 github.com/aws/aws-sdk-go-v2 v1.17.5 - github.com/aws/aws-sdk-go-v2/config v1.18.13 + github.com/aws/aws-sdk-go-v2/config v1.18.15 github.com/aws/aws-sdk-go-v2/credentials v1.13.15 - github.com/aws/aws-sdk-go-v2/service/s3 v1.30.3 + github.com/aws/aws-sdk-go-v2/service/s3 v1.30.5 github.com/docker/go-connections v0.4.0 github.com/imdario/mergo v0.3.13 github.com/stretchr/testify v1.8.2 github.com/testcontainers/testcontainers-go v0.18.0 - golang.org/x/mod v0.8.0 + golang.org/x/mod v0.9.0 gotest.tools/gotestsum v1.9.0 ) @@ -23,12 +23,12 @@ require ( github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.20 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.21 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.24 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.23 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.12.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.18.5 // indirect @@ -63,7 +63,7 @@ require ( github.com/sirupsen/logrus v1.9.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect diff --git a/modules/localstack/go.sum b/modules/localstack/go.sum index 7d9554d226..1e0defeb42 100644 --- a/modules/localstack/go.sum +++ b/modules/localstack/go.sum @@ -9,47 +9,38 @@ github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/b github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/aws/aws-sdk-go v1.44.211 h1:YNr5DwdzG/8y9Tl0QrPTnC99aFUHgT5hhy6GpnnzHK4= github.com/aws/aws-sdk-go v1.44.211/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.17.5 h1:TzCUW1Nq4H8Xscph5M/skINUitxM5UBAyvm2s7XBzL4= github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= -github.com/aws/aws-sdk-go-v2/config v1.18.13 h1:v0xlYqbO6/EVlM8tUn2QEOA7btQxcgidEq2JRDBPTho= -github.com/aws/aws-sdk-go-v2/config v1.18.13/go.mod h1:r39wGSZB7wPDW1i54JyQXUpc5KsWjh5z/3S5D9eCqDg= -github.com/aws/aws-sdk-go-v2/credentials v1.13.13/go.mod h1:DW9nbIIF9MrIja0cBQrUpeWYQMSlNmP8fevLUyF9W38= +github.com/aws/aws-sdk-go-v2/config v1.18.15 h1:509yMO0pJUGUugBP2H9FOFyV+7Mz7sRR+snfDN5W4NY= +github.com/aws/aws-sdk-go-v2/config v1.18.15/go.mod h1:vS0tddZqpE8cD9CyW0/kITHF5Bq2QasW9Y1DFHD//O0= github.com/aws/aws-sdk-go-v2/credentials v1.13.15 h1:0rZQIi6deJFjOEgHI9HI2eZcLPPEGQPictX66oRFLL8= github.com/aws/aws-sdk-go-v2/credentials v1.13.15/go.mod h1:vRMLMD3/rXU+o6j2MW5YefrGMBmdTvkLLGqFwMLBHQc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 h1:Kbiv9PGnQfG/imNI4L/heyUXvzKmcWSBeDvkrQz5pFc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23/go.mod h1:mOtmAg65GT1HIL/HT/PynwPbS+UG0BgCZ6vhkPqnxWo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 h1:9/aKwwus0TQxppPXFmf010DFrE+ssSbzroLVYINA+xE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 h1:b/Vn141DBuLVgXbhRWIrl9g+ww7G+ScV5SzniWR13jQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 h1:J4xhFd6zHhdF9jPP0FQJ6WknzBboGMBNjKOv4iTuw4A= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.20 h1:YIvKIfPXQVp0EhXUV644kmQo6cQPPSRmC44A1HSoJeg= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.20/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 h1:IVx9L7YFhpPq0tTnGo8u8TpluFu7nAn9X3sUDMb11c0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30/go.mod h1:vsbq62AOBwQ1LJ/GWKFxX8beUEYeRp/Agitrxee2/qM= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.21 h1:QdxdY43AiwsqG/VAqHA7bIVSm3rKr8/p9i05ydA0/RM= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.21/go.mod h1:QtIEat7ksHH8nFItljyvMI0dGj8lipK2XZ4PhNihTEU= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 h1:c5+bNdV8E4fIPteWx4HZSkqI07oY9exbfQ7JH7Yx4PI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23/go.mod h1:1jcUfF+FAOEwtIcNiHPaV4TSoZqkUIPzrohmD7fb95c= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.24 h1:Qmm8klpAdkuN3/rPrIMa/hZQ1z93WMBPjOzdAsbSnlo= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.24/go.mod h1:QelGeWBVRh9PbbXsfXKTFlU9FjT6W2yP+dW5jMQzOkg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 h1:QoOybhwRfciWUBbZ0gp9S7XaDnCuSTeK/fySB99V1ls= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23/go.mod h1:9uPh+Hrz2Vn6oMnQYiUi/zbh3ovbnQk19YKINkQny44= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 h1:ISLJ2BKXe4zzyZ7mp5ewKECiw0U7KpLgS3S6OxY9Cm0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK54XArazLvn2wvWMRBi/jGrWii46qbr5DyPGjc= -github.com/aws/aws-sdk-go-v2/service/s3 v1.30.3 h1:PVieHTwugdlHedlxLpYLQsOZAq736RScuEb/m4zhzc4= -github.com/aws/aws-sdk-go-v2/service/s3 v1.30.3/go.mod h1:XN3YcdmnWYZ3Hrnojvo5p2mc/wfF973nkq3ClXPDMHk= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.2/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.23 h1:qc+RW0WWZ2KApMnsu/EVCPqLTyIH55uc7YQq7mq4XqE= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.23/go.mod h1:FJhZWVWBCcgAF8jbep7pxQ1QUsjzTwa9tvEXGw2TDRo= +github.com/aws/aws-sdk-go-v2/service/s3 v1.30.5 h1:kFfb+NMap4R7nDvBYyABa/nw7KFMtAfygD1Hyoxh4uE= +github.com/aws/aws-sdk-go-v2/service/s3 v1.30.5/go.mod h1:Dze3kNt4T+Dgb8YCfuIFSBLmE6hadKNxqfdF0Xmqz1I= github.com/aws/aws-sdk-go-v2/service/sso v1.12.4 h1:qJdM48OOLl1FBSzI7ZrA1ZfLwOyCYqkXV5lko1hYDBw= github.com/aws/aws-sdk-go-v2/service/sso v1.12.4/go.mod h1:jtLIhd+V+lft6ktxpItycqHqiVXrPIRjWIsFIlzMriw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.2/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4 h1:YRkWXQveFb0tFC0TLktmmhGsOcCgLwvq88MC2al47AA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4/go.mod h1:zVwRrfdSmbRZWkUkWjOItY7SOalnFnq/Yg2LVPqDjwc= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU= github.com/aws/aws-sdk-go-v2/service/sts v1.18.5 h1:L1600eLr0YvTT7gNh3Ni24yGI7NSHkq9Gp62vijPRCs= github.com/aws/aws-sdk-go-v2/service/sts v1.18.5/go.mod h1:1mKZHLLpDMHTNSYPJ7qrcnCQdHCWsNQaT0xRvq2u80s= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= @@ -224,8 +215,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -287,8 +278,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/modules/pulsar/go.mod b/modules/pulsar/go.mod index b6495a59af..a58a935532 100644 --- a/modules/pulsar/go.mod +++ b/modules/pulsar/go.mod @@ -70,7 +70,7 @@ require ( golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/modules/pulsar/go.sum b/modules/pulsar/go.sum index 1762c38ca8..87694e503c 100644 --- a/modules/pulsar/go.sum +++ b/modules/pulsar/go.sum @@ -663,8 +663,8 @@ golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/reaper.go b/reaper.go index cf74d6aaba..5d5c912e0a 100644 --- a/reaper.go +++ b/reaper.go @@ -98,7 +98,6 @@ func newReaper(ctx context.Context, sessionID string, provider ReaperProvider, o testcontainersdocker.LabelReaper: "true", }, SkipReaper: true, - RegistryCred: reaperOpts.RegistryCredentials, Mounts: Mounts(BindMount(dockerHost, "/var/run/docker.sock")), Privileged: tcConfig.RyukPrivileged, WaitingFor: wait.ForListeningPort(listeningPort), diff --git a/reaper_test.go b/reaper_test.go index b05b2ec0b1..1032c88ee4 100644 --- a/reaper_test.go +++ b/reaper_test.go @@ -107,16 +107,6 @@ func Test_NewReaper(t *testing.T) { config: TestContainersConfig{}, ctx: context.WithValue(context.TODO(), testcontainersdocker.DockerHostContextKey, "unix:///value/in/context.sock"), }, - { - name: "with registry credentials", - req: createContainerRequest(func(req ContainerRequest) ContainerRequest { - creds := "registry-creds" - req.RegistryCred = creds - req.ReaperOptions = append(req.ReaperOptions, WithRegistryCredentials(creds)) - return req - }), - config: TestContainersConfig{}, - }, } for _, test := range tests { @@ -157,7 +147,6 @@ func Test_ReaperForNetwork(t *testing.T) { Name: networkName, CheckDuplicate: true, ReaperOptions: []ContainerOption{ - WithRegistryCredentials("credentials"), WithImageName("reaperImage"), }, }, @@ -170,7 +159,6 @@ func Test_ReaperForNetwork(t *testing.T) { _, err := newReaper(ctx, "sessionId", provider, req.ReaperOptions...) assert.EqualError(t, err, "expected") - assert.Equal(t, "credentials", provider.req.RegistryCred) assert.Equal(t, "reaperImage", provider.req.Image) assert.Equal(t, "reaperImage", provider.req.ReaperImage) } diff --git a/testresources/.docker/config.json b/testresources/.docker/config.json new file mode 100644 index 0000000000..af4b84ef1c --- /dev/null +++ b/testresources/.docker/config.json @@ -0,0 +1,8 @@ +{ + "auths": { + "https://index.docker.io/v1/": {}, + "https://example.com": {}, + "https://my.private.registry": {} + }, + "credsStore": "desktop" +} \ No newline at end of file