@@ -57,6 +57,12 @@ const aliasOfAllRules = "*"
5757
5858var generatedCodePattern = regexp .MustCompile (`^// Code generated .* DO NOT EDIT\.$` )
5959
60+ // ignoreLocation keeps the location of an ignored rule
61+ type ignoreLocation struct {
62+ file string
63+ line string
64+ }
65+
6066// The Context is populated with data parsed from the source code as it is scanned.
6167// It is passed through to all rule functions as they are called. Rules may use
6268// this data in conjunction with the encountered AST node.
@@ -69,7 +75,7 @@ type Context struct {
6975 Root * ast.File
7076 Imports * ImportTracker
7177 Config Config
72- Ignores [ ]map [string ][]issue.SuppressionInfo
78+ Ignores map [ ignoreLocation ]map [string ][]issue.SuppressionInfo
7379 PassedValues map [string ]interface {}
7480}
7581
@@ -360,7 +366,7 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
360366 if result != nil {
361367 if passIssues , ok := result .([]* issue.Issue ); ok {
362368 for _ , iss := range passIssues {
363- gosec .updateIssues (iss , false , []issue. SuppressionInfo {} )
369+ gosec .updateIssues (iss )
364370 }
365371 }
366372 }
@@ -521,10 +527,8 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
521527// Visit runs the gosec visitor logic over an AST created by parsing go code.
522528// Rule methods added with AddRule will be invoked as necessary.
523529func (gosec * Analyzer ) Visit (n ast.Node ) ast.Visitor {
524- ignores , ok := gosec .updateIgnoredRules (n )
525- if ! ok {
526- return gosec
527- }
530+ // Update any potentially ignored rules at the node location
531+ gosec .updateIgnoredRules (n )
528532
529533 // Using ast.File instead of ast.ImportSpec, so that we can track all imports at once.
530534 switch i := n .(type ) {
@@ -533,56 +537,55 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
533537 }
534538
535539 for _ , rule := range gosec .ruleset .RegisteredFor (n ) {
536- suppressions , ignored := gosec .updateSuppressions (rule .ID (), ignores )
537540 issue , err := rule .Match (n , gosec .context )
538541 if err != nil {
539542 file , line := GetLocation (n , gosec .context )
540543 file = path .Base (file )
541544 gosec .logger .Printf ("Rule error: %v => %s (%s:%d)\n " , reflect .TypeOf (rule ), err , file , line )
542545 }
543- gosec .updateIssues (issue , ignored , suppressions )
546+ gosec .updateIssues (issue )
544547 }
545548 return gosec
546549}
547550
548- func (gosec * Analyzer ) updateIgnoredRules (n ast.Node ) (map [string ][]issue.SuppressionInfo , bool ) {
549- if n == nil {
550- if len (gosec .context .Ignores ) > 0 {
551- gosec .context .Ignores = gosec .context .Ignores [1 :]
552- }
553- return nil , false
554- }
555- // Get any new rule exclusions.
551+ func (gosec * Analyzer ) updateIgnoredRules (n ast.Node ) {
556552 ignoredRules := gosec .ignore (n )
557-
558- // Now create the union of exclusions.
559- ignores := map [string ][]issue.SuppressionInfo {}
560- if len (gosec .context .Ignores ) > 0 {
561- for k , v := range gosec .context .Ignores [0 ] {
562- ignores [k ] = v
553+ if len (ignoredRules ) > 0 {
554+ if gosec .context .Ignores == nil {
555+ gosec .context .Ignores = make (map [ignoreLocation ]map [string ][]issue.SuppressionInfo )
556+ }
557+ line := issue .GetLine (gosec .context .FileSet .File (n .Pos ()), n )
558+ ignoreLocation := ignoreLocation {
559+ file : gosec .context .FileSet .File (n .Pos ()).Name (),
560+ line : line ,
561+ }
562+ current , ok := gosec .context .Ignores [ignoreLocation ]
563+ if ! ok {
564+ current = map [string ][]issue.SuppressionInfo {}
563565 }
566+ for r , s := range ignoredRules {
567+ if current [r ] == nil {
568+ current [r ] = []issue.SuppressionInfo {}
569+ }
570+ current [r ] = append (current [r ], s )
571+ }
572+ gosec .context .Ignores [ignoreLocation ] = current
564573 }
574+ }
565575
566- for ruleID , suppression := range ignoredRules {
567- ignores [ruleID ] = append (ignores [ruleID ], suppression )
576+ func (gosec * Analyzer ) getSuppressionsAtLineInFile (file string , line string , id string ) ([]issue.SuppressionInfo , bool ) {
577+ ignores , ok := gosec .context .Ignores [ignoreLocation {file : file , line : line }]
578+ if ! ok {
579+ ignores = make (map [string ][]issue.SuppressionInfo )
568580 }
569581
570- // Push the new set onto the stack.
571- gosec .context .Ignores = append ([]map [string ][]issue.SuppressionInfo {ignores }, gosec .context .Ignores ... )
572-
573- return ignores , true
574- }
575-
576- func (gosec * Analyzer ) updateSuppressions (id string , ignores map [string ][]issue.SuppressionInfo ) ([]issue.SuppressionInfo , bool ) {
577- // Check if all rules are ignored.
582+ // Check if the rule was specifically suppressed at this location.
578583 generalSuppressions , generalIgnored := ignores [aliasOfAllRules ]
579- // Check if the specific rule is ignored
580584 ruleSuppressions , ruleIgnored := ignores [id ]
581-
582585 ignored := generalIgnored || ruleIgnored
583586 suppressions := append (generalSuppressions , ruleSuppressions ... )
584587
585- // Track external suppressions.
588+ // Track external suppressions of this rule .
586589 if gosec .ruleset .IsRuleSuppressed (id ) {
587590 ignored = true
588591 suppressions = append (suppressions , issue.SuppressionInfo {
@@ -593,8 +596,9 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.
593596 return suppressions , ignored
594597}
595598
596- func (gosec * Analyzer ) updateIssues (issue * issue.Issue , ignored bool , suppressions []issue. SuppressionInfo ) {
599+ func (gosec * Analyzer ) updateIssues (issue * issue.Issue ) {
597600 if issue != nil {
601+ suppressions , ignored := gosec .getSuppressionsAtLineInFile (issue .File , issue .Line , issue .RuleID )
598602 if gosec .showIgnored {
599603 issue .NoSec = ignored
600604 }
0 commit comments