1
0
Fork 0
mirror of https://code.forgejo.org/forgejo/runner.git synced 2025-08-11 17:50:58 +00:00

Docker auth (#891)

* feat: read docker credentials from local docker config

* fix: url.Parse requires protocol

Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de>

* fix: docker decides by the existence of . or : if...

... the image is in a custom registry or not.

Co-authored-by: Björn Brauer <zaubernerd@zaubernerd.de>

* fix: make docker hostname detection more robust

* test: mock docker config for getImagePullOptions test

By default github actions have a docker config set with a token to pull
images from docker hub.

Co-authored-by: Markus Wolf <markus.wolf@new-work.se>

Co-authored-by: Markus Wolf <markus.wolf@new-work.se>
This commit is contained in:
Björn Brauer 2021-11-27 19:21:32 +01:00 committed by GitHub
parent d2ef16b698
commit 7951ad80fd
4 changed files with 73 additions and 2 deletions

View file

@ -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
}

View file

@ -77,6 +77,7 @@ func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput)
imagePullOptions := types.ImagePullOptions{ imagePullOptions := types.ImagePullOptions{
Platform: input.Platform, Platform: input.Platform,
} }
if input.Username != "" && input.Password != "" { if input.Username != "" && input.Password != "" {
logger := common.Logger(ctx) logger := common.Logger(ctx)
logger.Debugf("using authentication for docker pull") logger.Debugf("using authentication for docker pull")
@ -91,6 +92,21 @@ func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput)
return imagePullOptions, err 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) imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON)
} }

View file

@ -4,6 +4,8 @@ import (
"context" "context"
"testing" "testing"
"github.com/docker/cli/cli/config"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
assert "github.com/stretchr/testify/assert" assert "github.com/stretchr/testify/assert"
) )
@ -35,9 +37,11 @@ func TestCleanImage(t *testing.T) {
func TestGetImagePullOptions(t *testing.T) { func TestGetImagePullOptions(t *testing.T) {
ctx := context.Background() ctx := context.Background()
config.SetDir("/non-existent/docker")
options, err := getImagePullOptions(ctx, NewDockerPullExecutorInput{}) options, err := getImagePullOptions(ctx, NewDockerPullExecutorInput{})
assert.Nil(t, err, "Failed to create ImagePullOptions") 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{ options, err = getImagePullOptions(ctx, NewDockerPullExecutorInput{
Image: "", Image: "",
@ -45,5 +49,13 @@ func TestGetImagePullOptions(t *testing.T) {
Password: "password", Password: "password",
}) })
assert.Nil(t, err, "Failed to create ImagePullOptions") 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")
} }

View file

@ -0,0 +1,7 @@
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "dXNlcm5hbWU6cGFzc3dvcmQK"
}
}
}