Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,13 @@ You could put the description or justification text for the annotation. The
justification should be after the rule(s) to suppress and start with two or
more dashes, e.g: `//#nosec G101 G102 -- This is a false positive`

In some cases you may also want to revisit places where `#nosec` annotations
Alternatively, gosec also supports the `//gosec:disable` directive, which functions similar to `#nosec`:

```go
//gosec:disable G101 -- This is a false positive
```

In some cases you may also want to revisit places where `#nosec` or `//gosec:disable` annotations
have been used. To run the scanner and ignore any `#nosec` annotations you
can do the following:

Expand Down
100 changes: 63 additions & 37 deletions analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const externalSuppressionJustification = "Globally suppressed."

const aliasOfAllRules = "*"

var directiveRegexp = regexp.MustCompile("^//gosec:disable(?: (.+))?$")

type ignore struct {
start int
end int
Expand Down Expand Up @@ -582,53 +584,77 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
}

for _, group := range groups {
comment := strings.TrimSpace(group.Text())
foundDefaultTag := strings.HasPrefix(comment, noSecDefaultTag) || regexp.MustCompile("\n *"+noSecDefaultTag).MatchString(comment)
foundAlternativeTag := strings.HasPrefix(comment, noSecAlternativeTag) || regexp.MustCompile("\n *"+noSecAlternativeTag).MatchString(comment)

if foundDefaultTag || foundAlternativeTag {
gosec.stats.NumNosec++

// Discard what's in front of the nosec tag.
if foundDefaultTag {
comment = strings.SplitN(comment, noSecDefaultTag, 2)[1]
} else {
comment = strings.SplitN(comment, noSecAlternativeTag, 2)[1]
}
found, args := findNoSecDirective(group, noSecDefaultTag, noSecAlternativeTag)
if !found {
continue
}

// Extract the directive and the justification.
justification := ""
commentParts := regexp.MustCompile(`-{2,}`).Split(comment, 2)
directive := commentParts[0]
if len(commentParts) > 1 {
justification = strings.TrimSpace(strings.TrimRight(commentParts[1], "\n"))
}
gosec.stats.NumNosec++

// Pull out the specific rules that are listed to be ignored.
re := regexp.MustCompile(`(G\d{3})`)
matches := re.FindAllStringSubmatch(directive, -1)
// Extract the directive and the justification.
justification := ""
commentParts := regexp.MustCompile(`-{2,}`).Split(args, 2)
directive := commentParts[0]
if len(commentParts) > 1 {
justification = strings.TrimSpace(strings.TrimRight(commentParts[1], "\n"))
}

suppression := issue.SuppressionInfo{
Kind: "inSource",
Justification: justification,
}
// Pull out the specific rules that are listed to be ignored.
re := regexp.MustCompile(`(G\d{3})`)
matches := re.FindAllStringSubmatch(directive, -1)

// Find the rule IDs to ignore.
ignores := make(map[string]issue.SuppressionInfo)
for _, v := range matches {
ignores[v[1]] = suppression
}
suppression := issue.SuppressionInfo{
Kind: "inSource",
Justification: justification,
}

// If no specific rules were given, ignore everything.
if len(matches) == 0 {
ignores[aliasOfAllRules] = suppression
}
return ignores
// Find the rule IDs to ignore.
ignores := make(map[string]issue.SuppressionInfo)
for _, v := range matches {
ignores[v[1]] = suppression
}

// If no specific rules were given, ignore everything.
if len(matches) == 0 {
ignores[aliasOfAllRules] = suppression
}
return ignores
}
return nil
}

// findNoSecDirective checks if the comment group contains `#nosec` or `//gosec:disable` directive.
// If found, it returns true and the directive's arguments.
func findNoSecDirective(group *ast.CommentGroup, noSecDefaultTag, noSecAlternativeTag string) (bool, string) {
// Check if the comment grounp has a nosec comment.
for _, tag := range []string{noSecDefaultTag, noSecAlternativeTag} {
if found, args := findNoSecTag(group, tag); found {
return true, args
}
}

// Check if the comment group has a directive comment.
for _, c := range group.List {
match := directiveRegexp.FindStringSubmatch(c.Text)
if len(match) > 0 {
return true, match[0]
}
}

return false, ""
}

func findNoSecTag(group *ast.CommentGroup, tag string) (bool, string) {
comment := strings.TrimSpace(group.Text())

if strings.HasPrefix(comment, tag) || regexp.MustCompile("\n *"+tag).MatchString(comment) {
// Discard what's in front of the nosec tag.
return true, strings.SplitN(comment, tag, 2)[1]
}

return false, ""
}

// Visit runs the gosec visitor logic over an AST created by parsing go code.
// Rule methods added with AddRule will be invoked as necessary.
func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
Expand Down
Loading
Loading