Prometheus: Fix escaping of quotation marks for variables (#93415)

* Prometheus: Fix escaping of quotation marks for non-regex variables

* Prometheus: Fix escaping of double quotation marks for regex variables

* Prometheus: Add escaping for adhoc filter label queries
This commit is contained in:
Brad Cowie 2024-11-06 23:19:09 +13:00 committed by GitHub
parent 228bf711f9
commit 2bfdee73e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 12 deletions

View File

@ -289,6 +289,16 @@ describe('PrometheusDatasource', () => {
operator: '=~',
value: `v'.*`,
},
{
key: 'k3',
operator: '=~',
value: `v".*`,
},
{
key: 'k4',
operator: '=~',
value: `\\v.*`,
},
];
ds.query({
interval: '15s',
@ -298,7 +308,7 @@ describe('PrometheusDatasource', () => {
} as DataQueryRequest<PromQuery>);
const [result] = fetchMockCalledWith(fetchMock);
expect(result).toMatchObject({
expr: `metric{job="foo", k1=~"v.*", k2=~"v\\\\'.*"} - metric{k1=~"v.*", k2=~"v\\\\'.*"}`,
expr: `metric{job="foo", k1=~"v.*", k2=~"v'.*", k3=~"v\\".*", k4=~"\\\\v.*"} - metric{k1=~"v.*", k2=~"v'.*", k3=~"v\\".*", k4=~"\\\\v.*"}`,
});
});
});
@ -478,8 +488,12 @@ describe('PrometheusDatasource', () => {
expect(prometheusRegularEscape('cryptodepression')).toEqual('cryptodepression');
});
it("should escape '", () => {
expect(prometheusRegularEscape("looking'glass")).toEqual("looking\\\\'glass");
it("should not escape '", () => {
expect(prometheusRegularEscape("looking'glass")).toEqual("looking'glass");
});
it('should escape "', () => {
expect(prometheusRegularEscape('looking"glass')).toEqual('looking\\"glass');
});
it('should escape \\', () => {
@ -487,11 +501,11 @@ describe('PrometheusDatasource', () => {
});
it('should escape multiple characters', () => {
expect(prometheusRegularEscape("'looking'glass'")).toEqual("\\\\'looking\\\\'glass\\\\'");
expect(prometheusRegularEscape('"looking"glass"')).toEqual('\\"looking\\"glass\\"');
});
it('should escape multiple different characters', () => {
expect(prometheusRegularEscape("'loo\\king'glass'")).toEqual("\\\\'loo\\\\king\\\\'glass\\\\'");
expect(prometheusRegularEscape('"loo\\king"glass"')).toEqual('\\"loo\\\\king\\"glass\\"');
});
});
@ -500,8 +514,9 @@ describe('PrometheusDatasource', () => {
expect(prometheusSpecialRegexEscape('cryptodepression')).toEqual('cryptodepression');
});
it('should escape $^*+?.()|\\', () => {
it('should escape $^*+?.()|\\"', () => {
expect(prometheusSpecialRegexEscape("looking'glass")).toEqual("looking\\\\'glass");
expect(prometheusSpecialRegexEscape('looking"glass')).toEqual('looking\\\\\\"glass');
expect(prometheusSpecialRegexEscape('looking{glass')).toEqual('looking\\\\{glass');
expect(prometheusSpecialRegexEscape('looking}glass')).toEqual('looking\\\\}glass');
expect(prometheusSpecialRegexEscape('looking[glass')).toEqual('looking\\\\[glass');
@ -549,8 +564,8 @@ describe('PrometheusDatasource', () => {
});
describe('and value is a string', () => {
it('should only escape single quotes', () => {
expect(ds.interpolateQueryExpr("abc'$^*{}[]+?.()|", customVariable)).toEqual("abc\\\\'$^*{}[]+?.()|");
it('should only escape double quotes and backslashes', () => {
expect(ds.interpolateQueryExpr('abc\'"$^*{}[]+?.()|\\', customVariable)).toEqual('abc\'\\"$^*{}[]+?.()|\\\\');
});
});

View File

@ -640,7 +640,7 @@ export class PrometheusDatasource
const labelFilters: QueryBuilderLabelFilter[] = options.filters.map((f) => ({
label: f.key,
value: f.value,
value: prometheusRegularEscape(f.value),
op: f.operator,
}));
const expr = promQueryModeller.renderLabels(labelFilters);
@ -672,7 +672,7 @@ export class PrometheusDatasource
const labelFilters: QueryBuilderLabelFilter[] = options.filters.map((f) => ({
label: f.key,
value: f.value,
value: prometheusRegularEscape(f.value),
op: f.operator,
}));
@ -1045,9 +1045,14 @@ export function extractRuleMappingFromGroups(groups: RawRecordingRules[]): RuleQ
// in language_utils.ts, but they are not exactly the same algorithm, and we found
// no way to reuse one in the another or vice versa.
export function prometheusRegularEscape<T>(value: T) {
return typeof value === 'string' ? value.replace(/\\/g, '\\\\').replace(/'/g, "\\\\'") : value;
return typeof value === 'string' ? value.replace(/\\/g, '\\\\').replace(/"/g, '\\"') : value;
}
export function prometheusSpecialRegexEscape<T>(value: T) {
return typeof value === 'string' ? value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]\'+?.()|]/g, '\\\\$&') : value;
return typeof value === 'string'
? value
.replace(/\\/g, '\\\\\\\\')
.replace(/"/g, '\\\\\\"')
.replace(/[$^*{}\[\]\'+?.()|]/g, '\\\\$&')
: value;
}