cmd/govulncheck: add a -dir flag for testing
When the "testmode" tag is active, add a flag that lets govulncheck
read source from any directory.
Update command tests to use the feature: remove the cdmodule
command and replace it with an environment variable.
This change will enable running the command tests
in parallel.
Change-Id: I6c166ee907520cebb10887835d58e9672b84d459
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/432355
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/govulncheck/main.go b/cmd/govulncheck/main.go
index 8bf044d..bd97ff9 100644
--- a/cmd/govulncheck/main.go
+++ b/cmd/govulncheck/main.go
@@ -13,6 +13,7 @@
"go/build"
"os"
"os/exec"
+ "path/filepath"
"sort"
"strings"
@@ -28,6 +29,7 @@
jsonFlag = flag.Bool("json", false, "output JSON")
verboseFlag = flag.Bool("v", false, "print a full call stack for each vulnerability")
testFlag = flag.Bool("test", false, "analyze test files. Only valid for source code.")
+ dirFlag string
)
func init() {
@@ -97,15 +99,16 @@
}
} else {
cfg := &packages.Config{
+ Dir: filepath.FromSlash(dirFlag),
Tests: *testFlag,
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(build.Default.BuildTags, ","))},
}
pkgs, err = govulncheck.LoadPackages(cfg, patterns...)
if err != nil {
// Try to provide a meaningful and actionable error message.
- if !fileExists("go.mod") {
+ if !fileExists(filepath.Join(dirFlag, "go.mod")) {
die(noGoModErrorMessage)
- } else if !fileExists("go.sum") {
+ } else if !fileExists(filepath.Join(dirFlag, "go.sum")) {
die(noGoSumErrorMessage)
}
die("govulncheck: %v", err)
diff --git a/cmd/govulncheck/main_command_118_test.go b/cmd/govulncheck/main_command_118_test.go
index 5fe6330..2437f8b 100644
--- a/cmd/govulncheck/main_command_118_test.go
+++ b/cmd/govulncheck/main_command_118_test.go
@@ -36,20 +36,15 @@
t.Fatal(err)
}
ts.DisableLogging = false
- // Define a command that lets us cd into a module directory.
- // The modules for these tests live under testdata/modules.
- ts.Commands["cdmodule"] = func(args []string, inputFile string) ([]byte, error) {
- if len(args) != 1 {
- return nil, errors.New("need exactly 1 argument")
- }
- return nil, os.Chdir(filepath.Join(testDir, "testdata", "modules", args[0]))
- }
// Define a command that runs govulncheck with our local DB. We can't use
// cmdtest.Program for this because it doesn't let us set the environment,
// and that is the only way to tell govulncheck about an alternative vuln
// database.
- binary, cleanup := buildtest.GoBuild(t, ".") // build govulncheck
- defer cleanup()
+ binary, cleanup := buildtest.GoBuild(t, ".", "testmode") // build govulncheck
+ // Use Cleanup instead of defer, because when subtests are parallel, defer
+ // runs too early.
+ t.Cleanup(cleanup)
+
ts.Commands["govulncheck"] = func(args []string, inputFile string) ([]byte, error) {
cmd := exec.Command(binary, args...)
if inputFile != "" {
@@ -78,13 +73,14 @@
"nogosum": true,
}
+ os.Setenv("moddir", filepath.Join(testDir, "testdata", "modules"))
for _, md := range moduleDirs {
if skipBuild[filepath.Base(md)] {
continue
}
- binary, cleanup := buildtest.GoBuild(t, md)
- defer cleanup()
+ binary, cleanup := buildtest.GoBuild(t, md, "")
+ t.Cleanup(cleanup)
// Set an environment variable to the path to the binary, so tests
// can refer to it.
varName := filepath.Base(md) + "_binary"
diff --git a/cmd/govulncheck/main_testmode.go b/cmd/govulncheck/main_testmode.go
new file mode 100644
index 0000000..0ac803b
--- /dev/null
+++ b/cmd/govulncheck/main_testmode.go
@@ -0,0 +1,13 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build testmode
+
+package main
+
+import "flag"
+
+func init() {
+ flag.StringVar(&dirFlag, "dir", "", "directory to use for loading source files")
+}
diff --git a/cmd/govulncheck/testdata/default.ct b/cmd/govulncheck/testdata/default.ct
index 327e906..e86d477 100644
--- a/cmd/govulncheck/testdata/default.ct
+++ b/cmd/govulncheck/testdata/default.ct
@@ -1,15 +1,13 @@
# Test of default mode.
# No vulnerabilities, no output.
-$ cdmodule novuln
-$ govulncheck .
+$ govulncheck -dir ${moddir}/novuln .
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
No vulnerabilities found.
-$ cdmodule vuln
-$ govulncheck . --> FAIL 3
+$ govulncheck -dir ${moddir}/vuln . --> FAIL 3
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/import-no-call.ct b/cmd/govulncheck/testdata/import-no-call.ct
index 0fbe8c2..69d414b 100644
--- a/cmd/govulncheck/testdata/import-no-call.ct
+++ b/cmd/govulncheck/testdata/import-no-call.ct
@@ -1,8 +1,7 @@
# Test of default mode.
# All vulnerabilities imported, but never called.
-$ cdmodule vuln3
-$ govulncheck .
+$ govulncheck -dir ${moddir}/vuln3 .
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/json.ct b/cmd/govulncheck/testdata/json.ct
index 9e75f84..e7cc2b3 100644
--- a/cmd/govulncheck/testdata/json.ct
+++ b/cmd/govulncheck/testdata/json.ct
@@ -2,8 +2,7 @@
# TODO(zpavlinovic): add test for stdlib that works
# on all underlying Go build systems.
-$ cdmodule novuln
-$ govulncheck -json .
+$ govulncheck -dir ${moddir}/novuln -json .
{
"Calls": {
"Functions": {},
@@ -40,8 +39,7 @@
]
}
-$ cdmodule vuln
-$ govulncheck -json .
+$ govulncheck -dir ${moddir}/vuln -json .
{
"Calls": {
"Functions": {
diff --git a/cmd/govulncheck/testdata/manystacks-verbose.ct b/cmd/govulncheck/testdata/manystacks-verbose.ct
index ae6980a..6de910c 100644
--- a/cmd/govulncheck/testdata/manystacks-verbose.ct
+++ b/cmd/govulncheck/testdata/manystacks-verbose.ct
@@ -1,5 +1,4 @@
-$ cdmodule manystacks
-$ govulncheck -v . --> FAIL 3
+$ govulncheck -dir ${moddir}/manystacks -v . --> FAIL 3
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/manystacks.ct b/cmd/govulncheck/testdata/manystacks.ct
index 00e0354..cfadefa 100644
--- a/cmd/govulncheck/testdata/manystacks.ct
+++ b/cmd/govulncheck/testdata/manystacks.ct
@@ -1,5 +1,4 @@
-$ cdmodule manystacks
-$ govulncheck . --> FAIL 3
+$ govulncheck -dir ${moddir}/manystacks . --> FAIL 3
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/multi-module.ct b/cmd/govulncheck/testdata/multi-module.ct
index c191c53..98d9f88 100644
--- a/cmd/govulncheck/testdata/multi-module.ct
+++ b/cmd/govulncheck/testdata/multi-module.ct
@@ -1,7 +1,6 @@
# Test fix correctness for vulns affecting multiple modules
-$ cdmodule multimodvuln
-$ govulncheck .
+$ govulncheck -dir ${moddir}/multimodvuln .
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/nogomod.ct b/cmd/govulncheck/testdata/nogomod.ct
index a6b5ed3..4390707 100644
--- a/cmd/govulncheck/testdata/nogomod.ct
+++ b/cmd/govulncheck/testdata/nogomod.ct
@@ -1,7 +1,6 @@
# Test of missing go.mod error message.
-$ cdmodule nogomod
-$ govulncheck . --> FAIL 1
+$ govulncheck -dir ${moddir}/nogomod . --> FAIL 1
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/nogosum.ct b/cmd/govulncheck/testdata/nogosum.ct
index f68ab95..eaeb61e 100644
--- a/cmd/govulncheck/testdata/nogosum.ct
+++ b/cmd/govulncheck/testdata/nogosum.ct
@@ -1,7 +1,6 @@
# Test of missing go.sum error message.
-$ cdmodule nogosum
-$ govulncheck . --> FAIL 1
+$ govulncheck -dir ${moddir}/nogosum . --> FAIL 1
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/stdlib.ct b/cmd/govulncheck/testdata/stdlib.ct
index 67f4b3c..090a713 100644
--- a/cmd/govulncheck/testdata/stdlib.ct
+++ b/cmd/govulncheck/testdata/stdlib.ct
@@ -1,7 +1,6 @@
# Test of stdlib vuln detection.
-$ cdmodule stdvuln
-$ govulncheck . --> FAIL 3
+$ govulncheck -dir ${moddir}/stdvuln . --> FAIL 3
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/two-symbols.ct b/cmd/govulncheck/testdata/two-symbols.ct
index ecefbb7..8e0e087 100644
--- a/cmd/govulncheck/testdata/two-symbols.ct
+++ b/cmd/govulncheck/testdata/two-symbols.ct
@@ -1,5 +1,4 @@
-$ cdmodule vuln2
-$ govulncheck . --> FAIL 3
+$ govulncheck -dir ${moddir}/vuln2 . --> FAIL 3
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/cmd/govulncheck/testdata/usage.ct b/cmd/govulncheck/testdata/usage.ct
index 4d2d761..72afbcc 100644
--- a/cmd/govulncheck/testdata/usage.ct
+++ b/cmd/govulncheck/testdata/usage.ct
@@ -3,6 +3,8 @@
govulncheck [flags] package...
govulncheck [flags] binary
+ -dir string
+ directory to use for loading source files
-json
output JSON
-tags list
@@ -20,6 +22,8 @@
govulncheck [flags] package...
govulncheck [flags] binary
+ -dir string
+ directory to use for loading source files
-json
output JSON
-tags list
diff --git a/cmd/govulncheck/testdata/verbose.ct b/cmd/govulncheck/testdata/verbose.ct
index df96302..dcab77f 100644
--- a/cmd/govulncheck/testdata/verbose.ct
+++ b/cmd/govulncheck/testdata/verbose.ct
@@ -1,15 +1,13 @@
# Test of verbose mode.
# No vulnerabilities, no output.
-$ cdmodule novuln
-$ govulncheck -v .
+$ govulncheck -dir ${moddir}/novuln -v .
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
No vulnerabilities found.
-$ cdmodule vuln
-$ govulncheck -v . --> FAIL 3
+$ govulncheck -dir ${moddir}/vuln -v . --> FAIL 3
govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback.
Scanning for dependencies with known vulnerabilities...
diff --git a/internal/buildtest/buildtest.go b/internal/buildtest/buildtest.go
index c8b1417..559ca08 100644
--- a/internal/buildtest/buildtest.go
+++ b/internal/buildtest/buildtest.go
@@ -25,7 +25,7 @@
// envVarVals, which should be an alternating list of variables and values.
// It returns the path to the resulting binary, and a function
// to call when finished with the binary.
-func GoBuild(t *testing.T, dir string, envVarVals ...string) (binaryPath string, cleanup func()) {
+func GoBuild(t *testing.T, dir, tags string, envVarVals ...string) (binaryPath string, cleanup func()) {
switch runtime.GOOS {
case "android", "js", "ios":
t.Skipf("skipping on OS without 'go build' %s", runtime.GOOS)
@@ -65,7 +65,11 @@
if _, err := os.Stat(goCommandPath); err != nil {
t.Fatal(err)
}
- cmd := exec.Command(goCommandPath, "build", "-o", binaryPath+exeSuffix)
+ args := []string{"build", "-o", binaryPath + exeSuffix}
+ if tags != "" {
+ args = append(args, "-tags", tags)
+ }
+ cmd := exec.Command(goCommandPath, args...)
cmd.Dir = dir
cmd.Env = env
cmd.Stdout = os.Stdout
diff --git a/vulncheck/internal/binscan/scan_test.go b/vulncheck/internal/binscan/scan_test.go
index 673598a..4fbabe9 100644
--- a/vulncheck/internal/binscan/scan_test.go
+++ b/vulncheck/internal/binscan/scan_test.go
@@ -20,7 +20,7 @@
for _, gg := range []string{"linux/amd64", "darwin/amd64", "windows/amd64"} {
t.Run(gg, func(t *testing.T) {
goos, goarch, _ := strings.Cut(gg, "/")
- binary, done := buildtest.GoBuild(t, "testdata", "GOOS", goos, "GOARCH", goarch)
+ binary, done := buildtest.GoBuild(t, "testdata", "", "GOOS", goos, "GOARCH", goarch)
defer done()
f, err := os.Open(binary)
diff --git a/vulncheck/internal/gosym/pclntab_test.go b/vulncheck/internal/gosym/pclntab_test.go
index b1e433f..c116d71 100644
--- a/vulncheck/internal/gosym/pclntab_test.go
+++ b/vulncheck/internal/gosym/pclntab_test.go
@@ -31,7 +31,7 @@
t.Skipf("skipping in short mode on non-Linux system %s", runtime.GOARCH)
}
- return buildtest.GoBuild(t, "testdata", "GOOS", "linux")
+ return buildtest.GoBuild(t, "testdata", "", "GOOS", "linux")
}
// skipIfNotELF skips the test if we are not running on an ELF system.