diff --git a/cmd/util.go b/cmd/util.go index 98a3769..5c36fa6 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -4,7 +4,9 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "regexp" + "strconv" "strings" "github.com/aquasecurity/kube-bench/check" @@ -116,6 +118,57 @@ func getBinaries(v *viper.Viper) map[string]string { return binmap } +// getConfigFilePath locates the config files we should be using based on either the specified +// version, or the running version of kubernetes if not specified +func getConfigFilePath(specifiedVersion string, runningVersion string, filename string) (path string, err error) { + var fileVersion string + + if specifiedVersion != "" { + fileVersion = specifiedVersion + } else { + fileVersion = runningVersion + } + + for { + path = filepath.Join(cfgDir, fileVersion) + file := filepath.Join(path, string(filename)) + glog.V(2).Info(fmt.Sprintf("Looking for config file: %s\n", file)) + + if _, err = os.Stat(file); !os.IsNotExist(err) { + if specifiedVersion == "" && fileVersion != runningVersion { + glog.V(1).Info(fmt.Sprintf("No test file found for %s - using tests for Kubernetes %s\n", runningVersion, fileVersion)) + } + return path, nil + } + + // If we were given an explicit version to look for, don't look for any others + if specifiedVersion != "" { + return "", err + } + + fileVersion = decrementVersion(fileVersion) + if fileVersion == "" { + return "", fmt.Errorf("no test files found <= runningVersion") + } + } +} + +// decrementVersion decrements the version number +// We want to decrement individually even through versions where we don't supply test files +// just in case someone wants to specify their own test files for that version +func decrementVersion(version string) string { + split := strings.Split(version, ".") + minor, err := strconv.Atoi(split[1]) + if err != nil { + return "" + } + if minor <= 1 { + return "" + } + split[1] = strconv.Itoa(minor - 1) + return strings.Join(split, ".") +} + // getConfigFiles finds which of the set of candidate config files exist // accepts a string 't' which indicates the type of config file, conf, // podspec or untifile. diff --git a/cmd/util_test.go b/cmd/util_test.go index 3650ea0..539f400 100644 --- a/cmd/util_test.go +++ b/cmd/util_test.go @@ -15,7 +15,9 @@ package cmd import ( + "io/ioutil" "os" + "path/filepath" "reflect" "strconv" "testing" @@ -306,3 +308,45 @@ func TestMakeSubsitutions(t *testing.T) { }) } } + +func TestGetConfigFilePath(t *testing.T) { + var err error + cfgDir, err = ioutil.TempDir("", "kube-bench-test") + if err != nil { + t.Fatalf("Failed to create temp directory") + } + defer os.RemoveAll(cfgDir) + d := filepath.Join(cfgDir, "1.8") + err = os.Mkdir(d, 0666) + if err != nil { + t.Fatalf("Failed to create temp file") + } + ioutil.WriteFile(filepath.Join(d, "master.yaml"), []byte("hello world"), 0666) + + cases := []struct { + specifiedVersion string + runningVersion string + succeed bool + exp string + }{ + {runningVersion: "1.8", succeed: true, exp: d}, + {runningVersion: "1.9", succeed: true, exp: d}, + {runningVersion: "1.10", succeed: true, exp: d}, + {runningVersion: "1.1", succeed: false}, + {specifiedVersion: "1.8", succeed: true, exp: d}, + {specifiedVersion: "1.9", succeed: false}, + {specifiedVersion: "1.10", succeed: false}, + } + + for _, c := range cases { + t.Run(c.specifiedVersion+"-"+c.runningVersion, func(t *testing.T) { + path, err := getConfigFilePath(c.specifiedVersion, c.runningVersion, "/master.yaml") + if err != nil && c.succeed { + t.Fatalf("Error %v", err) + } + if path != c.exp { + t.Fatalf("Got %s expected %s", path, c.exp) + } + }) + } +}