cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.22.2

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/discovery/discovery.go

132lines · modecode

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