refactor(core): Convert external-secrets code into a backend module (#15769)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™
2025-06-05 14:21:29 +02:00
committed by GitHub
parent 10dc73fc82
commit 1587eb0742
31 changed files with 40 additions and 34 deletions

View File

@@ -11,7 +11,6 @@ import {
ObjectStoreService,
DataDeduplicationService,
ErrorReporter,
ExternalSecretsProxy,
} from 'n8n-core';
import { ensureError, sleep, UserError } from 'n8n-workflow';
@@ -26,7 +25,6 @@ import { TestRunCleanupService } from '@/evaluation.ee/test-runner/test-run-clea
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
import { TelemetryEventRelay } from '@/events/relays/telemetry.event-relay';
import { ExternalHooks } from '@/external-hooks';
import { ExternalSecretsManager } from '@/external-secrets.ee/external-secrets-manager.ee';
import { License } from '@/license';
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
import { ModuleRegistry } from '@/modules/module-registry';
@@ -88,7 +86,6 @@ export abstract class BaseCommand extends Command {
instance: this.instanceSettings,
})
) {
// register module in the registry for the dependency injection
await import(`../modules/${moduleName}/${moduleName}.module`);
this.modulesConfig.addLoadedModule(moduleName);
@@ -276,12 +273,6 @@ export abstract class BaseCommand extends Command {
}
}
async initExternalSecrets() {
const secretsManager = Container.get(ExternalSecretsManager);
await secretsManager.init();
Container.get(ExternalSecretsProxy).setManager(secretsManager);
}
initWorkflowHistory() {
Container.get(WorkflowHistoryManager).init();
}

View File

@@ -232,8 +232,6 @@ export class Start extends BaseCommand {
this.logger.debug('Data deduplication service init complete');
await this.initExternalHooks();
this.logger.debug('External hooks init complete');
await this.initExternalSecrets();
this.logger.debug('External secrets init complete');
this.initWorkflowHistory();
this.logger.debug('Workflow history init complete');

View File

@@ -77,8 +77,6 @@ export class Webhook extends BaseCommand {
this.logger.debug('Data deduplication service init complete');
await this.initExternalHooks();
this.logger.debug('External hooks init complete');
await this.initExternalSecrets();
this.logger.debug('External secrets init complete');
await this.loadModules();
}

View File

@@ -94,8 +94,6 @@ export class Worker extends BaseCommand {
this.logger.debug('Data deduplication service init complete');
await this.initExternalHooks();
this.logger.debug('External hooks init complete');
await this.initExternalSecrets();
this.logger.debug('External secrets init complete');
await this.initEventBus();
this.logger.debug('Event bus init complete');
await this.initScalingService();

View File

@@ -12,19 +12,19 @@ describe('ModulesConfig', () => {
it('should initialize with insights modules if no environment variable is set', () => {
const config = Container.get(ModulesConfig);
expect(config.modules).toEqual(['insights']);
expect(config.modules).toEqual(['insights', 'external-secrets.ee']);
});
it('should parse valid module names from environment variable', () => {
process.env.N8N_ENABLED_MODULES = 'insights';
const config = Container.get(ModulesConfig);
expect(config.modules).toEqual(['insights']);
expect(config.modules).toEqual(['insights', 'external-secrets.ee']);
});
it('should disable valid module names from environment variable', () => {
process.env.N8N_DISABLED_MODULES = 'insights';
const config = Container.get(ModulesConfig);
expect(config.modules).toEqual([]);
expect(config.modules).toEqual(['external-secrets.ee']);
});
it('should throw UnexpectedError for invalid module names', () => {

View File

@@ -0,0 +1,20 @@
import type { BaseN8nModule } from '@n8n/decorators';
import { N8nModule } from '@n8n/decorators';
import { ExternalSecretsProxy } from 'n8n-core';
import { ExternalSecretsManager } from './external-secrets-manager.ee';
import './external-secrets.controller.ee';
@N8nModule()
export class ExternalSecretsModule implements BaseN8nModule {
constructor(
private readonly manager: ExternalSecretsManager,
private readonly externalSecretsProxy: ExternalSecretsProxy,
) {}
async initialize() {
const { externalSecretsProxy, manager } = this;
await manager.init();
externalSecretsProxy.setManager(manager);
}
}

View File

@@ -10,7 +10,7 @@ export type ModulePreInit = {
shouldLoadModule: (ctx: ModulePreInitContext) => boolean;
};
const moduleNames = ['insights'] as const;
const moduleNames = ['insights', 'external-secrets.ee'] as const;
export type ModuleName = (typeof moduleNames)[number];
class Modules extends CommaSeparatedStringArray<ModuleName> {
@@ -36,7 +36,7 @@ export class ModulesConfig {
disabledModules: Modules = [];
// Default modules are always enabled unless explicitly disabled
private readonly defaultModules: ModuleName[] = ['insights'];
private readonly defaultModules: ModuleName[] = ['insights', 'external-secrets.ee'];
// Loaded modules are the ones that have been loaded so far by the instance
readonly loadedModules = new Set<ModuleName>();

View File

@@ -56,7 +56,6 @@ import '@/credentials/credentials.controller';
import '@/eventbus/event-bus.controller';
import '@/events/events.controller';
import '@/executions/executions.controller';
import '@/external-secrets.ee/external-secrets.controller.ee';
import '@/license/license.controller';
import '@/evaluation.ee/test-runs.controller.ee';
import '@/workflows/workflow-history.ee/workflow-history.controller.ee';

View File

@@ -9,7 +9,6 @@ import config from '@/config';
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
import { LogStreamingEventRelay } from '@/events/relays/log-streaming.event-relay';
import { ExternalHooks } from '@/external-hooks';
import { ExternalSecretsManager } from '@/external-secrets.ee/external-secrets-manager.ee';
import { License } from '@/license';
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
import { Push } from '@/push';
@@ -31,7 +30,6 @@ mockInstance(LoadNodesAndCredentials);
const binaryDataService = mockInstance(BinaryDataService);
const communityPackagesService = mockInstance(CommunityPackagesService);
const externalHooks = mockInstance(ExternalHooks);
const externalSecretsManager = mockInstance(ExternalSecretsManager);
const license = mockInstance(License, { loadCertStr: async () => '' });
const messageEventBus = mockInstance(MessageEventBus);
const logStreamingEventRelay = mockInstance(LogStreamingEventRelay);
@@ -54,7 +52,6 @@ test('worker initializes all its components', async () => {
expect(binaryDataService.init).toHaveBeenCalledTimes(1);
expect(communityPackagesService.init).toHaveBeenCalledTimes(1);
expect(externalHooks.init).toHaveBeenCalledTimes(1);
expect(externalSecretsManager.init).toHaveBeenCalledTimes(1);
expect(messageEventBus.initialize).toHaveBeenCalledTimes(1);
expect(scalingService.setupQueue).toHaveBeenCalledTimes(1);
expect(scalingService.setupWorker).toHaveBeenCalledTimes(1);

View File

@@ -7,10 +7,13 @@ import type { IDataObject } from 'n8n-workflow';
import config from '@/config';
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
import type { EventService } from '@/events/event.service';
import { ExternalSecretsManager } from '@/external-secrets.ee/external-secrets-manager.ee';
import { ExternalSecretsProviders } from '@/external-secrets.ee/external-secrets-providers.ee';
import type { ExternalSecretsSettings, SecretsProviderState } from '@/external-secrets.ee/types';
import { License } from '@/license';
import { ExternalSecretsManager } from '@/modules/external-secrets.ee/external-secrets-manager.ee';
import { ExternalSecretsProviders } from '@/modules/external-secrets.ee/external-secrets-providers.ee';
import type {
ExternalSecretsSettings,
SecretsProviderState,
} from '@/modules/external-secrets.ee/types';
import {
DummyProvider,

View File

@@ -250,10 +250,6 @@ export const setupTestServer = ({
await import('@/controllers/tags.controller');
break;
case 'externalSecrets':
await import('@/external-secrets.ee/external-secrets.controller.ee');
break;
case 'workflowHistory':
await import('@/workflows/workflow-history.ee/workflow-history.controller.ee');
break;
@@ -292,8 +288,11 @@ export const setupTestServer = ({
case 'folder':
await import('@/controllers/folder.controller');
case 'externalSecrets':
await import('@/modules/external-secrets.ee/external-secrets.ee.module');
case 'insights':
await import('@/modules/insights/insights.controller');
await import('@/modules/insights/insights.module');
}
}

View File

@@ -1,7 +1,10 @@
import type { IDataObject, INodeProperties } from 'n8n-workflow';
import { SecretsProvider } from '@/external-secrets.ee/types';
import type { SecretsProviderSettings, SecretsProviderState } from '@/external-secrets.ee/types';
import { SecretsProvider } from '@/modules/external-secrets.ee/types';
import type {
SecretsProviderSettings,
SecretsProviderState,
} from '@/modules/external-secrets.ee/types';
export class MockProviders {
providers: Record<string, { new (): SecretsProvider }> = {