diff --git a/go.sum b/go.sum index fd66322..4615e8a 100644 --- a/go.sum +++ b/go.sum @@ -408,6 +408,7 @@ github.com/docker/docker v20.10.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05b github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.10+incompatible h1:GKkP0T7U4ks6X3lmmHKC2QDprnpRJor2Z5a8m62R9ZM= github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= diff --git a/pkg/container/docker_auth.go b/pkg/container/docker_auth.go new file mode 100644 index 0000000..c470039 --- /dev/null +++ b/pkg/container/docker_auth.go @@ -0,0 +1,36 @@ +package container + +import ( + "strings" + + "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/credentials" + "github.com/docker/docker/api/types" + log "github.com/sirupsen/logrus" +) + +func LoadDockerAuthConfig(image string) (types.AuthConfig, error) { + config, err := config.Load(config.Dir()) + if err != nil { + log.Warnf("Could not load docker config: %v", err) + return types.AuthConfig{}, err + } + + if !config.ContainsAuth() { + config.CredentialsStore = credentials.DetectDefaultStore(config.CredentialsStore) + } + + hostName := "index.docker.io" + index := strings.IndexRune(image, '/') + if index > -1 && (strings.ContainsAny(image[:index], ".:") || image[:index] == "localhost") { + hostName = image[:index] + } + + authConfig, err := config.GetAuthConfig(hostName) + if err != nil { + log.Warnf("Could not get auth config from docker config: %v", err) + return types.AuthConfig{}, err + } + + return types.AuthConfig(authConfig), nil +} diff --git a/pkg/container/docker_pull.go b/pkg/container/docker_pull.go index 99cbdcd..e20d686 100644 --- a/pkg/container/docker_pull.go +++ b/pkg/container/docker_pull.go @@ -77,6 +77,7 @@ func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput) imagePullOptions := types.ImagePullOptions{ Platform: input.Platform, } + if input.Username != "" && input.Password != "" { logger := common.Logger(ctx) logger.Debugf("using authentication for docker pull") @@ -91,6 +92,21 @@ func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput) return imagePullOptions, err } + imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON) + } else { + authConfig, err := LoadDockerAuthConfig(input.Image) + if err != nil { + return imagePullOptions, err + } + if authConfig.Username == "" && authConfig.Password == "" { + return imagePullOptions, nil + } + + encodedJSON, err := json.Marshal(authConfig) + if err != nil { + return imagePullOptions, err + } + imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON) } diff --git a/pkg/container/docker_pull_test.go b/pkg/container/docker_pull_test.go index e242865..fa9705a 100644 --- a/pkg/container/docker_pull_test.go +++ b/pkg/container/docker_pull_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + "github.com/docker/cli/cli/config" + log "github.com/sirupsen/logrus" assert "github.com/stretchr/testify/assert" ) @@ -35,9 +37,11 @@ func TestCleanImage(t *testing.T) { func TestGetImagePullOptions(t *testing.T) { ctx := context.Background() + config.SetDir("/non-existent/docker") + options, err := getImagePullOptions(ctx, NewDockerPullExecutorInput{}) assert.Nil(t, err, "Failed to create ImagePullOptions") - assert.Equal(t, options.RegistryAuth, "", "RegistryAuth should be empty if no username or password is set") + assert.Equal(t, "", options.RegistryAuth, "RegistryAuth should be empty if no username or password is set") options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{ Image: "", @@ -45,5 +49,13 @@ func TestGetImagePullOptions(t *testing.T) { Password: "password", }) assert.Nil(t, err, "Failed to create ImagePullOptions") - assert.Equal(t, options.RegistryAuth, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9", "Username and Password should be provided") + assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9", options.RegistryAuth, "Username and Password should be provided") + + config.SetDir("testdata/docker-pull-options") + + options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{ + Image: "nektos/act", + }) + assert.Nil(t, err, "Failed to create ImagePullOptions") + assert.Equal(t, "eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicGFzc3dvcmQiOiJwYXNzd29yZFxuIiwic2VydmVyYWRkcmVzcyI6Imh0dHBzOi8vaW5kZXguZG9ja2VyLmlvL3YxLyJ9", options.RegistryAuth, "RegistryAuth should be taken from local docker config") } diff --git a/pkg/container/testdata/docker-pull-options/config.json b/pkg/container/testdata/docker-pull-options/config.json new file mode 100644 index 0000000..c8b8e7c --- /dev/null +++ b/pkg/container/testdata/docker-pull-options/config.json @@ -0,0 +1,7 @@ +{ + "auths": { + "https://index.docker.io/v1/": { + "auth": "dXNlcm5hbWU6cGFzc3dvcmQK" + } + } +}