Skip to content
This repository has been archived by the owner on Sep 9, 2020. It is now read-only.

Commit

Permalink
validate env var DEPCACHEDIR is a valid path if set
Browse files Browse the repository at this point in the history
- fs.go - Add method `IsValidPath` to check if given file path string is valid.
  Add tests as well.
- main.go - After loading cachedir from env, if it has been set, check
  validity, exit with status 1 if not. Update integration tests for this
  scenario.
  • Loading branch information
sudo-suhas committed Oct 17, 2017
1 parent d797b39 commit e52321c
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 29 deletions.
68 changes: 47 additions & 21 deletions cmd/dep/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,31 +65,57 @@ func TestDepCachedir(t *testing.T) {

initPath := filepath.Join("testdata", "cachedir")

testProj := integration.NewTestProject(t, initPath, wd, runMain)
defer testProj.Cleanup()
t.Run("env-cachedir", func(t *testing.T) {
t.Parallel()
testProj := integration.NewTestProject(t, initPath, wd, runMain)
defer testProj.Cleanup()

testProj.TempDir("cachedir")
cachedir := testProj.Path("cachedir")
testProj.Setenv("DEPCACHEDIR", cachedir)
testProj.TempDir("cachedir")
cachedir := testProj.Path("cachedir")
testProj.Setenv("DEPCACHEDIR", cachedir)

// Running `dep ensure` will pull in the dependency into cachedir.
err = testProj.DoRun([]string{"ensure"})
if err != nil {
// Log the error output from running `dep ensure`, could be useful.
t.Log(testProj.GetStderr())
t.Fatalf("got an unexpected error: %s", err.Error())
}
// Running `dep ensure` will pull in the dependency into cachedir.
err = testProj.DoRun([]string{"ensure"})
if err != nil {
// Log the error output from running `dep ensure`, could be useful.
t.Logf("`dep ensure` error output: \n%s", testProj.GetStderr())
t.Errorf("got an unexpected error: %s", err)
}

// Check that the cache was created in the cachedir. Our fixture has the dependency
// `github.com/sdboyer/deptest`
_, err = os.Stat(testProj.Path("cachedir", "sources", "https---github.com-sdboyer-deptest"))
if err != nil {
if os.IsNotExist(err) {
t.Fatal("Expected cachedir to have been populated but none was found")
} else {
t.Fatalf("Got unexpected error: %s", err)
// Check that the cache was created in the cachedir. Our fixture has the dependency
// `github.com/sdboyer/deptest`
_, err = os.Stat(testProj.Path("cachedir", "sources", "https---github.com-sdboyer-deptest"))
if err != nil {
if os.IsNotExist(err) {
t.Error("expected cachedir to have been populated but none was found")
} else {
t.Errorf("got an unexpected error: %s", err)
}
}
}
})
t.Run("env-invalid-cachedir", func(t *testing.T) {
t.Parallel()
testProj := integration.NewTestProject(t, initPath, wd, runMain)
defer testProj.Cleanup()

cachedir := "/invalid/path"
testProj.Setenv("DEPCACHEDIR", cachedir)
wantErr := fmt.Sprintf(
"dep: $DEPCACHEDIR set to an invalid or inaccessible path: %q", cachedir,
)

// Running `dep ensure` will pull in the dependency into cachedir.
err = testProj.DoRun([]string{"ensure"})

if err == nil {
// Log the output from running `dep ensure`, could be useful.
t.Logf("test run output: \n%s\n%s", testProj.GetStdout(), testProj.GetStderr())
t.Error("unexpected result: \n\t(GOT) nil\n\t(WNT) exit status 1")
} else if gotErr := strings.TrimSpace(testProj.GetStderr()); gotErr != wantErr {
t.Errorf("unexpected error output: \n\t(GOT) %s\n\t(WNT) %s", gotErr, wantErr)
}
})

}

// execCmd is a test.RunFunc which runs the program in another process.
Expand Down
24 changes: 16 additions & 8 deletions cmd/dep/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"text/tabwriter"

"github.com/golang/dep"
"github.com/golang/dep/internal/fs"
)

type command interface {
Expand Down Expand Up @@ -121,33 +122,40 @@ func (c *Config) Run() (exitCode int) {
for _, cmd := range commands {
if cmd.Name() == cmdName {
// Build flag set with global flags in there.
fs := flag.NewFlagSet(cmdName, flag.ContinueOnError)
fs.SetOutput(c.Stderr)
verbose := fs.Bool("v", false, "enable verbose logging")
flags := flag.NewFlagSet(cmdName, flag.ContinueOnError)
flags.SetOutput(c.Stderr)
verbose := flags.Bool("v", false, "enable verbose logging")

// Register the subcommand flags in there, too.
cmd.Register(fs)
cmd.Register(flags)

// Override the usage text to something nicer.
resetUsage(errLogger, fs, cmdName, cmd.Args(), cmd.LongHelp())
resetUsage(errLogger, flags, cmdName, cmd.Args(), cmd.LongHelp())

if printCommandHelp {
fs.Usage()
flags.Usage()
exitCode = 1
return
}

// Parse the flags the user gave us.
// flag package automatically prints usage and error message in err != nil
// or if '-h' flag provided
if err := fs.Parse(c.Args[2:]); err != nil {
if err := flags.Parse(c.Args[2:]); err != nil {
exitCode = 1
return
}

// Cachedir is loaded from env if present. `$GOPATH/pkg/dep` is used as the
// fallback cache location.
cachedir := getEnv(c.Env, "DEPCACHEDIR")
if cachedir != "" && !fs.IsValidPath(cachedir) {
errLogger.Printf(
"dep: $DEPCACHEDIR set to an invalid or inaccessible path: %q\n", cachedir,
)
exitCode = 1
return
}

// Set up dep context.
ctx := &dep.Ctx{
Expand All @@ -162,7 +170,7 @@ func (c *Config) Run() (exitCode int) {
ctx.SetPaths(c.WorkingDir, GOPATHS...)

// Run the command with the post-flag-processing args.
if err := cmd.Run(ctx, fs.Args()); err != nil {
if err := cmd.Run(ctx, flags.Args()); err != nil {
errLogger.Printf("%v\n", err)
exitCode = 1
return
Expand Down
18 changes: 18 additions & 0 deletions internal/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,24 @@ func cloneSymlink(sl, dst string) error {
return os.Symlink(resolved, dst)
}

// IsValidPath checks if the given string is a valid path.
func IsValidPath(fp string) bool {
// See https://stackoverflow.com/questions/35231846/golang-check-if-string-is-valid-path
// Check if file/dir already exists
if _, err := os.Stat(fp); err == nil {
return true
}

// Attempt to create it
var d []byte
if err := ioutil.WriteFile(fp, d, 0644); err == nil {
os.Remove(fp) // And delete it
return true
}

return false
}

// IsDir determines is the path given is a directory or not.
func IsDir(name string) (bool, error) {
fi, err := os.Stat(name)
Expand Down
41 changes: 41 additions & 0 deletions internal/fs/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,47 @@ func setupInaccessibleDir(t *testing.T, op func(dir string) error) func() {
return cleanup
}

func TestIsValidPath(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

var dn string

cleanup := setupInaccessibleDir(t, func(dir string) error {
dn = filepath.Join(dir, "dir")
return os.Mkdir(dn, 0777)
})
defer cleanup()

tests := map[string]bool{
wd: true,
filepath.Join(wd, "testdata"): true,
filepath.Join(wd, "main.go"): true,
filepath.Join(wd, "this_file_does_not_exist.thing"): true,
dn: false,
"": false,
"/invalid/path": false,
}

if runtime.GOOS == "windows" {
// This test doesn't work on Microsoft Windows because
// of the differences in how file permissions are
// implemented. For this to work, the directory where
// the directory exists should be inaccessible.
delete(tests, dn)
}

for fp, want := range tests {
got := IsValidPath(fp)

if got != want {
t.Fatalf("expected %t for %s, got %t", want, fp, got)
}
}
}

func TestIsRegular(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
Expand Down

0 comments on commit e52321c

Please sign in to comment.