mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
feat(core): Read ephemeral license from environment and clean up ee flags (#5808)
Co-authored-by: Cornelius Suermann <cornelius@n8n.io>
This commit is contained in:
parent
3ae69337ee
commit
83aef17120
|
@ -115,7 +115,7 @@
|
||||||
"tsconfig-paths": "^4.1.2"
|
"tsconfig-paths": "^4.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@n8n_io/license-sdk": "~1.8.0",
|
"@n8n_io/license-sdk": "~2.0.0",
|
||||||
"@oclif/command": "^1.8.16",
|
"@oclif/command": "^1.8.16",
|
||||||
"@oclif/core": "^1.16.4",
|
"@oclif/core": "^1.16.4",
|
||||||
"@oclif/errors": "^1.3.6",
|
"@oclif/errors": "^1.3.6",
|
||||||
|
|
|
@ -2,8 +2,6 @@ import type { LdapConfig } from './types';
|
||||||
|
|
||||||
export const LDAP_FEATURE_NAME = 'features.ldap';
|
export const LDAP_FEATURE_NAME = 'features.ldap';
|
||||||
|
|
||||||
export const LDAP_ENABLED = 'enterprise.features.ldap';
|
|
||||||
|
|
||||||
export const LDAP_LOGIN_LABEL = 'sso.ldap.loginLabel';
|
export const LDAP_LOGIN_LABEL = 'sso.ldap.loginLabel';
|
||||||
|
|
||||||
export const LDAP_LOGIN_ENABLED = 'sso.ldap.loginEnabled';
|
export const LDAP_LOGIN_ENABLED = 'sso.ldap.loginEnabled';
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { LdapManager } from './LdapManager.ee';
|
||||||
import {
|
import {
|
||||||
BINARY_AD_ATTRIBUTES,
|
BINARY_AD_ATTRIBUTES,
|
||||||
LDAP_CONFIG_SCHEMA,
|
LDAP_CONFIG_SCHEMA,
|
||||||
LDAP_ENABLED,
|
|
||||||
LDAP_FEATURE_NAME,
|
LDAP_FEATURE_NAME,
|
||||||
LDAP_LOGIN_ENABLED,
|
LDAP_LOGIN_ENABLED,
|
||||||
LDAP_LOGIN_LABEL,
|
LDAP_LOGIN_LABEL,
|
||||||
|
@ -37,7 +36,7 @@ import {
|
||||||
*/
|
*/
|
||||||
export const isLdapEnabled = (): boolean => {
|
export const isLdapEnabled = (): boolean => {
|
||||||
const license = Container.get(License);
|
const license = Container.get(License);
|
||||||
return isUserManagementEnabled() && (config.getEnv(LDAP_ENABLED) || license.isLdapEnabled());
|
return isUserManagementEnabled() && license.isLdapEnabled();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { TEntitlement, TLicenseContainerStr } from '@n8n_io/license-sdk';
|
import type { TEntitlement, TLicenseBlock } from '@n8n_io/license-sdk';
|
||||||
import { LicenseManager } from '@n8n_io/license-sdk';
|
import { LicenseManager } from '@n8n_io/license-sdk';
|
||||||
import type { ILogger } from 'n8n-workflow';
|
import type { ILogger } from 'n8n-workflow';
|
||||||
import { getLogger } from './Logger';
|
import { getLogger } from './Logger';
|
||||||
|
@ -7,7 +7,12 @@ import * as Db from '@/Db';
|
||||||
import { LICENSE_FEATURES, N8N_VERSION, SETTINGS_LICENSE_CERT_KEY } from './constants';
|
import { LICENSE_FEATURES, N8N_VERSION, SETTINGS_LICENSE_CERT_KEY } from './constants';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
|
|
||||||
async function loadCertStr(): Promise<TLicenseContainerStr> {
|
async function loadCertStr(): Promise<TLicenseBlock> {
|
||||||
|
// if we have an ephemeral license, we don't want to load it from the database
|
||||||
|
const ephemeralLicense = config.get('license.cert');
|
||||||
|
if (ephemeralLicense) {
|
||||||
|
return ephemeralLicense;
|
||||||
|
}
|
||||||
const databaseSettings = await Db.collections.Settings.findOne({
|
const databaseSettings = await Db.collections.Settings.findOne({
|
||||||
where: {
|
where: {
|
||||||
key: SETTINGS_LICENSE_CERT_KEY,
|
key: SETTINGS_LICENSE_CERT_KEY,
|
||||||
|
@ -17,7 +22,9 @@ async function loadCertStr(): Promise<TLicenseContainerStr> {
|
||||||
return databaseSettings?.value ?? '';
|
return databaseSettings?.value ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveCertStr(value: TLicenseContainerStr): Promise<void> {
|
async function saveCertStr(value: TLicenseBlock): Promise<void> {
|
||||||
|
// if we have an ephemeral license, we don't want to save it to the database
|
||||||
|
if (config.get('license.cert')) return;
|
||||||
await Db.collections.Settings.upsert(
|
await Db.collections.Settings.upsert(
|
||||||
{
|
{
|
||||||
key: SETTINGS_LICENSE_CERT_KEY,
|
key: SETTINGS_LICENSE_CERT_KEY,
|
||||||
|
|
|
@ -311,8 +311,8 @@ class Server extends AbstractServer {
|
||||||
sharing: false,
|
sharing: false,
|
||||||
ldap: false,
|
ldap: false,
|
||||||
saml: false,
|
saml: false,
|
||||||
logStreaming: config.getEnv('enterprise.features.logStreaming'),
|
logStreaming: false,
|
||||||
advancedExecutionFilters: config.getEnv('enterprise.features.advancedExecutionFilters'),
|
advancedExecutionFilters: false,
|
||||||
},
|
},
|
||||||
hideUsagePage: config.getEnv('hideUsagePage'),
|
hideUsagePage: config.getEnv('hideUsagePage'),
|
||||||
license: {
|
license: {
|
||||||
|
|
|
@ -57,10 +57,7 @@ export function isUserManagementEnabled(): boolean {
|
||||||
|
|
||||||
export function isSharingEnabled(): boolean {
|
export function isSharingEnabled(): boolean {
|
||||||
const license = Container.get(License);
|
const license = Container.get(License);
|
||||||
return (
|
return isUserManagementEnabled() && license.isSharingEnabled();
|
||||||
isUserManagementEnabled() &&
|
|
||||||
(config.getEnv('enterprise.features.sharing') || license.isSharingEnabled())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRoleId(scope: Role['scope'], name: Role['name']): Promise<Role['id']> {
|
export async function getRoleId(scope: Role['scope'], name: Role['name']): Promise<Role['id']> {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
|
import type { Request } from 'express';
|
||||||
import bodyParser from 'body-parser';
|
import bodyParser from 'body-parser';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
@ -12,12 +13,26 @@ import * as Db from '@/Db';
|
||||||
import type { Role } from '@db/entities/Role';
|
import type { Role } from '@db/entities/Role';
|
||||||
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
import { hashPassword } from '@/UserManagement/UserManagementHelper';
|
||||||
import { eventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
|
import { eventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
|
||||||
|
import Container from 'typedi';
|
||||||
|
import { License } from '../License';
|
||||||
|
|
||||||
if (process.env.E2E_TESTS !== 'true') {
|
if (process.env.E2E_TESTS !== 'true') {
|
||||||
console.error('E2E endpoints only allowed during E2E tests');
|
console.error('E2E endpoints only allowed during E2E tests');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const enabledFeatures = {
|
||||||
|
sharing: true, //default to true here instead of setting it in config/index.ts for e2e
|
||||||
|
ldap: false,
|
||||||
|
saml: false,
|
||||||
|
logStreaming: false,
|
||||||
|
advancedExecutionFilters: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Feature = keyof typeof enabledFeatures;
|
||||||
|
|
||||||
|
Container.get(License).isFeatureEnabled = (feature: Feature) => enabledFeatures[feature] ?? false;
|
||||||
|
|
||||||
const tablesToTruncate = [
|
const tablesToTruncate = [
|
||||||
'auth_identity',
|
'auth_identity',
|
||||||
'auth_provider_sync_history',
|
'auth_provider_sync_history',
|
||||||
|
@ -78,7 +93,7 @@ const setupUserManagement = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetLogStreaming = async () => {
|
const resetLogStreaming = async () => {
|
||||||
config.set('enterprise.features.logStreaming', false);
|
enabledFeatures.logStreaming = false;
|
||||||
for (const id in eventBus.destinations) {
|
for (const id in eventBus.destinations) {
|
||||||
await eventBus.removeDestination(id);
|
await eventBus.removeDestination(id);
|
||||||
}
|
}
|
||||||
|
@ -127,7 +142,8 @@ e2eController.post('/db/setup-owner', bodyParser.json(), async (req, res) => {
|
||||||
res.writeHead(204).end();
|
res.writeHead(204).end();
|
||||||
});
|
});
|
||||||
|
|
||||||
e2eController.post('/enable-feature/:feature', async (req, res) => {
|
e2eController.post('/enable-feature/:feature', async (req: Request<{ feature: Feature }>, res) => {
|
||||||
config.set(`enterprise.features.${req.params.feature}`, true);
|
const { feature } = req.params;
|
||||||
|
enabledFeatures[feature] = true;
|
||||||
res.writeHead(204).end();
|
res.writeHead(204).end();
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,10 +26,6 @@ if (inE2ETests) {
|
||||||
|
|
||||||
const config = convict(schema, { args: [] });
|
const config = convict(schema, { args: [] });
|
||||||
|
|
||||||
if (inE2ETests) {
|
|
||||||
config.set('enterprise.features.sharing', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
config.getEnv = config.get;
|
config.getEnv = config.get;
|
||||||
|
|
||||||
|
|
|
@ -990,31 +990,6 @@ export const schema = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
enterprise: {
|
|
||||||
features: {
|
|
||||||
sharing: {
|
|
||||||
format: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
ldap: {
|
|
||||||
format: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
saml: {
|
|
||||||
format: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
logStreaming: {
|
|
||||||
format: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
advancedExecutionFilters: {
|
|
||||||
format: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
sso: {
|
sso: {
|
||||||
justInTimeProvisioning: {
|
justInTimeProvisioning: {
|
||||||
format: Boolean,
|
format: Boolean,
|
||||||
|
@ -1166,6 +1141,12 @@ export const schema = {
|
||||||
env: 'N8N_LICENSE_TENANT_ID',
|
env: 'N8N_LICENSE_TENANT_ID',
|
||||||
doc: 'Tenant id used by the license manager',
|
doc: 'Tenant id used by the license manager',
|
||||||
},
|
},
|
||||||
|
cert: {
|
||||||
|
format: String,
|
||||||
|
default: '',
|
||||||
|
env: 'N8N_LICENSE_CERT',
|
||||||
|
doc: 'Ephemeral license certificate',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
hideUsagePage: {
|
hideUsagePage: {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import config from '@/config';
|
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
|
||||||
export function isLogStreamingEnabled(): boolean {
|
export function isLogStreamingEnabled(): boolean {
|
||||||
const license = Container.get(License);
|
const license = Container.get(License);
|
||||||
return config.getEnv('enterprise.features.logStreaming') || license.isLogStreamingEnabled();
|
return license.isLogStreamingEnabled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { Container } from 'typedi';
|
||||||
import type { IExecutionFlattedDb } from '@/Interfaces';
|
import type { IExecutionFlattedDb } from '@/Interfaces';
|
||||||
import type { ExecutionStatus } from 'n8n-workflow';
|
import type { ExecutionStatus } from 'n8n-workflow';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import config from '@/config';
|
|
||||||
|
|
||||||
export function getStatusUsingPreviousExecutionStatusMethod(
|
export function getStatusUsingPreviousExecutionStatusMethod(
|
||||||
execution: IExecutionFlattedDb,
|
execution: IExecutionFlattedDb,
|
||||||
|
@ -22,8 +21,5 @@ export function getStatusUsingPreviousExecutionStatusMethod(
|
||||||
|
|
||||||
export function isAdvancedExecutionFiltersEnabled(): boolean {
|
export function isAdvancedExecutionFiltersEnabled(): boolean {
|
||||||
const license = Container.get(License);
|
const license = Container.get(License);
|
||||||
return (
|
return license.isAdvancedExecutionFiltersEnabled();
|
||||||
config.getEnv('enterprise.features.advancedExecutionFilters') ||
|
|
||||||
license.isAdvancedExecutionFiltersEnabled()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,6 @@ export class SamlUrls {
|
||||||
|
|
||||||
export const SAML_PREFERENCES_DB_KEY = 'features.saml';
|
export const SAML_PREFERENCES_DB_KEY = 'features.saml';
|
||||||
|
|
||||||
export const SAML_ENTERPRISE_FEATURE_ENABLED = 'enterprise.features.saml';
|
|
||||||
|
|
||||||
export const SAML_LOGIN_LABEL = 'sso.saml.loginLabel';
|
export const SAML_LOGIN_LABEL = 'sso.saml.loginLabel';
|
||||||
|
|
||||||
export const SAML_LOGIN_ENABLED = 'sso.saml.loginEnabled';
|
export const SAML_LOGIN_ENABLED = 'sso.saml.loginEnabled';
|
||||||
|
|
|
@ -10,7 +10,7 @@ import type { SamlPreferences } from './types/samlPreferences';
|
||||||
import type { SamlUserAttributes } from './types/samlUserAttributes';
|
import type { SamlUserAttributes } from './types/samlUserAttributes';
|
||||||
import type { FlowResult } from 'samlify/types/src/flow';
|
import type { FlowResult } from 'samlify/types/src/flow';
|
||||||
import type { SamlAttributeMapping } from './types/samlAttributeMapping';
|
import type { SamlAttributeMapping } from './types/samlAttributeMapping';
|
||||||
import { SAML_ENTERPRISE_FEATURE_ENABLED, SAML_LOGIN_ENABLED, SAML_LOGIN_LABEL } from './constants';
|
import { SAML_LOGIN_ENABLED, SAML_LOGIN_LABEL } from './constants';
|
||||||
import {
|
import {
|
||||||
isEmailCurrentAuthenticationMethod,
|
isEmailCurrentAuthenticationMethod,
|
||||||
isSamlCurrentAuthenticationMethod,
|
isSamlCurrentAuthenticationMethod,
|
||||||
|
@ -52,10 +52,7 @@ export function setSamlLoginLabel(label: string): void {
|
||||||
|
|
||||||
export function isSamlLicensed(): boolean {
|
export function isSamlLicensed(): boolean {
|
||||||
const license = Container.get(License);
|
const license = Container.get(License);
|
||||||
return (
|
return isUserManagementEnabled() && license.isSamlEnabled();
|
||||||
isUserManagementEnabled() &&
|
|
||||||
(license.isSamlEnabled() || config.getEnv(SAML_ENTERPRISE_FEATURE_ENABLED))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSamlLicensedAndEnabled(): boolean {
|
export function isSamlLicensedAndEnabled(): boolean {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import config from '@/config';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import syslog from 'syslog-client';
|
import syslog from 'syslog-client';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import Container from 'typedi';
|
||||||
import type { SuperAgentTest } from 'supertest';
|
import type { SuperAgentTest } from 'supertest';
|
||||||
import * as utils from './shared/utils';
|
import * as utils from './shared/utils';
|
||||||
import * as testDb from './shared/testDb';
|
import * as testDb from './shared/testDb';
|
||||||
|
@ -23,6 +24,7 @@ import { MessageEventBusDestinationWebhook } from '@/eventbus/MessageEventBusDes
|
||||||
import { MessageEventBusDestinationSentry } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSentry.ee';
|
import { MessageEventBusDestinationSentry } from '@/eventbus/MessageEventBusDestination/MessageEventBusDestinationSentry.ee';
|
||||||
import { EventMessageAudit } from '@/eventbus/EventMessageClasses/EventMessageAudit';
|
import { EventMessageAudit } from '@/eventbus/EventMessageClasses/EventMessageAudit';
|
||||||
import { EventNamesTypes } from '@/eventbus/EventMessageClasses';
|
import { EventNamesTypes } from '@/eventbus/EventMessageClasses';
|
||||||
|
import { License } from '@/License';
|
||||||
|
|
||||||
jest.unmock('@/eventbus/MessageEventBus/MessageEventBus');
|
jest.unmock('@/eventbus/MessageEventBus/MessageEventBus');
|
||||||
jest.mock('axios');
|
jest.mock('axios');
|
||||||
|
@ -77,6 +79,7 @@ async function confirmIdSent(id: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
Container.get(License).isLogStreamingEnabled = () => true;
|
||||||
app = await utils.initTestServer({ endpointGroups: ['eventBus'] });
|
app = await utils.initTestServer({ endpointGroups: ['eventBus'] });
|
||||||
|
|
||||||
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
|
@ -101,7 +104,6 @@ beforeAll(async () => {
|
||||||
utils.initConfigFile();
|
utils.initConfigFile();
|
||||||
config.set('eventBus.logWriter.logBaseName', 'n8n-test-logwriter');
|
config.set('eventBus.logWriter.logBaseName', 'n8n-test-logwriter');
|
||||||
config.set('eventBus.logWriter.keepLogCount', 1);
|
config.set('eventBus.logWriter.keepLogCount', 1);
|
||||||
config.set('enterprise.features.logStreaming', true);
|
|
||||||
config.set('userManagement.disabled', false);
|
config.set('userManagement.disabled', false);
|
||||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||||
|
|
||||||
|
@ -110,6 +112,7 @@ beforeAll(async () => {
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
jest.mock('@/eventbus/MessageEventBus/MessageEventBus');
|
jest.mock('@/eventbus/MessageEventBus/MessageEventBus');
|
||||||
|
Container.reset();
|
||||||
await testDb.terminate();
|
await testDb.terminate();
|
||||||
await eventBus.close();
|
await eventBus.close();
|
||||||
});
|
});
|
||||||
|
@ -178,7 +181,6 @@ test.skip('should send message to syslog', async () => {
|
||||||
eventName: 'n8n.test.message' as EventNamesTypes,
|
eventName: 'n8n.test.message' as EventNamesTypes,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
});
|
});
|
||||||
config.set('enterprise.features.logStreaming', true);
|
|
||||||
|
|
||||||
const syslogDestination = eventBus.destinations[
|
const syslogDestination = eventBus.destinations[
|
||||||
testSyslogDestination.id!
|
testSyslogDestination.id!
|
||||||
|
@ -219,7 +221,6 @@ test.skip('should confirm send message if there are no subscribers', async () =>
|
||||||
eventName: 'n8n.test.unsub' as EventNamesTypes,
|
eventName: 'n8n.test.unsub' as EventNamesTypes,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
});
|
});
|
||||||
config.set('enterprise.features.logStreaming', true);
|
|
||||||
|
|
||||||
const syslogDestination = eventBus.destinations[
|
const syslogDestination = eventBus.destinations[
|
||||||
testSyslogDestination.id!
|
testSyslogDestination.id!
|
||||||
|
@ -255,7 +256,6 @@ test('should anonymize audit message to syslog ', async () => {
|
||||||
},
|
},
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
});
|
});
|
||||||
config.set('enterprise.features.logStreaming', true);
|
|
||||||
|
|
||||||
const syslogDestination = eventBus.destinations[
|
const syslogDestination = eventBus.destinations[
|
||||||
testSyslogDestination.id!
|
testSyslogDestination.id!
|
||||||
|
@ -317,7 +317,6 @@ test('should send message to webhook ', async () => {
|
||||||
eventName: 'n8n.test.message' as EventNamesTypes,
|
eventName: 'n8n.test.message' as EventNamesTypes,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
});
|
});
|
||||||
config.set('enterprise.features.logStreaming', true);
|
|
||||||
|
|
||||||
const webhookDestination = eventBus.destinations[
|
const webhookDestination = eventBus.destinations[
|
||||||
testWebhookDestination.id!
|
testWebhookDestination.id!
|
||||||
|
@ -352,7 +351,6 @@ test('should send message to sentry ', async () => {
|
||||||
eventName: 'n8n.test.message' as EventNamesTypes,
|
eventName: 'n8n.test.message' as EventNamesTypes,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
});
|
});
|
||||||
config.set('enterprise.features.logStreaming', true);
|
|
||||||
|
|
||||||
const sentryDestination = eventBus.destinations[
|
const sentryDestination = eventBus.destinations[
|
||||||
testSentryDestination.id!
|
testSentryDestination.id!
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import type { Entry as LdapUser } from 'ldapts';
|
import type { Entry as LdapUser } from 'ldapts';
|
||||||
import { Not } from 'typeorm';
|
import { Not } from 'typeorm';
|
||||||
|
import Container from 'typedi';
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import * as Db from '@/Db';
|
import * as Db from '@/Db';
|
||||||
|
@ -12,11 +13,12 @@ import { LdapService } from '@/Ldap/LdapService.ee';
|
||||||
import { encryptPassword, saveLdapSynchronization } from '@/Ldap/helpers';
|
import { encryptPassword, saveLdapSynchronization } from '@/Ldap/helpers';
|
||||||
import type { LdapConfig } from '@/Ldap/types';
|
import type { LdapConfig } from '@/Ldap/types';
|
||||||
import { sanitizeUser } from '@/UserManagement/UserManagementHelper';
|
import { sanitizeUser } from '@/UserManagement/UserManagementHelper';
|
||||||
|
import { getCurrentAuthenticationMethod, setCurrentAuthenticationMethod } from '@/sso/ssoHelpers';
|
||||||
|
import { License } from '@/License';
|
||||||
import { randomEmail, randomName, uniqueId } from './../shared/random';
|
import { randomEmail, randomName, uniqueId } from './../shared/random';
|
||||||
import * as testDb from './../shared/testDb';
|
import * as testDb from './../shared/testDb';
|
||||||
import type { AuthAgent } from '../shared/types';
|
import type { AuthAgent } from '../shared/types';
|
||||||
import * as utils from '../shared/utils';
|
import * as utils from '../shared/utils';
|
||||||
import { getCurrentAuthenticationMethod, setCurrentAuthenticationMethod } from '@/sso/ssoHelpers';
|
|
||||||
|
|
||||||
jest.mock('@/telemetry');
|
jest.mock('@/telemetry');
|
||||||
jest.mock('@/UserManagement/email/NodeMailer');
|
jest.mock('@/UserManagement/email/NodeMailer');
|
||||||
|
@ -41,6 +43,7 @@ const defaultLdapConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
Container.get(License).isLdapEnabled = () => true;
|
||||||
app = await utils.initTestServer({ endpointGroups: ['auth', 'ldap'] });
|
app = await utils.initTestServer({ endpointGroups: ['auth', 'ldap'] });
|
||||||
|
|
||||||
const [globalOwnerRole, fetchedGlobalMemberRole] = await testDb.getAllRoles();
|
const [globalOwnerRole, fetchedGlobalMemberRole] = await testDb.getAllRoles();
|
||||||
|
@ -77,10 +80,10 @@ beforeEach(async () => {
|
||||||
config.set('userManagement.disabled', false);
|
config.set('userManagement.disabled', false);
|
||||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||||
config.set('userManagement.emails.mode', '');
|
config.set('userManagement.emails.mode', '');
|
||||||
config.set('enterprise.features.ldap', true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
Container.reset();
|
||||||
await testDb.terminate();
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
import Container from 'typedi';
|
||||||
import type { SuperAgentTest } from 'supertest';
|
import type { SuperAgentTest } from 'supertest';
|
||||||
import config from '@/config';
|
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import { setSamlLoginEnabled } from '@/sso/saml/samlHelpers';
|
import { setSamlLoginEnabled } from '@/sso/saml/samlHelpers';
|
||||||
import { getCurrentAuthenticationMethod, setCurrentAuthenticationMethod } from '@/sso/ssoHelpers';
|
import { getCurrentAuthenticationMethod, setCurrentAuthenticationMethod } from '@/sso/ssoHelpers';
|
||||||
|
import { License } from '@/License';
|
||||||
import { randomEmail, randomName, randomValidPassword } from '../shared/random';
|
import { randomEmail, randomName, randomValidPassword } from '../shared/random';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
import * as utils from '../shared/utils';
|
import * as utils from '../shared/utils';
|
||||||
|
@ -13,16 +14,17 @@ let authOwnerAgent: SuperAgentTest;
|
||||||
|
|
||||||
async function enableSaml(enable: boolean) {
|
async function enableSaml(enable: boolean) {
|
||||||
await setSamlLoginEnabled(enable);
|
await setSamlLoginEnabled(enable);
|
||||||
config.set('enterprise.features.saml', enable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
Container.get(License).isSamlEnabled = () => true;
|
||||||
const app = await utils.initTestServer({ endpointGroups: ['me', 'saml'] });
|
const app = await utils.initTestServer({ endpointGroups: ['me', 'saml'] });
|
||||||
owner = await testDb.createOwner();
|
owner = await testDb.createOwner();
|
||||||
authOwnerAgent = utils.createAuthAgent(app)(owner);
|
authOwnerAgent = utils.createAuthAgent(app)(owner);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
Container.reset();
|
||||||
await testDb.terminate();
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -74,13 +74,13 @@ import { InternalHooks } from '@/InternalHooks';
|
||||||
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
|
||||||
import { PostHogClient } from '@/posthog';
|
import { PostHogClient } from '@/posthog';
|
||||||
import { LdapManager } from '@/Ldap/LdapManager.ee';
|
import { LdapManager } from '@/Ldap/LdapManager.ee';
|
||||||
import { LDAP_ENABLED } from '@/Ldap/constants';
|
|
||||||
import { handleLdapInit } from '@/Ldap/helpers';
|
import { handleLdapInit } from '@/Ldap/helpers';
|
||||||
import { Push } from '@/push';
|
import { Push } from '@/push';
|
||||||
import { setSamlLoginEnabled } from '@/sso/saml/samlHelpers';
|
import { setSamlLoginEnabled } from '@/sso/saml/samlHelpers';
|
||||||
import { SamlService } from '@/sso/saml/saml.service.ee';
|
import { SamlService } from '@/sso/saml/saml.service.ee';
|
||||||
import { SamlController } from '@/sso/saml/routes/saml.controller.ee';
|
import { SamlController } from '@/sso/saml/routes/saml.controller.ee';
|
||||||
import { EventBusController } from '@/eventbus/eventBus.controller';
|
import { EventBusController } from '@/eventbus/eventBus.controller';
|
||||||
|
import { License } from '@/License';
|
||||||
|
|
||||||
export const mockInstance = <T>(
|
export const mockInstance = <T>(
|
||||||
ctor: new (...args: any[]) => T,
|
ctor: new (...args: any[]) => T,
|
||||||
|
@ -186,7 +186,7 @@ export async function initTestServer({
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'ldap':
|
case 'ldap':
|
||||||
config.set(LDAP_ENABLED, true);
|
Container.get(License).isLdapEnabled = () => true;
|
||||||
await handleLdapInit();
|
await handleLdapInit();
|
||||||
const { service, sync } = LdapManager.getInstance();
|
const { service, sync } = LdapManager.getInstance();
|
||||||
registerController(
|
registerController(
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import Container from 'typedi';
|
||||||
import type { SuperAgentTest } from 'supertest';
|
import type { SuperAgentTest } from 'supertest';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import type { INode } from 'n8n-workflow';
|
import type { INode } from 'n8n-workflow';
|
||||||
|
|
||||||
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
|
import * as UserManagementHelpers from '@/UserManagement/UserManagementHelper';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import config from '@/config';
|
|
||||||
|
|
||||||
import * as utils from './shared/utils';
|
import * as utils from './shared/utils';
|
||||||
import * as testDb from './shared/testDb';
|
import * as testDb from './shared/testDb';
|
||||||
|
@ -12,6 +12,7 @@ import { createWorkflow } from './shared/testDb';
|
||||||
import type { SaveCredentialFunction } from './shared/types';
|
import type { SaveCredentialFunction } from './shared/types';
|
||||||
import { makeWorkflow } from './shared/utils';
|
import { makeWorkflow } from './shared/utils';
|
||||||
import { randomCredentialPayload } from './shared/random';
|
import { randomCredentialPayload } from './shared/random';
|
||||||
|
import { License } from '@/License';
|
||||||
|
|
||||||
let owner: User;
|
let owner: User;
|
||||||
let member: User;
|
let member: User;
|
||||||
|
@ -23,6 +24,7 @@ let saveCredential: SaveCredentialFunction;
|
||||||
let sharingSpy: jest.SpyInstance<boolean>;
|
let sharingSpy: jest.SpyInstance<boolean>;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
Container.get(License).isSharingEnabled = () => true;
|
||||||
const app = await utils.initTestServer({ endpointGroups: ['workflows'] });
|
const app = await utils.initTestServer({ endpointGroups: ['workflows'] });
|
||||||
|
|
||||||
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
const globalOwnerRole = await testDb.getGlobalOwnerRole();
|
||||||
|
@ -42,8 +44,6 @@ beforeAll(async () => {
|
||||||
sharingSpy = jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(true);
|
sharingSpy = jest.spyOn(UserManagementHelpers, 'isSharingEnabled').mockReturnValue(true);
|
||||||
|
|
||||||
await utils.initNodeTypes();
|
await utils.initNodeTypes();
|
||||||
|
|
||||||
config.set('enterprise.features.sharing', true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
@ -51,6 +51,7 @@ beforeEach(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
Container.reset();
|
||||||
await testDb.terminate();
|
await testDb.terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -151,8 +151,8 @@ importers:
|
||||||
packages/cli:
|
packages/cli:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@n8n_io/license-sdk':
|
'@n8n_io/license-sdk':
|
||||||
specifier: ~1.8.0
|
specifier: ~2.0.0
|
||||||
version: 1.8.0
|
version: 2.0.0
|
||||||
'@oclif/command':
|
'@oclif/command':
|
||||||
specifier: ^1.8.16
|
specifier: ^1.8.16
|
||||||
version: 1.8.18(@oclif/config@1.18.5)(supports-color@8.1.1)
|
version: 1.8.18(@oclif/config@1.18.5)(supports-color@8.1.1)
|
||||||
|
@ -4284,16 +4284,14 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@n8n_io/license-sdk@1.8.0:
|
/@n8n_io/license-sdk@2.0.0:
|
||||||
resolution: {integrity: sha512-dSBD6EHTu6kWWz1ILxtCcaQqVZu+p/8J0eQ2ntx7Jk8BYSvn5Hh4Oz5M81ut9Pz+2uak+GnIuI6KeYUe1QBXIQ==}
|
resolution: {integrity: sha512-JBgVqp2Hp8QkEHwWmDvoU8dLrq0wZlK38FnwaX/yZiCGpEz1+zywFxaggxbDYXxvhX3cwlgxv3o3kfVaYX1Xlw==}
|
||||||
engines: {node: '>=14.0.0', npm: '>=7.10.0'}
|
engines: {node: '>=14.0.0', npm: '>=7.10.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
axios: 1.1.3
|
|
||||||
crypto-js: 4.1.1
|
crypto-js: 4.1.1
|
||||||
node-machine-id: 1.1.12
|
node-machine-id: 1.1.12
|
||||||
node-rsa: 1.1.1
|
node-rsa: 1.1.1
|
||||||
transitivePeerDependencies:
|
undici: 5.21.0
|
||||||
- debug
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@n8n_io/riot-tmpl@3.0.0:
|
/@n8n_io/riot-tmpl@3.0.0:
|
||||||
|
@ -8220,16 +8218,6 @@ packages:
|
||||||
- debug
|
- debug
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/axios@1.1.3:
|
|
||||||
resolution: {integrity: sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==}
|
|
||||||
dependencies:
|
|
||||||
follow-redirects: 1.15.2(debug@3.2.7)
|
|
||||||
form-data: 4.0.0
|
|
||||||
proxy-from-env: 1.1.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- debug
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/babel-core@7.0.0-bridge.0(@babel/core@7.20.12):
|
/babel-core@7.0.0-bridge.0(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
|
resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -20766,6 +20754,13 @@ packages:
|
||||||
undertaker-registry: 1.0.1
|
undertaker-registry: 1.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/undici@5.21.0:
|
||||||
|
resolution: {integrity: sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==}
|
||||||
|
engines: {node: '>=12.18'}
|
||||||
|
dependencies:
|
||||||
|
busboy: 1.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/unescape@1.0.1:
|
/unescape@1.0.1:
|
||||||
resolution: {integrity: sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==}
|
resolution: {integrity: sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
Loading…
Reference in a new issue