internal/worker: set executable bit on copied analysis binary

Change-Id: Ibf7beaacea4d902ac441e84a86cf4575e7b65a8c
Reviewed-on: https://go-review.googlesource.com/c/pkgsite-metrics/+/472176
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
diff --git a/internal/worker/analysis.go b/internal/worker/analysis.go
index 45d5dd0..e27b449 100644
--- a/internal/worker/analysis.go
+++ b/internal/worker/analysis.go
@@ -171,7 +171,7 @@
 		return err
 	}
 	bucket := c.Bucket(binaryBucket)
-	return copyFromGCS(ctx, bucket, path.Join(analysisBinariesBucketDir, srcPath), destPath)
+	return copyFromGCS(ctx, bucket, path.Join(analysisBinariesBucketDir, srcPath), destPath, true)
 }
 
 // Run the binary on the module.
diff --git a/internal/worker/vulncheck_scan.go b/internal/worker/vulncheck_scan.go
index 2f6855a..e8ac0ce 100644
--- a/internal/worker/vulncheck_scan.go
+++ b/internal/worker/vulncheck_scan.go
@@ -608,7 +608,7 @@
 	log.Debug(ctx, "copying to temp dir",
 		"from", gcsPathname, "module", modulePath, "version", version, "dir", binDir)
 	localPathname := filepath.Join(tempDir, "binary")
-	if err := copyFromGCS(ctx, s.gcsBucket, gcsPathname, localPathname); err != nil {
+	if err := copyFromGCS(ctx, s.gcsBucket, gcsPathname, localPathname, false); err != nil {
 		return nil, err
 	}
 
@@ -634,9 +634,15 @@
 	return res.Vulns, nil
 }
 
-func copyFromGCS(ctx context.Context, bucket *storage.BucketHandle, srcPath, destPath string) (err error) {
+func copyFromGCS(ctx context.Context, bucket *storage.BucketHandle, srcPath, destPath string, executable bool) (err error) {
 	defer derrors.Wrap(&err, "copyFromGCS(%q, %q)", srcPath, destPath)
-	destf, err := os.Create(destPath)
+	var mode os.FileMode
+	if executable {
+		mode = 0755
+	} else {
+		mode = 0644
+	}
+	destf, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
 	if err != nil {
 		return err
 	}