From 5efedeb6dcaa692bcd32c0cad77ebf76ac693eef Mon Sep 17 00:00:00 2001 From: Chmouel Boudjnah Date: Tue, 9 Apr 2019 16:29:59 +0200 Subject: [PATCH] git-init don't assume the image is running as root We check what is our real home for our compared to what we have with $HOME and symlink it so GIT+SSH works. We use the go-homedir lib because user.Current doesn't work when cross compiling (i.e: from osx with ko) Fixes #724 --- Gopkg.lock | 9 + cmd/git-init/main.go | 24 ++- .../github.com/mitchellh/go-homedir/LICENSE | 21 +++ .../mitchellh/go-homedir/homedir.go | 167 ++++++++++++++++++ 4 files changed, 214 insertions(+), 7 deletions(-) create mode 100644 vendor/github.com/mitchellh/go-homedir/LICENSE create mode 100644 vendor/github.com/mitchellh/go-homedir/homedir.go diff --git a/Gopkg.lock b/Gopkg.lock index ec76d482167..a9f9120f193 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -421,6 +421,14 @@ revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" version = "v1.0.1" +[[projects]] + digest = "1:f9f72e583aaacf1d1ac5d6121abd4afd3c690baa9e14e1d009df26bf831ba347" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + pruneopts = "NUT" + revision = "af06845cf3004701891bf4fdb884bfe4920b3727" + version = "v1.1.0" + [[projects]] digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f" name = "github.com/modern-go/concurrent" @@ -1195,6 +1203,7 @@ "github.com/knative/pkg/webhook", "github.com/knative/test-infra/scripts", "github.com/knative/test-infra/tools/dep-collector", + "github.com/mitchellh/go-homedir", "go.opencensus.io/trace", "go.uber.org/zap", "go.uber.org/zap/zaptest/observer", diff --git a/cmd/git-init/main.go b/cmd/git-init/main.go index c3d3ed2d269..481cff009f8 100644 --- a/cmd/git-init/main.go +++ b/cmd/git-init/main.go @@ -22,6 +22,7 @@ import ( "os/exec" "github.com/knative/pkg/logging" + homedir "github.com/mitchellh/go-homedir" "go.uber.org/zap" ) @@ -59,15 +60,24 @@ func main() { logger, _ := logging.NewLogger("", "git-init") defer logger.Sync() - // HACK HACK HACK - // Git seems to ignore $HOME/.ssh and look in /root/.ssh for unknown reasons. - // As a workaround, symlink /root/.ssh to where we expect the $HOME to land. - // This means SSH auth only works for our built-in git support, and not - // custom steps. - err := os.Symlink("/builder/home/.ssh", "/root/.ssh") + // HACK: This is to get git+ssh to work since ssh doesn't respect the HOME + // env variable. + homepath, err := homedir.Dir() if err != nil { - logger.Fatalf("Unexpected error creating symlink: %v", err) + logger.Fatalf("Unexpected error: getting the user home directory: %v", err) } + homeenv := os.Getenv("HOME") + if homeenv != "" && homeenv != homepath { + if _, err := os.Stat(homepath + "/.ssh"); os.IsNotExist(err) { + err = os.Symlink(homeenv+"/.ssh", homepath+"/.ssh") + if err != nil { + // Only do a warning, in case we don't have a real home + // directory writable in our image + logger.Warnf("Unexpected error: creating symlink: %v", err) + } + } + } + if *revision == "" { *revision = "master" } diff --git a/vendor/github.com/mitchellh/go-homedir/LICENSE b/vendor/github.com/mitchellh/go-homedir/LICENSE new file mode 100644 index 00000000000..f9c841a51e0 --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go new file mode 100644 index 00000000000..25378537ead --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/homedir.go @@ -0,0 +1,167 @@ +package homedir + +import ( + "bytes" + "errors" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync" +) + +// DisableCache will disable caching of the home directory. Caching is enabled +// by default. +var DisableCache bool + +var homedirCache string +var cacheLock sync.RWMutex + +// Dir returns the home directory for the executing user. +// +// This uses an OS-specific method for discovering the home directory. +// An error is returned if a home directory cannot be detected. +func Dir() (string, error) { + if !DisableCache { + cacheLock.RLock() + cached := homedirCache + cacheLock.RUnlock() + if cached != "" { + return cached, nil + } + } + + cacheLock.Lock() + defer cacheLock.Unlock() + + var result string + var err error + if runtime.GOOS == "windows" { + result, err = dirWindows() + } else { + // Unix-like system, so just assume Unix + result, err = dirUnix() + } + + if err != nil { + return "", err + } + homedirCache = result + return result, nil +} + +// Expand expands the path to include the home directory if the path +// is prefixed with `~`. If it isn't prefixed with `~`, the path is +// returned as-is. +func Expand(path string) (string, error) { + if len(path) == 0 { + return path, nil + } + + if path[0] != '~' { + return path, nil + } + + if len(path) > 1 && path[1] != '/' && path[1] != '\\' { + return "", errors.New("cannot expand user-specific home dir") + } + + dir, err := Dir() + if err != nil { + return "", err + } + + return filepath.Join(dir, path[1:]), nil +} + +// Reset clears the cache, forcing the next call to Dir to re-detect +// the home directory. This generally never has to be called, but can be +// useful in tests if you're modifying the home directory via the HOME +// env var or something. +func Reset() { + cacheLock.Lock() + defer cacheLock.Unlock() + homedirCache = "" +} + +func dirUnix() (string, error) { + homeEnv := "HOME" + if runtime.GOOS == "plan9" { + // On plan9, env vars are lowercase. + homeEnv = "home" + } + + // First prefer the HOME environmental variable + if home := os.Getenv(homeEnv); home != "" { + return home, nil + } + + var stdout bytes.Buffer + + // If that fails, try OS specific commands + if runtime.GOOS == "darwin" { + cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) + cmd.Stdout = &stdout + if err := cmd.Run(); err == nil { + result := strings.TrimSpace(stdout.String()) + if result != "" { + return result, nil + } + } + } else { + cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + // If the error is ErrNotFound, we ignore it. Otherwise, return it. + if err != exec.ErrNotFound { + return "", err + } + } else { + if passwd := strings.TrimSpace(stdout.String()); passwd != "" { + // username:password:uid:gid:gecos:home:shell + passwdParts := strings.SplitN(passwd, ":", 7) + if len(passwdParts) > 5 { + return passwdParts[5], nil + } + } + } + } + + // If all else fails, try the shell + stdout.Reset() + cmd := exec.Command("sh", "-c", "cd && pwd") + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return "", err + } + + result := strings.TrimSpace(stdout.String()) + if result == "" { + return "", errors.New("blank output when reading home directory") + } + + return result, nil +} + +func dirWindows() (string, error) { + // First prefer the HOME environmental variable + if home := os.Getenv("HOME"); home != "" { + return home, nil + } + + // Prefer standard environment variable USERPROFILE + if home := os.Getenv("USERPROFILE"); home != "" { + return home, nil + } + + drive := os.Getenv("HOMEDRIVE") + path := os.Getenv("HOMEPATH") + home := drive + path + if drive == "" || path == "" { + return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") + } + + return home, nil +}