mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Don't crash the page when trying to filter rules by regex (#89466)
This commit is contained in:
parent
27e800768e
commit
c88de7f4d0
@ -256,4 +256,26 @@ describe('filterRules', function () {
|
||||
expect(filtered[0]?.groups[0]?.rules).toHaveLength(1);
|
||||
expect(filtered[0]?.groups[0]?.rules[0]?.name).toBe('CPU too high');
|
||||
});
|
||||
|
||||
it('does not crash when trying to filter with regex-like strings', () => {
|
||||
const rules = [mockCombinedRule({ name: '[alongnameinthefirstgroup]' })];
|
||||
|
||||
const ns = mockCombinedRuleNamespace({
|
||||
name: 'foo|bar',
|
||||
groups: [
|
||||
// Create group with regex-like name so we can test that searching for it doesn't crash,
|
||||
// and so we can test further paths of the filtering
|
||||
// (we need some a group to be matched so we can test filtering by rule name as well)
|
||||
mockCombinedRuleGroup('some|group', rules),
|
||||
],
|
||||
});
|
||||
|
||||
const ruleQuery = '[alongnameinthefirstgroup][thishas spaces][somethingelse]';
|
||||
const namespaceQuery = 'foo|bar';
|
||||
const groupQuery = 'some|group';
|
||||
|
||||
const performFilter = () =>
|
||||
filterRules([ns], getFilter({ groupName: groupQuery, ruleName: ruleQuery, namespace: namespaceQuery }));
|
||||
expect(performFilter).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
@ -28,6 +28,19 @@ import { useURLSearchParams } from './useURLSearchParams';
|
||||
const MAX_NEEDLE_SIZE = 25;
|
||||
const INFO_THRESHOLD = Infinity;
|
||||
|
||||
/**
|
||||
* Escape query strings so that regex characters don't interfere
|
||||
* with uFuzzy search methods.
|
||||
*
|
||||
* The fuzzy searching will take the query and generate a regex - but if the query
|
||||
* contains a regex itself, then it can easily end up being split in a bad place
|
||||
* and end up creating an invalid expression
|
||||
*/
|
||||
const escapeQueryRegex = (query: string) => {
|
||||
// see https://stackoverflow.com/a/6969486
|
||||
return query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
};
|
||||
|
||||
export function useRulesFilter() {
|
||||
const [queryParams, updateQueryParams] = useURLSearchParams();
|
||||
const searchQuery = queryParams.get('search') ?? '';
|
||||
@ -130,10 +143,12 @@ export const filterRules = (
|
||||
if (namespaceFilter) {
|
||||
const namespaceHaystack = filteredNamespaces.map((ns) => ns.name);
|
||||
|
||||
const escapedQuery = escapeQueryRegex(namespaceFilter);
|
||||
|
||||
const ufuzzy = getSearchInstance(namespaceFilter);
|
||||
const [idxs, info, order] = ufuzzy.search(
|
||||
namespaceHaystack,
|
||||
namespaceFilter,
|
||||
escapedQuery,
|
||||
getOutOfOrderLimit(namespaceFilter),
|
||||
INFO_THRESHOLD
|
||||
);
|
||||
@ -157,9 +172,11 @@ const reduceNamespaces = (filterState: RulesFilter) => {
|
||||
const groupsHaystack = filteredGroups.map((g) => g.name);
|
||||
const ufuzzy = getSearchInstance(groupNameFilter);
|
||||
|
||||
const escapedQuery = escapeQueryRegex(groupNameFilter);
|
||||
|
||||
const [idxs, info, order] = ufuzzy.search(
|
||||
groupsHaystack,
|
||||
groupNameFilter,
|
||||
escapedQuery,
|
||||
getOutOfOrderLimit(groupNameFilter),
|
||||
INFO_THRESHOLD
|
||||
);
|
||||
@ -193,10 +210,11 @@ const reduceGroups = (filterState: RulesFilter) => {
|
||||
if (ruleNameQuery) {
|
||||
const rulesHaystack = filteredRules.map((r) => r.name);
|
||||
const ufuzzy = getSearchInstance(ruleNameQuery);
|
||||
const escapedQuery = escapeQueryRegex(ruleNameQuery);
|
||||
|
||||
const [idxs, info, order] = ufuzzy.search(
|
||||
rulesHaystack,
|
||||
ruleNameQuery,
|
||||
escapedQuery,
|
||||
getOutOfOrderLimit(ruleNameQuery),
|
||||
INFO_THRESHOLD
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user