refactor(core): Abstract away InstanceSettings and encryptionKey into injectable services (no-changelog) (#7471)
This change ensures that things like `encryptionKey` and `instanceId` are always available directly where they are needed, instead of passing them around throughout the code.
This commit is contained in:
committed by
GitHub
parent
519680c2cf
commit
b6de910cbe
@@ -12,6 +12,7 @@ import { CredentialsHelper } from '@/CredentialsHelper';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||
import { mockInstance } from '../integration/shared/utils';
|
||||
import Container from 'typedi';
|
||||
|
||||
describe('CredentialsHelper', () => {
|
||||
const TEST_ENCRYPTION_KEY = 'test';
|
||||
@@ -277,7 +278,7 @@ describe('CredentialsHelper', () => {
|
||||
},
|
||||
};
|
||||
|
||||
const credentialsHelper = new CredentialsHelper(TEST_ENCRYPTION_KEY);
|
||||
const credentialsHelper = Container.get(CredentialsHelper);
|
||||
|
||||
const result = await credentialsHelper.authenticate(
|
||||
testData.input.credentials,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { SettingsRepository } from '@/databases/repositories';
|
||||
import { Container } from 'typedi';
|
||||
import { Cipher } from 'n8n-core';
|
||||
import { SettingsRepository } from '@/databases/repositories';
|
||||
import type { ExternalSecretsSettings } from '@/Interfaces';
|
||||
import { License } from '@/License';
|
||||
import { ExternalSecretsManager } from '@/ExternalSecrets/ExternalSecretsManager.ee';
|
||||
import { ExternalSecretsProviders } from '@/ExternalSecrets/ExternalSecretsProviders.ee';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { UserSettings } from 'n8n-core';
|
||||
import Container from 'typedi';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { mockInstance } from '../../integration/shared/utils';
|
||||
import {
|
||||
DummyProvider,
|
||||
@@ -13,56 +13,42 @@ import {
|
||||
FailedProvider,
|
||||
MockProviders,
|
||||
} from '../../shared/ExternalSecrets/utils';
|
||||
import { AES, enc } from 'crypto-js';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
|
||||
const connectedDate = '2023-08-01T12:32:29.000Z';
|
||||
const encryptionKey = 'testkey';
|
||||
let settings: string | null = null;
|
||||
const mockProvidersInstance = new MockProviders();
|
||||
const settingsRepo = mock<SettingsRepository>({
|
||||
async getEncryptedSecretsProviderSettings() {
|
||||
return settings;
|
||||
},
|
||||
async saveEncryptedSecretsProviderSettings(data) {
|
||||
settings = data;
|
||||
},
|
||||
});
|
||||
let licenseMock: License;
|
||||
let providersMock: ExternalSecretsProviders;
|
||||
let manager: ExternalSecretsManager | undefined;
|
||||
|
||||
const createMockSettings = (settings: ExternalSecretsSettings): string => {
|
||||
return AES.encrypt(JSON.stringify(settings), encryptionKey).toString();
|
||||
};
|
||||
|
||||
const decryptSettings = (settings: string) => {
|
||||
return JSON.parse(AES.decrypt(settings ?? '', encryptionKey).toString(enc.Utf8));
|
||||
};
|
||||
|
||||
describe('External Secrets Manager', () => {
|
||||
const connectedDate = '2023-08-01T12:32:29.000Z';
|
||||
let settings: string | null = null;
|
||||
|
||||
const mockProvidersInstance = new MockProviders();
|
||||
const license = mockInstance(License);
|
||||
const settingsRepo = mockInstance(SettingsRepository);
|
||||
mockInstance(InternalHooks);
|
||||
const cipher = Container.get(Cipher);
|
||||
|
||||
let providersMock: ExternalSecretsProviders;
|
||||
let manager: ExternalSecretsManager;
|
||||
|
||||
const createMockSettings = (settings: ExternalSecretsSettings): string => {
|
||||
return cipher.encrypt(settings);
|
||||
};
|
||||
|
||||
const decryptSettings = (settings: string) => {
|
||||
return JSON.parse(cipher.decrypt(settings));
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
jest
|
||||
.spyOn(UserSettings, 'getEncryptionKey')
|
||||
.mockReturnValue(new Promise((resolve) => resolve(encryptionKey)));
|
||||
providersMock = mockInstance(ExternalSecretsProviders, mockProvidersInstance);
|
||||
licenseMock = mockInstance(License, {
|
||||
isExternalSecretsEnabled() {
|
||||
return true;
|
||||
},
|
||||
settings = createMockSettings({
|
||||
dummy: { connected: true, connectedAt: new Date(connectedDate), settings: {} },
|
||||
});
|
||||
mockInstance(InternalHooks);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockProvidersInstance.setProviders({
|
||||
dummy: DummyProvider,
|
||||
});
|
||||
settings = createMockSettings({
|
||||
dummy: { connected: true, connectedAt: new Date(connectedDate), settings: {} },
|
||||
});
|
||||
|
||||
Container.remove(ExternalSecretsManager);
|
||||
license.isExternalSecretsEnabled.mockReturnValue(true);
|
||||
settingsRepo.getEncryptedSecretsProviderSettings.mockResolvedValue(settings);
|
||||
manager = new ExternalSecretsManager(settingsRepo, license, providersMock, cipher);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -71,8 +57,6 @@ describe('External Secrets Manager', () => {
|
||||
});
|
||||
|
||||
test('should get secret', async () => {
|
||||
manager = new ExternalSecretsManager(settingsRepo, licenseMock, providersMock);
|
||||
|
||||
await manager.init();
|
||||
|
||||
expect(manager.getSecret('dummy', 'test1')).toBe('value1');
|
||||
@@ -82,8 +66,6 @@ describe('External Secrets Manager', () => {
|
||||
mockProvidersInstance.setProviders({
|
||||
dummy: ErrorProvider,
|
||||
});
|
||||
manager = new ExternalSecretsManager(settingsRepo, licenseMock, providersMock);
|
||||
|
||||
expect(async () => manager!.init()).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -91,16 +73,12 @@ describe('External Secrets Manager', () => {
|
||||
mockProvidersInstance.setProviders({
|
||||
dummy: ErrorProvider,
|
||||
});
|
||||
manager = new ExternalSecretsManager(settingsRepo, licenseMock, providersMock);
|
||||
|
||||
await manager.init();
|
||||
expect(() => manager!.shutdown()).not.toThrow();
|
||||
manager = undefined;
|
||||
});
|
||||
|
||||
test('should save provider settings', async () => {
|
||||
manager = new ExternalSecretsManager(settingsRepo, licenseMock, providersMock);
|
||||
|
||||
const settingsSpy = jest.spyOn(settingsRepo, 'saveEncryptedSecretsProviderSettings');
|
||||
|
||||
await manager.init();
|
||||
@@ -122,8 +100,6 @@ describe('External Secrets Manager', () => {
|
||||
|
||||
test('should call provider update functions on a timer', async () => {
|
||||
jest.useFakeTimers();
|
||||
manager = new ExternalSecretsManager(settingsRepo, licenseMock, providersMock);
|
||||
|
||||
await manager.init();
|
||||
|
||||
const updateSpy = jest.spyOn(manager.getProvider('dummy')!, 'update');
|
||||
@@ -138,15 +114,7 @@ describe('External Secrets Manager', () => {
|
||||
test('should not call provider update functions if the not licensed', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
manager = new ExternalSecretsManager(
|
||||
settingsRepo,
|
||||
mock<License>({
|
||||
isExternalSecretsEnabled() {
|
||||
return false;
|
||||
},
|
||||
}),
|
||||
providersMock,
|
||||
);
|
||||
license.isExternalSecretsEnabled.mockReturnValue(false);
|
||||
|
||||
await manager.init();
|
||||
|
||||
@@ -165,7 +133,6 @@ describe('External Secrets Manager', () => {
|
||||
mockProvidersInstance.setProviders({
|
||||
dummy: FailedProvider,
|
||||
});
|
||||
manager = new ExternalSecretsManager(settingsRepo, licenseMock, providersMock);
|
||||
|
||||
await manager.init();
|
||||
|
||||
@@ -179,8 +146,6 @@ describe('External Secrets Manager', () => {
|
||||
});
|
||||
|
||||
test('should reinitialize a provider when save provider settings', async () => {
|
||||
manager = new ExternalSecretsManager(settingsRepo, licenseMock, providersMock);
|
||||
|
||||
await manager.init();
|
||||
|
||||
const dummyInitSpy = jest.spyOn(DummyProvider.prototype, 'init');
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { LicenseManager } from '@n8n_io/license-sdk';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import config from '@/config';
|
||||
import { License } from '@/License';
|
||||
import { N8N_VERSION } from '@/constants';
|
||||
import { mockInstance } from '../integration/shared/utils';
|
||||
|
||||
jest.mock('@n8n_io/license-sdk');
|
||||
|
||||
@@ -21,10 +23,11 @@ describe('License', () => {
|
||||
});
|
||||
|
||||
let license: License;
|
||||
const instanceSettings = mockInstance(InstanceSettings, { instanceId: MOCK_INSTANCE_ID });
|
||||
|
||||
beforeEach(async () => {
|
||||
license = new License();
|
||||
await license.init(MOCK_INSTANCE_ID);
|
||||
license = new License(instanceSettings);
|
||||
await license.init();
|
||||
});
|
||||
|
||||
test('initializes license manager', async () => {
|
||||
@@ -45,8 +48,8 @@ describe('License', () => {
|
||||
});
|
||||
|
||||
test('initializes license manager for worker', async () => {
|
||||
license = new License();
|
||||
await license.init(MOCK_INSTANCE_ID, 'worker');
|
||||
license = new License(instanceSettings);
|
||||
await license.init('worker');
|
||||
expect(LicenseManager).toHaveBeenCalledWith({
|
||||
autoRenewEnabled: false,
|
||||
autoRenewOffset: MOCK_RENEW_OFFSET,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { PostHog } from 'posthog-node';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import config from '@/config';
|
||||
import { mockInstance } from '../integration/shared/utils';
|
||||
|
||||
jest.mock('posthog-node');
|
||||
|
||||
@@ -10,6 +12,8 @@ describe('PostHog', () => {
|
||||
const apiKey = 'api-key';
|
||||
const apiHost = 'api-host';
|
||||
|
||||
const instanceSettings = mockInstance(InstanceSettings, { instanceId });
|
||||
|
||||
beforeAll(() => {
|
||||
config.set('diagnostics.config.posthog.apiKey', apiKey);
|
||||
config.set('diagnostics.config.posthog.apiHost', apiHost);
|
||||
@@ -21,8 +25,8 @@ describe('PostHog', () => {
|
||||
});
|
||||
|
||||
it('inits PostHog correctly', async () => {
|
||||
const ph = new PostHogClient();
|
||||
await ph.init(instanceId);
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
await ph.init();
|
||||
|
||||
expect(PostHog.prototype.constructor).toHaveBeenCalledWith(apiKey, { host: apiHost });
|
||||
});
|
||||
@@ -30,8 +34,8 @@ describe('PostHog', () => {
|
||||
it('does not initialize or track if diagnostics are not enabled', async () => {
|
||||
config.set('diagnostics.enabled', false);
|
||||
|
||||
const ph = new PostHogClient();
|
||||
await ph.init(instanceId);
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
await ph.init();
|
||||
|
||||
ph.track({
|
||||
userId: 'test',
|
||||
@@ -50,8 +54,8 @@ describe('PostHog', () => {
|
||||
test: true,
|
||||
};
|
||||
|
||||
const ph = new PostHogClient();
|
||||
await ph.init(instanceId);
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
await ph.init();
|
||||
|
||||
ph.track({
|
||||
userId,
|
||||
@@ -70,8 +74,8 @@ describe('PostHog', () => {
|
||||
|
||||
it('gets feature flags', async () => {
|
||||
const createdAt = new Date();
|
||||
const ph = new PostHogClient();
|
||||
await ph.init(instanceId);
|
||||
const ph = new PostHogClient(instanceSettings);
|
||||
await ph.init();
|
||||
|
||||
await ph.getFeatureFlags({
|
||||
id: userId,
|
||||
|
||||
@@ -9,12 +9,11 @@ import {
|
||||
} from '@/environments/sourceControl/sourceControlHelper.ee';
|
||||
import { License } from '@/License';
|
||||
import { SourceControlPreferencesService } from '@/environments/sourceControl/sourceControlPreferences.service.ee';
|
||||
import { UserSettings } from 'n8n-core';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import path from 'path';
|
||||
import {
|
||||
SOURCE_CONTROL_SSH_FOLDER,
|
||||
SOURCE_CONTROL_GIT_FOLDER,
|
||||
SOURCE_CONTROL_SSH_KEY_NAME,
|
||||
} from '@/environments/sourceControl/constants';
|
||||
import { LoggerProxy } from 'n8n-workflow';
|
||||
import { getLogger } from '@/Logger';
|
||||
@@ -184,10 +183,9 @@ describe('Source Control', () => {
|
||||
});
|
||||
|
||||
it('should check for git and ssh folders and create them if required', async () => {
|
||||
const userFolder = UserSettings.getUserN8nFolderPath();
|
||||
const sshFolder = path.join(userFolder, SOURCE_CONTROL_SSH_FOLDER);
|
||||
const gitFolder = path.join(userFolder, SOURCE_CONTROL_GIT_FOLDER);
|
||||
const sshKeyName = path.join(sshFolder, SOURCE_CONTROL_SSH_KEY_NAME);
|
||||
const { n8nFolder } = Container.get(InstanceSettings);
|
||||
const sshFolder = path.join(n8nFolder, SOURCE_CONTROL_SSH_FOLDER);
|
||||
const gitFolder = path.join(n8nFolder, SOURCE_CONTROL_GIT_FOLDER);
|
||||
let hasThrown = false;
|
||||
try {
|
||||
accessSync(sshFolder, fsConstants.F_OK);
|
||||
|
||||
@@ -4,6 +4,8 @@ import config from '@/config';
|
||||
import { flushPromises } from './Helpers';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { mockInstance } from '../integration/shared/utils';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
|
||||
jest.unmock('@/telemetry');
|
||||
jest.mock('@/license/License.service', () => {
|
||||
@@ -28,6 +30,7 @@ describe('Telemetry', () => {
|
||||
let telemetry: Telemetry;
|
||||
const instanceId = 'Telemetry unit test';
|
||||
const testDateTime = new Date('2022-01-01 00:00:00');
|
||||
const instanceSettings = mockInstance(InstanceSettings, { instanceId });
|
||||
|
||||
beforeAll(() => {
|
||||
startPulseSpy = jest
|
||||
@@ -49,11 +52,10 @@ describe('Telemetry', () => {
|
||||
beforeEach(async () => {
|
||||
spyTrack.mockClear();
|
||||
|
||||
const postHog = new PostHogClient();
|
||||
await postHog.init(instanceId);
|
||||
const postHog = new PostHogClient(instanceSettings);
|
||||
await postHog.init();
|
||||
|
||||
telemetry = new Telemetry(postHog, mock());
|
||||
telemetry.setInstanceId(instanceId);
|
||||
telemetry = new Telemetry(postHog, mock(), instanceSettings);
|
||||
(telemetry as any).rudderStack = mockRudderStack;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user