fix(Form Trigger Node): Add default value for authentication parameter to prevent crash on old workflows (#32627)

Co-authored-by: returnSGD <returnSGD@users.noreply.github.com>
This commit is contained in:
Bernhard Wittmann
2026-06-19 09:19:26 +02:00
committed by GitHub
parent ade94af96a
commit 940f389c6f
4 changed files with 37 additions and 8 deletions
@@ -436,7 +436,7 @@ describe('FormTrigger, formWebhook', () => {
.calledWith('formDescription')
.mockReturnValue('Test Description');
executeFunctions.getNodeParameter.calledWith('responseMode').mockReturnValue('onReceived');
executeFunctions.getNodeParameter.calledWith('authentication').mockReturnValue('none');
executeFunctions.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('none');
executeFunctions.getRequestObject.mockReturnValue({ method: 'GET', query: {} } as any);
executeFunctions.getMode.mockReturnValue('manual');
executeFunctions.getInstanceId.mockReturnValue('instanceId');
@@ -447,6 +447,32 @@ describe('FormTrigger, formWebhook', () => {
vi.clearAllMocks();
});
it('renders the form when the node has no stored authentication parameter', async () => {
const ctx = mock<IWebhookFunctions>();
ctx.getNode.mockReturnValue({ typeVersion: 1, name: 'Form Trigger' } as INode);
// Mirror the engine: getNodeParameter throws when the key is absent and
// no default is supplied, but returns the default when one is given.
ctx.getNodeParameter.calledWith('authentication').mockImplementation(() => {
throw new Error('Could not get parameter');
});
ctx.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('none');
ctx.getNodeParameter.calledWith('options').mockReturnValue({});
ctx.getNodeParameter.calledWith('formFields.values').mockReturnValue([]);
ctx.getNodeParameter.calledWith('formTitle').mockReturnValue('Test Form');
ctx.getNodeParameter.calledWith('formDescription').mockReturnValue('');
ctx.getNodeParameter.calledWith('responseMode').mockReturnValue('onReceived');
ctx.getRequestObject.mockReturnValue({ method: 'GET', query: {}, headers: {} } as any);
ctx.getResponseObject.mockReturnValue({ render: vi.fn(), setHeader: vi.fn() } as any);
ctx.getMode.mockReturnValue('manual');
ctx.getInstanceId.mockReturnValue('instanceId');
ctx.getChildNodes.mockReturnValue([]);
await expect(formWebhook(ctx)).resolves.toEqual({ noWebhookResponse: true });
});
it('should call response render', async () => {
const mockRender = vi.fn();
@@ -831,7 +857,7 @@ describe('FormTrigger, formWebhook', () => {
ctx.getNodeParameter.calledWith('formTitle').mockReturnValue('Test Form');
ctx.getNodeParameter.calledWith('formDescription').mockReturnValue('Test Description');
ctx.getNodeParameter.calledWith('responseMode').mockReturnValue('onReceived');
ctx.getNodeParameter.calledWith('authentication').mockReturnValue('n8nUserAuth');
ctx.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('n8nUserAuth');
ctx.getNodeParameter.calledWith('formFields.values').mockReturnValue(formFields);
ctx.getRequestObject.mockReturnValue(request as any);
ctx.getHeaderData.mockReturnValue(request.headers);
@@ -879,7 +905,7 @@ describe('FormTrigger, formWebhook', () => {
};
ctx.getNode.mockReturnValue({ typeVersion: 2.6 } as INode);
ctx.getNodeParameter.calledWith('options').mockReturnValue({});
ctx.getNodeParameter.calledWith('authentication').mockReturnValue('n8nUserAuth');
ctx.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('n8nUserAuth');
ctx.getRequestObject.mockReturnValue({
method: 'GET',
originalUrl: '/form/test',
@@ -793,7 +793,7 @@ export async function formWebhook(
return { noWebhookResponse: true };
}
const authentication = (context.getNodeParameter(authProperty) as string) ?? 'none';
const authentication = context.getNodeParameter(authProperty, 'none') as string;
let authedUser: IUser | undefined;
if (node.typeVersion > 1) {
if (authentication === 'n8nUserAuth') {
@@ -714,7 +714,7 @@ describe('Auth token generation', () => {
await generateFormPostBasicAuthToken(webhookFunctions, 'authentication');
expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith('authentication');
expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith('authentication', 'none');
});
it('should use passed authentication key', async () => {
@@ -725,7 +725,10 @@ describe('Auth token generation', () => {
await generateFormPostBasicAuthToken(webhookFunctions, 'incomingAuthentication');
expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith('incomingAuthentication');
expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith(
'incomingAuthentication',
'none',
);
});
it('should handle "none" authentication', async () => {
+2 -2
View File
@@ -236,7 +236,7 @@ export async function validateWebhookAuthentication(
ctx: IWebhookFunctions,
authPropertyName: string,
): Promise<IDataObject | undefined> {
const authentication = ctx.getNodeParameter(authPropertyName) as string;
const authentication = ctx.getNodeParameter(authPropertyName, 'none') as string;
if (authentication === 'none') return;
const req = ctx.getRequestObject();
@@ -426,7 +426,7 @@ export async function generateFormPostBasicAuthToken(
) {
const node = context.getNode();
const authentication = context.getNodeParameter(authPropertyName);
const authentication = context.getNodeParameter(authPropertyName, 'none');
if (authentication === 'none') return;
let credentials: ICredentialDataDecryptedObject | undefined;