Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use env vars for registry credentials in kp import #279

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions pkg/commands/import/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ func NewImportCommand(
const (
confirmMessage = "Confirm with y:"
noChangesConfirmMessage = "Re-upload images with y:"
envVarRegistryUrl = "REGISTRY_URL"
envVarRegistryUser = "REGISTRY_USER"
envVarRegistryPassword = "REGISTRY_PASSWORD"
)

confirmMsgMap := map[bool]string{
Expand Down Expand Up @@ -98,8 +101,14 @@ cat dependencies.yaml | kp import -f -`,
}

defaultKeychain := authn.DefaultKeychain
kc := authn.NewMultiKeychain(
authn.NewKeychainFromHelper(
importpkg.NewCredHelperFromEnvVars(envVarRegistryUrl, envVarRegistryUser, envVarRegistryPassword)),
defaultKeychain,
)
ncarlson marked this conversation as resolved.
Show resolved Hide resolved

if showChanges {
hasChanges, summary, err := importpkg.SummarizeChange(ctx, defaultKeychain, descriptor, kpConfig, importpkg.NewDefaultRelocatedImageProvider(imgFetcher), differ, cs)
hasChanges, summary, err := importpkg.SummarizeChange(ctx, kc, descriptor, kpConfig, importpkg.NewDefaultRelocatedImageProvider(imgFetcher), differ, cs)
if err != nil {
return err
}
Expand All @@ -125,7 +134,7 @@ cat dependencies.yaml | kp import -f -`,
if ch.IsDryRun() {
objs, err = importer.ImportDescriptorDryRun(
ctx,
authn.DefaultKeychain,
kc,
kpConfig,
rawDescriptor,
)
Expand All @@ -135,7 +144,7 @@ cat dependencies.yaml | kp import -f -`,
} else {
objs, err = importer.ImportDescriptor(
ctx,
authn.DefaultKeychain,
kc,
kpConfig,
rawDescriptor,
)
Expand Down
44 changes: 44 additions & 0 deletions pkg/import/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package _import

import (
"os"
"strconv"

"github.com/google/go-containerregistry/pkg/authn"
"github.com/pkg/errors"
)

type CredHelper struct {
Auths map[string]authn.Basic
}

func NewCredHelperFromEnvVars(serverURLEnvVar string, usernameEnvVar string, passwordEnvVar string) *CredHelper {
suffixes := [11]string{""}
for i := 0; i <= 9; i++ {
suffixes[i+1] = "_" + strconv.Itoa(i)
}

auths := map[string]authn.Basic{}

for _, suffix := range suffixes {
if serverUrl := os.Getenv(serverURLEnvVar + suffix); serverUrl != "" {
auths[serverUrl] = authn.Basic{
Username: os.Getenv(usernameEnvVar + suffix),
Password: os.Getenv(passwordEnvVar + suffix),
}
}
}

return &CredHelper{
Auths: auths,
}
}
ncarlson marked this conversation as resolved.
Show resolved Hide resolved

func (c *CredHelper) Get(serverURL string) (string, string, error) {
auth, found := c.Auths[serverURL]
if found == false {
return "", "", errors.New("serverURL does not refer to a known registry")
} else {
return auth.Username, auth.Password, nil
}
}
209 changes: 209 additions & 0 deletions pkg/import/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package _import_test

import (
"os"
"testing"

"github.com/sclevine/spec"
"github.com/stretchr/testify/require"

importpkg "github.com/vmware-tanzu/kpack-cli/pkg/import"
)

func TestCredHelper(t *testing.T) {
spec.Run(t, "TestCredHelper", testCredHelper)
}

func testCredHelper(t *testing.T, when spec.G, it spec.S) {
const envVarRegistryUrl = "REGISTRY_URL_TEST_VAR"
const envVarRegistryUser = "REGISTRY_USER_TEST_VAR"
const envVarRegistryPassword = "REGISTRY_PASSWORD_TEST_VAR"

when("one registry credential is provided by environment variables and Get is called", func() {
var credHelper *importpkg.CredHelper

it.Before(func() {
require.NoError(t, os.Setenv(envVarRegistryUrl, "some-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser, "some-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword, "some-registry-password"))
})

it.After(func() {
require.NoError(t, os.Setenv(envVarRegistryUrl, ""))
require.NoError(t, os.Setenv(envVarRegistryUser, ""))
require.NoError(t, os.Setenv(envVarRegistryPassword, ""))
})

it("returns username and password provided by environment variables", func() {
credHelper = importpkg.NewCredHelperFromEnvVars(envVarRegistryUrl, envVarRegistryUser, envVarRegistryPassword)
require.Equal(t, len(credHelper.Auths), 1)
registryUser, registryPassword, err := credHelper.Get(os.Getenv(envVarRegistryUrl))
require.NoError(t, err)
require.Equal(t, "some-registry-user", registryUser)
require.Equal(t, "some-registry-password", registryPassword)
})
})

when("many registry credentials are provided by environment variables and Get is called", func() {
var credHelper *importpkg.CredHelper

it.Before(func() {
require.NoError(t, os.Setenv(envVarRegistryUrl+"_0", "fizz-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_0", "fizz-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_0", "fizz-registry-password"))
require.NoError(t, os.Setenv(envVarRegistryUrl+"_1", "fuzz-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_1", "fuzz-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_1", "fuzz-registry-password"))
require.NoError(t, os.Setenv(envVarRegistryUrl, "some-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser, "some-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword, "some-registry-password"))
})

it.After(func() {
require.NoError(t, os.Setenv(envVarRegistryUrl+"_0", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_0", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_0", ""))
require.NoError(t, os.Setenv(envVarRegistryUrl+"_1", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_1", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_1", ""))
require.NoError(t, os.Setenv(envVarRegistryUrl, ""))
require.NoError(t, os.Setenv(envVarRegistryUser, ""))
require.NoError(t, os.Setenv(envVarRegistryPassword, ""))
})

it("returns username and password provided by environment variables", func() {
credHelper = importpkg.NewCredHelperFromEnvVars(envVarRegistryUrl, envVarRegistryUser, envVarRegistryPassword)
require.Equal(t, len(credHelper.Auths), 3)
registryUser, registryPassword, err := credHelper.Get(os.Getenv(envVarRegistryUrl + "_0"))
require.NoError(t, err)
require.Equal(t, "fizz-registry-user", registryUser)
require.Equal(t, "fizz-registry-password", registryPassword)
registryUser, registryPassword, err = credHelper.Get(os.Getenv(envVarRegistryUrl + "_1"))
require.NoError(t, err)
require.Equal(t, "fuzz-registry-user", registryUser)
require.Equal(t, "fuzz-registry-password", registryPassword)
registryUser, registryPassword, err = credHelper.Get(os.Getenv(envVarRegistryUrl))
require.NoError(t, err)
require.Equal(t, "some-registry-user", registryUser)
require.Equal(t, "some-registry-password", registryPassword)
})
})

when("more than 10 registry credentials are provided by environment variables that "+
"have a \"_N\" suffix (e.g., REGISTRY_URL_N where N is an integer >= 0 and <= 9) "+
"and no credential is provided by environment variables with an empty suffix (e.g., REGISTRY_URL) "+
"and Get is called", func() {
var credHelper *importpkg.CredHelper

it.Before(func() {
require.NoError(t, os.Setenv(envVarRegistryUrl+"_0", "zero-registry.io"))
ncarlson marked this conversation as resolved.
Show resolved Hide resolved
require.NoError(t, os.Setenv(envVarRegistryUser+"_0", "zero-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_0", "zero-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_1", "one-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_1", "one-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_1", "one-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_2", "two-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_2", "two-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_2", "two-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_3", "three-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_3", "three-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_3", "three-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_4", "four-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_4", "four-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_4", "four-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_5", "five-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_5", "five-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_5", "five-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_6", "six-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_6", "six-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_6", "six-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_7", "seven-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_7", "seven-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_7", "seven-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_8", "eight-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_8", "eight-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_8", "eight-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_9", "nine-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_9", "nine-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_9", "nine-registry-password"))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_10", "ten-registry.io"))
require.NoError(t, os.Setenv(envVarRegistryUser+"_10", "ten-registry-user"))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_10", "ten-registry-password"))
})

it.After(func() {
require.NoError(t, os.Setenv(envVarRegistryUrl+"_0", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_0", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_0", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_1", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_1", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_1", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_2", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_2", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_2", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_3", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_3", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_3", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_4", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_4", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_4", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_5", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_5", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_5", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_6", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_6", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_6", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_7", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_7", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_7", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_8", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_8", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_8", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_9", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_9", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_9", ""))

require.NoError(t, os.Setenv(envVarRegistryUrl+"_10", ""))
require.NoError(t, os.Setenv(envVarRegistryUser+"_10", ""))
require.NoError(t, os.Setenv(envVarRegistryPassword+"_10", ""))
})

it("returns credentials for REGISTRY_URL_N where N is an integer >= 0 and <= 9", func() {
credHelper = importpkg.NewCredHelperFromEnvVars(envVarRegistryUrl, envVarRegistryUser, envVarRegistryPassword)
require.Equal(t, len(credHelper.Auths), 10)
registryUser, registryPassword, err := credHelper.Get(os.Getenv(envVarRegistryUrl + "_0"))
require.NoError(t, err)
require.Equal(t, "zero-registry-user", registryUser)
require.Equal(t, "zero-registry-password", registryPassword)
registryUser, registryPassword, err = credHelper.Get(os.Getenv(envVarRegistryUrl + "_4"))
require.NoError(t, err)
require.Equal(t, "four-registry-user", registryUser)
require.Equal(t, "four-registry-password", registryPassword)
registryUser, registryPassword, err = credHelper.Get(os.Getenv(envVarRegistryUrl + "_9"))
require.NoError(t, err)
require.Equal(t, "nine-registry-user", registryUser)
require.Equal(t, "nine-registry-password", registryPassword)
registryUser, registryPassword, err = credHelper.Get(os.Getenv(envVarRegistryUrl + "_10"))
require.ErrorContains(t, err, "serverURL does not refer to a known registry")
})
})
}