Run func without HOME defined/ unaccessible .config dir (#2236)

* fixed integration tests

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* def creds back

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* docker config.json credentials test when HOME not defined

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* pack test

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* simplify

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* og creds, small fixes

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* s2i test no home

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* remove unnecessary stuff

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* deploy test without home

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* confict fix after rebase

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* move test, dont delete

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* runtime change

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* node image signals fixed and smaller size for GH actions

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* return err

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* cred test

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

* clean up comments

Signed-off-by: gauron99 <fridrich.david19@gmail.com>

---------

Signed-off-by: gauron99 <fridrich.david19@gmail.com>
This commit is contained in:
David Fridrich 2024-06-04 02:04:52 +02:00 committed by GitHub
parent a2bc6f6ffd
commit aa909bdc44
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 183 additions and 23 deletions

View File

@ -159,9 +159,6 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro
cfg buildConfig cfg buildConfig
f fn.Function f fn.Function
) )
if err = config.CreatePaths(); err != nil { // for possible auth.json usage
return
}
if cfg, err = newBuildConfig().Prompt(); err != nil { // gather values into a single instruction set if cfg, err = newBuildConfig().Prompt(); err != nil { // gather values into a single instruction set
return return
} }

View File

@ -233,9 +233,6 @@ func runDeploy(cmd *cobra.Command, newClient ClientFactory) (err error) {
cfg deployConfig cfg deployConfig
f fn.Function f fn.Function
) )
if err = config.CreatePaths(); err != nil { // for possible auth.json usage
return
}
if cfg, err = newDeployConfig(cmd).Prompt(); err != nil { if cfg, err = newDeployConfig(cmd).Prompt(); err != nil {
return return
} }

View File

@ -1894,3 +1894,36 @@ func TestDeploy_NoErrorOnOldFunctionNotFound(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
} }
// TestDeploy_WithoutHome ensures that deploying a function without HOME &
// XDG_CONFIG_HOME defined succeeds
func TestDeploy_WithoutHome(t *testing.T) {
var (
root = FromTempDirectory(t)
ns = "myns"
)
t.Setenv("HOME", "")
t.Setenv("XDG_CONFIG_HOME", "")
// Create a basic go Function
f := fn.Function{
Runtime: "go",
Root: root,
}
_, err := fn.New().Init(f)
if err != nil {
t.Fatal(err)
}
// Deploy the function
cmd := NewDeployCmd(NewTestClient(
fn.WithDeployer(mock.NewDeployer()),
fn.WithRegistry(TestRegistry)))
cmd.SetArgs([]string{fmt.Sprintf("--namespace=%s", ns)})
err = cmd.Execute()
if err != nil {
t.Fatal(err)
}
}

View File

@ -211,7 +211,7 @@ func (b *Builder) Build(ctx context.Context, f fn.Function, platforms []fn.Platf
if err = impl.Build(ctx, opts); err != nil { if err = impl.Build(ctx, opts); err != nil {
if ctx.Err() != nil { if ctx.Err() != nil {
return // SIGINT return // SIGINT
} else if !b.verbose { } else if b.verbose {
err = fmt.Errorf("failed to build the function: %w", err) err = fmt.Errorf("failed to build the function: %w", err)
fmt.Fprintln(color.Stderr(), "") fmt.Fprintln(color.Stderr(), "")
_, _ = io.Copy(color.Stderr(), &b.outBuff) _, _ = io.Copy(color.Stderr(), &b.outBuff)

View File

@ -165,24 +165,31 @@ func NewCredentialsProvider(configPath string, opts ...Opt) docker.CredentialsPr
} }
} }
// default credential loaders map -- load only those that should be there.
var defaultCredentialLoaders = []CredentialsCallback{}
c.authFilePath = filepath.Join(configPath, "auth.json") c.authFilePath = filepath.Join(configPath, "auth.json")
sys := &containersTypes.SystemContext{ sys := &containersTypes.SystemContext{
AuthFilePath: c.authFilePath, AuthFilePath: c.authFilePath,
} }
home, err := os.UserHomeDir() if _, err := os.Stat(c.authFilePath); err == nil {
if err != nil { defaultCredentialLoaders = append(defaultCredentialLoaders,
panic(err)
}
dockerConfigPath := filepath.Join(home, ".docker", "config.json")
var defaultCredentialLoaders = []CredentialsCallback{
func(registry string) (docker.Credentials, error) { func(registry string) (docker.Credentials, error) {
return getCredentialsByCredentialHelper(c.authFilePath, registry) return getCredentialsByCredentialHelper(c.authFilePath, registry)
}, })
}
// add only if home dir is defined -- for .docker/config.json creds
home, err := os.UserHomeDir()
if err == nil {
dockerConfigPath := filepath.Join(home, ".docker", "config.json")
defaultCredentialLoaders = append(defaultCredentialLoaders,
func(registry string) (docker.Credentials, error) { func(registry string) (docker.Credentials, error) {
return getCredentialsByCredentialHelper(dockerConfigPath, registry) return getCredentialsByCredentialHelper(dockerConfigPath, registry)
}, })
}
defaultCredentialLoaders = append(defaultCredentialLoaders,
func(registry string) (docker.Credentials, error) { func(registry string) (docker.Credentials, error) {
creds, err := dockerConfig.GetCredentials(sys, registry) creds, err := dockerConfig.GetCredentials(sys, registry)
if err != nil { if err != nil {
@ -195,7 +202,8 @@ func NewCredentialsProvider(configPath string, opts ...Opt) docker.CredentialsPr
Username: creds.Username, Username: creds.Username,
Password: creds.Password, Password: creds.Password,
}, nil }, nil
}, })
defaultCredentialLoaders = append(defaultCredentialLoaders,
func(registry string) (docker.Credentials, error) { func(registry string) (docker.Credentials, error) {
// Fallback onto default docker config locations // Fallback onto default docker config locations
emptySys := &containersTypes.SystemContext{} emptySys := &containersTypes.SystemContext{}
@ -207,11 +215,11 @@ func NewCredentialsProvider(configPath string, opts ...Opt) docker.CredentialsPr
Username: creds.Username, Username: creds.Username,
Password: creds.Password, Password: creds.Password,
}, nil }, nil
}, })
defaultCredentialLoaders = append(defaultCredentialLoaders,
func(registry string) (docker.Credentials, error) { // empty credentials provider for unsecured registries func(registry string) (docker.Credentials, error) { // empty credentials provider for unsecured registries
return docker.Credentials{}, nil return docker.Credentials{}, nil
}, })
}
c.credentialLoaders = append(c.credentialLoaders, defaultCredentialLoaders...) c.credentialLoaders = append(c.credentialLoaders, defaultCredentialLoaders...)

View File

@ -20,6 +20,7 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
@ -284,7 +285,6 @@ func startServer(t *testing.T, uname, pwd string) (addr, addrTLS string) {
panic(err) panic(err)
} }
}() }()
// make the testing CA trusted by default HTTP transport/client // make the testing CA trusted by default HTTP transport/client
oldDefaultTransport := http.DefaultTransport oldDefaultTransport := http.DefaultTransport
newDefaultTransport := http.DefaultTransport.(*http.Transport).Clone() newDefaultTransport := http.DefaultTransport.(*http.Transport).Clone()
@ -549,6 +549,77 @@ func TestCredentialsProviderSavingFromUserInput(t *testing.T) {
} }
} }
// TestCredentialsWithoutHome tests different scenarios when HOME is not set
func TestCredentialsWithoutHome(t *testing.T) {
type args struct {
promptUser creds.CredentialsCallback
verifyCredentials creds.VerifyCredentialsCallback
registry string
setUpEnv setUpEnv
}
tests := []struct {
name string
testHomePathEmpty bool
args args
want Credentials
}{
{
name: "empty home with correct user prompt",
testHomePathEmpty: true,
args: args{
promptUser: correctPwdCallback, // user inputs correct credentials
verifyCredentials: correctVerifyCbk,
registry: "docker.io",
setUpEnv: setEmptyHome,
},
want: Credentials{Username: dockerIoUser, Password: dockerIoUserPwd},
},
{
name: "empty config with user prompt",
args: args{
promptUser: correctPwdCallback,
verifyCredentials: correctVerifyCbk,
registry: "docker.io",
},
want: Credentials{Username: dockerIoUser, Password: dockerIoUserPwd},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resetHomeDir(t)
if tt.args.setUpEnv != nil {
tt.args.setUpEnv(t)
}
// prepare config path for credentials provider
var configPath string
if tt.testHomePathEmpty {
configPath = ""
} else {
configPath = testConfigPath(t)
}
credentialsProvider := creds.NewCredentialsProvider(
configPath,
creds.WithPromptForCredentials(tt.args.promptUser),
creds.WithVerifyCredentials(tt.args.verifyCredentials),
)
got, err := credentialsProvider(context.Background(), tt.args.registry+"/someorg/someimage:sometag")
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("got: %v, want: %v", got, tt.want)
}
})
}
}
// ********************** helper functions below **************************** \\
func resetHomeDir(t *testing.T) { func resetHomeDir(t *testing.T) {
t.TempDir() t.TempDir()
if err := os.RemoveAll(homeTempDir); err != nil { if err := os.RemoveAll(homeTempDir); err != nil {
@ -903,3 +974,10 @@ func (i *inMemoryHelper) Delete(serverURL string) error {
return credentials.NewErrCredentialsNotFound() return credentials.NewErrCredentialsNotFound()
} }
// set home variables to empty values
func setEmptyHome(t *testing.T) {
t.Helper()
t.Setenv("HOME", "")
t.Setenv("XDG_CONFIG_HOME", "")
}

View File

@ -19,6 +19,7 @@ import (
"github.com/docker/docker/client" "github.com/docker/docker/client"
"knative.dev/func/pkg/builders/buildpacks" "knative.dev/func/pkg/builders/buildpacks"
"knative.dev/func/pkg/builders/s2i"
"knative.dev/func/pkg/docker" "knative.dev/func/pkg/docker"
fn "knative.dev/func/pkg/functions" fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/knative" "knative.dev/func/pkg/knative"
@ -545,6 +546,31 @@ func Handle(ctx context.Context, w http.ResponseWriter, req *http.Request) {
} }
} }
// TestDeployWithoutHome ensures that running client.New works without
// home
func TestDeployWithoutHome(t *testing.T) {
root, cleanup := Mktemp(t)
defer cleanup()
t.Setenv("HOME", "")
t.Setenv("XDG_CONFIG_HOME", "")
verbose := false
name := "test-deploy-no-home"
f := fn.Function{Runtime: "node", Name: name, Root: root, Namespace: DefaultNamespace}
// client with s2i builder because pack needs HOME
client := newClientWithS2i(verbose)
// expect to succeed
_, _, err := client.New(context.Background(), f)
if err != nil {
t.Fatalf("expected no errors but got %v", err)
}
defer del(t, client, name, DefaultNamespace)
}
// *********** // ***********
// Helpers // Helpers
// *********** // ***********
@ -571,6 +597,27 @@ func newClient(verbose bool) *fn.Client {
) )
} }
// copy of newClient just builder is s2i instead of buildpacks
func newClientWithS2i(verbose bool) *fn.Client {
builder := s2i.NewBuilder(s2i.WithVerbose(verbose))
pusher := docker.NewPusher(docker.WithVerbose(verbose))
deployer := knative.NewDeployer(knative.WithDeployerVerbose(verbose))
describer := knative.NewDescriber(verbose)
remover := knative.NewRemover(verbose)
lister := knative.NewLister(verbose)
return fn.New(
fn.WithRegistry(DefaultRegistry),
fn.WithVerbose(verbose),
fn.WithBuilder(builder),
fn.WithPusher(pusher),
fn.WithDeployer(deployer),
fn.WithDescriber(describer),
fn.WithRemover(remover),
fn.WithLister(lister),
)
}
// Del cleans up after a test by removing a function by name. // Del cleans up after a test by removing a function by name.
// (test fails if the named function does not exist) // (test fails if the named function does not exist)
// //