■ ■ ■ ■ ■ ■
new/detector/evaluator/evaluator.go
| skipped 4 lines |
5 | 5 | | "strings" |
6 | 6 | | |
7 | 7 | | "github.com/bearer/bearer/new/detector/types" |
8 | | - | "github.com/bearer/bearer/new/language/tree" |
9 | 8 | | langtree "github.com/bearer/bearer/new/language/tree" |
10 | 9 | | languagetypes "github.com/bearer/bearer/new/language/types" |
11 | 10 | | "golang.org/x/exp/slices" |
12 | 11 | | ) |
13 | 12 | | |
14 | 13 | | type evaluator struct { |
15 | | - | lang languagetypes.Language |
16 | | - | detectorSet types.DetectorSet |
17 | | - | detectionCache map[langtree.NodeID]map[string][]*types.Detection |
18 | | - | executingDetectors map[langtree.NodeID][]string |
19 | | - | fileName string |
| 14 | + | lang languagetypes.Language |
| 15 | + | detectorSet types.DetectorSet |
| 16 | + | detectionCache map[langtree.NodeID]map[string][]*types.Detection |
| 17 | + | executingDetectors map[langtree.NodeID][]string |
| 18 | + | fileName string |
| 19 | + | rulesDisabledForNodes map[string][]*langtree.Node |
20 | 20 | | } |
21 | 21 | | |
22 | 22 | | func New( |
| skipped 5 lines |
28 | 28 | | detectionCache := make(map[langtree.NodeID]map[string][]*types.Detection) |
29 | 29 | | |
30 | 30 | | return &evaluator{ |
31 | | - | lang: lang, |
32 | | - | fileName: fileName, |
33 | | - | detectorSet: detectorSet, |
34 | | - | detectionCache: detectionCache, |
35 | | - | executingDetectors: make(map[langtree.NodeID][]string), |
| 31 | + | lang: lang, |
| 32 | + | fileName: fileName, |
| 33 | + | detectorSet: detectorSet, |
| 34 | + | detectionCache: detectionCache, |
| 35 | + | executingDetectors: make(map[langtree.NodeID][]string), |
| 36 | + | rulesDisabledForNodes: mapNodesToDisabledRules(tree.RootNode()), |
36 | 37 | | } |
37 | 38 | | } |
38 | 39 | | |
| skipped 70 lines |
109 | 110 | | return detections, nil |
110 | 111 | | } |
111 | 112 | | |
| 113 | + | func (evaluator *evaluator) ruleDisabledForNode(ruleId string, node *langtree.Node) bool { |
| 114 | + | nodesToIgnore := evaluator.rulesDisabledForNodes[ruleId] |
| 115 | + | if nodesToIgnore == nil { |
| 116 | + | return false |
| 117 | + | } |
| 118 | + | |
| 119 | + | // check node |
| 120 | + | for _, ignoredNode := range nodesToIgnore { |
| 121 | + | if ignoredNode.Equal(node) { |
| 122 | + | return true |
| 123 | + | } |
| 124 | + | } |
| 125 | + | |
| 126 | + | // check node ancestors |
| 127 | + | parent := node.Parent() |
| 128 | + | for parent != nil { |
| 129 | + | for _, ignoredNode := range nodesToIgnore { |
| 130 | + | if ignoredNode.Equal(parent) { |
| 131 | + | return true |
| 132 | + | } |
| 133 | + | } |
| 134 | + | |
| 135 | + | parent = parent.Parent() |
| 136 | + | } |
| 137 | + | |
| 138 | + | return false |
| 139 | + | } |
| 140 | + | |
| 141 | + | func mapNodesToDisabledRules(rootNode *langtree.Node) map[string][]*langtree.Node { |
| 142 | + | res := make(map[string][]*langtree.Node) |
| 143 | + | var disabledRules []string |
| 144 | + | err := rootNode.Walk(func(node *langtree.Node, visitChildren func() error) error { |
| 145 | + | if node.Type() == "comment" { |
| 146 | + | // reset rules skipped array |
| 147 | + | disabledRules = []string{} |
| 148 | + | |
| 149 | + | nodeContent := node.Content() |
| 150 | + | if strings.Contains(nodeContent, "bearer:disable") { |
| 151 | + | ruleIdsStr := strings.Split(nodeContent, "bearer:disable")[1] |
| 152 | + | |
| 153 | + | for _, ruleId := range strings.Split(ruleIdsStr, ",") { |
| 154 | + | disabledRules = append(disabledRules, strings.TrimSpace(ruleId)) |
| 155 | + | } |
| 156 | + | } |
| 157 | + | |
| 158 | + | return visitChildren() |
| 159 | + | } |
| 160 | + | |
| 161 | + | // add rules skipped and node to result map |
| 162 | + | for _, ruleId := range disabledRules { |
| 163 | + | res[ruleId] = append(res[ruleId], node) |
| 164 | + | } |
| 165 | + | |
| 166 | + | // reset rules skipped array |
| 167 | + | disabledRules = []string{} |
| 168 | + | return visitChildren() |
| 169 | + | }) |
| 170 | + | |
| 171 | + | // walk itself shouldn't trigger an error, and we aren't creating any |
| 172 | + | if err != nil { |
| 173 | + | panic(err) |
| 174 | + | } |
| 175 | + | |
| 176 | + | return res |
| 177 | + | } |
| 178 | + | |
112 | 179 | | func (evaluator *evaluator) nonUnifiedNodeDetections( |
113 | 180 | | node *langtree.Node, |
114 | 181 | | detectorType string, |
| skipped 64 lines |
179 | 246 | | } |
180 | 247 | | |
181 | 248 | | func (evaluator *evaluator) detectAtNode(node *langtree.Node, detectorType string) error { |
| 249 | + | if evaluator.ruleDisabledForNode(detectorType, node) { |
| 250 | + | return nil |
| 251 | + | } |
| 252 | + | |
182 | 253 | | return evaluator.withCycleProtection(node, detectorType, func() error { |
183 | 254 | | detections, err := evaluator.detectorSet.DetectAt(node, detectorType, evaluator) |
184 | 255 | | if err != nil { |
| skipped 12 lines |
197 | 268 | | }) |
198 | 269 | | } |
199 | 270 | | |
200 | | - | func (evaluator *evaluator) withCycleProtection(node *tree.Node, detectorType string, body func() error) error { |
| 271 | + | func (evaluator *evaluator) withCycleProtection(node *langtree.Node, detectorType string, body func() error) error { |
201 | 272 | | nodeID := node.ID() |
202 | 273 | | |
203 | 274 | | executingDetectors := evaluator.executingDetectors[nodeID] |
| skipped 26 lines |