internal/worker: remove binary mode from govulncheck

Binary analysis is done as part of compare mode, so we don't have to
support binary mode independently (which is anyhow analyzing only one
binary).

This CL also makes few simple related refactorings:
 - make explicit that govulncheck_sandbox will not run binary analysis
 - remove dependency of govulncheck_sandbox on internal/worker. The
   latter actually depends on the former, so the only reason why this
   compiled in the past is because worker called sandbox via command
   line

This should result in code simplification.

Change-Id: Ia6374904f78c21f240fe5a769a21e349f68576cc
Reviewed-on: https://go-review.googlesource.com/c/pkgsite-metrics/+/527978
Reviewed-by: Maceo Thompson <maceothompson@google.com>
Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/cmd/govulncheck_sandbox/govulncheck_sandbox.go b/cmd/govulncheck_sandbox/govulncheck_sandbox.go
index 97a808f..077901d 100644
--- a/cmd/govulncheck_sandbox/govulncheck_sandbox.go
+++ b/cmd/govulncheck_sandbox/govulncheck_sandbox.go
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This program runs govulncheck on a module or a binary and then
+// This program runs govulncheck on a module in source mode and then
 // writes the result as JSON. It is intended to be run in a sandbox.
+// For running govulncheck on binaries, see cmd/compare_sandbox.
 //
 // Unless it panics, this program always terminates with exit code 0.
 // If there is an error, it writes a JSON object with field "Error".
@@ -19,7 +20,6 @@
 	"os"
 
 	"golang.org/x/pkgsite-metrics/internal/govulncheck"
-	"golang.org/x/pkgsite-metrics/internal/worker"
 )
 
 // main function for govulncheck sandbox that accepts four inputs
@@ -44,13 +44,14 @@
 		fail(errors.New("need four args: govulncheck path, mode, input module dir or binary, full path to vuln db"))
 		return
 	}
-	mode := args[1]
-	if !worker.IsValidGovulncheckMode(mode) {
-		fail(fmt.Errorf("%q is not a valid mode", mode))
+
+	modeFlag := args[1]
+	if modeFlag == govulncheck.FlagBinary {
+		fail(errors.New("binaries are only analyzed in compare_sandbox"))
 		return
 	}
 
-	resp, err := runGovulncheck(args[0], mode, args[2], args[3])
+	resp, err := runGovulncheck(args[0], modeFlag, args[2], args[3])
 	if err != nil {
 		fail(err)
 		return
@@ -65,21 +66,12 @@
 	fmt.Println()
 }
 
-func runGovulncheck(govulncheckPath, mode, filePath, vulnDBDir string) (*govulncheck.SandboxResponse, error) {
+func runGovulncheck(govulncheckPath, modeFlag, filePath, vulnDBDir string) (*govulncheck.SandboxResponse, error) {
 	response := govulncheck.SandboxResponse{
 		Stats: govulncheck.ScanStats{},
 	}
-	var modeFlag, pattern string
-	switch mode {
-	case govulncheck.ModeBinary:
-		modeFlag = govulncheck.FlagBinary
-		pattern = filePath
-	case govulncheck.ModeGovulncheck:
-		modeFlag = govulncheck.FlagSource
-		pattern = "./..."
-	}
 
-	findings, err := govulncheck.RunGovulncheckCmd(govulncheckPath, modeFlag, pattern, filePath, vulnDBDir, &response.Stats)
+	findings, err := govulncheck.RunGovulncheckCmd(govulncheckPath, modeFlag, "./...", filePath, vulnDBDir, &response.Stats)
 	if err != nil {
 		return nil, err
 	}
diff --git a/cmd/govulncheck_sandbox/govulncheck_sandbox_test.go b/cmd/govulncheck_sandbox/govulncheck_sandbox_test.go
index 98e0d53..e369d81 100644
--- a/cmd/govulncheck_sandbox/govulncheck_sandbox_test.go
+++ b/cmd/govulncheck_sandbox/govulncheck_sandbox_test.go
@@ -6,8 +6,6 @@
 
 import (
 	"bytes"
-	"os"
-	"os/exec"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -15,10 +13,8 @@
 
 	"golang.org/x/exp/slices"
 	"golang.org/x/pkgsite-metrics/internal/buildtest"
-	"golang.org/x/pkgsite-metrics/internal/derrors"
 	"golang.org/x/pkgsite-metrics/internal/govulncheck"
 	"golang.org/x/pkgsite-metrics/internal/govulncheckapi"
-	"golang.org/x/pkgsite-metrics/internal/worker"
 )
 
 func Test(t *testing.T) {
@@ -54,7 +50,7 @@
 	}
 
 	t.Run("source", func(t *testing.T) {
-		resp, err := runTest([]string{govulncheckPath, worker.ModeGovulncheck, module, vulndb})
+		resp, err := runTest([]string{govulncheckPath, govulncheck.FlagSource, module, vulndb})
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -68,22 +64,6 @@
 		}
 	})
 
-	t.Run("binary", func(t *testing.T) {
-		t.Skip("govulncheck may not support the Go version")
-		binary := filepath.Join(module, "vuln")
-		cmd := exec.Command("go", "build")
-		cmd.Dir = module
-		if _, err := cmd.Output(); err != nil {
-			t.Fatal(derrors.IncludeStderr(err))
-		}
-		defer os.Remove(binary)
-		resp, err := runTest([]string{govulncheckPath, worker.ModeBinary, binary, vulndb})
-		if err != nil {
-			t.Fatal(err)
-		}
-		checkVuln(t, resp.Findings)
-	})
-
 	// Errors
 	for _, test := range []struct {
 		name string
@@ -97,17 +77,22 @@
 		},
 		{
 			name: "no vulndb",
-			args: []string{govulncheckPath, worker.ModeGovulncheck, module, "DNE"},
+			args: []string{govulncheckPath, govulncheck.FlagSource, module, "DNE"},
 			want: "URL missing path",
 		},
 		{
 			name: "no mode",
-			args: []string{govulncheckPath, "MODE", module, vulndb},
+			args: []string{govulncheckPath, "unsupported mode", module, vulndb},
 			want: "not a valid mode",
 		},
 		{
+			name: "no mode",
+			args: []string{govulncheckPath, govulncheck.FlagBinary, module, vulndb},
+			want: "binaries are only analyzed",
+		},
+		{
 			name: "no module",
-			args: []string{govulncheckPath, worker.ModeGovulncheck, "nosuchmodule", vulndb},
+			args: []string{govulncheckPath, govulncheck.FlagSource, "nosuchmodule", vulndb},
 			// Once govulncheck destinguishes this issue from no .mod file,
 			// update want to reflect govulncheck's new output
 			want: "no go.mod",
diff --git a/internal/worker/govulncheck_enqueue.go b/internal/worker/govulncheck_enqueue.go
index 60d6694..01b18a4 100644
--- a/internal/worker/govulncheck_enqueue.go
+++ b/internal/worker/govulncheck_enqueue.go
@@ -12,14 +12,11 @@
 	"sort"
 	"strings"
 
-	"cloud.google.com/go/storage"
 	"golang.org/x/pkgsite-metrics/internal/config"
 	"golang.org/x/pkgsite-metrics/internal/derrors"
 	"golang.org/x/pkgsite-metrics/internal/govulncheck"
-	"golang.org/x/pkgsite-metrics/internal/log"
 	"golang.org/x/pkgsite-metrics/internal/queue"
 	"golang.org/x/pkgsite-metrics/internal/scan"
-	"google.golang.org/api/iterator"
 )
 
 // handleEnqueue enqueues multiple modules for a single govulncheck mode.
@@ -82,21 +79,13 @@
 		modspecs []scan.ModuleSpec
 	)
 	for _, mode := range modes {
-		var reqs []*govulncheck.Request
-		if mode == ModeBinary {
-			reqs, err = readBinaries(ctx, cfg.BinaryBucket)
+		if modspecs == nil {
+			modspecs, err = readModules(ctx, cfg, params.File, params.Min)
 			if err != nil {
 				return nil, err
 			}
-		} else {
-			if modspecs == nil {
-				modspecs, err = readModules(ctx, cfg, params.File, params.Min)
-				if err != nil {
-					return nil, err
-				}
-			}
-			reqs = moduleSpecsToGovulncheckScanRequests(modspecs, mode)
 		}
+		reqs := moduleSpecsToGovulncheckScanRequests(modspecs, mode)
 		for _, req := range reqs {
 			if req.Module != "std" { // ignore the standard library
 				tasks = append(tasks, req)
@@ -134,37 +123,3 @@
 	}
 	return mode, nil
 }
-
-// gcsBinaryDir is the directory in the GCS bucket that contains binaries that should be scanned.
-const gcsBinaryDir = "binaries"
-
-func readBinaries(ctx context.Context, bucketName string) (reqs []*govulncheck.Request, err error) {
-	defer derrors.Wrap(&err, "readBinaries(%q)", bucketName)
-	if bucketName == "" {
-		log.Infof(ctx, "binary bucket not configured; not enqueuing binaries")
-		return nil, nil
-	}
-	c, err := storage.NewClient(ctx)
-	if err != nil {
-		return nil, err
-	}
-	iter := c.Bucket(bucketName).Objects(ctx, &storage.Query{Prefix: gcsBinaryDir})
-	for {
-		attrs, err := iter.Next()
-		if err == iterator.Done {
-			break
-		}
-		if err != nil {
-			return nil, err
-		}
-		mp, err := scan.ParseModuleURLPath(strings.TrimPrefix(attrs.Name, gcsBinaryDir+"/"))
-		if err != nil {
-			return nil, err
-		}
-		reqs = append(reqs, &govulncheck.Request{
-			ModuleURLPath: mp,
-			QueryParams:   govulncheck.QueryParams{Mode: ModeBinary},
-		})
-	}
-	return reqs, nil
-}
diff --git a/internal/worker/govulncheck_enqueue_test.go b/internal/worker/govulncheck_enqueue_test.go
index d59c766..a206109 100644
--- a/internal/worker/govulncheck_enqueue_test.go
+++ b/internal/worker/govulncheck_enqueue_test.go
@@ -6,7 +6,6 @@
 
 import (
 	"context"
-	"flag"
 	"fmt"
 	"testing"
 
@@ -17,39 +16,6 @@
 	"golang.org/x/pkgsite-metrics/internal/scan"
 )
 
-var binaryBucket = flag.String("binary-bucket", "", "bucket for scannable binaries")
-
-func TestReadBinaries(t *testing.T) {
-	if *binaryBucket == "" {
-		t.Skip("missing -binary-bucket")
-	}
-	sreqs, err := readBinaries(context.Background(), *binaryBucket)
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := &govulncheck.Request{
-		ModuleURLPath: scan.ModuleURLPath{
-			Module:  "golang.org/x/pkgsite",
-			Version: "v0.0.0-20221004150836-873fb37c2479",
-			Suffix:  "cmd/worker",
-		},
-		QueryParams: govulncheck.QueryParams{Mode: ModeBinary},
-	}
-	found := false
-	for _, sr := range sreqs {
-		if *sr == *want {
-			found = true
-			break
-		}
-	}
-	if !found {
-		t.Errorf("did not find %+v in results:", want)
-		for _, r := range sreqs {
-			t.Logf("  %+v", r)
-		}
-	}
-}
-
 func TestCreateQueueTasks(t *testing.T) {
 	vreq := func(path, version, mode string, importedBy int) *govulncheck.Request {
 		return &govulncheck.Request{
@@ -98,7 +64,7 @@
 		want    []string
 		wantErr bool
 	}{
-		{"", true, []string{ModeBinary, ModeGovulncheck}, false},
+		{"", true, []string{ModeGovulncheck}, false},
 		{"", false, []string{ModeGovulncheck}, false},
 		{"imports", true, nil, true},
 	} {
diff --git a/internal/worker/govulncheck_scan.go b/internal/worker/govulncheck_scan.go
index 8ac5bc0..4e1f66d 100644
--- a/internal/worker/govulncheck_scan.go
+++ b/internal/worker/govulncheck_scan.go
@@ -32,10 +32,6 @@
 	// difference in precision of vulnerability detection.
 	modeImports string = "IMPORTS"
 
-	// ModeBinary runs the govulncheck binary in binary mode.
-	// TODO: needed?
-	ModeBinary string = "BINARY"
-
 	// ModeGovulncheck runs the govulncheck binary in default (source) mode.
 	ModeGovulncheck = "GOVULNCHECK"
 
@@ -43,6 +39,10 @@
 	// and binary mode.
 	ModeCompare = "COMPARE"
 
+	// modeBinary is only used by ModeCompare for reporting results. It cannot
+	// be directly triggered by scan endpoints.
+	modeBinary string = "BINARY"
+
 	// sandboxGoCache is the location of the Go cache inside the sandbox. The
 	// user is root and their $HOME directory is /root. The Go cache resides
 	// in its default location, $HOME/.cache/go-build.
@@ -51,13 +51,17 @@
 
 // modes is a set of govulncheck modes externally visible.
 var modes = map[string]bool{
-	ModeBinary:      true,
 	ModeGovulncheck: true,
 	ModeCompare:     true,
 }
 
-func IsValidGovulncheckMode(mode string) bool {
-	return modes[mode]
+func modeToGovulncheckFlag(mode string) string {
+	switch mode {
+	case modeBinary: // for sanity
+		return govulncheck.FlagBinary
+	default:
+		return govulncheck.FlagSource
+	}
 }
 
 var scanCounter = event.NewCounter("scans", &event.MetricOptions{Namespace: metricNamespace})
@@ -242,7 +246,7 @@
 				continue
 			}
 
-			binRow := createComparisonRow(pkg, &results.BinaryResults, baseRow, ModeBinary)
+			binRow := createComparisonRow(pkg, &results.BinaryResults, baseRow, modeBinary)
 			srcRow := createComparisonRow(pkg, &results.SourceResults, baseRow, ModeGovulncheck)
 			log.Infof(ctx, "found %d vulns in binary mode and %d vulns in source mode for package %s (module: %s)", len(binRow.Vulns), len(srcRow.Vulns), pkg, sreq.Path())
 			rows = append(rows, binRow, srcRow)
@@ -267,7 +271,7 @@
 		CommitTime:  baseRow.CommitTime,
 		WorkVersion: baseRow.WorkVersion,
 	}
-	if mode == ModeBinary {
+	if mode == modeBinary {
 		row.ScanMode = "COMPARE - BINARY"
 		row.BinaryBuildSeconds = bigquery.NullFloat(result.Stats.BuildTime.Seconds())
 	} else {
@@ -318,7 +322,7 @@
 
 	log.Infof(ctx, "running scanner.runScanModule: %s@%s", sreq.Path(), sreq.Version)
 	stats := &govulncheck.ScanStats{}
-	vulns, err := s.runScanModule(ctx, sreq.Module, info.Version, sreq.Suffix, sreq.Mode, stats)
+	vulns, err := s.runScanModule(ctx, sreq.Module, info.Version, sreq.Mode, stats)
 	row.ScanSeconds = stats.ScanSeconds
 	row.ScanMemory = int64(stats.ScanMemory)
 	if err != nil {
@@ -381,11 +385,11 @@
 //
 // For ModeGovulncheck, these are all vulns that are actually
 // called. For modeImports, these are all vulns, called or just
-// imported. For ModeBinary, these are exactly all the vulns
+// imported. For modeBinary, these are exactly all the vulns
 // since binary analysis does not distinguish between called
 // and imported vulnerabilities.
 func vulnsForMode(vulns []*govulncheck.Vuln, mode string) []*govulncheck.Vuln {
-	if mode == ModeBinary {
+	if mode == modeBinary {
 		return vulns
 	}
 
@@ -409,28 +413,23 @@
 	return vs
 }
 
-// runScanModule fetches the module version from the proxy, and analyzes it for
-// vulnerabilities.
-func (s *scanner) runScanModule(ctx context.Context, modulePath, version, binaryDir, mode string, stats *govulncheck.ScanStats) (bvulns []*govulncheck.Vuln, err error) {
+// runScanModule fetches the module version from the proxy, and analyzes its source
+// code for vulnerabilities. The analysis of binaries is done in CompareModules.
+func (s *scanner) runScanModule(ctx context.Context, modulePath, version, mode string, stats *govulncheck.ScanStats) (bvulns []*govulncheck.Vuln, err error) {
 	err = doScan(ctx, modulePath, version, s.insecure, func() (err error) {
-		// In ModeBinary, path is a file path to the input binary.
-		// Otherwise, it is a path to the input module directory.
-		inputPath := binaryDir
-		if mode != ModeBinary {
-			// In source analysis modes, download the module first.
-			inputPath = moduleDir(modulePath, version)
-			defer derrors.Cleanup(&err, func() error { return os.RemoveAll(inputPath) })
-			const init = true
-			if err := prepareModule(ctx, modulePath, version, inputPath, s.proxyClient, s.insecure, init); err != nil {
-				return err
-			}
+		// Download the module first.
+		inputPath := moduleDir(modulePath, version)
+		defer derrors.Cleanup(&err, func() error { return os.RemoveAll(inputPath) })
+		const init = true
+		if err := prepareModule(ctx, modulePath, version, inputPath, s.proxyClient, s.insecure, init); err != nil {
+			return err
 		}
 
 		var findings []*govulncheckapi.Finding
 		if s.insecure {
-			findings, err = s.runGovulncheckScanInsecure(ctx, modulePath, version, inputPath, mode, stats)
+			findings, err = s.runGovulncheckScanInsecure(inputPath, mode, stats)
 		} else {
-			findings, err = s.runGovulncheckScanSandbox(ctx, modulePath, version, inputPath, mode, stats)
+			findings, err = s.runGovulncheckScanSandbox(ctx, inputPath, mode, stats)
 		}
 		if err != nil {
 			return err
@@ -445,52 +444,12 @@
 	return bvulns, err
 }
 
-func (s *scanner) runGovulncheckScanSandbox(ctx context.Context, modulePath, version, inputPath, mode string, stats *govulncheck.ScanStats) (_ []*govulncheckapi.Finding, err error) {
-	if mode == ModeBinary {
-		return s.runBinaryScanSandbox(ctx, modulePath, version, inputPath, stats)
-	}
-
+func (s *scanner) runGovulncheckScanSandbox(ctx context.Context, inputPath, mode string, stats *govulncheck.ScanStats) (_ []*govulncheckapi.Finding, err error) {
 	smdir := strings.TrimPrefix(inputPath, sandboxRoot)
 	err = s.sbox.Validate()
 	log.Debugf(ctx, "sandbox Validate returned %v", err)
 
-	response, err := s.runGovulncheckSandbox(ctx, ModeGovulncheck, smdir)
-	if err != nil {
-		return nil, err
-	}
-	stats.ScanMemory = response.Stats.ScanMemory
-	stats.ScanSeconds = response.Stats.ScanSeconds
-	return response.Findings, nil
-}
-
-func (s *scanner) runBinaryScanSandbox(ctx context.Context, modulePath, version, binDir string, stats *govulncheck.ScanStats) ([]*govulncheckapi.Finding, error) {
-	if s.gcsBucket == nil {
-		return nil, errors.New("binary bucket not configured; set GO_ECOSYSTEM_BINARY_BUCKET")
-	}
-	// Copy the binary from GCS to the local disk, because vulncheck.Binary
-	// ultimately requires a ReaderAt and GCS doesn't provide that.
-	gcsPathname := fmt.Sprintf("%s/%s@%s/%s", gcsBinaryDir, modulePath, version, binDir)
-	destDir := s.binaryDir
-	log.Debug(ctx, "copying",
-		"from", gcsPathname,
-		"to", destDir,
-		"module", modulePath, "version", version,
-		"dir", binDir)
-	destf, err := os.CreateTemp(destDir, "govulncheck-binary-")
-	if err != nil {
-		return nil, err
-	}
-	defer os.Remove(destf.Name())
-	rc, err := s.gcsBucket.Object(gcsPathname).NewReader(ctx)
-	if err != nil {
-		return nil, err
-	}
-	defer rc.Close()
-	if err := copyAndClose(destf, rc); err != nil {
-		return nil, err
-	}
-
-	response, err := s.runGovulncheckSandbox(ctx, ModeBinary, destf.Name())
+	response, err := s.runGovulncheckSandbox(ctx, modeToGovulncheckFlag(mode), smdir)
 	if err != nil {
 		return nil, err
 	}
@@ -507,7 +466,7 @@
 		log.Debugf(ctx, "Sandbox running %s", goOut)
 	}
 	log.Infof(ctx, "running govulncheck in sandbox: mode %s, arg %q", mode, arg)
-	cmd := s.sbox.Command(filepath.Join(s.binaryDir, "govulncheck_sandbox"), s.govulncheckPath, mode, arg, s.vulnDBDir)
+	cmd := s.sbox.Command(filepath.Join(s.binaryDir, "govulncheck_sandbox"), s.govulncheckPath, modeToGovulncheckFlag(mode), arg, s.vulnDBDir)
 	stdout, err := cmd.Output()
 	log.Infof(ctx, "govulncheck in sandbox finished with err=%v", err)
 	if err != nil {
@@ -527,36 +486,8 @@
 	return govulncheck.UnmarshalCompareResponse(stdout)
 }
 
-func (s *scanner) runGovulncheckScanInsecure(ctx context.Context, modulePath, version, inputPath, mode string, stats *govulncheck.ScanStats) (_ []*govulncheckapi.Finding, err error) {
-	if mode == ModeBinary {
-		return s.runBinaryScanInsecure(ctx, modulePath, version, inputPath, os.TempDir(), stats)
-	}
-
-	findings, err := govulncheck.RunGovulncheckCmd(s.govulncheckPath, govulncheck.FlagSource, "./...", inputPath, s.vulnDBDir, stats)
-	if err != nil {
-		return nil, err
-	}
-	return findings, nil
-}
-
-func (s *scanner) runBinaryScanInsecure(ctx context.Context, modulePath, version, binDir, tempDir string, stats *govulncheck.ScanStats) ([]*govulncheckapi.Finding, error) {
-	if s.gcsBucket == nil {
-		return nil, errors.New("binary bucket not configured; set GO_ECOSYSTEM_BINARY_BUCKET")
-	}
-	// Copy the binary from GCS to the local disk, because govulncheck
-	// ultimately requires a ReaderAt and GCS doesn't provide that.
-	gcsPathname := fmt.Sprintf("%s/%s@%s/%s", gcsBinaryDir, modulePath, version, binDir)
-	log.Debug(ctx, "copying to temp dir",
-		"from", gcsPathname, "module", modulePath, "version", version, "dir", binDir)
-	localPathname := filepath.Join(tempDir, "binary")
-	if err := copyToLocalFile(localPathname, false, gcsPathname, gcsOpenFileFunc(ctx, s.gcsBucket)); err != nil {
-		return nil, err
-	}
-	findings, err := govulncheck.RunGovulncheckCmd(s.govulncheckPath, govulncheck.FlagBinary, localPathname, "", s.vulnDBDir, stats)
-	if err != nil {
-		return nil, err
-	}
-	return findings, nil
+func (s *scanner) runGovulncheckScanInsecure(inputPath, mode string, stats *govulncheck.ScanStats) (_ []*govulncheckapi.Finding, err error) {
+	return govulncheck.RunGovulncheckCmd(s.govulncheckPath, modeToGovulncheckFlag(mode), "./...", inputPath, s.vulnDBDir, stats)
 }
 
 func isGovulncheckLoadError(err error) bool {
diff --git a/internal/worker/govulncheck_scan_test.go b/internal/worker/govulncheck_scan_test.go
index 83c53be..2c4dfa9 100644
--- a/internal/worker/govulncheck_scan_test.go
+++ b/internal/worker/govulncheck_scan_test.go
@@ -5,7 +5,6 @@
 package worker
 
 import (
-	"context"
 	"errors"
 	"fmt"
 	"io"
@@ -14,10 +13,8 @@
 	"strings"
 	"testing"
 
-	"cloud.google.com/go/storage"
 	"golang.org/x/pkgsite-metrics/internal/buildtest"
 	"golang.org/x/pkgsite-metrics/internal/govulncheck"
-	test "golang.org/x/pkgsite-metrics/internal/testing"
 )
 
 func TestAsScanError(t *testing.T) {
@@ -51,7 +48,7 @@
 	}{
 		{modeImports, "A:false, B:false, C:false"},
 		{ModeGovulncheck, "C:true"},
-		{ModeBinary, "A:false, B:false, C:true"},
+		{modeBinary, "A:false, B:false, C:true"},
 	} {
 		tc := tc
 		t.Run(tc.mode, func(t *testing.T) {
@@ -97,54 +94,28 @@
 		t.Fatal(err)
 	}
 
-	ctx := context.Background()
-	for _, tc := range []struct {
-		name  string
-		input string
-		mode  string
-	}{
-		{"source", "../testdata/module", ModeGovulncheck},
-		// test_vuln binary on gcs is built from ../testdata/module.
-		{"binary", "test_vuln", ModeBinary},
-	} {
-		tc := tc
-		t.Run(tc.name, func(t *testing.T) {
-			s := &scanner{insecure: true, govulncheckPath: govulncheckPath, vulnDBDir: vulndb}
+	s := &scanner{insecure: true, govulncheckPath: govulncheckPath, vulnDBDir: vulndb}
 
-			if tc.mode == ModeBinary {
-				test.NeedsIntegrationEnv(t)
-
-				gcsClient, err := storage.NewClient(ctx)
-				if err != nil {
-					t.Fatal(err)
-				}
-				s.gcsBucket = gcsClient.Bucket("go-ecosystem")
-			}
-
-			stats := &govulncheck.ScanStats{}
-			findings, err := s.runGovulncheckScanInsecure(ctx,
-				"golang.org/vuln", "v0.0.0",
-				tc.input, tc.mode, stats)
-			if err != nil {
-				t.Fatal(err)
-			}
-			wantID := "GO-2021-0113"
-			found := false
-			for _, v := range findings {
-				if v.OSV == wantID {
-					found = true
-					break
-				}
-			}
-			if !found {
-				t.Errorf("want %s, did not find it in %d vulns", wantID, len(findings))
-			}
-			if got := stats.ScanSeconds; got <= 0 {
-				t.Errorf("scan time not collected or negative: %v", got)
-			}
-			if got := stats.ScanMemory; got <= 0 && runtime.GOOS == "linux" {
-				t.Errorf("scan memory not collected or negative: %v", got)
-			}
-		})
+	stats := &govulncheck.ScanStats{}
+	findings, err := s.runGovulncheckScanInsecure("../testdata/module", ModeGovulncheck, stats)
+	if err != nil {
+		t.Fatal(err)
+	}
+	wantID := "GO-2021-0113"
+	found := false
+	for _, v := range findings {
+		if v.OSV == wantID {
+			found = true
+			break
+		}
+	}
+	if !found {
+		t.Errorf("want %s, did not find it in %d vulns", wantID, len(findings))
+	}
+	if got := stats.ScanSeconds; got <= 0 {
+		t.Errorf("scan time not collected or negative: %v", got)
+	}
+	if got := stats.ScanMemory; got <= 0 && runtime.GOOS == "linux" {
+		t.Errorf("scan memory not collected or negative: %v", got)
 	}
 }