cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.17.3

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

cmd/pint/scan.go

170lines · modecode

1package main
2
3import (
4 "context"
5 "regexp"
6 "strconv"
7 "sync"
8 "time"
9
10 "github.com/rs/zerolog/log"
11
12 "github.com/cloudflare/pint/internal/checks"
13 "github.com/cloudflare/pint/internal/config"
14 "github.com/cloudflare/pint/internal/discovery"
15 "github.com/cloudflare/pint/internal/output"
16 "github.com/cloudflare/pint/internal/reporter"
17)
18
19var yamlErrRe = regexp.MustCompile("^yaml: line (.+): (.+)$")
20
21const yamlParseReporter = "yaml/parse"
22
23func tryDecodingYamlError(e string) (int, string) {
24 parts := yamlErrRe.FindStringSubmatch(e)
25 if len(parts) > 2 {
26 line, err := strconv.Atoi(parts[1])
27 if err != nil {
28 return 1, e
29 }
30 return line, parts[2]
31 }
32 return 1, e
33}
34
35func checkRules(ctx context.Context, workers int, cfg config.Config, entries []discovery.Entry) (summary reporter.Summary) {
36 jobs := make(chan scanJob, workers*5)
37 results := make(chan reporter.Report, workers*5)
38 wg := sync.WaitGroup{}
39
40 for w := 1; w <= workers; w++ {
41 wg.Add(1)
42 go func() {
43 defer wg.Done()
44 scanWorker(ctx, jobs, results)
45 }()
46 }
47
48 go func() {
49 defer close(results)
50 wg.Wait()
51 }()
52
53 go func() {
54 for _, entry := range entries {
55 if entry.PathError == nil && entry.Rule.Error.Err == nil {
56 if entry.Rule.RecordingRule != nil {
57 rulesParsedTotal.WithLabelValues(config.RecordingRuleType).Inc()
58 log.Debug().
59 Str("path", entry.Path).
60 Str("record", entry.Rule.RecordingRule.Record.Value.Value).
61 Str("lines", output.FormatLineRangeString(entry.Rule.Lines())).
62 Msg("Found recording rule")
63 }
64 if entry.Rule.AlertingRule != nil {
65 rulesParsedTotal.WithLabelValues(config.AlertingRuleType).Inc()
66 log.Debug().
67 Str("path", entry.Path).
68 Str("alert", entry.Rule.AlertingRule.Alert.Value.Value).
69 Str("lines", output.FormatLineRangeString(entry.Rule.Lines())).
70 Msg("Found alerting rule")
71 }
72
73 checkList := cfg.GetChecksForRule(ctx, entry.Path, entry.Rule)
74 for _, check := range checkList {
75 check := check
76 jobs <- scanJob{entry: entry, allEntries: entries, check: check}
77 }
78 } else {
79 if entry.Rule.Error.Err != nil {
80 log.Debug().
81 Str("path", entry.Path).
82 Str("lines", output.FormatLineRangeString(entry.Rule.Lines())).
83 Msg("Found invalid rule")
84 rulesParsedTotal.WithLabelValues(config.InvalidRuleType).Inc()
85 }
86
87 jobs <- scanJob{entry: entry, allEntries: entries, check: nil}
88 }
89 }
90 defer close(jobs)
91 }()
92
93 for result := range results {
94 summary.Reports = append(summary.Reports, result)
95 }
96
97 lastRunTime.SetToCurrentTime()
98
99 return
100}
101
102type scanJob struct {
103 allEntries []discovery.Entry
104 entry discovery.Entry
105 check checks.RuleChecker
106}
107
108func scanWorker(ctx context.Context, jobs <-chan scanJob, results chan<- reporter.Report) {
109 for job := range jobs {
110 job := job
111
112 select {
113 case <-ctx.Done():
114 return
115 default:
116 if job.entry.PathError != nil {
117 line, e := tryDecodingYamlError(job.entry.PathError.Error())
118 results <- reporter.Report{
119 Path: job.entry.Path,
120 ModifiedLines: job.entry.ModifiedLines,
121 Problem: checks.Problem{
122 Lines: []int{line},
123 Reporter: yamlParseReporter,
124 Text: e,
125 Severity: checks.Fatal,
126 },
127 Owner: job.entry.Owner,
128 }
129 } else if job.entry.Rule.Error.Err != nil {
130 results <- reporter.Report{
131 Path: job.entry.Path,
132 ModifiedLines: job.entry.ModifiedLines,
133 Rule: job.entry.Rule,
134 Problem: checks.Problem{
135 Fragment: job.entry.Rule.Error.Fragment,
136 Lines: []int{job.entry.Rule.Error.Line},
137 Reporter: yamlParseReporter,
138 Text: job.entry.Rule.Error.Err.Error(),
139 Severity: checks.Fatal,
140 },
141 Owner: job.entry.Owner,
142 }
143 } else {
144 start := time.Now()
145 probles := job.check.Check(ctx, job.entry.Rule, job.allEntries)
146 duration := time.Since(start)
147 checkDuration.WithLabelValues(job.check.Reporter()).Observe(duration.Seconds())
148 for _, problem := range probles {
149 results <- reporter.Report{
150 Path: job.entry.Path,
151 ModifiedLines: job.entry.ModifiedLines,
152 Rule: job.entry.Rule,
153 Problem: problem,
154 Owner: job.entry.Owner,
155 }
156 }
157 }
158 }
159 }
160}
161
162func submitReports(reps []reporter.Reporter, summary reporter.Summary) (err error) {
163 for _, rep := range reps {
164 err = rep.Submit(summary)
165 if err != nil {
166 return err
167 }
168 }
169 return nil
170}
171