Repository: google/go-flow-levee
Pull request #69 (2020-08-27 16:51:15)

Fix bug in config.IsSinkFunction
`config.IsSinkFunction` uses `Pkg.Name()` when it should use `Pkg.Path()`.

I've reworked the tests to cover this.

- [x] Tests pass
- [x] Appropriate changes to README are included in PR


Patch:
diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go
index 76ac020..58a4379 100644
--- a/internal/pkg/config/config.go
+++ b/internal/pkg/config/config.go
@@ -65,7 +65,7 @@ func (c Config) IsSinkFunction(f *ssa.Function) bool {
 	}
 
 	for _, p := range c.Sinks {
-		if !p.PackageRE.MatchString(f.Pkg.Pkg.Name()) || !p.MethodRE.MatchString(f.Name()) {
+		if !p.PackageRE.MatchString(f.Pkg.Pkg.Path()) || !p.MethodRE.MatchString(f.Name()) {
 			continue
 		}
 		if p.ReceiverRE.MatchString(recvName) {


Test patch:
diff --git a/internal/pkg/config/config_test.go b/internal/pkg/config/config_test.go
index 0c951cf..36d36d9 100644
--- a/internal/pkg/config/config_test.go
+++ b/internal/pkg/config/config_test.go
@@ -52,5 +52,7 @@ func TestConfig(t *testing.T) {
 	if err := FlagSet.Set("config", filepath.Join(testdata, "test-config.json")); err != nil {
 		t.Fatal(err)
 	}
-	analysistest.Run(t, testdata, testAnalyzer, "core", "notcore")
+	for _, p := range []string{"example.com/core", "example.com/notcore", "notexample.com/core"} {
+		analysistest.Run(t, testdata, testAnalyzer, p)
+	}
 }
diff --git a/internal/pkg/config/testdata/src/core/core.go b/internal/pkg/config/testdata/src/example.com/core/core.go
similarity index 100%
rename from internal/pkg/config/testdata/src/core/core.go
rename to internal/pkg/config/testdata/src/example.com/core/core.go
diff --git a/internal/pkg/config/testdata/src/notcore/notcore.go b/internal/pkg/config/testdata/src/example.com/notcore/notcore.go
similarity index 100%
rename from internal/pkg/config/testdata/src/notcore/notcore.go
rename to internal/pkg/config/testdata/src/example.com/notcore/notcore.go
diff --git a/internal/pkg/config/testdata/src/notexample.com/core/core.go b/internal/pkg/config/testdata/src/notexample.com/core/core.go
new file mode 100644
index 0000000..d56edbf
--- /dev/null
+++ b/internal/pkg/config/testdata/src/notexample.com/core/core.go
@@ -0,0 +1,25 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package core
+
+func Sink() {}
+
+func NotSink() {}
+
+type Sinker struct{}
+
+func (s Sinker) Do() {}
+
+func (s Sinker) DoNot() {}
diff --git a/internal/pkg/config/testdata/test-config.json b/internal/pkg/config/testdata/test-config.json
index 4d03234..de3b362 100644
--- a/internal/pkg/config/testdata/test-config.json
+++ b/internal/pkg/config/testdata/test-config.json
@@ -1,11 +1,11 @@
 {
   "Sinks": [
     {
-      "PackageRE": "^core$",
+      "PackageRE": "^example.com/core$",
       "MethodRE": "^Sink$"
     },
     {
-      "PackageRE": "^core$",
+      "PackageRE": "^example.com/core$",
       "MethodRE": "^Do$",
       "TypeRE": "^Sinker$"
     }
diff --git a/internal/pkg/levee/testdata/src/example.com/tests/collections/chans.go b/internal/pkg/levee/testdata/src/example.com/tests/collections/chans.go
new file mode 100644
index 0000000..752cafa
--- /dev/null
+++ b/internal/pkg/levee/testdata/src/example.com/tests/collections/chans.go
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package collections
+
+import (
+	"example.com/core"
+)
+
+func TestSourceReceivedFromChannelIsTainted(sources <-chan core.Source) {
+	s := <-sources
+	core.Sink(s) // want "a source has reached a sink"
+}
+
+func TestChannelIsTaintedWhenSourceIsPlacedOnIt(sources chan<- core.Source) {
+	sources <- core.Source{}
+	core.Sink(sources) // want "a source has reached a sink"
+}
+
+func TestValueObtainedFromTaintedChannelIsTainted(c chan interface{}) {
+	c <- core.Source{}
+	s := <-c
+	core.Sink(s) // want "a source has reached a sink"
+}
+
+func TestChannelIsNoLongerTaintedWhenNilledOut(sources chan core.Source) {
+	sources <- core.Source{}
+	sources = nil
+	core.Sink(sources)
+}