diff --git a/public/app/features/alerting/unified/utils/notification-policies.test.ts b/public/app/features/alerting/unified/utils/notification-policies.test.ts
index b6f12be2866..9dd13f9dfdd 100644
--- a/public/app/features/alerting/unified/utils/notification-policies.test.ts
+++ b/public/app/features/alerting/unified/utils/notification-policies.test.ts
@@ -476,6 +476,17 @@ describe('matchLabels', () => {
expect(result).toHaveProperty('matches', false);
expect(result.labelsMatch).toMatchSnapshot();
});
+
+ it('does not match unanchored regular expressions', () => {
+ const result = matchLabels([['foo', MatcherOperator.regex, 'bar']], [['foo', 'barbarbar']]);
+ // This may seem unintuitive, but this is how Alertmanager matches, as it anchors the regex
+ expect(result.matches).toEqual(false);
+ });
+
+ it('matches regular expressions with wildcards', () => {
+ const result = matchLabels([['foo', MatcherOperator.regex, '.*bar.*']], [['foo', 'barbarbar']]);
+ expect(result.matches).toEqual(true);
+ });
});
describe('unquoteRouteMatchers', () => {
diff --git a/public/app/features/alerting/unified/utils/notification-policies.ts b/public/app/features/alerting/unified/utils/notification-policies.ts
index 8b419161078..8e60490d7f8 100644
--- a/public/app/features/alerting/unified/utils/notification-policies.ts
+++ b/public/app/features/alerting/unified/utils/notification-policies.ts
@@ -232,8 +232,17 @@ type OperatorPredicate = (labelValue: string, matcherValue: string) => boolean;
const OperatorFunctions: Record = {
[MatcherOperator.equal]: (lv, mv) => lv === mv,
[MatcherOperator.notEqual]: (lv, mv) => lv !== mv,
- [MatcherOperator.regex]: (lv, mv) => new RegExp(mv).test(lv),
- [MatcherOperator.notRegex]: (lv, mv) => !new RegExp(mv).test(lv),
+ // At the time of writing, Alertmanager compiles to another (anchored) Regular Expression,
+ // so we should also anchor our UI matches for consistency with this behaviour
+ // https://github.com/prometheus/alertmanager/blob/fd37ce9c95898ca68be1ab4d4529517174b73c33/pkg/labels/matcher.go#L69
+ [MatcherOperator.regex]: (lv, mv) => {
+ const re = new RegExp(`^(?:${mv})$`);
+ return re.test(lv);
+ },
+ [MatcherOperator.notRegex]: (lv, mv) => {
+ const re = new RegExp(`^(?:${mv})$`);
+ return !re.test(lv);
+ },
};
function isLabelMatchInSet(matcher: ObjectMatcher, labels: Label[]): boolean {