robocar-base/vendor/github.com/testcontainers/testcontainers-go/docker_auth.go

119 lines
3.3 KiB
Go

package testcontainers
import (
"context"
"encoding/base64"
"encoding/json"
"os"
"github.com/cpuguy83/dockercfg"
"github.com/docker/docker/api/types/registry"
"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, registry.AuthConfig, error) {
defaultRegistry := defaultRegistry(ctx)
reg := testcontainersdocker.ExtractRegistry(image, defaultRegistry)
cfgs, err := getDockerAuthConfigs()
if err != nil {
return reg, registry.AuthConfig{}, err
}
if cfg, ok := cfgs[reg]; ok {
return reg, cfg, nil
}
return reg, registry.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 {
client, err := testcontainersdocker.NewClient(ctx)
if err != nil {
return testcontainersdocker.IndexDockerIO
}
defer client.Close()
info, err := 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]registry.AuthConfig, error) {
cfg, err := getDockerConfig()
if err != nil {
return nil, err
}
cfgs := map[string]registry.AuthConfig{}
for k, v := range cfg.AuthConfigs {
ac := registry.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
}
// in the case where the auth field in the .docker/conf.json is empty, and the user has credential helpers registered
// the auth comes from there
for k := range cfg.CredentialHelpers {
ac := registry.AuthConfig{}
u, p, _ := dockercfg.GetRegistryCredentials(k)
ac.Username = u
ac.Password = p
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
}