Repository: n8n-io/n8n
Pull request #15356: fix: Remove `variable:read` as a valid API key scope and make `variable:update` selectable in the UI (no-changelog)
Author: login: riascho
Labels: name: n8n team
description: Authored by the n8n team
Created: 2025-05-13T14:37:29Z | Merged: 2025-05-16T17:36:43Z

## Summary

<!--
Describe what the PR does and how to test.
Photos and videos are recommended.
-->

PR makes `variable:update` scope selectable and add test for when the scope middleware is injected (when the scopes feature is enabled)

## Related Linear tickets, Github issues, and Community forum posts

<!--
Include links to **Linear ticket** or Github issue or Community forum post.
Important in order to close *automatically* and provide context to reviewers.
https://linear.app/n8n/issue/
-->
<!-- Use "closes #<issue-number>", "fixes #<issue-number>", or "resolves #<issue-number>" to automatically close issues when the PR is merged. -->


## Review / Merge checklist

- [x] PR title and summary are descriptive. ([conventions](../blob/master/.github/pull_request_title_conventions.md)) <!--
   **Remember, the title automatically goes into the changelog.
   Use `(no-changelog)` otherwise.**
-->
- [x] [Docs updated](https://github.com/n8n-io/n8n-docs) or follow-up ticket created. -> https://github.com/n8n-io/n8n-docs/pull/3154
- [ ] Tests included. <!--
   A bug is not considered fixed, unless a test is added to prevent it from happening again.
   A feature is not complete without tests.
-->
- [ ] PR Labeled with `release/backport` (if the PR is an urgent fix that needs to be backported)



Diff:
diff --git a/packages/@n8n/permissions/src/constants.ee.ts b/packages/@n8n/permissions/src/constants.ee.ts
index ed2270fb97a24..3e984b26d302f 100644
--- a/packages/@n8n/permissions/src/constants.ee.ts
+++ b/packages/@n8n/permissions/src/constants.ee.ts
@@ -30,7 +30,7 @@ export const RESOURCES = {
 export const API_KEY_RESOURCES = {
 	tag: [...DEFAULT_OPERATIONS] as const,
 	workflow: [...DEFAULT_OPERATIONS, 'move', 'activate', 'deactivate'] as const,
-	variable: DEFAULT_OPERATIONS,
+	variable: ['create', 'update', 'delete', 'list'] as const,
 	securityAudit: ['generate'] as const,
 	project: ['create', 'update', 'delete', 'list'] as const,
 	user: ['read', 'list', 'create', 'changeRole', 'delete'] as const,
diff --git a/packages/@n8n/permissions/src/public-api-permissions.ee.ts b/packages/@n8n/permissions/src/public-api-permissions.ee.ts
index 92bf4e3d4fe9d..c05e9998097c5 100644
--- a/packages/@n8n/permissions/src/public-api-permissions.ee.ts
+++ b/packages/@n8n/permissions/src/public-api-permissions.ee.ts
@@ -15,6 +15,7 @@ export const OWNER_API_KEY_SCOPES: ApiKeyScope[] = [
 	'variable:create',
 	'variable:delete',
 	'variable:list',
+	'variable:update',
 	'tag:create',
 	'tag:read',
 	'tag:update',
diff --git a/packages/cli/test/integration/public-api/endpoints-with-scopes-enabled.test.ts b/packages/cli/test/integration/public-api/endpoints-with-scopes-enabled.test.ts
index 45db327cf13c7..6978734649375 100644
--- a/packages/cli/test/integration/public-api/endpoints-with-scopes-enabled.test.ts
+++ b/packages/cli/test/integration/public-api/endpoints-with-scopes-enabled.test.ts
@@ -1,4 +1,4 @@
-import type { TagEntity } from '@n8n/db';
+import type { TagEntity, Variables } from '@n8n/db';
 import { ApiKeyRepository } from '@n8n/db';
 import { CredentialsRepository } from '@n8n/db';
 import { ProjectRepository } from '@n8n/db';
@@ -22,7 +22,7 @@ import {
 	createUser,
 	getUserById,
 } from '@test-integration/db/users';
-import { createVariable, getVariableOrFail } from '@test-integration/db/variables';
+import { createVariable, getVariableByIdOrFail } from '@test-integration/db/variables';
 import { createWorkflow } from '@test-integration/db/workflows';
 import { randomName } from '@test-integration/random';
 import type { CredentialPayload, SaveCredentialFunction } from '@test-integration/types';
@@ -57,6 +57,7 @@ describe('Public API endpoints with feat:apiKeyScopes enabled', () => {
 			'quota:maxTeamProjects': -1,
 		},
 	});
+
 	let apiKeyRepository: ApiKeyRepository;
 
 	beforeAll(async () => {
@@ -979,7 +980,7 @@ describe('Public API endpoints with feat:apiKeyScopes enabled', () => {
 					 * Assert
 					 */
 					expect(response.status).toBe(201);
-					await expect(getVariableOrFail(response.body.id)).resolves.toEqual(
+					await expect(getVariableByIdOrFail(response.body.id)).resolves.toEqual(
 						expect.objectContaining(variablePayload),
 					);
 				});
@@ -1005,6 +1006,36 @@ describe('Public API endpoints with feat:apiKeyScopes enabled', () => {
 					expect(response.status).toBe(403);
 				});
 			});
+
+			describe('PUT /variables/:id', () => {
+				const variablePayload = { key: 'updatedKey', value: 'updatedValue' };
+				let variable: Variables;
+				beforeEach(async () => {
+					variable = await createVariable();
+				});
+
+				it('should update a variable if API key has scope "variable:update"', async () => {
+					const owner = await createOwnerWithApiKey({ scopes: ['variable:update'] });
+
+					const response = await testServer
+						.publicApiAgentFor(owner)
+						.put(`/variables/${variable.id}`)
+						.send(variablePayload);
+
+					expect(response.status).toBe(204);
+					const updatedVariable = await getVariableByIdOrFail(variable.id);
+					expect(updatedVariable).toEqual(expect.objectContaining(variablePayload));
+				});
+
+				test('should fail to update variable when API key doesn\'t have "variable:update" scope', async () => {
+					const owner = await createOwnerWithApiKey({ scopes: ['variable:list'] });
+
+					await testServer
+						.publicApiAgentFor(owner)
+						.put(`/variables/${variable.id}`)
+						.send(variablePayload);
+				});
+			});
 		});
 
 		describe('projects', () => {
diff --git a/packages/cli/test/integration/public-api/variables.test.ts b/packages/cli/test/integration/public-api/variables.test.ts
index 98befd8745344..d3b46a5b31933 100644
--- a/packages/cli/test/integration/public-api/variables.test.ts
+++ b/packages/cli/test/integration/public-api/variables.test.ts
@@ -2,7 +2,7 @@ import type { User, Variables } from '@n8n/db';
 
 import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
 import { createOwnerWithApiKey } from '@test-integration/db/users';
-import { createVariable, getVariableOrFail } from '@test-integration/db/variables';
+import { createVariable, getVariableByIdOrFail } from '@test-integration/db/variables';
 import { setupTestServer } from '@test-integration/utils';
 
 import * as testDb from '../shared/test-db';
@@ -83,7 +83,7 @@ describe('Variables in Public API', () => {
 			 * Assert
 			 */
 			expect(response.status).toBe(201);
-			await expect(getVariableOrFail(response.body.id)).resolves.toEqual(
+			await expect(getVariableByIdOrFail(response.body.id)).resolves.toEqual(
 				expect.objectContaining(variablePayload),
 			);
 		});
@@ -126,7 +126,7 @@ describe('Variables in Public API', () => {
 				.send(variablePayload);
 
 			expect(response.status).toBe(204);
-			const updatedVariable = await getVariableOrFail(variable.id);
+			const updatedVariable = await getVariableByIdOrFail(variable.id);
 			expect(updatedVariable).toEqual(expect.objectContaining(variablePayload));
 		});
 
@@ -164,7 +164,7 @@ describe('Variables in Public API', () => {
 			 * Assert
 			 */
 			expect(response.status).toBe(204);
-			await expect(getVariableOrFail(variable.id)).rejects.toThrow();
+			await expect(getVariableByIdOrFail(variable.id)).rejects.toThrow();
 		});
 
 		it('if not licensed, should reject', async () => {
diff --git a/packages/cli/test/integration/shared/db/variables.ts b/packages/cli/test/integration/shared/db/variables.ts
index 9f1835533babe..c703c024438ee 100644
--- a/packages/cli/test/integration/shared/db/variables.ts
+++ b/packages/cli/test/integration/shared/db/variables.ts
@@ -3,10 +3,34 @@ import { VariablesRepository } from '@n8n/db';
 import { Container } from '@n8n/di';
 import { randomString } from 'n8n-workflow';
 
+import { VariablesService } from '@/environments.ee/variables/variables.service.ee';
+
 export async function createVariable(key = randomString(5), value = randomString(5)) {
-	return await Container.get(VariablesRepository).save({ id: generateNanoId(), key, value });
+	const result = await Container.get(VariablesRepository).save({
+		id: generateNanoId(),
+		key,
+		value,
+	});
+	await Container.get(VariablesService).updateCache();
+	return result;
 }
 
-export async function getVariableOrFail(id: string) {
+export async function getVariableByIdOrFail(id: string) {
 	return await Container.get(VariablesRepository).findOneOrFail({ where: { id } });
 }
+
+export async function getVariableByKey(key: string) {
+	return await Container.get(VariablesRepository).findOne({
+		where: {
+			key,
+		},
+	});
+}
+
+export async function getVariableById(id: string) {
+	return await Container.get(VariablesRepository).findOne({
+		where: {
+			id,
+		},
+	});
+}
diff --git a/packages/cli/test/integration/variables.test.ts b/packages/cli/test/integration/variables.test.ts
index 526a3ba6820fc..c8a28155bd93d 100644
--- a/packages/cli/test/integration/variables.test.ts
+++ b/packages/cli/test/integration/variables.test.ts
@@ -1,10 +1,8 @@
 import type { Variables } from '@n8n/db';
-import { generateNanoId } from '@n8n/db';
-import { VariablesRepository } from '@n8n/db';
 import { Container } from '@n8n/di';
 
-import { VariablesService } from '@/environments.ee/variables/variables.service.ee';
 import { CacheService } from '@/services/cache/cache.service';
+import { createVariable, getVariableById, getVariableByKey } from '@test-integration/db/variables';
 
 import { createOwner, createUser } from './shared/db/users';
 import * as testDb from './shared/test-db';
@@ -17,32 +15,6 @@ let authMemberAgent: SuperAgentTest;
 const testServer = utils.setupTestServer({ endpointGroups: ['variables'] });
 const license = testServer.license;
 
-async function createVariable(key: string, value: string) {
-	const result = await Container.get(VariablesRepository).save({
-		id: generateNanoId(),
-		key,
-		value,
-	});
-	await Container.get(VariablesService).updateCache();
-	return result;
-}
-
-async function getVariableByKey(key: string) {
-	return await Container.get(VariablesRepository).findOne({
-		where: {
-			key,
-		},
-	});
-}
-
-async function getVariableById(id: string) {
-	return await Container.get(VariablesRepository).findOne({
-		where: {
-			id,
-		},
-	});
-}
-
 beforeAll(async () => {
 	const owner = await createOwner();
 	authOwnerAgent = testServer.authAgentFor(owner);


Reviews:
user: login: netroy
body: maybe we should add the read endpoint instead?
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T14:39:51Z
user: login: cubic-dev-ai[bot]
body: mrge found 2 issues across 1 file. Review them in [mrge.io](https://mrge.io/pr/n8n-io/n8n/pull/15356)
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T14:40:04Z
user: login: RicardoE105
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T16:13:47Z
user: login: RicardoE105
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T16:14:09Z
user: login: RicardoE105
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T16:41:27Z
user: login: RicardoE105
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T17:19:00Z

Review comments:
diff_hunk: @@ -20,7 +20,7 @@ export const RESOURCES = {
 	sourceControl: ['pull', 'push', 'manage'] as const,
 	tag: [...DEFAULT_OPERATIONS] as const,
 	user: ['resetPassword', 'changeRole', ...DEFAULT_OPERATIONS] as const,
-	variable: [...DEFAULT_OPERATIONS] as const,
+	variable: ['create', 'update', 'delete', 'list'] as const,
path: packages/@n8n/permissions/src/constants.ee.ts
user: login: cubic-dev-ai[bot]
body: <!-- metadata:{"confidence":9,"steps":[{"text":"I'll review the changed code for issues. Let me first understand the context better by examining the file structure and related code.","toolCalls":[{"args":{"pattern":"packages/@n8n/permissions/src/*.ts"},"toolName":"listFiles"}]},{"text":"Let me check if there are any references to the `variable` resource in the codebase to understand the impact of this change:","toolCalls":[{"args":{"command":"grep -r \"variable\" packages/@n8n/permissions/src/ --include=\"*.ts\""},"toolName":"executeCommand"}]},{"text":"Let me check the API_KEY_RESOURCES section in the constants file, as it still uses DEFAULT_OPERATIONS for variables:","toolCalls":[{"args":{"command":"grep -A 10 \"API_KEY_RESOURCES\" packages/@n8n/permissions/src/constants.ee.ts"},"toolName":"executeCommand"}]},{"text":"Let me check the global-scopes file to see how the variable scopes are defined:","toolCalls":[{"args":{"command":"grep -A 10 -B 10 \"variable:\" packages/@n8n/permissions/src/roles/scopes/global-scopes.ee.ts"},"toolName":"executeCommand"}]},{"text":"Let me also check if there are any tests that might be affected by this change:","toolCalls":[{"args":{"command":"grep -A 5 -B 5 \"variable\" packages/@n8n/permissions/src/__tests__/types.test.ts"},"toolName":"executeCommand"}]}]} -->
Inconsistency between RESOURCES and API_KEY_RESOURCES for variable permissions. API_KEY_RESOURCES still uses DEFAULT_OPERATIONS which includes 'read'.
created_at: 2025-05-13T14:40:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -20,7 +20,7 @@
 	sourceControl: ['pull', 'push', 'manage'] as const,
 	tag: [...DEFAULT_OPERATIONS] as const,
 	user: ['resetPassword', 'changeRole', ...DEFAULT_OPERATIONS] as const,
-	variable: [...DEFAULT_OPERATIONS] as const,
+	variable: ['create', 'update', 'delete', 'list'] as const,
path: packages/@n8n/permissions/src/constants.ee.ts
user: login: cubic-dev-ai[bot]
body: <!-- metadata:{"confidence":9,"steps":[{"text":"I'll review the changed code against the rule \"Let compiler catch type related issues\" to determine if there are any violations that the TypeScript compiler wouldn't catch.\n\nLet me first understand what's happening in the code change:\n\n1. The original line: `variable: [...DEFAULT_OPERATIONS] as const,`\n2. The new line: `variable: ['create', 'update', 'delete', 'list'] as const,`\n\nThe change is removing the `read` operation from the `variable` resource by explicitly listing the operations instead of using the spread operator with `DEFAULT_OPERATIONS`.\n\nLet me check if there are any references to the `variable` resource that might be affected by this change:","toolCalls":[{"args":{"file":"packages/@n8n/permissions/src/constants.ee.ts","symbol":"RESOURCES"},"toolName":"findReferences"}]},{"text":"Let me also check if there are any references to the `variable` property specifically:","toolCalls":[{"args":{"command":"grep -r \"RESOURCES.*variable\" --include=\"*.ts\" ."},"toolName":"executeCommand"}]},{"text":"Let me check for any references to API_KEY_RESOURCES.variable:","toolCalls":[{"args":{"command":"grep -r \"API_KEY_RESOURCES.*variable\" --include=\"*.ts\" ."},"toolName":"executeCommand"}]},{"text":"Let me check if there's any inconsistency between RESOURCES.variable and API_KEY_RESOURCES.variable:","toolCalls":[{"args":{"command":"grep -A 20 -B 20 \"API_KEY_RESOURCES\" packages/@n8n/permissions/src/constants.ee.ts"},"toolName":"executeCommand"}]},{"text":"I've found a potential issue. In the changed code, `RESOURCES.variable` is now set to `['create', 'update', 'delete', 'list']`, but `API_KEY_RESOURCES.variable` is still set to `DEFAULT_OPERATIONS`, which includes the `read` operation.\n\nThis creates an inconsistency between the two constants. The TypeScript compiler won't catch this issue because both are valid string arrays, but it could lead to runtime issues if code expects the same operations to be available in both places.\n\nLet me check if there are any references to both constants together to confirm this is a real issue:","toolCalls":[{"args":{"command":"grep -r \"variable.*read\" --include=\"*.ts\" ."},"toolName":"executeCommand"}]},{"text":"Now I need to check if there are any references to API_KEY_RESOURCES.variable:","toolCalls":[{"args":{"command":"grep -r \"API_KEY_RESOURCES.*variable\" --include=\"*.ts\" packages/"},"toolName":"executeCommand"}]},{"text":"Let me check for any direct references to the variable resource in API_KEY_RESOURCES:","toolCalls":[{"args":{"file":"packages/@n8n/permissions/src/constants.ee.ts","symbol":"API_KEY_RESOURCES"},"toolName":"findReferences"}]}]} -->
Rule violated: **Let compiler catch type related issues**
      
      Inconsistency between RESOURCES.variable and API_KEY_RESOURCES.variable permissions
created_at: 2025-05-13T14:40:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -20,7 +20,7 @@
 	sourceControl: ['pull', 'push', 'manage'] as const,
 	tag: [...DEFAULT_OPERATIONS] as const,
 	user: ['resetPassword', 'changeRole', ...DEFAULT_OPERATIONS] as const,
-	variable: [...DEFAULT_OPERATIONS] as const,
+	variable: ['create', 'update', 'delete', 'list'] as const,
path: packages/@n8n/permissions/src/constants.ee.ts
user: login: RicardoE105
body: that is fine because `variable:read` is a scope we use the internal API but not in the public API
created_at: 2025-05-13T16:13:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -20,7 +20,7 @@ export const RESOURCES = {
 	sourceControl: ['pull', 'push', 'manage'] as const,
 	tag: [...DEFAULT_OPERATIONS] as const,
 	user: ['resetPassword', 'changeRole', ...DEFAULT_OPERATIONS] as const,
-	variable: [...DEFAULT_OPERATIONS] as const,
+	variable: ['create', 'update', 'delete', 'list'] as const,
path: packages/@n8n/permissions/src/constants.ee.ts
user: login: RicardoE105
body: [See another comment](https://github.com/n8n-io/n8n/pull/15356#discussion_r2087194406)
created_at: 2025-05-13T16:14:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,6 +15,7 @@ export const OWNER_API_KEY_SCOPES: ApiKeyScope[] = [
 	'variable:create',
 	'variable:delete',
 	'variable:list',
+	'variable:update',
path: packages/cli/src/public-api/permissions.ee/global-roles-scopes.ts
user: login: RicardoE105
body: this makes it a owner/admin only scope
created_at: 2025-05-13T16:41:27Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-05-13T15:30:12Z
body: ## [Codecov](https://app.codecov.io/gh/n8n-io/n8n/pull/15356?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=n8n-io) Report
All modified and coverable lines are covered by tests :white_check_mark:

:loudspeaker: Thoughts on this report? [Let us know!](https://github.com/codecov/feedback/issues/255)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-16T17:30:28Z
body: :white_check_mark: All Cypress E2E specs passed
author_association: CONTRIBUTOR
user: login: cypress[bot]
created_at: 2025-05-17T03:30:59Z
body: 
<h3>
  <a href="https://cloud.cypress.io/projects/5hbsdn?utm_source=github&utm_medium=PASSED&utm_campaign=project">n8n</a>&nbsp;
  <img src="https://assets.cypress.io/github-pr-comment-icons/chevron.svg" alt="" height="14" width="14" />&nbsp;
  <a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/overview?utm_source=github&utm_medium=PASSED&utm_campaign=run%20number">Run #10888</a>
</h3>

<details>
  <summary>
    <strong>Run Properties:</strong>&nbsp;
    <code><img src="https://assets.cypress.io/github-pr-comment-icons/passed.svg" alt="status check passed" height="10" width="10" />&nbsp;Passed&nbsp;<a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/overview?utm_source=github&utm_medium=PASSED&utm_campaign=run%20number">#10888</a></code> &nbsp;&bull;&nbsp;
    <code><img src="https://assets.cypress.io/github-pr-comment-icons/git-commit.svg" alt="git commit" width="10" height="10" /> <a href="https://github.com/n8n-io/n8n/commit/a1ee96d5605e28c36283f11b741501349dcf39f8">a1ee96d560</a>: 🌳 master 🖥️ browsers:node18.12.0-chrome107 🤖 PR User 🗃️ e2e/*</code>
  </summary><br />

  <table width="744">
    <tbody>
      <tr />
      <tr height="48">
        <td width="224">
          <strong>Project</strong>
        </td>
        <td width="520">
          <code><a href="https://cloud.cypress.io/projects/5hbsdn?utm_source=github&utm_medium=PASSED&utm_campaign=project">n8n</a></code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td width="224">
          <strong>Branch Review</strong>
        </th>
        <td>
          <code><a href="https://cloud.cypress.io/projects/5hbsdn/branches/master/review?utm_source=github&utm_medium=PASSED&utm_campaign=review%20changes&changeRequest=15356">master</a></code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Run status</strong></td>
        <td>
          <code><img src="https://assets.cypress.io/github-pr-comment-icons/passed.svg" alt="status check passed" height="10" width="10" />&nbsp;Passed&nbsp;<a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/overview?utm_source=github&utm_medium=PASSED&utm_campaign=run%20number">#10888</a></code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Run duration</strong></td>
        <td><code>04m 11s</code></td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Commit</strong></td>
        <td>
          <code><img src="https://assets.cypress.io/github-pr-comment-icons/git-commit.svg" alt="git commit" width="10" height="10" /> <a href="https://github.com/n8n-io/n8n/commit/a1ee96d5605e28c36283f11b741501349dcf39f8">a1ee96d560</a>: 🌳 master 🖥️ browsers:node18.12.0-chrome107 🤖 PR User 🗃️ e2e/*</code>
        </td>
      </tr>
      <tr />
      <tr height="48">
        <td><strong>Committer</strong></td>
        <td><code>Ria Scholz</code></td>
      </tr>
    </tbody>
    <tfoot>
      <tr />
      <tr height="48">
        <td colspan="2">
          <a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/properties?utm_source=github&utm_medium=PASSED&utm_campaign=properties">View all properties for this run ↗︎</a>
        </td>
      </tr>
    </tfoot>
  </table>
  <hr />
</details>

<table width="744">
  <thead>
    <tr />
    <tr height="48">
      <th colspan="2" align="left" width="744">Test results</th>
    </tr>
  </thead>
  <tbody>
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/failed.svg" alt="Tests that failed" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/overview?reviewViewBy=FAILED&utm_source=github&utm_medium=PASSED&utm_campaign=failed%20tests">
          <strong>Failures</strong>
        </a>
      </td>
      <td>
        <code><strong>0</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/flaky-v3.svg" alt="Tests that were flaky" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/overview?reviewViewBy=FLAKY&utm_source=github&utm_medium=PASSED&utm_campaign=flaky%20tests">
          <strong>Flaky</strong>
        </a>
      </td>
      <td>
        <code><strong>0</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/pending.svg" alt="Tests that did not run due to a developer annotating a test with .skip" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/test-results?utm_source=github&utm_medium=PASSED&utm_campaign=pending%20tests&statuses=%5B%7B%22value%22%3A%22PENDING%22%2C%22label%22%3A%22PENDING%22%7D%5D">
          <strong>Pending</strong>
        </a>
      </td>
      <td>
        <code><strong>7</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/skipped-v3.svg" alt="Tests that did not run due to a failure in a mocha hook" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/test-results?utm_source=github&utm_medium=PASSED&utm_campaign=skipped%20tests&statuses=%5B%7B%22value%22%3A%22SKIPPED%22%2C%22label%22%3A%22SKIPPED%22%7D%5D">
          <strong>Skipped</strong>
        </a>
      </td>
      <td>
        <code><strong>0</strong></code>
      </td>
    </tr>
    <tr />
    <tr height="48">
      <td width="224">
        <img src="https://assets.cypress.io/github-pr-comment-icons/passed.svg" alt="Tests that passed" width="10" height="10" />&nbsp;
        <a href="https://cloud.cypress.io/projects/5hbsdn/runs/10888/overview?utm_source=github&utm_medium=PASSED&utm_campaign=passed%20tests">
          <strong>Passing</strong>
        </a>
      </td>
      <td>
        <code><strong>504</strong></code>
      </td>
    </tr><tfoot>
    <tr height="48"><td colspan="2"><a href="https://cloud.cypress.io/projects/5hbsdn/branches/master/review?utm_source=github&utm_medium=PASSED&utm_campaign=review%20changes&changeRequest=15356">View all changes introduced in this branch ↗︎</a></td></tr></tfoot>
  </tbody>
</table>






author_association: NONE
user: login: janober
created_at: 2025-05-19T13:11:45Z
body: Got released with [`n8n@1.94.0`](https://github.com/n8n-io/n8n/releases/tag/n8n%401.94.0)
author_association: MEMBER