Skip to content

Commit

Permalink
improve registry/trust.go ref processing, logging & test file
Browse files Browse the repository at this point in the history
  • Loading branch information
Pwuts committed Jan 18, 2023
1 parent cba8af0 commit abf1e32
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 71 deletions.
7 changes: 6 additions & 1 deletion pkg/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import (
log "github.com/sirupsen/logrus"
)

const (
DefaultRegistryDomain = "docker.io"
LegacyDefaultRegistryDomain = "index.docker.io"
)

// GetPullOptions creates a struct with all options needed for pulling images from a registry
func GetPullOptions(imageName string) (types.ImagePullOptions, error) {
auth, err := EncodedAuth(imageName)
Expand Down Expand Up @@ -47,7 +52,7 @@ func WarnOnAPIConsumption(container watchtowerTypes.Container) bool {

containerHost := ref.Domain(normalizedName)

if containerHost == "docker.io" || containerHost == "ghcr.io" {
if containerHost == DefaultRegistryDomain || containerHost == "ghcr.io" {
return true
}

Expand Down
45 changes: 25 additions & 20 deletions pkg/registry/trust.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"os"
"strings"

cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
Expand All @@ -18,26 +17,26 @@ import (
// EncodedAuth returns an encoded auth config for the given registry
// loaded from environment variables or docker config
// as available in that order
func EncodedAuth(ref string) (string, error) {
auth, err := EncodedEnvAuth(ref)
func EncodedAuth(imageRef string) (string, error) {
auth, err := EncodedEnvAuth()
if err != nil {
auth, err = EncodedConfigAuth(ref)
auth, err = EncodedConfigAuth(imageRef)
}
return auth, err
}

// EncodedEnvAuth returns an encoded auth config for the given registry
// loaded from environment variables
// Returns an error if authentication environment variables have not been set
func EncodedEnvAuth(ref string) (string, error) {
func EncodedEnvAuth() (string, error) {
username := os.Getenv("REPO_USER")
password := os.Getenv("REPO_PASS")
if username != "" && password != "" {
auth := types.AuthConfig{
Username: username,
Password: password,
}
log.Debugf("Loaded auth credentials for user %s on registry %s", auth.Username, ref)
log.Debugf("Loaded auth credentials for registry user %s from environment", auth.Username)
log.Tracef("Using auth password %s", auth.Password)
return EncodeAuth(auth)
}
Expand All @@ -48,43 +47,49 @@ func EncodedEnvAuth(ref string) (string, error) {
// loaded from the docker config
// Returns an empty string if credentials cannot be found for the referenced server
// The docker config must be mounted on the container
func EncodedConfigAuth(ref string) (string, error) {
server, err := ParseServerAddress(ref)
func EncodedConfigAuth(imageRef string) (string, error) {
registry, err := GetRegistryAddress(imageRef)
if err != nil {
log.Errorf("Unable to parse the image ref %s", err)
log.Errorf("Could not get registry from image ref %s: %s", imageRef, err)
return "", err
}

configDir := os.Getenv("DOCKER_CONFIG")
if configDir == "" {
configDir = "/"
}
configFile, err := cliconfig.Load(configDir)
if err != nil {
log.Errorf("Unable to find default config file %s", err)
log.Errorf("Unable to find default config file: %s", err)
return "", err
}
credStore := CredentialsStore(*configFile)
auth, _ := credStore.Get(server) // returns (types.AuthConfig{}) if server not in credStore
auth, _ := credStore.Get(registry) // returns (types.AuthConfig{}) if server not in credStore

if auth == (types.AuthConfig{}) {
log.WithField("config_file", configFile.Filename).Debugf("No credentials for %s found", server)
log.WithField("config_file", configFile.Filename).Debugf("No credentials for %s found", registry)
return "", nil
}
log.Debugf("Loaded auth credentials for user %s, on registry %s, from file %s", auth.Username, ref, configFile.Filename)
log.Debugf("Loaded auth credentials for user %s, on registry %s, from file %s", auth.Username, registry, configFile.Filename)
log.Tracef("Using auth password %s", auth.Password)
return EncodeAuth(auth)
}

// ParseServerAddress extracts the server part from a container image ref
func ParseServerAddress(ref string) (string, error) {

parsedRef, err := reference.Parse(ref)
// GetRegistryAddress extracts the server part from a container image ref,
// returning docker.io for single-part image names without an explicit domain
func GetRegistryAddress(imageRef string) (string, error) {
parsedRef, err := reference.Parse(imageRef)
if err != nil {
return ref, err
return "", err
}

parts := strings.Split(parsedRef.String(), "/")
return parts[0], nil
var registry string
if namedRef, ok := parsedRef.(reference.Named); ok {
registry = reference.Domain(namedRef)
} else {
registry = DefaultRegistryDomain
}
return registry, nil
}

// CredentialsStore returns a new credentials store based
Expand Down
96 changes: 46 additions & 50 deletions pkg/registry/trust_test.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,61 @@
package registry

import (
"os"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"os"
)

var _ = Describe("Testing with Ginkgo", func() {
It("encoded env auth_ should return an error if repo envs are unset", func() {
_ = os.Unsetenv("REPO_USER")
_ = os.Unsetenv("REPO_PASS")

_, err := EncodedEnvAuth("")
Expect(err).To(HaveOccurred())
})
It("encoded env auth_ should return auth hash if repo envs are set", func() {
var err error
expectedHash := "eyJ1c2VybmFtZSI6ImNvbnRhaW5ycnItdXNlciIsInBhc3N3b3JkIjoiY29udGFpbnJyci1wYXNzIn0="

err = os.Setenv("REPO_USER", "containrrr-user")
Expect(err).NotTo(HaveOccurred())

err = os.Setenv("REPO_PASS", "containrrr-pass")
Expect(err).NotTo(HaveOccurred())

config, err := EncodedEnvAuth("")
Expect(config).To(Equal(expectedHash))
Expect(err).NotTo(HaveOccurred())
var _ = Describe("Registry credential helpers", func() {
Describe("EncodedEnvAuth", func() {
It("should return an error if repo envs are unset", func() {
_ = os.Unsetenv("REPO_USER")
_ = os.Unsetenv("REPO_PASS")

_, err := EncodedEnvAuth()
Expect(err).To(HaveOccurred())
})
It("should return base64 auth string if repo envs are set", func() {
var err error
expected := "eyJ1c2VybmFtZSI6ImNvbnRhaW5ycnItdXNlciIsInBhc3N3b3JkIjoiY29udGFpbnJyci1wYXNzIn0="

err = os.Setenv("REPO_USER", "containrrr-user")
Expect(err).NotTo(HaveOccurred())

err = os.Setenv("REPO_PASS", "containrrr-pass")
Expect(err).NotTo(HaveOccurred())

config, err := EncodedEnvAuth()
Expect(config).To(Equal(expected))
Expect(err).NotTo(HaveOccurred())
})
})
It("encoded config auth_ should return an error if file is not present", func() {
var err error

err = os.Setenv("DOCKER_CONFIG", "/dev/null/should-fail")
Expect(err).NotTo(HaveOccurred())

_, err = EncodedConfigAuth("")
Expect(err).To(HaveOccurred())
Describe("EncodedConfigAuth", func() {
It("should return an error if file is not present", func() {
var err error

})
/*
* TODO:
* This part only confirms that it still works in the same way as it did
* with the old version of the docker api client sdk. I'd say that
* ParseServerAddress likely needs to be elaborated a bit to default to
* dockerhub in case no server address was provided.
*
* ++ @simskij, 2019-04-04
*/
It("parse server address_ should return error if passed empty string", func() {

_, err := ParseServerAddress("")
Expect(err).To(HaveOccurred())
})
It("parse server address_ should return the organization part if passed an image name missing server name", func() {
err = os.Setenv("DOCKER_CONFIG", "/dev/null/should-fail")
Expect(err).NotTo(HaveOccurred())

val, _ := ParseServerAddress("containrrr/config")
Expect(val).To(Equal("containrrr"))
_, err = EncodedConfigAuth("")
Expect(err).To(HaveOccurred())
})
})
It("parse server address_ should return the server name if passed a fully qualified image name", func() {

val, _ := ParseServerAddress("github.com/containrrrr/config")
Expect(val).To(Equal("github.com"))
Describe("GetServerAddress", func() {
It("should return error if passed empty string", func() {
_, err := GetRegistryAddress("")
Expect(err).To(HaveOccurred())
})
It("should return the organization part if passed an image name with no explicit domain", func() {
val, _ := GetRegistryAddress("containrrr/config")
Expect(val).To(Equal("containrrr"))
})
It("should return the server name if passed a fully qualified image name", func() {
val, _ := GetRegistryAddress("github.com/containrrr/config")
Expect(val).To(Equal("github.com"))
})
})
})

0 comments on commit abf1e32

Please sign in to comment.