Skip to content

Commit

Permalink
fix: fixes for go ga (#1546)
Browse files Browse the repository at this point in the history
* fix: support go versioned imports

* fix: allow identifier patterns to match package names

* fix: better guess for go package names

* fix: also strip go- prefix from packages

* fix: lookup index operand variables

* fix: handle another import case
  • Loading branch information
didroe authored Mar 21, 2024
1 parent 57f6a8a commit 3642a70
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 4 deletions.
142 changes: 142 additions & 0 deletions internal/languages/golang/.snapshots/TestImport--main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
high:
- rule:
cwe_ids:
- "42"
id: import_test
title: Test imports
description: Test imports
documentation_url: ""
line_number: 13
full_filename: main.go
filename: main.go
source:
location:
start: 13
end: 13
column:
start: 2
end: 10
sink:
location:
start: 13
end: 13
column:
start: 2
end: 10
content: ""
parent_line_number: 13
fingerprint: 7cec89718a2276537c30e7b656c0ecb2_0
old_fingerprint: 7cec89718a2276537c30e7b656c0ecb2_0
- rule:
cwe_ids:
- "42"
id: import_test
title: Test imports
description: Test imports
documentation_url: ""
line_number: 14
full_filename: main.go
filename: main.go
source:
location:
start: 14
end: 14
column:
start: 2
end: 10
sink:
location:
start: 14
end: 14
column:
start: 2
end: 10
content: ""
parent_line_number: 14
fingerprint: 7cec89718a2276537c30e7b656c0ecb2_1
old_fingerprint: 7cec89718a2276537c30e7b656c0ecb2_1
- rule:
cwe_ids:
- "42"
id: import_test
title: Test imports
description: Test imports
documentation_url: ""
line_number: 15
full_filename: main.go
filename: main.go
source:
location:
start: 15
end: 15
column:
start: 2
end: 10
sink:
location:
start: 15
end: 15
column:
start: 2
end: 10
content: ""
parent_line_number: 15
fingerprint: 7cec89718a2276537c30e7b656c0ecb2_2
old_fingerprint: 7cec89718a2276537c30e7b656c0ecb2_2
- rule:
cwe_ids:
- "42"
id: import_test
title: Test imports
description: Test imports
documentation_url: ""
line_number: 16
full_filename: main.go
filename: main.go
source:
location:
start: 16
end: 16
column:
start: 2
end: 10
sink:
location:
start: 16
end: 16
column:
start: 2
end: 10
content: ""
parent_line_number: 16
fingerprint: 7cec89718a2276537c30e7b656c0ecb2_3
old_fingerprint: 7cec89718a2276537c30e7b656c0ecb2_3
- rule:
cwe_ids:
- "42"
id: import_test
title: Test imports
description: Test imports
documentation_url: ""
line_number: 17
full_filename: main.go
filename: main.go
source:
location:
start: 17
end: 17
column:
start: 2
end: 10
sink:
location:
start: 17
end: 17
column:
start: 2
end: 10
content: ""
parent_line_number: 17
fingerprint: 7cec89718a2276537c30e7b656c0ecb2_4
old_fingerprint: 7cec89718a2276537c30e7b656c0ecb2_4

31 changes: 27 additions & 4 deletions internal/languages/golang/analyzer/analyzer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package analyzer

import (
"regexp"
"strings"

sitter "github.com/smacker/go-tree-sitter"
Expand All @@ -11,6 +12,9 @@ import (
"github.com/bearer/bearer/internal/util/stringutil"
)

var versionRegex = regexp.MustCompile(`\Av\d+\z`)
var versionSuffixRegex = regexp.MustCompile(`\.v\d+\z`)

type analyzer struct {
builder *tree.Builder
scope *language.Scope
Expand Down Expand Up @@ -58,7 +62,7 @@ func (analyzer *analyzer) Analyze(node *sitter.Node, visitChildren func() error)
case "identifier":
return visitChildren()
case "index_expression":
return visitChildren()
return analyzer.analyzeIndexExpression(node, visitChildren)
default:
analyzer.builder.Dataflow(node, analyzer.builder.ChildrenFor(node)...)
return visitChildren()
Expand Down Expand Up @@ -95,14 +99,26 @@ func (analyzer *analyzer) analyzeImportSpec(node *sitter.Node, visitChildren fun
name := node.ChildByFieldName("name")
path := node.ChildByFieldName("path")

var guessedName string
if name != nil {
analyzer.scope.Declare(analyzer.builder.ContentFor(name), path)
guessedName = analyzer.builder.ContentFor(name)
} else {
packageName := strings.Split(analyzer.builder.ContentFor(path), "/")
guessedName := stringutil.StripQuotes((packageName[len(packageName)-1]))
analyzer.scope.Declare(guessedName, path)
guessedName = stringutil.StripQuotes((packageName[len(packageName)-1]))

// account for imports like `github.com/airbrake/gobrake/v5`
if versionRegex.MatchString(guessedName) && len(packageName) > 1 {
guessedName = stringutil.StripQuotes((packageName[len(packageName)-2]))
}

// account for imports like `github.com/foo/bar.v3`
guessedName = versionSuffixRegex.ReplaceAllString(guessedName, "")
}

guessedName = strings.TrimSuffix(guessedName, "-go")
guessedName = strings.TrimPrefix(guessedName, "go-")
analyzer.scope.Declare(guessedName, path)

return visitChildren()
}

Expand Down Expand Up @@ -179,6 +195,13 @@ func (analyzer *analyzer) analyzeSelectorExpression(node *sitter.Node, visitChil
return visitChildren()
}

// foo[bar]
func (analyzer *analyzer) analyzeIndexExpression(node *sitter.Node, visitChildren func() error) error {
analyzer.lookupVariable(node.ChildByFieldName("operand"))

return visitChildren()
}

// method parameter declaration
//
// fn(a string)
Expand Down
7 changes: 7 additions & 0 deletions internal/languages/golang/golang_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@ var loggerRule []byte
//go:embed testdata/scope_rule.yml
var scopeRule []byte

//go:embed testdata/import_rule.yml
var importRule []byte

func TestFlow(t *testing.T) {
testhelper.GetRunner(t, loggerRule, "Go").RunTest(t, "./testdata/testcases/flow", ".snapshots/flow/")
}

func TestScope(t *testing.T) {
testhelper.GetRunner(t, scopeRule, "Go").RunTest(t, "./testdata/scope", ".snapshots/")
}

func TestImport(t *testing.T) {
testhelper.GetRunner(t, importRule, "Go").RunTest(t, "./testdata/import", ".snapshots/")
}
4 changes: 4 additions & 0 deletions internal/languages/golang/pattern/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ func (*Pattern) IsRoot(node *tree.Node) bool {
}

func (patternLanguage *Pattern) NodeTypes(node *tree.Node) []string {
if node.Type() == "identifier" && node.Parent().Type() == "source_file" {
return []string{"identifier", "package_identifier"}
}

return []string{node.Type()}
}

Expand Down
19 changes: 19 additions & 0 deletions internal/languages/golang/testdata/import/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"example.com/a/v5"
"example.com/b"
"example.com/c-go.v5"
"example.com/go-d"

e "example.com/foo"
)

func m() {
a.Test()
b.Test()
c.Test()
d.Test()
e.Test()
other.Test()
}
23 changes: 23 additions & 0 deletions internal/languages/golang/testdata/import_rule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
languages:
- go
patterns:
- pattern: $<PACKAGE>.Test()
filters:
- variable: PACKAGE
detection: import_test_package
scope: cursor
auxiliary:
- id: import_test_package
patterns:
- import ($<!>"example.com/a/v5")
- import ($<!>"example.com/b")
- import ($<!>"example.com/c-go.v5")
- import ($<!>"example.com/go-d")
- import ($<!>"example.com/foo")
severity: high
metadata:
description: Test imports
remediation_message: Test imports
cwe_id:
- 42
id: import_test

0 comments on commit 3642a70

Please sign in to comment.