mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-24 23:22:38 +08:00
chore(core): License flag for the dynamic credential module (#22971)
This commit is contained in:
@@ -58,6 +58,10 @@ export class LicenseState {
|
||||
return this.isLicensed(LICENSE_FEATURES.CUSTOM_ROLES);
|
||||
}
|
||||
|
||||
isDynamicCredentialsLicensed() {
|
||||
return this.isLicensed(LICENSE_FEATURES.DYNAMIC_CREDENTIALS);
|
||||
}
|
||||
|
||||
isSharingLicensed() {
|
||||
return this.isLicensed('feat:sharing');
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ export const LICENSE_FEATURES = {
|
||||
WORKFLOW_DIFFS: 'feat:workflowDiffs',
|
||||
CUSTOM_ROLES: 'feat:customRoles',
|
||||
AI_BUILDER: 'feat:aiBuilder',
|
||||
DYNAMIC_CREDENTIALS: 'feat:dynamicCredentials',
|
||||
} as const;
|
||||
|
||||
export const LICENSE_QUOTAS = {
|
||||
|
||||
@@ -86,6 +86,7 @@ type PushRequest = Request<
|
||||
@RestController('/e2e')
|
||||
export class E2EController {
|
||||
private enabledFeatures: Record<BooleanLicenseFeature, boolean> = {
|
||||
[LICENSE_FEATURES.DYNAMIC_CREDENTIALS]: false,
|
||||
[LICENSE_FEATURES.SHARING]: false,
|
||||
[LICENSE_FEATURES.LDAP]: false,
|
||||
[LICENSE_FEATURES.SAML]: false,
|
||||
|
||||
@@ -221,6 +221,11 @@ export class License implements LicenseProvider {
|
||||
return this.manager?.hasFeatureEnabled(feature) ?? false;
|
||||
}
|
||||
|
||||
/** @deprecated Use `LicenseState.isDynamicCredentialsLicensed` instead. */
|
||||
isDynamicCredentialsEnabled() {
|
||||
return this.isLicensed(LICENSE_FEATURES.DYNAMIC_CREDENTIALS);
|
||||
}
|
||||
|
||||
/** @deprecated Use `LicenseState.isSharingLicensed` instead. */
|
||||
isSharingEnabled() {
|
||||
return this.isLicensed(LICENSE_FEATURES.SHARING);
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { LICENSE_FEATURES } from '@n8n/constants';
|
||||
import type { ModuleInterface } from '@n8n/decorators';
|
||||
import { BackendModule, OnShutdown } from '@n8n/decorators';
|
||||
import { Container } from '@n8n/di';
|
||||
|
||||
@BackendModule({ name: 'dynamic-credentials', licenseFlag: 'feat:externalSecrets' })
|
||||
function isFeatureFlagEnabled(): boolean {
|
||||
return process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS === 'true';
|
||||
}
|
||||
|
||||
// TODO: Remove LICENSE_FEATURES.EXTERNAL_SECRETS with dynamic credentials feature once it is in the license server
|
||||
@BackendModule({ name: 'dynamic-credentials', licenseFlag: LICENSE_FEATURES.EXTERNAL_SECRETS })
|
||||
export class DynamicCredentialsModule implements ModuleInterface {
|
||||
async init() {
|
||||
if (!isFeatureFlagEnabled()) {
|
||||
return;
|
||||
}
|
||||
await import('./dynamic-credentials.controller');
|
||||
await import('./credential-resolvers.controller');
|
||||
await import('./context-establishment-hooks');
|
||||
@@ -15,6 +24,9 @@ export class DynamicCredentialsModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async entities() {
|
||||
if (!isFeatureFlagEnabled()) {
|
||||
return [];
|
||||
}
|
||||
const { DynamicCredentialResolver } = await import('./database/entities/credential-resolver');
|
||||
const { DynamicCredentialEntry } = await import('./database/entities/dynamic-credential-entry');
|
||||
|
||||
|
||||
+4
-2
@@ -5,9 +5,9 @@ import { GLOBAL_OWNER_ROLE, GLOBAL_MEMBER_ROLE } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { DynamicCredentialResolverService } from '@/modules/dynamic-credentials.ee/services/credential-resolver.service';
|
||||
import { DynamicCredentialResolverRepository } from '@/modules/dynamic-credentials.ee/database/repositories/credential-resolver.repository';
|
||||
import { DynamicCredentialResolverService } from '@/modules/dynamic-credentials.ee/services/credential-resolver.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
|
||||
import { createUser } from '../shared/db/users';
|
||||
import type { SuperAgentTest } from '../shared/types';
|
||||
@@ -19,6 +19,8 @@ const licenseMock = mock<LicenseState>();
|
||||
licenseMock.isLicensed.mockReturnValue(true);
|
||||
Container.set(LicenseState, licenseMock);
|
||||
|
||||
process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS = 'true';
|
||||
|
||||
const testServer = utils.setupTestServer({
|
||||
endpointGroups: ['credentials'],
|
||||
enabledFeatures: ['feat:externalSecrets'],
|
||||
|
||||
+5
-1
@@ -3,19 +3,23 @@ import { Container } from '@n8n/di';
|
||||
|
||||
import { DynamicCredentialEntryStorage } from '@/modules/dynamic-credentials.ee/credential-resolvers/storage/dynamic-credential-entry-storage';
|
||||
|
||||
import { createCredentials } from '../shared/db/credentials';
|
||||
import { createDynamicCredentialResolver } from './shared/db-helpers';
|
||||
import { createCredentials } from '../shared/db/credentials';
|
||||
|
||||
describe('DynamicCredentialEntryStorage', () => {
|
||||
let storage: DynamicCredentialEntryStorage;
|
||||
let previousEnvVar: string | undefined;
|
||||
|
||||
beforeAll(async () => {
|
||||
previousEnvVar = process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS;
|
||||
process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS = 'true';
|
||||
await testModules.loadModules(['dynamic-credentials']);
|
||||
await testDb.init();
|
||||
storage = Container.get(DynamicCredentialEntryStorage);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS = previousEnvVar;
|
||||
await testDb.terminate();
|
||||
});
|
||||
|
||||
|
||||
+6
-2
@@ -2,23 +2,27 @@ import { testDb, testModules } from '@n8n/backend-test-utils';
|
||||
import { CredentialsRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
|
||||
import { DynamicCredentialEntryRepository } from '@/modules/dynamic-credentials.ee/database/repositories/dynamic-credential-entry.repository';
|
||||
import { DynamicCredentialEntry } from '@/modules/dynamic-credentials.ee/database/entities/dynamic-credential-entry';
|
||||
import { DynamicCredentialResolverRepository } from '@/modules/dynamic-credentials.ee/database/repositories/credential-resolver.repository';
|
||||
import { DynamicCredentialEntryRepository } from '@/modules/dynamic-credentials.ee/database/repositories/dynamic-credential-entry.repository';
|
||||
|
||||
import { createCredentials } from '../shared/db/credentials';
|
||||
import { createDynamicCredentialResolver } from './shared/db-helpers';
|
||||
import { createCredentials } from '../shared/db/credentials';
|
||||
|
||||
describe('DynamicCredentialEntryRepository', () => {
|
||||
let repository: DynamicCredentialEntryRepository;
|
||||
let previousEnvVar: string | undefined;
|
||||
|
||||
beforeAll(async () => {
|
||||
previousEnvVar = process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS;
|
||||
process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS = 'true';
|
||||
await testModules.loadModules(['dynamic-credentials']);
|
||||
await testDb.init();
|
||||
repository = Container.get(DynamicCredentialEntryRepository);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
process.env.N8N_ENV_FEAT_CONTEXT_ESTABLISHMENT_HOOKS = previousEnvVar;
|
||||
await testDb.terminate();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user