fix: Limit declarative routing during base URL ownership checks (#39058)

Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com>
This commit is contained in:
n8n-cat-bot[bot] 2026-09-18 11:31:53 +00:00 committed by GitHub
parent d75fb91d1d
commit 3d00ed98b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 25 additions and 3 deletions

View File

@ -2846,6 +2846,21 @@ describe('RoutingNode', () => {
expect(requestOptions.allowedDomains).toBeUndefined();
});
test('prepares a dynamic path segment when the base URL is static', async () => {
// Regression test for NODE-6014.
const result = await runWithCredential(
{ apiKey: 'testApiKey' },
{
routedUrl: '=/tests/{{toPathSegment($parameter["endpoint"])}}',
nodeParameters: { endpoint: 'project-123' },
},
);
const requestOptions = (result?.[0]?.[0]?.json as { requestOptions: IHttpRequestOptions })
.requestOptions;
expect(requestOptions.url).toBe('/tests/project-123');
});
describe('when requestDefaults.baseURL reads an optional override parameter', () => {
// Mirrors LmChatOpenAi/LmOpenAi/OpenAiAssistant/EmbeddingsOpenAi's
// `$parameter.options?.baseURL || <credential-owned default>` pattern.

View File

@ -886,6 +886,7 @@ export class RoutingNode {
runIndex,
'',
{ ...parameterKeys, $value: value },
true,
);
this.mergeOptions(scratch, tempOptions);
@ -902,6 +903,7 @@ export class RoutingNode {
runIndex: number,
path: string,
additionalKeys?: IWorkflowDataProxyAdditionalKeys,
baseUrlOnly = false,
): DeclarativeRestApiSettings.ResultOptions | undefined {
const returnData: DeclarativeRestApiSettings.ResultOptions = {
options: {
@ -942,11 +944,13 @@ export class RoutingNode {
) as string;
}
if (nodeProperties.routing.operations) {
if (!baseUrlOnly && nodeProperties.routing.operations) {
returnData.requestOperations = { ...nodeProperties.routing.operations };
}
if (nodeProperties.routing.request) {
for (const key of Object.keys(nodeProperties.routing.request)) {
if (baseUrlOnly && key !== 'baseURL') continue;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let propertyValue = (nodeProperties.routing.request as Record<string, any>)[key];
// If the value is an expression resolve it
@ -964,7 +968,7 @@ export class RoutingNode {
}
}
if (nodeProperties.routing.send) {
if (!baseUrlOnly && nodeProperties.routing.send) {
let propertyName = nodeProperties.routing.send.property;
if (propertyName !== undefined) {
// If the propertyName is an expression resolve it
@ -1034,7 +1038,7 @@ export class RoutingNode {
returnData.preSend.push(...nodeProperties.routing.send.preSend);
}
}
if (nodeProperties.routing.output) {
if (!baseUrlOnly && nodeProperties.routing.output) {
if (nodeProperties.routing.output.maxResults !== undefined) {
let maxResultsValue = nodeProperties.routing.output.maxResults;
if (typeof maxResultsValue === 'string' && maxResultsValue.charAt(0) === '=') {
@ -1118,6 +1122,7 @@ export class RoutingNode {
runIndex,
`${basePath}${nodeProperties.name}`,
{ ...additionalKeys, $value: optionValue, $version: node.typeVersion },
baseUrlOnly,
);
this.mergeOptions(returnData, tempOptions);
@ -1142,6 +1147,7 @@ export class RoutingNode {
runIndex,
`${basePath}${nodeProperties.name}`,
{ ...additionalKeys, $version: node.typeVersion },
baseUrlOnly,
);
this.mergeOptions(returnData, tempOptions);
@ -1190,6 +1196,7 @@ export class RoutingNode {
$index: i,
$parent: value[i],
},
baseUrlOnly,
);
this.mergeOptions(returnData, tempOptions);