first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,332 @@
import type { IDataObject, INodeProperties } from 'n8n-workflow';
import { ExternalSecretsProviders } from '@/modules/external-secrets.ee/external-secrets-providers.ee';
import { SecretsProvider } from '@/modules/external-secrets.ee/types';
import type { SecretsProviderSettings } from '@/modules/external-secrets.ee/types';
export class MockProviders extends ExternalSecretsProviders {
override providers: Record<string, { new (): SecretsProvider }> = {
dummy: DummyProvider,
};
setProviders(providers: Record<string, { new (): SecretsProvider }>) {
this.providers = providers;
}
}
export class DummyProvider extends SecretsProvider {
properties: INodeProperties[] = [
{
name: 'username',
displayName: 'Username',
type: 'string',
default: '',
required: true,
},
{
name: 'other',
displayName: 'Other',
type: 'string',
default: '',
},
{
name: 'password',
displayName: 'Password',
type: 'string',
default: '',
typeOptions: {
password: true,
},
},
];
secrets: Record<string, string> = {};
displayName = 'Dummy Provider';
name = 'dummy';
_updateSecrets: Record<string, string> = {
test1: 'value1',
test2: 'value2',
};
async init(_settings: SecretsProviderSettings<IDataObject>): Promise<void> {}
protected async doConnect(): Promise<void> {
// Connected successfully - base class will set state
}
async disconnect(): Promise<void> {}
async update(): Promise<void> {
this.secrets = this._updateSecrets;
}
async test(): Promise<[boolean] | [boolean, string]> {
return [true];
}
getSecret(name: string): IDataObject | undefined {
return this.secrets[name] as unknown as IDataObject | undefined;
}
hasSecret(name: string): boolean {
return name in this.secrets;
}
getSecretNames(): string[] {
return Object.keys(this.secrets);
}
}
export class AnotherDummyProvider extends SecretsProvider {
properties: INodeProperties[] = [
{
name: 'username',
displayName: 'Username',
type: 'string',
default: '',
required: true,
},
];
secrets: Record<string, string> = {};
displayName = 'Another Dummy Provider';
name = 'another_dummy';
_updateSecrets: Record<string, string> = {
test1: 'value1',
test2: 'value2',
};
async init(_settings: SecretsProviderSettings<IDataObject>): Promise<void> {}
protected async doConnect(): Promise<void> {
// Connected successfully - base class will set state
}
async disconnect(): Promise<void> {}
async update(): Promise<void> {
this.secrets = this._updateSecrets;
}
async test(): Promise<[boolean] | [boolean, string]> {
return [true];
}
getSecret(name: string): IDataObject | undefined {
return this.secrets[name] as unknown as IDataObject | undefined;
}
hasSecret(name: string): boolean {
return name in this.secrets;
}
getSecretNames(): string[] {
return Object.keys(this.secrets);
}
}
export class ErrorProvider extends SecretsProvider {
secrets: Record<string, string> = {};
displayName = 'Error Provider';
name = 'dummy';
properties = [];
async init(_settings: SecretsProviderSettings<IDataObject>): Promise<void> {
throw new Error();
}
protected async doConnect(): Promise<void> {
throw new Error('Connection failed');
}
async disconnect(): Promise<void> {
// no-op
}
async update(): Promise<void> {
throw new Error();
}
async test(): Promise<[boolean] | [boolean, string]> {
throw new Error();
}
getSecret(_name: string): IDataObject | undefined {
throw new Error();
}
hasSecret(_name: string): boolean {
throw new Error();
}
getSecretNames(): string[] {
throw new Error();
}
}
export class FailedProvider extends SecretsProvider {
secrets: Record<string, string> = {};
displayName = 'Failed Provider';
name = 'dummy';
properties = [];
async init(_settings: SecretsProviderSettings<IDataObject>): Promise<void> {}
protected async doConnect(): Promise<void> {
throw new Error('Failed to connect');
}
async disconnect(): Promise<void> {}
async update(): Promise<void> {}
async test(): Promise<[boolean] | [boolean, string]> {
return [true];
}
getSecret(name: string): IDataObject | undefined {
return this.secrets[name] as unknown as IDataObject | undefined;
}
hasSecret(name: string): boolean {
return name in this.secrets;
}
getSecretNames(): string[] {
return Object.keys(this.secrets);
}
}
export class TestFailProvider extends SecretsProvider {
secrets: Record<string, string> = {};
displayName = 'Test Failed Provider';
name = 'dummy';
properties = [];
_updateSecrets: Record<string, string> = {
test1: 'value1',
test2: 'value2',
};
async init(_settings: SecretsProviderSettings<IDataObject>): Promise<void> {}
protected async doConnect(): Promise<void> {
// Connected successfully - base class will set state
}
async disconnect(): Promise<void> {}
async update(): Promise<void> {
this.secrets = this._updateSecrets;
}
async test(): Promise<[boolean] | [boolean, string]> {
return [false];
}
getSecret(name: string): IDataObject | undefined {
return this.secrets[name] as unknown as IDataObject | undefined;
}
hasSecret(name: string): boolean {
return name in this.secrets;
}
getSecretNames(): string[] {
return Object.keys(this.secrets);
}
}
export function createDummyProvider({
name,
secrets,
displayName,
properties,
}: {
name: string;
displayName?: string;
secrets?: Record<string, string>;
properties?: INodeProperties[];
}): { new (): SecretsProvider } {
const defaultSecrets = secrets ?? {
test1: 'value1',
test2: 'value2',
};
class FreshProvider extends SecretsProvider {
name = name;
displayName = displayName ?? name;
properties: INodeProperties[] = properties ?? [
{
name: 'username',
displayName: 'Username',
type: 'string',
default: '',
required: true,
},
{
name: 'other',
displayName: 'Other',
type: 'string',
default: '',
},
{
name: 'password',
displayName: 'Password',
type: 'string',
default: '',
typeOptions: {
password: true,
},
},
];
secrets: Record<string, string> = { ...defaultSecrets };
_updateSecrets: Record<string, string> = { ...defaultSecrets };
async init(_settings: SecretsProviderSettings<IDataObject>): Promise<void> {}
protected async doConnect(): Promise<void> {
// Connected successfully - base class will set state
}
async disconnect(): Promise<void> {}
async update(): Promise<void> {
this.secrets = this._updateSecrets;
}
async test(): Promise<[boolean] | [boolean, string]> {
return [true];
}
getSecret(name: string): IDataObject | undefined {
return this.secrets[name] as unknown as IDataObject | undefined;
}
hasSecret(name: string): boolean {
return name in this.secrets;
}
getSecretNames(): string[] {
return Object.keys(this.secrets);
}
}
return FreshProvider;
}
+43
View File
@@ -0,0 +1,43 @@
import {
NodeConnectionTypes,
type IDataObject,
type ITaskData,
type NodeConnectionType,
} from 'n8n-workflow';
type TaskData = {
data: IDataObject;
outputIndex?: number;
nodeConnectionType?: NodeConnectionType;
};
export function toITaskData(taskData: TaskData[], overrides?: Partial<ITaskData>): ITaskData {
const result: ITaskData = {
executionStatus: 'success',
executionTime: 0,
startTime: 0,
executionIndex: 0,
source: [],
data: {},
...(overrides ?? {}),
};
// NOTE: Here to make TS happy.
result.data = result.data ?? {};
for (const taskDatum of taskData) {
const type = taskDatum.nodeConnectionType ?? NodeConnectionTypes.Main;
const outputIndex = taskDatum.outputIndex ?? 0;
result.data[type] = result.data[type] ?? [];
const dataConnection = result.data[type];
dataConnection[outputIndex] = [{ json: taskDatum.data }];
}
for (const [type, dataConnection] of Object.entries(result.data)) {
for (const [index, maybe] of dataConnection.entries()) {
result.data[type][index] = maybe ?? null;
}
}
return result;
}
+26
View File
@@ -0,0 +1,26 @@
import {
randomCredentialPayload,
randomEmail,
randomName,
uniqueId,
} from '@n8n/backend-test-utils';
import { CredentialsEntity, Project, User } from '@n8n/db';
import { randomInt } from 'n8n-workflow';
export const mockCredential = (): CredentialsEntity =>
Object.assign(new CredentialsEntity(), randomCredentialPayload());
export const mockUser = (): User =>
Object.assign(new User(), {
id: randomInt(1000),
email: randomEmail(),
firstName: randomName(),
lastName: randomName(),
});
export const mockProject = (): Project =>
Object.assign(new Project(), {
id: uniqueId(),
type: 'personal',
name: 'Nathan Fillion <nathan.fillion@n8n.io>',
});
+20
View File
@@ -0,0 +1,20 @@
import { mockInstance } from '@n8n/backend-test-utils';
import { DataSource, EntityManager, type EntityMetadata } from '@n8n/typeorm';
import { mock } from 'jest-mock-extended';
import type { Cipher, Class } from 'n8n-core';
export const mockEntityManager = (entityClass: Class) => {
const entityManager = mockInstance(EntityManager);
const dataSource = mockInstance(DataSource, {
manager: entityManager,
getMetadata: () => mock<EntityMetadata>({ target: entityClass }),
});
Object.assign(entityManager, { connection: dataSource });
return entityManager;
};
export const mockCipher = () =>
mock<Cipher>({
encrypt: (data) => (typeof data === 'string' ? data : JSON.stringify(data)),
decrypt: (data) => data,
});
+6
View File
@@ -0,0 +1,6 @@
export const badPasswords = {
pass: 'Password must be 8 to 64 characters long. Password must contain at least 1 number. Password must contain at least 1 uppercase letter.',
password:
'Password must contain at least 1 number. Password must contain at least 1 uppercase letter.',
password1: 'Password must contain at least 1 uppercase letter.',
};