diff --git a/act/container/docker_auth.go b/act/container/docker_auth.go new file mode 100644 index 00000000..c470039a --- /dev/null +++ b/act/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/act/container/docker_pull.go b/act/container/docker_pull.go index 99cbdcdb..e20d686c 100644 --- a/act/container/docker_pull.go +++ b/act/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/act/container/docker_pull_test.go b/act/container/docker_pull_test.go index e242865c..fa9705a4 100644 --- a/act/container/docker_pull_test.go +++ b/act/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/act/container/testdata/docker-pull-options/config.json b/act/container/testdata/docker-pull-options/config.json new file mode 100644 index 00000000..c8b8e7c9 --- /dev/null +++ b/act/container/testdata/docker-pull-options/config.json @@ -0,0 +1,7 @@ +{ + "auths": { + "https://index.docker.io/v1/": { + "auth": "dXNlcm5hbWU6cGFzc3dvcmQK" + } + } +}