Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions workspaces/orchestrator/.changeset/heavy-lions-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-orchestrator-backend-module-loki': patch
---

Fix to allow properly quoted LoqQL querys in the selector field
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ describe('LokiProvider', () => {
},
}),
),
).toThrow(/must not contain "\}"/);
).toThrow(/must not contain unquoted "\{" or "\}"/);
});

it('rejects logPipelineFilters containing opening brace', () => {
Expand All @@ -171,13 +171,13 @@ describe('LokiProvider', () => {
loki: {
baseUrl: 'http://localhost:3100',
token: 't',
logPipelineFilters: ['| pattern `{stream}`'],
logPipelineFilters: ['| foo {bar="baz"}'],
},
},
},
}),
),
).toThrow(/must not contain "\{"/);
).toThrow(/must not contain unquoted "\{" or "\}"/);
});

it('rejects logPipelineFilters entries that trim to empty (whitespace-only)', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,47 @@ describe('parseAndValidateLogPipelineFilters', () => {
/orchestrator\.workflowLogProvider\.loki\.logPipelineFilters\[0\]: entry must not contain line breaks/,
);
});

it('accepts line_format with Go template braces inside double quotes', () => {
const mockConfig = {
getOptionalStringArray: () => ['| line_format "{{.message}}"'],
} as unknown as Config;
expect(
parseAndValidateLogPipelineFilters(
mockConfig,
'orchestrator.workflowLogProvider.loki.logPipelineFilters',
),
).toEqual(['| line_format "{{.message}}"']);
});

it('accepts braces inside backtick-quoted pattern literals', () => {
const mockConfig = {
getOptionalStringArray: () => ['| pattern `{stream}`'],
} as unknown as Config;
expect(
parseAndValidateLogPipelineFilters(
mockConfig,
'orchestrator.workflowLogProvider.loki.logPipelineFilters',
),
).toEqual(['| pattern `{stream}`']);
});

it.each([['| json }'], ['| foo {bar="baz"}']])(
'rejects unquoted braces: %s',
raw => {
const mockConfig = {
getOptionalStringArray: () => [raw],
} as unknown as Config;
expect(() =>
parseAndValidateLogPipelineFilters(
mockConfig,
'orchestrator.workflowLogProvider.loki.logPipelineFilters',
),
).toThrow(
/orchestrator\.workflowLogProvider\.loki\.logPipelineFilters\[0\]: entry must not contain unquoted "\{" or "\}"/,
);
},
);
});

describe('hostnameMatchesAllowedHosts', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,55 @@ export function parseAndValidateLogStreamSelectors(
});
}

/**
* Rejects `{` / `}` outside quoted LogQL literals so pipeline config cannot
* close the stream selector (`{...}`) and inject a new selector. Braces inside
* `"..."` or `` `...` `` (e.g. `line_format "{{.message}}"`) are allowed.
*/
function assertNoUnquotedLogQlBraces(element: string, context: string): void {
let i = 0;
while (i < element.length) {
const ch = element[i];
if (ch === '"') {
i = skipQuotedString(element, i + 1, '"', context);
continue;
}
if (ch === '`') {
i = skipQuotedString(element, i + 1, '`', context);
continue;
}
if (ch === '{' || ch === '}') {
throw new InputError(
`${context}: entry must not contain unquoted "{" or "}"`,
);
}
i++;
}
}

function skipQuotedString(
element: string,
start: number,
quote: '"' | '`',
context: string,
): number {
let i = start;
while (i < element.length) {
const ch = element[i];
if (quote === '"' && ch === '\\') {
i += 2;
continue;
}
if (ch === quote) {
return i + 1;
}
i++;
}
throw new InputError(
`${context}: entry contains an unclosed ${quote === '"' ? 'double-quoted' : 'backtick-quoted'} string`,
);
}

/**
* Reads and validates `logPipelineFilters` at startup.
*/
Expand All @@ -200,12 +249,7 @@ export function parseAndValidateLogPipelineFilters(
if (/[\r\n\u2028\u2029]/.test(element)) {
throw new InputError(`${ctx}: entry must not contain line breaks`);
}
if (element.includes('{')) {
throw new InputError(`${ctx}: entry must not contain "{"`);
}
if (element.includes('}')) {
throw new InputError(`${ctx}: entry must not contain "}"`);
}
assertNoUnquotedLogQlBraces(element, ctx);
return element;
});
}
Expand Down
Loading