fix(core): Fix missing encryption key check on workers (#14603)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™
2025-04-14 16:58:22 +02:00
committed by GitHub
parent 981eaf0728
commit de03452631
4 changed files with 34 additions and 19 deletions

View File

@@ -3,7 +3,6 @@ import { Flags, type Config } from '@oclif/core';
import config from '@/config';
import { N8N_VERSION, inTest } from '@/constants';
import { WorkerMissingEncryptionKey } from '@/errors/worker-missing-encryption-key.error';
import { EventMessageGeneric } from '@/eventbus/event-message-classes/event-message-generic';
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
import { LogStreamingEventRelay } from '@/events/relays/log-streaming.event-relay';
@@ -58,8 +57,6 @@ export class Worker extends BaseCommand {
}
constructor(argv: string[], cmdConfig: Config) {
if (!process.env.N8N_ENCRYPTION_KEY) throw new WorkerMissingEncryptionKey();
if (config.getEnv('executions.mode') !== 'queue') {
config.set('executions.mode', 'queue');
}

View File

@@ -2,18 +2,18 @@ import { mock } from 'jest-mock-extended';
jest.mock('node:fs', () => mock<typeof fs>());
import * as fs from 'node:fs';
import { InstanceSettings } from '@/instance-settings';
import { InstanceSettingsConfig } from '@/instance-settings/instance-settings-config';
import { Logger } from '@/logging/logger';
import { mockInstance } from '@test/utils';
import type { Logger } from '@/logging/logger';
import { InstanceSettings } from '../instance-settings';
import { InstanceSettingsConfig } from '../instance-settings-config';
import { WorkerMissingEncryptionKey } from '../worker-missing-encryption-key.error';
describe('InstanceSettings', () => {
const userFolder = '/test';
process.env.N8N_USER_FOLDER = userFolder;
const settingsFile = `${userFolder}/.n8n/config`;
const mockFs = mock(fs);
const logger = mockInstance(Logger);
const logger = mock<Logger>();
const createInstanceSettings = (opts?: Partial<InstanceSettingsConfig>) =>
new InstanceSettings(
@@ -27,6 +27,9 @@ describe('InstanceSettings', () => {
beforeEach(() => {
jest.resetAllMocks();
mockFs.statSync.mockReturnValue({ mode: 0o600 } as fs.Stats);
process.argv[2] = 'main';
process.env = { N8N_USER_FOLDER: userFolder };
});
describe('If the settings file exists', () => {
@@ -184,6 +187,11 @@ describe('InstanceSettings', () => {
},
);
});
it("should throw on a worker process, if encryption key isn't set via env", () => {
process.argv[2] = 'worker';
expect(() => createInstanceSettings()).toThrowError(WorkerMissingEncryptionKey);
});
});
describe('constructor', () => {

View File

@@ -9,6 +9,7 @@ import { Memoized } from '@/decorators';
import { Logger } from '@/logging/logger';
import { InstanceSettingsConfig } from './instance-settings-config';
import { WorkerMissingEncryptionKey } from './worker-missing-encryption-key.error';
const nanoid = customAlphabet(ALPHABET, 16);
@@ -46,7 +47,7 @@ export class InstanceSettings {
readonly enforceSettingsFilePermissions = this.loadEnforceSettingsFilePermissionsFlag();
private settings = this.loadOrCreate();
private settings: Settings;
/**
* Fixed ID of this n8n instance, for telemetry.
@@ -54,7 +55,7 @@ export class InstanceSettings {
*
* @example '258fce876abf5ea60eb86a2e777e5e190ff8f3e36b5b37aafec6636c31d4d1f9'
*/
readonly instanceId = this.generateInstanceId();
readonly instanceId: string;
readonly instanceType: InstanceType;
@@ -68,6 +69,8 @@ export class InstanceSettings {
: 'main';
this.hostId = `${this.instanceType}-${nanoid()}`;
this.settings = this.loadOrCreate();
this.instanceId = this.generateInstanceId();
}
/**
@@ -177,6 +180,7 @@ export class InstanceSettings {
* settings file with an auto-generated encryption key.
*/
private loadOrCreate(): Settings {
const encryptionKeyFromEnv = process.env.N8N_ENCRYPTION_KEY;
if (existsSync(this.settingsFile)) {
const content = readFileSync(this.settingsFile, 'utf8');
this.ensureSettingsFilePermissions();
@@ -189,7 +193,7 @@ export class InstanceSettings {
const { encryptionKey, tunnelSubdomain } = settings;
if (process.env.N8N_ENCRYPTION_KEY && encryptionKey !== process.env.N8N_ENCRYPTION_KEY) {
if (encryptionKeyFromEnv && encryptionKey !== encryptionKeyFromEnv) {
throw new ApplicationError(
`Mismatching encryption keys. The encryption key in the settings file ${this.settingsFile} does not match the N8N_ENCRYPTION_KEY env var. Please make sure both keys match. More information: https://docs.n8n.io/hosting/environment-variables/configuration-methods/#encryption-key`,
);
@@ -198,19 +202,25 @@ export class InstanceSettings {
return { encryptionKey, tunnelSubdomain };
}
if (!encryptionKeyFromEnv) {
if (this.instanceType === 'worker') {
throw new WorkerMissingEncryptionKey();
}
if (!inTest) {
this.logger.info(
`No encryption key found - Auto-generating and saving to: ${this.settingsFile}`,
);
}
}
mkdirSync(this.n8nFolder, { recursive: true });
const encryptionKey = process.env.N8N_ENCRYPTION_KEY ?? randomBytes(24).toString('base64');
const encryptionKey = encryptionKeyFromEnv ?? randomBytes(24).toString('base64');
const settings: Settings = { encryptionKey };
this.save(settings);
if (!inTest && !process.env.N8N_ENCRYPTION_KEY) {
this.logger.info(
`No encryption key found - Auto-generated and saved to: ${this.settingsFile}`,
);
}
this.ensureSettingsFilePermissions();
return settings;