cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.25.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/discovery/discovery.go

141lines · modecode

1package discovery
2
3import (
4 "errors"
5 "os"
6 "regexp"
7 "strings"
8
9 "github.com/prometheus/prometheus/model/rulefmt"
10
11 "github.com/cloudflare/pint/internal/output"
12 "github.com/cloudflare/pint/internal/parser"
13
14 "github.com/rs/zerolog/log"
15)
16
17const (
18 FileOwnerComment = "file/owner"
19 RuleOwnerComment = "rule/owner"
20)
21
22var ignoredErrors = []string{
23 "one of 'record' or 'alert' must be set",
24 "could not parse expression: ",
25 "cannot unmarshal !!seq into rulefmt.ruleGroups",
26}
27
28func isStrictIgnored(err error) bool {
29 s := err.Error()
30
31 werr := &rulefmt.WrappedError{}
32 if errors.As(err, &werr) {
33 if uerr := werr.Unwrap(); uerr != nil {
34 s = uerr.Error()
35 }
36 }
37 for _, ign := range ignoredErrors {
38 if strings.Contains(s, ign) {
39 return true
40 }
41 }
42 return false
43}
44
45type RuleFinder interface {
46 Find() ([]Entry, error)
47}
48
49type Entry struct {
50 Path string
51 PathError error
52 ModifiedLines []int
53 Rule parser.Rule
54 Owner string
55}
56
57func readFile(path string, isStrict bool) (entries []Entry, err error) {
58 p := parser.NewParser()
59
60 f, err := os.Open(path)
61 if err != nil {
62 return nil, err
63 }
64
65 content, err := parser.ReadContent(f)
66 f.Close()
67 if err != nil {
68 return nil, err
69 }
70
71 contentLines := []int{}
72 for i := 1; i <= strings.Count(string(content), "\n"); i++ {
73 contentLines = append(contentLines, i)
74 }
75
76 fileOwner, _ := parser.GetComment(string(content), FileOwnerComment)
77
78 if isStrict {
79 if _, errs := rulefmt.Parse(content); len(errs) > 0 {
80 for _, err := range errs {
81 if isStrictIgnored(err) {
82 continue
83 }
84 log.Error().
85 Err(err).
86 Str("path", path).
87 Str("lines", output.FormatLineRangeString(contentLines)).
88 Msg("Failed to unmarshal file content")
89 entries = append(entries, Entry{
90 Path: path,
91 PathError: err,
92 Owner: fileOwner.Value,
93 ModifiedLines: contentLines,
94 })
95 }
96 if len(entries) > 0 {
97 return entries, nil
98 }
99 }
100 }
101
102 rules, err := p.Parse(content)
103 if err != nil {
104 log.Error().
105 Err(err).
106 Str("path", path).
107 Str("lines", output.FormatLineRangeString(contentLines)).
108 Msg("Failed to parse file content")
109 entries = append(entries, Entry{
110 Path: path,
111 PathError: err,
112 Owner: fileOwner.Value,
113 ModifiedLines: contentLines,
114 })
115 return entries, nil
116 }
117
118 for _, rule := range rules {
119 owner, ok := rule.GetComment(RuleOwnerComment)
120 if !ok {
121 owner = fileOwner
122 }
123 entries = append(entries, Entry{
124 Path: path,
125 Rule: rule,
126 Owner: owner.Value,
127 })
128 }
129
130 log.Info().Str("path", path).Int("rules", len(entries)).Msg("File parsed")
131 return entries, nil
132}
133
134func matchesAny(re []*regexp.Regexp, s string) bool {
135 for _, r := range re {
136 if v := r.MatchString(s); v {
137 return true
138 }
139 }
140 return false
141}