mirror of
https://github.com/prymitive/karma
synced 2026-08-23 11:56:20 +00:00
Merge pull request #1546 from prymitive/anchor-regexes
fix(backend): anchor all regexes in the config
This commit is contained in:
+3
-2
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/prymitive/karma/internal/alertmanager"
|
||||
"github.com/prymitive/karma/internal/config"
|
||||
"github.com/prymitive/karma/internal/models"
|
||||
"github.com/prymitive/karma/internal/regex"
|
||||
"github.com/prymitive/karma/internal/slices"
|
||||
)
|
||||
|
||||
@@ -188,7 +189,7 @@ func newSilenceACLFromConfig(cfg config.SilenceACLRule) (*silenceACL, error) {
|
||||
}
|
||||
|
||||
if filter.NameRegex != "" {
|
||||
re, err := regexp.Compile(filter.NameRegex)
|
||||
re, err := regex.CompileAnchored(filter.NameRegex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ACL rule, failed to parse name_re %q: %s", filter.NameRegex, err)
|
||||
}
|
||||
@@ -196,7 +197,7 @@ func newSilenceACLFromConfig(cfg config.SilenceACLRule) (*silenceACL, error) {
|
||||
}
|
||||
|
||||
if filter.ValueRegex != "" {
|
||||
re, err := regexp.Compile(filter.ValueRegex)
|
||||
re, err := regex.CompileAnchored(filter.ValueRegex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ACL rule, failed to parse value_re %q: %s", filter.ValueRegex, err)
|
||||
}
|
||||
|
||||
+3
-3
@@ -9,7 +9,6 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -17,6 +16,7 @@ import (
|
||||
"github.com/prymitive/karma/internal/alertmanager"
|
||||
"github.com/prymitive/karma/internal/config"
|
||||
"github.com/prymitive/karma/internal/models"
|
||||
"github.com/prymitive/karma/internal/regex"
|
||||
"github.com/prymitive/karma/internal/transform"
|
||||
"github.com/prymitive/karma/internal/uri"
|
||||
|
||||
@@ -80,7 +80,7 @@ func headerAuth(name, valueRegex string) gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
r := regexp.MustCompile("^" + valueRegex + "$")
|
||||
r := regex.MustCompileAnchored(valueRegex)
|
||||
matches := r.FindAllStringSubmatch(user, 1)
|
||||
if len(matches) > 0 && len(matches[0]) > 1 {
|
||||
c.Set(gin.AuthUserKey, matches[0][1])
|
||||
@@ -274,7 +274,7 @@ func mainSetup(errorHandling pflag.ErrorHandling) (*gin.Engine, error) {
|
||||
if rule.Regex == "" || rule.URITemplate == "" {
|
||||
return nil, fmt.Errorf("Invalid link detect rule, regex '%s' uriTemplate '%s'", rule.Regex, rule.URITemplate)
|
||||
}
|
||||
re, err := regexp.Compile(rule.Regex)
|
||||
re, err := regex.CompileAnchored(rule.Regex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid link detect rule '%s': %s", rule.Regex, err)
|
||||
}
|
||||
|
||||
@@ -203,9 +203,11 @@ matchers:
|
||||
Filter works by comparing `name` and `name_re` with silence matcher `name`,
|
||||
`value` and `value_re` with silence matcher `value` and `isRegex` on the
|
||||
filter with `isRegex` on silence matcher. See examples below.
|
||||
All regexes will be automatically anchored.
|
||||
- `matchers:required` - list of additional matchers that must be part of the
|
||||
silence if it matches groups, alertmanagers and filters. This is only used
|
||||
if `action` is set to `requireMatcher`.
|
||||
All regexes will be automatically anchored.
|
||||
Syntax for each matcher:
|
||||
|
||||
```YAML
|
||||
|
||||
@@ -44,7 +44,7 @@ Syntax:
|
||||
authentication:
|
||||
header:
|
||||
name: string
|
||||
value_re: string
|
||||
value_re: regex
|
||||
basicAuth:
|
||||
users:
|
||||
- username: string
|
||||
@@ -59,6 +59,7 @@ authentication:
|
||||
request header value (when `authentication:users:header:name` is set).
|
||||
It must include one numbered capturing group, whatever is matched by that
|
||||
group will be used as the silence form author field.
|
||||
All regexes are anchored.
|
||||
This option must be set when `authentication:users:header:name` is set.
|
||||
- `authentication:users` - list of users (username & password) allowed to login.
|
||||
Passwords are stored plain without any encryption.
|
||||
@@ -654,7 +655,7 @@ labels:
|
||||
custom:
|
||||
foo:
|
||||
- value: string
|
||||
value_re: string
|
||||
value_re: regex
|
||||
color: string
|
||||
keep: list of strings
|
||||
strip: list of strings
|
||||
@@ -674,7 +675,8 @@ labels:
|
||||
|
||||
- `value` - the exact value of the label to match against
|
||||
- `value_re` - Go compatible
|
||||
[regular expression](https://golang.org/pkg/regexp/) to match against
|
||||
[regular expression](https://golang.org/pkg/regexp/) to match against.
|
||||
All regexes will be automatically anchored.
|
||||
- `color`: color to apply if either `value` or `value_re` matches
|
||||
|
||||
Either `value` or `value_re` is required, both can be set in which case
|
||||
@@ -854,7 +856,8 @@ silences:
|
||||
turn them into links.
|
||||
Each rule must specify:
|
||||
- `regex` - regular expression that matches ticket system IDs. Each regex must
|
||||
contain at least one capture group `(regex)`.
|
||||
contain at least one capture group `(regex)`. All regexes will be
|
||||
automatically anchored.
|
||||
- `uriTemplate` - template string that will be used to generate a link.
|
||||
Each template must include `$1` which will be replaced with text matched
|
||||
by the `regex`.
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prymitive/karma/internal/regex"
|
||||
"github.com/prymitive/karma/internal/slices"
|
||||
"github.com/prymitive/karma/internal/uri"
|
||||
|
||||
@@ -243,7 +243,7 @@ func (config *configSchema) Read(flags *pflag.FlagSet) string {
|
||||
}
|
||||
|
||||
if config.Authentication.Header.ValueRegex != "" {
|
||||
_, err = regexp.Compile(config.Authentication.Header.ValueRegex)
|
||||
_, err = regex.CompileAnchored(config.Authentication.Header.ValueRegex)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid regex for authentication.header.value_re: %s", err.Error())
|
||||
}
|
||||
@@ -295,7 +295,7 @@ func (config *configSchema) Read(flags *pflag.FlagSet) string {
|
||||
log.Fatalf("Custom label color for '%s' is missing 'value' or 'value_re'", labelName)
|
||||
}
|
||||
if customColor.ValueRegex != "" {
|
||||
config.Labels.Color.Custom[labelName][i].CompiledRegex, err = regexp.Compile(customColor.ValueRegex)
|
||||
config.Labels.Color.Custom[labelName][i].CompiledRegex, err = regex.CompileAnchored(customColor.ValueRegex)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse custom color regex rule '%s' for '%s' label: %s", customColor.ValueRegex, labelName, err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package regex
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func wrapRegex(r string) string {
|
||||
var prefix, suffix string
|
||||
if !strings.HasPrefix(r, "^") {
|
||||
prefix = "^"
|
||||
}
|
||||
if !strings.HasSuffix(r, "$") {
|
||||
suffix = "$"
|
||||
}
|
||||
return prefix + r + suffix
|
||||
}
|
||||
|
||||
func MustCompileAnchored(r string) *regexp.Regexp {
|
||||
|
||||
return regexp.MustCompile(wrapRegex(r))
|
||||
}
|
||||
|
||||
func CompileAnchored(r string) (*regexp.Regexp, error) {
|
||||
return regexp.Compile(wrapRegex(r))
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package regex_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/prymitive/karma/internal/regex"
|
||||
)
|
||||
|
||||
func TestMustCompileAnchored(t *testing.T) {
|
||||
type testCaseT struct {
|
||||
in string
|
||||
out string
|
||||
}
|
||||
|
||||
testCases := []testCaseT{
|
||||
{in: "foo", out: "^foo$"},
|
||||
{in: "^foo", out: "^foo$"},
|
||||
{in: "foo$", out: "^foo$"},
|
||||
{in: "^foo$", out: "^foo$"},
|
||||
{in: "^^foo$", out: "^^foo$"},
|
||||
{in: "foo$$", out: "^foo$$"},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(fmt.Sprintf("%q => %q", testCase.in, testCase.out), func(t *testing.T) {
|
||||
r := regex.MustCompileAnchored(testCase.in)
|
||||
if r.String() != testCase.out {
|
||||
t.Errorf("Regex mismatch, expected %q got %q", testCase.out, r.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompileAnchored(t *testing.T) {
|
||||
type testCaseT struct {
|
||||
in string
|
||||
out string
|
||||
error bool
|
||||
}
|
||||
|
||||
testCases := []testCaseT{
|
||||
{in: "foo", out: "^foo$"},
|
||||
{in: "^foo", out: "^foo$"},
|
||||
{in: "foo$", out: "^foo$"},
|
||||
{in: "^foo$", out: "^foo$"},
|
||||
{in: "^^foo$", out: "^^foo$"},
|
||||
{in: "foo$$", out: "^foo$$"},
|
||||
{in: ".******", out: "", error: true},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(fmt.Sprintf("%q => %q", testCase.in, testCase.out), func(t *testing.T) {
|
||||
r, err := regex.CompileAnchored(testCase.in)
|
||||
hadError := err != nil
|
||||
if testCase.error != hadError {
|
||||
t.Errorf("CompileAnchored err=%v, expected error=%v", err, testCase.error)
|
||||
}
|
||||
if err == nil {
|
||||
if r.String() != testCase.out {
|
||||
t.Errorf("Regex mismatch, expected %q got %q", testCase.out, r.String())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user