Influx: Improve variable regex handling (#111853)

This commit is contained in:
Andreas Christou
2025-10-02 15:57:39 +02:00
committed by GitHub
parent d04d4782b7
commit b50737a76c
2 changed files with 36 additions and 10 deletions
@@ -273,6 +273,15 @@ describe('interpolateQueryExpr', () => {
replace: jest.fn().mockImplementation((...rest: unknown[]) => 'templateVarReplaced'), replace: jest.fn().mockImplementation((...rest: unknown[]) => 'templateVarReplaced'),
} as unknown as TemplateSrv; } as unknown as TemplateSrv;
let ds = getMockInfluxDS(getMockDSInstanceSettings(), templateSrvStub); let ds = getMockInfluxDS(getMockDSInstanceSettings(), templateSrvStub);
// Mock console.warn as we expect tests to use it
beforeEach(() => {
jest.spyOn(console, 'warn').mockImplementation();
});
afterEach(() => {
jest.restoreAllMocks();
});
it('should return the value as it is', () => { it('should return the value as it is', () => {
const value = 'normalValue'; const value = 'normalValue';
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build(); const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
@@ -281,6 +290,18 @@ describe('interpolateQueryExpr', () => {
expect(result).toBe(expectation); expect(result).toBe(expectation);
}); });
it('should return the escaped value if the value wrapped in regex without !~ or =~', () => {
const value = '/special/path';
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
const result = ds.interpolateQueryExpr(
value,
variableMock,
'select atan(z/sqrt(3.14)), that where path /$tempVar/'
);
const expectation = `\\/special\\/path`;
expect(result).toBe(expectation);
});
it('should return the escaped value if the value wrapped in regex', () => { it('should return the escaped value if the value wrapped in regex', () => {
const value = '/special/path'; const value = '/special/path';
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build(); const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
@@ -360,10 +360,7 @@ export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery,
// we want to see how it's been used. If it is used in a regex expression // we want to see how it's been used. If it is used in a regex expression
// we escape it. Otherwise, we return it directly. // we escape it. Otherwise, we return it directly.
// The regex below searches for regexes within the query string // The regex below searches for regexes within the query string
const regexMatcher = new RegExp( const regexMatcher = new RegExp(/(?<=\/).+?(?=\/)/, 'gm');
/(\s*(=|!)~\s*)\/((?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+)\/((?:g(?:im?|mi?)?|i(?:gm?|mg?)?|m(?:gi?|ig?)?)?)/,
'gm'
);
// If matches are found this regex is evaluated to check if the variable is contained in the regex /^...$/ (^ and $ is optional) // If matches are found this regex is evaluated to check if the variable is contained in the regex /^...$/ (^ and $ is optional)
// i.e. /^$myVar$/ or /$myVar/ or /^($myVar)$/ // i.e. /^$myVar$/ or /$myVar/ or /^($myVar)$/
const regex = new RegExp(`\\/(?:\\^)?(.*)(\\$${variable.name})(.*)(?:\\$)?\\/`, 'gm'); const regex = new RegExp(`\\/(?:\\^)?(.*)(\\$${variable.name})(.*)(?:\\$)?\\/`, 'gm');
@@ -377,14 +374,22 @@ export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery,
if (!queryMatches) { if (!queryMatches) {
return value; return value;
} }
// Use the variable specific regex against the query
if (!query.match(regex)) {
return value;
}
for (const match of queryMatches) { for (const match of queryMatches) {
if (!match.match(regex)) { // It is expected that the RegExp should be valid. As our regex matcher matches any text between two '/'
continue; // we also validate that the expression compiles before assuming it is a regular expression.
} try {
new RegExp(match);
// If the value is a string array first escape them then join them with pipe // If the value is a string array first escape them then join them with pipe
// then put inside parenthesis. // then put inside parenthesis.
return typeof value === 'string' ? escapeRegex(value) : `(${value.map((v) => escapeRegex(v)).join('|')})`; return typeof value === 'string' ? escapeRegex(value) : `(${value.map((v) => escapeRegex(v)).join('|')})`;
} catch (e) {
console.warn(`Supplied match is not valid regex: ${match}`);
}
} }
return value; return value;