mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 13:39:44 +02:00
refactor(core): move ownership service to backend services
This commit is contained in:
parent
01da88958d
commit
0275af7854
|
|
@ -26,6 +26,7 @@ export {
|
|||
} from './services/workflow-sharing.service';
|
||||
export { FolderFinderService } from './services/folder-finder.service';
|
||||
export { InstanceWriteAccessService } from './services/instance-write-access.service';
|
||||
export { OwnershipService } from './services/ownership.service';
|
||||
export { UrlService } from './services/url.service';
|
||||
export {
|
||||
classifyRestError,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import {
|
||||
Project,
|
||||
CredentialsEntity,
|
||||
SharedWorkflow,
|
||||
User,
|
||||
WorkflowEntity,
|
||||
|
|
@ -14,17 +13,20 @@ import {
|
|||
GLOBAL_OWNER_ROLE,
|
||||
PROJECT_OWNER_ROLE,
|
||||
} from '@n8n/db';
|
||||
import type { SharedCredentials, SettingsRepository } from '@n8n/db';
|
||||
import type { SharedCredentials } from '@n8n/db';
|
||||
import { PROJECT_OWNER_ROLE_SLUG } from '@n8n/permissions';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
import { BadRequestError } from '@n8n/errors';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
import { mockCredential, mockProject } from '@test/mock-objects';
|
||||
import { CacheService } from '../cache/cache.service';
|
||||
import { OwnershipService } from '../ownership.service';
|
||||
|
||||
import { CacheService } from '@n8n/backend-services';
|
||||
const mockCredential = () => new CredentialsEntity();
|
||||
const mockProject = () =>
|
||||
Object.assign(new Project(), {
|
||||
id: randomUUID(),
|
||||
type: 'personal' as const,
|
||||
name: 'Test project',
|
||||
});
|
||||
|
||||
describe('OwnershipService', () => {
|
||||
const userRepository = mockInstance(UserRepository);
|
||||
|
|
@ -32,21 +34,13 @@ describe('OwnershipService', () => {
|
|||
const projectRelationRepository = mockInstance(ProjectRelationRepository);
|
||||
const projectRepository = mockInstance(ProjectRepository);
|
||||
const cacheService = mockInstance(CacheService);
|
||||
const passwordUtility = mockInstance(PasswordUtility);
|
||||
const logger = mockInstance(Logger);
|
||||
const eventService = mock<EventService>();
|
||||
const settingsRepository = mock<SettingsRepository>();
|
||||
|
||||
const ownershipService = new OwnershipService(
|
||||
cacheService,
|
||||
eventService,
|
||||
logger,
|
||||
passwordUtility,
|
||||
projectRelationRepository,
|
||||
projectRepository,
|
||||
sharedWorkflowRepository,
|
||||
userRepository,
|
||||
settingsRepository,
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -108,9 +102,9 @@ describe('OwnershipService', () => {
|
|||
test('should not use the repository if the owner was found in the cache', async () => {
|
||||
// ARRANGE
|
||||
const project = new Project();
|
||||
project.id = uuid();
|
||||
project.id = randomUUID();
|
||||
const owner = new User();
|
||||
owner.id = uuid();
|
||||
owner.id = randomUUID();
|
||||
owner.role = GLOBAL_OWNER_ROLE;
|
||||
const projectRelation = new ProjectRelation();
|
||||
projectRelation.role = PROJECT_OWNER_ROLE;
|
||||
|
|
@ -274,7 +268,7 @@ describe('OwnershipService', () => {
|
|||
describe('invalidateProjectOwnerCacheByUserId()', () => {
|
||||
test('should delete cache entry for personal project', async () => {
|
||||
const project = new Project();
|
||||
project.id = uuid();
|
||||
project.id = randomUUID();
|
||||
projectRepository.getPersonalProjectForUser.mockResolvedValueOnce(project);
|
||||
|
||||
await ownershipService.invalidateProjectOwnerCacheByUserId('some-user-id');
|
||||
|
|
@ -331,123 +325,4 @@ describe('OwnershipService', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setupOwner()', () => {
|
||||
it('should throw a BadRequestError if the instance owner is already setup', async () => {
|
||||
userRepository.hasClaimedInstanceOwner.mockResolvedValueOnce(true);
|
||||
|
||||
const execution = ownershipService.setupOwner(mock());
|
||||
await expect(execution).rejects.toThrow(BadRequestError);
|
||||
await expect(execution).rejects.toThrow('Instance owner already setup');
|
||||
|
||||
expect(userRepository.save).not.toHaveBeenCalled();
|
||||
expect(eventService.emit).not.toHaveBeenCalled();
|
||||
expect(logger.debug).toHaveBeenCalledWith(
|
||||
'Request to claim instance ownership failed because instance owner already exists',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw a BadRequestError if the shell user is not found', async () => {
|
||||
userRepository.hasClaimedInstanceOwner.mockResolvedValueOnce(false);
|
||||
userRepository.findOne.mockResolvedValueOnce(null);
|
||||
|
||||
const execution = ownershipService.setupOwner(mock());
|
||||
await expect(execution).rejects.toThrow(BadRequestError);
|
||||
await expect(execution).rejects.toThrow('Instance owner shell user not found');
|
||||
|
||||
expect(userRepository.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup the instance owner successfully', async () => {
|
||||
const user = mock<User>({
|
||||
id: 'userId',
|
||||
role: GLOBAL_OWNER_ROLE,
|
||||
authIdentities: [],
|
||||
});
|
||||
|
||||
const payload = {
|
||||
email: 'valid@email.com',
|
||||
password: 'NewPassword123',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe',
|
||||
};
|
||||
|
||||
// not quite perfect as we hash the password.
|
||||
const expected = { ...user, ...payload, id: 'newUserId' };
|
||||
|
||||
userRepository.hasClaimedInstanceOwner.mockResolvedValueOnce(false);
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(expected);
|
||||
|
||||
const actual = await ownershipService.setupOwner(payload);
|
||||
|
||||
expect(userRepository.save).toHaveBeenCalledWith(user, { transaction: false });
|
||||
expect(eventService.emit).toHaveBeenCalledWith('instance-owner-setup', {
|
||||
userId: 'newUserId',
|
||||
});
|
||||
expect(actual.id).toEqual('newUserId');
|
||||
});
|
||||
|
||||
it('should normalize email to lowercase', async () => {
|
||||
const user = mock<User>({
|
||||
id: 'userId',
|
||||
role: GLOBAL_OWNER_ROLE,
|
||||
authIdentities: [],
|
||||
});
|
||||
|
||||
const payload = {
|
||||
email: 'Admin@Example.COM',
|
||||
password: 'NewPassword123',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe',
|
||||
};
|
||||
|
||||
userRepository.hasClaimedInstanceOwner.mockResolvedValueOnce(false);
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(user);
|
||||
|
||||
await ownershipService.setupOwner(payload);
|
||||
|
||||
expect(user.email).toBe('admin@example.com');
|
||||
});
|
||||
|
||||
it('should skip hasInstanceOwner check when override is true', async () => {
|
||||
const user = mock<User>({
|
||||
id: 'userId',
|
||||
role: GLOBAL_OWNER_ROLE,
|
||||
authIdentities: [],
|
||||
});
|
||||
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(user);
|
||||
|
||||
await ownershipService.setupOwner(
|
||||
{ email: 'a@b.com', password: 'hash', firstName: 'A', lastName: 'B' },
|
||||
{ overwriteExisting: true },
|
||||
);
|
||||
|
||||
expect(userRepository.hasClaimedInstanceOwner).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use pre-hashed password when preHashed is true', async () => {
|
||||
const user = mock<User>({
|
||||
id: 'userId',
|
||||
role: GLOBAL_OWNER_ROLE,
|
||||
authIdentities: [],
|
||||
});
|
||||
|
||||
const preHashedPassword = '$2b$10$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ01234';
|
||||
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(user);
|
||||
|
||||
await ownershipService.setupOwner(
|
||||
{ email: 'a@b.com', password: preHashedPassword, firstName: 'A', lastName: 'B' },
|
||||
{ overwriteExisting: true, passwordIsHashed: true },
|
||||
);
|
||||
|
||||
expect(user.password).toBe(preHashedPassword);
|
||||
expect(passwordUtility.hash).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,38 +1,27 @@
|
|||
import { OwnerSetupRequestDto } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { CacheService, EventService } from '@n8n/backend-services';
|
||||
import type { ListQueryDb } from '@n8n/db';
|
||||
import {
|
||||
GLOBAL_OWNER_ROLE,
|
||||
Project,
|
||||
User,
|
||||
ProjectRelationRepository,
|
||||
ProjectRepository,
|
||||
SharedWorkflowRepository,
|
||||
UserRepository,
|
||||
Role,
|
||||
SettingsRepository,
|
||||
Scope,
|
||||
SharedWorkflowRepository,
|
||||
User,
|
||||
UserRepository,
|
||||
} from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
|
||||
import config from '@/config';
|
||||
import { BadRequestError } from '@n8n/errors';
|
||||
|
||||
import { PasswordUtility } from './password.utility';
|
||||
import { CacheService } from './cache/cache.service';
|
||||
|
||||
@Service()
|
||||
export class OwnershipService {
|
||||
constructor(
|
||||
private cacheService: CacheService,
|
||||
private eventService: EventService,
|
||||
private logger: Logger,
|
||||
private passwordUtility: PasswordUtility,
|
||||
private projectRelationRepository: ProjectRelationRepository,
|
||||
private projectRepository: ProjectRepository,
|
||||
private sharedWorkflowRepository: SharedWorkflowRepository,
|
||||
private userRepository: UserRepository,
|
||||
private settingsRepository: SettingsRepository,
|
||||
) {}
|
||||
|
||||
// To make use of the cache service we should store POJOs, these
|
||||
|
|
@ -256,55 +245,4 @@ export class OwnershipService {
|
|||
async hasInstanceOwner() {
|
||||
return await this.userRepository.hasClaimedInstanceOwner();
|
||||
}
|
||||
|
||||
async setupOwner(
|
||||
payload: OwnerSetupRequestDto,
|
||||
options?: { overwriteExisting?: boolean; passwordIsHashed?: boolean },
|
||||
) {
|
||||
const { email, firstName, lastName, password } = payload;
|
||||
|
||||
if (!options?.overwriteExisting && (await this.hasInstanceOwner())) {
|
||||
this.logger.debug(
|
||||
'Request to claim instance ownership failed because instance owner already exists',
|
||||
);
|
||||
throw new BadRequestError('Instance owner already setup');
|
||||
}
|
||||
|
||||
let shellUser = await this.userRepository.findOne({
|
||||
where: { role: { slug: GLOBAL_OWNER_ROLE.slug } },
|
||||
relations: ['role'],
|
||||
});
|
||||
|
||||
if (!shellUser) {
|
||||
this.logger.error('Could not find shell user with global:owner role');
|
||||
throw new BadRequestError('Instance owner shell user not found');
|
||||
}
|
||||
|
||||
shellUser.email = email.toLowerCase();
|
||||
shellUser.firstName = firstName;
|
||||
shellUser.lastName = lastName;
|
||||
shellUser.lastActiveAt = new Date();
|
||||
shellUser.password = options?.passwordIsHashed
|
||||
? password
|
||||
: await this.passwordUtility.hash(password);
|
||||
|
||||
shellUser = await this.userRepository.save(shellUser, { transaction: false });
|
||||
|
||||
this.logger.info('Owner was set up successfully');
|
||||
this.eventService.emit('instance-owner-setup', { userId: shellUser.id });
|
||||
|
||||
// The next block needs to be deleted and is temporary for now
|
||||
// See packages/cli/src/config/schema.ts for more info
|
||||
// We update the SettingsRepository so when we "startup" next time
|
||||
// the config state is restored.
|
||||
// #region Delete me
|
||||
await this.settingsRepository.update(
|
||||
{ key: 'userManagement.isInstanceOwnerSetUp' },
|
||||
{ value: JSON.stringify(true) },
|
||||
);
|
||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||
// #endregion
|
||||
|
||||
return shellUser;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { EventService, WorkflowSharingService } from '@n8n/backend-services';
|
||||
import type { EventService, WorkflowSharingService, OwnershipService } from '@n8n/backend-services';
|
||||
import { mockLogger } from '@n8n/backend-test-utils';
|
||||
import type { GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import type { Project, WorkflowEntity, WorkflowHistory, WorkflowRepository } from '@n8n/db';
|
||||
|
|
@ -45,7 +45,6 @@ import type {
|
|||
} from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import type { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { PolicyViolationError } from '@/policy/policy-violation.error';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { PollCursorService } from '@/workflows/triggers/poll-cursor.service';
|
||||
import { TriggerExecutionContextFactory } from '@/workflows/triggers/trigger-execution-context.factory';
|
||||
import type { WorkflowExecutionService } from '@/workflows/workflow-execution.service';
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import { ExecutionAlreadyResumingError } from '@/errors/execution-already-resumi
|
|||
import { ExecutionPersistence } from '@/executions/execution-persistence';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import type { MultiMainSetup } from '@/scaling/multi-main-setup.ee';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
import type { WorkflowPublisherService } from '@/workflows/workflow-publisher.service';
|
||||
import { WaitTracker } from '@/wait-tracker';
|
||||
import type { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { EventService, UrlService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, OwnershipService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { ExecutionsConfig, GlobalConfig, type NodesConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import type { WorkflowEntity, Project, WorkflowHistory } from '@n8n/db';
|
||||
|
|
@ -47,7 +47,6 @@ import { AgentsService } from '@/modules/agents/agents.service';
|
|||
import { AgentsSettingsService } from '@/modules/agents/agents-settings.service';
|
||||
import { DataTableProxyService } from '@/modules/data-table/data-table-proxy.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import type {
|
|||
import { VariablesService } from '@/environments.ee/variables/variables.service.ee';
|
||||
import { ExecutionPersistence } from '@/executions/execution-persistence';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import {
|
||||
getLastExecutedNodeData,
|
||||
getLastExecutedNodeRuns,
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ import {
|
|||
} from '@/executions/pre-execution-checks';
|
||||
import { ManualExecutionService } from '@/manual-execution.service';
|
||||
import { EngineV2Dispatcher } from '@/services/engine-v2-dispatcher.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import { EXECUTION_ENDED_WITHOUT_RESPONSE } from '@/webhooks/constants';
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ import { PollTriggerJobRegistrar } from '@/scheduling/poll-trigger-node/poll-tri
|
|||
import type { ScheduleTriggerCollectionSession } from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import { ScheduleTriggerJobRegistrar } from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import { ActiveWorkflowsService } from '@/services/active-workflows.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import * as WebhookHelpers from '@/webhooks/webhook-helpers';
|
||||
import { WebhookService } from '@/webhooks/webhook.service';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-da
|
|||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
||||
import { NodeTypes } from '../../node-types';
|
||||
import { OwnershipService } from '../../services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { ChatExecutionManager } from '../chat-execution-manager';
|
||||
import type { ChatMessage } from '../chat-service.types';
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import { WorkflowRunner } from '../workflow-runner';
|
|||
import type { ChatMessage } from './chat-service.types';
|
||||
import { findResumeNode, redirectIfToolExecutor } from './utils';
|
||||
import { NodeTypes } from '../node-types';
|
||||
import { OwnershipService } from '../services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { stripToolSuffix } from '../utils';
|
||||
|
||||
@Service()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import { License } from '@/license';
|
|||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { CommunityPackagesService } from '@/modules/community-packages/community-packages.service';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { ShutdownService } from '@/shutdown/shutdown.service';
|
||||
import { TaskRunnerModule } from '@/task-runners/task-runner-module';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import { License } from '@/license';
|
|||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { CommunityPackagesService } from '@/modules/community-packages/community-packages.service';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { ShutdownService } from '@/shutdown/shutdown.service';
|
||||
import { TaskRunnerModule } from '@/task-runners/task-runner-module';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { sep } from 'path';
|
|||
import { z } from 'zod';
|
||||
|
||||
import { ActiveExecutions } from '@/active-executions';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { findCliWorkflowStart } from '@/utils';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { WorkflowRepository } from '@n8n/db';
|
||||
import { Command } from '@n8n/decorators';
|
||||
import { Container } from '@n8n/di';
|
||||
|
|
@ -7,7 +7,6 @@ import { ExecutionBaseError, UnexpectedError, UserError } from 'n8n-workflow';
|
|||
import { z } from 'zod';
|
||||
|
||||
import { ActiveExecutions } from '@/active-executions';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { findCliWorkflowStart, isWorkflowIdValid } from '@/utils';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
import { getWorkflowProjectDetailsSafe } from '@/workflows/utils';
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ import { OwnerController } from '@/controllers/owner.controller';
|
|||
import { BadRequestError } from '@n8n/errors';
|
||||
import type { PostHogClient } from '@/posthog';
|
||||
import type { BannerService } from '@/services/banner.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnerSetupService } from '@/services/owner-setup.service';
|
||||
import type { UserService } from '@/services/user.service';
|
||||
|
||||
describe('OwnerController', () => {
|
||||
const authService = mock<AuthService>();
|
||||
const bannerService = mock<BannerService>();
|
||||
const userService = mock<UserService>();
|
||||
const ownershipService = mock<OwnershipService>();
|
||||
const ownerSetupService = mock<OwnerSetupService>();
|
||||
const postHogClient = mock<PostHogClient>();
|
||||
|
||||
const controller = new OwnerController(
|
||||
|
|
@ -21,12 +21,12 @@ describe('OwnerController', () => {
|
|||
bannerService,
|
||||
userService,
|
||||
postHogClient,
|
||||
ownershipService,
|
||||
ownerSetupService,
|
||||
);
|
||||
|
||||
describe('setupOwner', () => {
|
||||
it('should pass on errors from the service', async () => {
|
||||
ownershipService.setupOwner.mockRejectedValueOnce(
|
||||
ownerSetupService.setupOwner.mockRejectedValueOnce(
|
||||
new BadRequestError('Instance owner already setup'),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import { Response } from 'express';
|
|||
import { AuthService } from '@/auth/auth.service';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { BannerService } from '@/services/banner.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { OwnerSetupService } from '@/services/owner-setup.service';
|
||||
|
||||
@RestController('/owner')
|
||||
export class OwnerController {
|
||||
|
|
@ -16,7 +16,7 @@ export class OwnerController {
|
|||
private readonly bannerService: BannerService,
|
||||
private readonly userService: UserService,
|
||||
private readonly postHog: PostHogClient,
|
||||
private readonly ownershipService: OwnershipService,
|
||||
private readonly ownerSetupService: OwnerSetupService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
|
@ -24,7 +24,7 @@ export class OwnerController {
|
|||
*/
|
||||
@Post('/setup', { skipAuth: true })
|
||||
async setupOwner(req: AuthenticatedRequest, res: Response, @Body payload: OwnerSetupRequestDto) {
|
||||
const owner = await this.ownershipService.setupOwner(payload);
|
||||
const owner = await this.ownerSetupService.setupOwner(payload);
|
||||
this.authService.issueCookie(res, owner, req.authInfo?.usedMfa ?? false, req.browserId);
|
||||
return await this.userService.toPublic(owner, { posthog: this.postHog, withScopes: true });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,16 @@ import type {
|
|||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { CredentialConnectionStatusProxy } from '@/credentials/credential-connection-status-proxy';
|
||||
import { type CredentialsFinderService, type RoleService } from '@n8n/backend-services';
|
||||
import type {
|
||||
CredentialsFinderService,
|
||||
RoleService,
|
||||
OwnershipService,
|
||||
} from '@n8n/backend-services';
|
||||
import type { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { EnterpriseCredentialsService } from '@/credentials/credentials.service.ee';
|
||||
import type { ExternalSecretsConfig } from '@/modules/external-secrets.ee/external-secrets.config';
|
||||
import type { SecretsProviderAccessCheckService } from '@/modules/external-secrets.ee/secret-provider-access-check.service.ee';
|
||||
import type { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
describe('EnterpriseCredentialsService', () => {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ import { CredentialDescriptionsService } from '@/credentials/credential-descript
|
|||
import type { PostHogClient } from '@/posthog';
|
||||
import { CREDENTIAL_DESCRIPTION_MAX_LENGTH } from '@n8n/api-types';
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
import {
|
||||
type EventService,
|
||||
type RoleService,
|
||||
type CredentialsFinderService,
|
||||
import type {
|
||||
EventService,
|
||||
RoleService,
|
||||
CredentialsFinderService,
|
||||
OwnershipService,
|
||||
} from '@n8n/backend-services';
|
||||
import type {
|
||||
CredentialsRepository,
|
||||
|
|
@ -66,7 +67,6 @@ import {
|
|||
} from '@/oauth/dcr-managed-fields';
|
||||
import * as checkAccess from '@/permissions.ee/check-access';
|
||||
import type { CredentialsTester } from '@/services/credentials-tester.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
import { mockExistingCredential } from './credentials.test-data';
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@ import { TransferCredentialError } from '@/errors/response-errors/transfer-crede
|
|||
import { ExternalSecretsConfig } from '@/modules/external-secrets.ee/external-secrets.config';
|
||||
import { SecretsProviderAccessCheckService } from '@/modules/external-secrets.ee/secret-provider-access-check.service.ee';
|
||||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService, RoleService, CredentialsFinderService } from '@n8n/backend-services';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService, CredentialsFinderService } from '@n8n/backend-services';
|
||||
|
||||
import { CredentialConnectionStatusProxy } from './credential-connection-status-proxy';
|
||||
import { CredentialsService } from './credentials.service';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import type { CreateCredentialDto, CredentialConnectionStatus } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService, RoleService, CredentialsFinderService } from '@n8n/backend-services';
|
||||
import {
|
||||
EventService,
|
||||
RoleService,
|
||||
CredentialsFinderService,
|
||||
OwnershipService,
|
||||
} from '@n8n/backend-services';
|
||||
import { Time } from '@n8n/constants';
|
||||
import {
|
||||
Project,
|
||||
|
|
@ -74,7 +79,6 @@ import type { PolicyActor } from '@/policy/policy-enforcement-backend';
|
|||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import type { CredentialRequest, ListQuery } from '@/requests';
|
||||
import { CredentialsTester } from '@/services/credentials-tester.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
import { CredentialConnectionStatusProxy } from './credential-connection-status-proxy';
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import { TestRunError } from '@/evaluation.ee/test-runner/errors.ee';
|
|||
import type { License } from '@/license';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import type { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
import type { Telemetry } from '@/telemetry';
|
||||
import type { WorkflowRunner } from '@/workflow-runner';
|
||||
import type { WorkflowHistoryService } from '@/workflows/workflow-history/workflow-history.service';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { ExecutionsConfig } from '@n8n/config';
|
||||
import type { EvaluationConfig, User } from '@n8n/db';
|
||||
import {
|
||||
|
|
@ -52,7 +52,6 @@ import {
|
|||
} from '@/evaluation.ee/test-runner/utils.ee';
|
||||
import { License } from '@/license';
|
||||
import { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
import { getWorkflowProjectDetailsSafe } from '@/workflows/utils';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, type OwnershipService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { EMPTY_CANVAS_GROUPS_FLAG } from '@n8n/api-types';
|
||||
import type { GlobalConfig } from '@n8n/config';
|
||||
|
|
@ -41,7 +41,6 @@ import { OtelConfig } from '@/modules/otel/otel.config';
|
|||
import type { PolicyRule } from '@/modules/type-availability-policies/policy-rule.types';
|
||||
import type { NodeTypes } from '@/node-types';
|
||||
import type { PostHogClient } from '@/posthog';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { Telemetry } from '@/telemetry';
|
||||
|
||||
const flushPromises = async () => await new Promise((resolve) => setImmediate(resolve));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { EMPTY_CANVAS_GROUPS_FLAG } from '@n8n/api-types';
|
||||
import { LicenseState } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import {
|
||||
CredentialsRepository,
|
||||
|
|
@ -59,7 +59,6 @@ import type {
|
|||
} from '@/modules/type-availability-policies/policy-rule.types';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
|
||||
import { EventRelay } from './event-relay';
|
||||
import { Telemetry } from '../../telemetry';
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import { createRunExecutionData, NodeOperationError } from 'n8n-workflow';
|
|||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { PolicyViolationError } from '@/policy/policy-violation.error';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { UrlService } from '@n8n/backend-services';
|
||||
import { OwnershipService, UrlService } from '@n8n/backend-services';
|
||||
import { WorkflowExecutionService } from '@/workflows/workflow-execution.service';
|
||||
|
||||
import { executeErrorWorkflow } from '../execute-error-workflow';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { PushMessage } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { ExecutionsConfig } from '@n8n/config';
|
||||
import type { Project, User } from '@n8n/db';
|
||||
|
|
@ -42,7 +42,6 @@ import { ExecutionRedactionServiceProxy } from '@/executions/execution-redaction
|
|||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Push } from '@/push';
|
||||
import { ExecutionMetadataService } from '@/services/execution-metadata.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
|
||||
import { WorkflowHookContextService } from '@/workflow-hook-context.service';
|
||||
import { WorkflowExecutionService } from '@/workflows/workflow-execution.service';
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ import { toErrorWorkflowContext } from 'n8n-workflow';
|
|||
|
||||
import type { IWorkflowErrorData } from '@/interfaces';
|
||||
import { isPolicyRefusal } from '@/policy/policy-violation.error';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { UrlService } from '@n8n/backend-services';
|
||||
import { OwnershipService, UrlService } from '@n8n/backend-services';
|
||||
|
||||
/**
|
||||
* Resolved lazily. A static import would close the cycle
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { EventService } from '@n8n/backend-services';
|
||||
import type { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { mockLogger } from '@n8n/backend-test-utils';
|
||||
import type { ExecutionsConfig } from '@n8n/config';
|
||||
import type { IExecutionResponse, Project } from '@n8n/db';
|
||||
|
|
@ -9,7 +9,6 @@ import { ExecutionAlreadyResumingError } from '@/errors/execution-already-resumi
|
|||
import { EnqueuedExecutionRecoveryService } from '@/executions/enqueued-execution-recovery.service';
|
||||
import type { ExecutionCrashService } from '@/executions/execution-crash.service';
|
||||
import type { ExecutionService } from '@/executions/execution.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { WorkflowPublisherService } from '@/workflows/workflow-publisher.service';
|
||||
import type { WorkflowRunner } from '@/workflow-runner';
|
||||
|
||||
|
|
|
|||
|
|
@ -34,11 +34,9 @@ import { ExecutionPersistence } from '@/executions/execution-persistence';
|
|||
import { ExecutionRecoveryService } from '@/executions/execution-recovery.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Push } from '@/push';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService, type EventService, WorkflowSharingService } from '@n8n/backend-services';
|
||||
import { WorkflowPublicationNotifier } from '@/workflows/publication/workflow-publication-notifier';
|
||||
import { WorkflowPushNotifier } from '@/workflows/workflow-push-notifier.service';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { WorkflowSharingService } from '@n8n/backend-services';
|
||||
import { createExecution } from '@test-integration/db/executions';
|
||||
|
||||
import { IN_PROGRESS_EXECUTION_DATA, OOM_WORKFLOW } from './constants';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { DeleteExecutionsDto } from '@n8n/api-types';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import type { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import type {
|
||||
|
|
@ -33,7 +33,6 @@ import type { ExecutionRequest } from '@/executions/execution.types';
|
|||
import type { ExecutionStopService } from '@/scaling/execution-stop.service';
|
||||
import { ScalingService } from '@/scaling/scaling.service';
|
||||
import type { Job } from '@/scaling/scaling.types';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { EngineDataPlaneProxyService } from '@/services/engine-data-plane-proxy.service';
|
||||
import type { WaitTracker } from '@/wait-tracker';
|
||||
import type { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { ExecutionsConfig } from '@n8n/config';
|
||||
import { Service } from '@n8n/di';
|
||||
import { ErrorReporter } from 'n8n-core';
|
||||
|
|
@ -9,7 +9,6 @@ import { strict as assert } from 'node:assert';
|
|||
import { ExecutionAlreadyResumingError } from '@/errors/execution-already-resuming.error';
|
||||
import { ExecutionCrashService } from '@/executions/execution-crash.service';
|
||||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { WorkflowPublisherService } from '@/workflows/workflow-publisher.service';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import { getLifecycleHooksForRegularMain } from '@/execution-lifecycle/execution
|
|||
import { ExecutionCrashService } from '@/executions/execution-crash.service';
|
||||
import { ExecutionPersistence } from '@/executions/execution-persistence';
|
||||
import { Push } from '@/push';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { UserManagementMailer } from '@/user-management/email/user-management-mailer';
|
||||
import { WorkflowPushNotifier } from '@/workflows/workflow-push-notifier.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { DeleteExecutionsDto } from '@n8n/api-types';
|
||||
import { ExecutionRedactionQueryDtoSchema } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import type {
|
||||
CreateExecutionPayload,
|
||||
|
|
@ -52,7 +52,6 @@ import { License } from '@/license';
|
|||
import { NodeTypes } from '@/node-types';
|
||||
import { ExecutionStopService } from '@/scaling/execution-stop.service';
|
||||
import { EngineDataPlaneProxyService } from '@/services/engine-data-plane-proxy.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { WaitTracker } from '@/wait-tracker';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
import { getWorkflowProjectDetailsSafe } from '@/workflows/utils';
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
|
||||
import type { CredentialsFinderService } from '@n8n/backend-services';
|
||||
import type { CredentialsFinderService, OwnershipService } from '@n8n/backend-services';
|
||||
import type { NodeTypes } from '@/node-types';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
import { CredentialsPermissionChecker } from '../credentials-permission-checker';
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ import {
|
|||
SubworkflowPolicyDenialError,
|
||||
} from '@/errors/subworkflow-policy-denial.error';
|
||||
import type { AccessService } from '@/services/access.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import type { UrlService } from '@n8n/backend-services';
|
||||
import { OwnershipService, type UrlService } from '@n8n/backend-services';
|
||||
|
||||
import { SubworkflowPolicyChecker } from '../subworkflow-policy-checker';
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@ import type { INode, INodeTypeDescription } from 'n8n-workflow';
|
|||
import { getActiveCredentialTypes, UserError } from 'n8n-workflow';
|
||||
|
||||
import { isCredSharingEnabled } from '@/constants/credential-sharing';
|
||||
import { CredentialsFinderService, type UnusableCredential } from '@n8n/backend-services';
|
||||
import {
|
||||
CredentialsFinderService,
|
||||
type UnusableCredential,
|
||||
OwnershipService,
|
||||
} from '@n8n/backend-services';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
class InvalidCredentialError extends UserError {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ import { type INode, type IWorkflowBase, type WorkflowSettings } from 'n8n-workf
|
|||
|
||||
import { SubworkflowPolicyDenialError } from '@/errors/subworkflow-policy-denial.error';
|
||||
import { AccessService } from '@/services/access.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { UrlService } from '@n8n/backend-services';
|
||||
import { OwnershipService, UrlService } from '@n8n/backend-services';
|
||||
|
||||
type Policy = WorkflowSettings.CallerPolicy;
|
||||
type DenialPolicy = Exclude<Policy, 'any'>;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import type { Logger } from '@n8n/backend-common';
|
|||
import type { InstanceSettingsLoaderConfig } from '@n8n/config';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnerSetupService } from '@/services/owner-setup.service';
|
||||
|
||||
import { OwnerInstanceSettingsLoader } from '../loaders/owner.instance-settings-loader';
|
||||
|
||||
describe('OwnerInstanceSettingsLoader', () => {
|
||||
const logger = mock<Logger>({ scoped: vi.fn().mockReturnThis() });
|
||||
const ownershipService = mock<OwnershipService>();
|
||||
const ownerSetupService = mock<OwnerSetupService>();
|
||||
|
||||
const validBcryptHash = '$2b$10$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ01234';
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
...configOverrides,
|
||||
} as InstanceSettingsLoaderConfig;
|
||||
|
||||
return new OwnerInstanceSettingsLoader(config, ownershipService, logger);
|
||||
return new OwnerInstanceSettingsLoader(config, ownerSetupService, logger);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -37,7 +37,7 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
const result = await loader.run();
|
||||
|
||||
expect(result).toBe('skipped');
|
||||
expect(ownershipService.setupOwner).not.toHaveBeenCalled();
|
||||
expect(ownerSetupService.setupOwner).not.toHaveBeenCalled();
|
||||
expect(logger.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
const result = await loader.run();
|
||||
|
||||
expect(result).toBe('skipped');
|
||||
expect(ownershipService.setupOwner).not.toHaveBeenCalled();
|
||||
expect(ownerSetupService.setupOwner).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should skip when ownerPasswordHash is set', async () => {
|
||||
|
|
@ -56,7 +56,7 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
const result = await loader.run();
|
||||
|
||||
expect(result).toBe('skipped');
|
||||
expect(ownershipService.setupOwner).not.toHaveBeenCalled();
|
||||
expect(ownerSetupService.setupOwner).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should skip when both email and password are set', async () => {
|
||||
|
|
@ -68,7 +68,7 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
const result = await loader.run();
|
||||
|
||||
expect(result).toBe('skipped');
|
||||
expect(ownershipService.setupOwner).not.toHaveBeenCalled();
|
||||
expect(ownerSetupService.setupOwner).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
expect(logger.info).toHaveBeenCalledWith(
|
||||
expect.stringContaining('N8N_INSTANCE_OWNER_MANAGED_BY_ENV is enabled'),
|
||||
);
|
||||
expect(ownershipService.setupOwner).toHaveBeenCalledWith(
|
||||
expect(ownerSetupService.setupOwner).toHaveBeenCalledWith(
|
||||
{
|
||||
email: 'admin@example.com',
|
||||
firstName: 'Jane',
|
||||
|
|
@ -128,8 +128,6 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
});
|
||||
|
||||
it('should overwrite existing owner', async () => {
|
||||
ownershipService.hasInstanceOwner.mockResolvedValue(true);
|
||||
|
||||
const loader = createLoader({
|
||||
ownerManagedByEnv: true,
|
||||
ownerEmail: 'new@example.com',
|
||||
|
|
@ -141,7 +139,7 @@ describe('OwnerInstanceSettingsLoader', () => {
|
|||
const result = await loader.run();
|
||||
|
||||
expect(result).toBe('created');
|
||||
expect(ownershipService.setupOwner).toHaveBeenCalledWith(
|
||||
expect(ownerSetupService.setupOwner).toHaveBeenCalledWith(
|
||||
{
|
||||
email: 'new@example.com',
|
||||
firstName: 'New',
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { InstanceSettingsLoaderConfig } from '@n8n/config';
|
|||
import { Service } from '@n8n/di';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnerSetupService } from '@/services/owner-setup.service';
|
||||
|
||||
import { InstanceBootstrappingError } from '../instance-bootstrapping.error';
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ const ownerEnvSchema = z
|
|||
export class OwnerInstanceSettingsLoader {
|
||||
constructor(
|
||||
private readonly instanceSettingsLoaderConfig: InstanceSettingsLoaderConfig,
|
||||
private readonly ownershipService: OwnershipService,
|
||||
private readonly ownerSetupService: OwnerSetupService,
|
||||
private logger: Logger,
|
||||
) {
|
||||
this.logger = this.logger.scoped('instance-settings-loader');
|
||||
|
|
@ -67,7 +67,7 @@ export class OwnerInstanceSettingsLoader {
|
|||
throw new InstanceBootstrappingError(result.error.issues[0].message);
|
||||
}
|
||||
|
||||
await this.ownershipService.setupOwner(result.data.payload, result.data.options);
|
||||
await this.ownerSetupService.setupOwner(result.data.payload, result.data.options);
|
||||
|
||||
return 'created';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@ import { NodeOperationError } from 'n8n-workflow';
|
|||
import type { MockInstance } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { InstanceWriteAccessService } from '@n8n/backend-services';
|
||||
import type { InstanceWriteAccessService, OwnershipService } from '@n8n/backend-services';
|
||||
import * as checkAccess from '@/permissions.ee/check-access';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
|
||||
import type { DataTableAggregateService } from '../data-table-aggregate.service';
|
||||
import { DataTableProxyService } from '../data-table-proxy.service';
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ import {
|
|||
|
||||
import { ForbiddenError } from '@n8n/errors';
|
||||
import { userHasScopes } from '@/permissions.ee/check-access';
|
||||
import { InstanceWriteAccessService } from '@n8n/backend-services';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { InstanceWriteAccessService, OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
import { DataTableAggregateService } from './data-table-aggregate.service';
|
||||
import { DataTableService } from './data-table.service';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import type { NodeTypes } from '@/node-types';
|
|||
import type { PostHogClient } from '@/posthog';
|
||||
import type { DataTableService } from '@/modules/data-table/data-table.service';
|
||||
import type { WorkflowRunner } from '@/workflow-runner';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import type { WorkflowStaticDataService } from '@/workflows/workflow-static-data.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
|||
import { DataTableService } from '@/modules/data-table/data-table.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
import { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import { WorkflowStaticDataService } from '@/workflows/workflow-static-data.service';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, type OwnershipService } from '@n8n/backend-services';
|
||||
import type {
|
||||
NodeExecuteAfterContext,
|
||||
NodeExecuteBeforeContext,
|
||||
|
|
@ -11,7 +11,6 @@ import { Workflow } from 'n8n-workflow';
|
|||
import type { INodeTypes, IRun, IRunExecutionData, WorkflowExecuteMode } from 'n8n-workflow';
|
||||
|
||||
import type { RelayEventMap } from '@/events/maps/relay.event-map';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
|
||||
import type { ExecutionLevelTracer } from '../execution-level-tracer';
|
||||
import { OtelLifecycleHandler, countInputItems, countOutputItems } from '../otel-lifecycle-handler';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { OnLifecycleEvent, OnPubSubEvent } from '@n8n/decorators';
|
||||
import type {
|
||||
WorkflowExecuteBeforeContext,
|
||||
|
|
@ -18,7 +18,6 @@ import type { CustomAttributes } from './execution-level-tracer.types';
|
|||
import { OtelSettingsService } from './otel-settings.service';
|
||||
import { OtelService } from './otel.service';
|
||||
import { TraceContextService } from './tracing-context';
|
||||
import { OwnershipService } from '../../services/ownership.service';
|
||||
|
||||
const isCustomTelemetryTag = (value: unknown): value is ICustomTelemetryTag =>
|
||||
typeof value === 'object' &&
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { PolicyViolationError } from '@/policy/policy-violation.error';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
import { PolicyCheckFailedError } from '../policy-check-failed.error';
|
||||
import { PolicyDecisionService } from '../policy-decision.service';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { WorkflowExecuteBeforeContext } from '@n8n/decorators';
|
|||
import { Service } from '@n8n/di';
|
||||
|
||||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
/**
|
||||
* The execution backstop. Every way an execution starts — main, queue worker,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import type {
|
|||
} from 'simple-git';
|
||||
|
||||
import { buildHttpsGitConfig, buildSshCommand } from '@/modules/promotions.ee/promotions-git.utils';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
import {
|
||||
SOURCE_CONTROL_DEFAULT_BRANCH,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { Project } from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
import { enforceWorkflowPublishPolicy } from '../enforce-workflow-publish';
|
||||
import type { PolicyActor } from '../policy-enforcement-backend';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { PolicedWorkflow } from '@n8n/decorators';
|
||||
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
import type { PolicyActor } from './policy-enforcement-backend';
|
||||
import type { PolicyEnforcementService } from './policy-enforcement.service';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { DynamicStructuredTool } from '@langchain/core/tools';
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import type { ExecutionsConfig } from '@n8n/config';
|
||||
import type { IExecutionResponse, ExecutionRepository, Project } from '@n8n/db';
|
||||
import { WorkflowPublishHistoryRepository } from '@n8n/db';
|
||||
|
|
@ -49,7 +49,6 @@ import { ExternalHooks } from '@/external-hooks';
|
|||
import type { ManualExecutionService } from '@/manual-execution.service';
|
||||
import { DataTableProxyService } from '@/modules/data-table/data-table-proxy.service';
|
||||
import type { NodeTypes } from '@/node-types';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import { WorkflowHookContextService } from '@/workflow-hook-context.service';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
/* eslint-disable @typescript-eslint/naming-convention -- item keys are pinned to the legacy ScheduleTrigger emit shape */
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import type { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import type { GlobalConfig } from '@n8n/config';
|
||||
import type { ExecutionEntity, ExecutionRepository, Project } from '@n8n/db';
|
||||
import { createDispatchReporter, type ClaimedTask } from '@n8n/scheduler';
|
||||
|
|
@ -11,7 +11,6 @@ import { CRON_NODE_TYPE, SCHEDULE_TRIGGER_NODE_TYPE, UnexpectedError } from 'n8n
|
|||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { DuplicateExecutionError } from '@/errors/duplicate-execution.error';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import type { TriggerExecutionContextFactory } from '@/workflows/triggers/trigger-execution-context.factory';
|
||||
import type { WorkflowExecutionService } from '@/workflows/workflow-execution.service';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import { ExecutionRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
|
|
@ -8,7 +8,6 @@ import { ErrorReporter } from 'n8n-core';
|
|||
import { CRON_NODE_TYPE, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { DuplicateExecutionError } from '@/errors/duplicate-execution.error';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import { TriggerExecutionContextFactory } from '@/workflows/triggers/trigger-execution-context.factory';
|
||||
import { getWorkflowProjectDetailsSafe } from '@/workflows/utils';
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
|
|||
import { BadRequestError } from '@n8n/errors';
|
||||
import type { License } from '@/license';
|
||||
import { AiGatewayService } from '@/services/ai-gateway.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { UrlService } from '@n8n/backend-services';
|
||||
import type { OwnershipService, UrlService } from '@n8n/backend-services';
|
||||
|
||||
const INSTANCE_BASE_URL = 'https://my-n8n.example.com';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { tmpdir } from 'node:os';
|
|||
import { join } from 'node:path';
|
||||
import type { Mock } from 'vitest';
|
||||
import type { LicenseState, Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import type { OwnershipService, UrlService } from '@n8n/backend-services';
|
||||
import type { GlobalConfig, SecurityConfig } from '@n8n/config';
|
||||
import type { WorkflowRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
|
|
@ -19,10 +20,8 @@ import { CommunityPackagesConfig } from '@/modules/community-packages/community-
|
|||
import type { PushConfig } from '@/push/push.config';
|
||||
import type { AiUsageService } from '@/services/ai-usage.service';
|
||||
import { FrontendService, type PublicFrontendSettings } from '@/services/frontend.service';
|
||||
import type { UrlService } from '@n8n/backend-services';
|
||||
import type { WorkflowReviewPolicyService } from '@/services/workflow-review-policy.service';
|
||||
import type { UserManagementMailer } from '@/user-management/email';
|
||||
import type { OwnershipService } from '../ownership.service';
|
||||
|
||||
// Mock the workflow history helper functions to avoid DI container issues in tests
|
||||
vi.mock('@/workflows/workflow-history/workflow-history-helper', () => ({
|
||||
|
|
|
|||
132
packages/cli/src/services/__tests__/owner-setup.service.test.ts
Normal file
132
packages/cli/src/services/__tests__/owner-setup.service.test.ts
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import type { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { GLOBAL_OWNER_ROLE, type SettingsRepository, User, UserRepository } from '@n8n/db';
|
||||
import { BadRequestError } from '@n8n/errors';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { OwnerSetupService } from '@/services/owner-setup.service';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
|
||||
describe('OwnerSetupService', () => {
|
||||
const ownershipService = mock<OwnershipService>();
|
||||
const eventService = mock<EventService>();
|
||||
const logger = mockInstance(Logger);
|
||||
const passwordUtility = mockInstance(PasswordUtility);
|
||||
const userRepository = mockInstance(UserRepository);
|
||||
const settingsRepository = mock<SettingsRepository>();
|
||||
|
||||
const ownerSetupService = new OwnerSetupService(
|
||||
ownershipService,
|
||||
eventService,
|
||||
logger,
|
||||
passwordUtility,
|
||||
userRepository,
|
||||
settingsRepository,
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should throw a BadRequestError if the instance owner is already setup', async () => {
|
||||
ownershipService.hasInstanceOwner.mockResolvedValueOnce(true);
|
||||
|
||||
const execution = ownerSetupService.setupOwner(mock());
|
||||
await expect(execution).rejects.toThrow(BadRequestError);
|
||||
await expect(execution).rejects.toThrow('Instance owner already setup');
|
||||
|
||||
expect(userRepository.save).not.toHaveBeenCalled();
|
||||
expect(eventService.emit).not.toHaveBeenCalled();
|
||||
expect(logger.debug).toHaveBeenCalledWith(
|
||||
'Request to claim instance ownership failed because instance owner already exists',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw a BadRequestError if the shell user is not found', async () => {
|
||||
ownershipService.hasInstanceOwner.mockResolvedValueOnce(false);
|
||||
userRepository.findOne.mockResolvedValueOnce(null);
|
||||
|
||||
const execution = ownerSetupService.setupOwner(mock());
|
||||
await expect(execution).rejects.toThrow(BadRequestError);
|
||||
await expect(execution).rejects.toThrow('Instance owner shell user not found');
|
||||
|
||||
expect(userRepository.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup the instance owner successfully', async () => {
|
||||
const user = mock<User>({
|
||||
id: 'userId',
|
||||
role: GLOBAL_OWNER_ROLE,
|
||||
authIdentities: [],
|
||||
});
|
||||
const payload = {
|
||||
email: 'valid@email.com',
|
||||
password: 'NewPassword123',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe',
|
||||
};
|
||||
const expected = { ...user, ...payload, id: 'newUserId' };
|
||||
|
||||
ownershipService.hasInstanceOwner.mockResolvedValueOnce(false);
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(expected);
|
||||
|
||||
const actual = await ownerSetupService.setupOwner(payload);
|
||||
|
||||
expect(userRepository.save).toHaveBeenCalledWith(user, { transaction: false });
|
||||
expect(eventService.emit).toHaveBeenCalledWith('instance-owner-setup', {
|
||||
userId: 'newUserId',
|
||||
});
|
||||
expect(settingsRepository.update).toHaveBeenCalledWith(
|
||||
{ key: 'userManagement.isInstanceOwnerSetUp' },
|
||||
{ value: JSON.stringify(true) },
|
||||
);
|
||||
expect(actual.id).toEqual('newUserId');
|
||||
});
|
||||
|
||||
it('should normalize email to lowercase', async () => {
|
||||
const user = mock<User>({ id: 'userId', role: GLOBAL_OWNER_ROLE, authIdentities: [] });
|
||||
|
||||
ownershipService.hasInstanceOwner.mockResolvedValueOnce(false);
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(user);
|
||||
|
||||
await ownerSetupService.setupOwner({
|
||||
email: 'Admin@Example.COM',
|
||||
password: 'NewPassword123',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe',
|
||||
});
|
||||
|
||||
expect(user.email).toBe('admin@example.com');
|
||||
});
|
||||
|
||||
it('should skip the owner check when overwriteExisting is true', async () => {
|
||||
const user = mock<User>({ id: 'userId', role: GLOBAL_OWNER_ROLE, authIdentities: [] });
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(user);
|
||||
|
||||
await ownerSetupService.setupOwner(
|
||||
{ email: 'a@b.com', password: 'hash', firstName: 'A', lastName: 'B' },
|
||||
{ overwriteExisting: true },
|
||||
);
|
||||
|
||||
expect(ownershipService.hasInstanceOwner).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use a pre-hashed password when passwordIsHashed is true', async () => {
|
||||
const user = mock<User>({ id: 'userId', role: GLOBAL_OWNER_ROLE, authIdentities: [] });
|
||||
const preHashedPassword = '$2b$10$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ01234';
|
||||
userRepository.findOne.mockResolvedValueOnce(user);
|
||||
userRepository.save.mockResolvedValueOnce(user);
|
||||
|
||||
await ownerSetupService.setupOwner(
|
||||
{ email: 'a@b.com', password: preHashedPassword, firstName: 'A', lastName: 'B' },
|
||||
{ overwriteExisting: true, passwordIsHashed: true },
|
||||
);
|
||||
|
||||
expect(user.password).toBe(preHashedPassword);
|
||||
expect(passwordUtility.hash).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -3,11 +3,13 @@ import { GLOBAL_OWNER_ROLE } from '@n8n/db';
|
|||
import { Container } from '@n8n/di';
|
||||
|
||||
import { HooksService } from '@/services/hooks.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { OwnerSetupService } from '@/services/owner-setup.service';
|
||||
import { createUserShell } from '@test-integration/db/users';
|
||||
|
||||
let hookService: HooksService;
|
||||
let ownershipService: OwnershipService;
|
||||
let ownerSetupService: OwnerSetupService;
|
||||
|
||||
// See PAY-4247 - This test case can be deleted when the ticket is complete
|
||||
describe('Ownership Service integration test', () => {
|
||||
|
|
@ -21,6 +23,7 @@ describe('Ownership Service integration test', () => {
|
|||
await testDb.init();
|
||||
hookService = Container.get(HooksService);
|
||||
ownershipService = Container.get(OwnershipService);
|
||||
ownerSetupService = Container.get(OwnerSetupService);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
|
@ -49,7 +52,7 @@ describe('Ownership Service integration test', () => {
|
|||
|
||||
it('should recognise ownership creation from api', async () => {
|
||||
expect(await ownershipService.hasInstanceOwner()).toBeFalsy();
|
||||
await ownershipService.setupOwner({
|
||||
await ownerSetupService.setupOwner({
|
||||
firstName: 'TEST',
|
||||
lastName: 'LN',
|
||||
password: 'PW',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ProjectRelation } from '@n8n/api-types';
|
||||
import type { Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type { EventService, OwnershipService, RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
type FolderRepository,
|
||||
type Project,
|
||||
|
|
@ -21,7 +21,6 @@ import type { EntityManager } from '@n8n/typeorm';
|
|||
import type { Mocked } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { OwnershipService } from '../ownership.service';
|
||||
import { ProjectService } from '../project.service.ee';
|
||||
|
||||
import type { ICredentialConnectionStatusProvider } from '@/credentials/credential-connection-status-provider.interface';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { InviteUsersRequestDto } from '@n8n/api-types';
|
||||
import { type EventService, UrlService, type RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
type EventService,
|
||||
type OwnershipService,
|
||||
type RoleService,
|
||||
UrlService,
|
||||
} from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import {
|
||||
|
|
@ -32,7 +37,6 @@ import type { UserManagementMailer } from '@/user-management/email';
|
|||
|
||||
import { JwtService } from '../jwt.service';
|
||||
import type { OwnershipTransferService } from '../ownership-transfer/ownership-transfer.service';
|
||||
import type { OwnershipService } from '../ownership.service';
|
||||
import type { ProjectService } from '../project.service.ee';
|
||||
import type { PublicApiKeyService } from '../public-api-key.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import type { Mock } from 'vitest';
|
||||
import {
|
||||
getPersonalProject,
|
||||
|
|
@ -30,7 +30,6 @@ import {
|
|||
} from 'n8n-workflow';
|
||||
|
||||
import { INSTANCE_ACTIVATED_SETTINGS_KEY } from '@/services/instance-activation.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
|
||||
import { createUser } from '@test-integration/db/users';
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error';
|
|||
import { BadRequestError } from '@n8n/errors';
|
||||
import { License } from '@/license';
|
||||
import { checkAiGatewayEligibility } from '@/services/ai-gateway-eligibility';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { UrlService } from '@n8n/backend-services';
|
||||
import { OwnershipService, UrlService } from '@n8n/backend-services';
|
||||
|
||||
interface GatewayTokenResponse {
|
||||
token: string;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { BinaryDataConfig, InstanceSettings, type Types } from 'n8n-core';
|
|||
import type { ICredentialType, INodeTypeBaseDescription, INodeTypeDescription } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
|
||||
import { UrlService } from '@n8n/backend-services';
|
||||
import { UrlService, OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
import { AiUsageService } from './ai-usage.service';
|
||||
import { WorkflowReviewPolicyService } from './workflow-review-policy.service';
|
||||
|
|
@ -28,7 +28,6 @@ import { MfaService } from '@/mfa/mfa.service';
|
|||
import { CommunityPackagesConfig } from '@/modules/community-packages/community-packages.config';
|
||||
import { isApiKeyAuthEnabled } from '@/public-api';
|
||||
import { PushConfig } from '@/push/push.config';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { getSamlLoginLabel, getCurrentAuthenticationMethod } from '@/sso.ee/sso-helpers';
|
||||
import { UserManagementMailer } from '@/user-management/email';
|
||||
import { resolveFrontendHealthEndpointPath } from '@/utils/health-endpoint.util';
|
||||
|
|
|
|||
73
packages/cli/src/services/owner-setup.service.ts
Normal file
73
packages/cli/src/services/owner-setup.service.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { OwnerSetupRequestDto } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GLOBAL_OWNER_ROLE, SettingsRepository, UserRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import { BadRequestError } from '@n8n/errors';
|
||||
|
||||
import config from '@/config';
|
||||
|
||||
import { PasswordUtility } from './password.utility';
|
||||
|
||||
@Service()
|
||||
export class OwnerSetupService {
|
||||
constructor(
|
||||
private readonly ownershipService: OwnershipService,
|
||||
private readonly eventService: EventService,
|
||||
private readonly logger: Logger,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly settingsRepository: SettingsRepository,
|
||||
) {}
|
||||
|
||||
async setupOwner(
|
||||
payload: OwnerSetupRequestDto,
|
||||
options?: { overwriteExisting?: boolean; passwordIsHashed?: boolean },
|
||||
) {
|
||||
const { email, firstName, lastName, password } = payload;
|
||||
|
||||
if (!options?.overwriteExisting && (await this.ownershipService.hasInstanceOwner())) {
|
||||
this.logger.debug(
|
||||
'Request to claim instance ownership failed because instance owner already exists',
|
||||
);
|
||||
throw new BadRequestError('Instance owner already setup');
|
||||
}
|
||||
|
||||
let shellUser = await this.userRepository.findOne({
|
||||
where: { role: { slug: GLOBAL_OWNER_ROLE.slug } },
|
||||
relations: ['role'],
|
||||
});
|
||||
|
||||
if (!shellUser) {
|
||||
this.logger.error('Could not find shell user with global:owner role');
|
||||
throw new BadRequestError('Instance owner shell user not found');
|
||||
}
|
||||
|
||||
shellUser.email = email.toLowerCase();
|
||||
shellUser.firstName = firstName;
|
||||
shellUser.lastName = lastName;
|
||||
shellUser.lastActiveAt = new Date();
|
||||
shellUser.password = options?.passwordIsHashed
|
||||
? password
|
||||
: await this.passwordUtility.hash(password);
|
||||
|
||||
shellUser = await this.userRepository.save(shellUser, { transaction: false });
|
||||
|
||||
this.logger.info('Owner was set up successfully');
|
||||
this.eventService.emit('instance-owner-setup', { userId: shellUser.id });
|
||||
|
||||
// The next block needs to be deleted and is temporary for now
|
||||
// See packages/cli/src/config/schema.ts for more info
|
||||
// We update the SettingsRepository so when we "startup" next time
|
||||
// the config state is restored.
|
||||
// #region Delete me
|
||||
await this.settingsRepository.update(
|
||||
{ key: 'userManagement.isInstanceOwnerSetUp' },
|
||||
{ value: JSON.stringify(true) },
|
||||
);
|
||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||
// #endregion
|
||||
|
||||
return shellUser;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
OwnershipTransferHandlerRegistry,
|
||||
type ProjectOwnershipTransferHandler,
|
||||
type OwnershipService,
|
||||
} from '@n8n/backend-services';
|
||||
import type {
|
||||
CredentialsEntity,
|
||||
|
|
@ -18,7 +19,6 @@ import type { CredentialsService } from '@/credentials/credentials.service';
|
|||
import type { PolicyActor } from '@/policy/policy-enforcement-backend';
|
||||
import type { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import type { FolderService } from '@/services/folder.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { WorkflowService } from '@/workflows/workflow.service';
|
||||
|
||||
import { OwnershipTransferService } from '../ownership-transfer.service';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { OwnershipTransferHandlerRegistry } from '@n8n/backend-services';
|
||||
import { OwnershipTransferHandlerRegistry, OwnershipService } from '@n8n/backend-services';
|
||||
import {
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
|
|
@ -11,7 +11,6 @@ import { CredentialsService } from '@/credentials/credentials.service';
|
|||
import type { PolicyActor } from '@/policy/policy-enforcement-backend';
|
||||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { FolderService } from '@/services/folder.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { WorkflowService } from '@/workflows/workflow.service';
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { CreateProjectDto, ProjectType, UpdateProjectDto } from '@n8n/api-types';
|
||||
import { LicenseState, Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService, OwnershipService } from '@n8n/backend-services';
|
||||
import {
|
||||
type User,
|
||||
FolderRepository,
|
||||
|
|
@ -37,8 +37,6 @@ import { UserError } from 'n8n-workflow';
|
|||
import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from '@n8n/errors';
|
||||
import { UserManagementMailer } from '@/user-management/email';
|
||||
|
||||
import { OwnershipService } from './ownership.service';
|
||||
|
||||
const INSTANCE_ACCESS_ROLE_ERROR =
|
||||
"This user has access through their instance role. Project roles can't change their access in this project.";
|
||||
const INSTANCE_ACCESS_REMOVE_ERROR =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { RoleChangeRequestDto } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService, UrlService, RoleService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, RoleService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import type { PublicUser } from '@n8n/db';
|
||||
import {
|
||||
|
|
@ -31,7 +31,6 @@ import { UserError } from 'n8n-workflow';
|
|||
import { validate as uuidValidate } from 'uuid';
|
||||
|
||||
import { JwtService } from './jwt.service';
|
||||
import { OwnershipService } from './ownership.service';
|
||||
import { ProjectService } from './project.service.ee';
|
||||
import { PublicApiKeyService } from './public-api-key.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger, TypedEmitter } from '@n8n/backend-common';
|
||||
import { EventService, isBillableExecution } from '@n8n/backend-services';
|
||||
import { EventService, isBillableExecution, OwnershipService } from '@n8n/backend-services';
|
||||
import { DatabaseConfig } from '@n8n/config';
|
||||
import type { CrashedExecution } from '@n8n/db';
|
||||
import {
|
||||
|
|
@ -23,7 +23,6 @@ import {
|
|||
import { UserService } from '@/services/user.service';
|
||||
|
||||
import { INSTANCE_ACTIVATED_SETTINGS_KEY } from './instance-activation.service';
|
||||
import { OwnershipService } from './ownership.service';
|
||||
|
||||
type CompletedRunOutcome = {
|
||||
mode: WorkflowExecuteMode;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
import { ActiveExecutions } from '@/active-executions';
|
||||
import { ExecutionAlreadyResumingError } from '@/errors/execution-already-resuming.error';
|
||||
import { ExecutionPersistence } from '@/executions/execution-persistence';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { WorkflowPublisherService } from '@/workflows/workflow-publisher.service';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { EngineConfig } from '@n8n/config';
|
||||
import type { Project, User } from '@n8n/db';
|
||||
|
|
@ -67,7 +67,6 @@ import { WebhookResponseRelay } from '@/scaling/webhook-response-relay';
|
|||
import { EngineDataPlaneProxyService } from '@/services/engine-data-plane-proxy.service';
|
||||
import { EngineV2Dispatcher } from '@/services/engine-v2-dispatcher.service';
|
||||
import { EngineV2WebhookResponseRegistry } from '@/modules/engine-v2/webhook-response/webhook-response-registry.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OAuth2FlowProxy } from '@/services/oauth2-flow-proxy.service';
|
||||
import type { ProtectedResource } from '@/services/protected-resource.registry';
|
||||
import { ProtectedResourceRegistry } from '@/services/protected-resource.registry';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { ExecutionsConfig, GlobalConfig } from '@n8n/config';
|
||||
import type { Project } from '@n8n/db';
|
||||
import { UserRepository } from '@n8n/db';
|
||||
|
|
@ -81,7 +81,6 @@ import {
|
|||
OAuthTokenVerifierProxy,
|
||||
} from '@/services/oauth-token-verifier-proxy.service';
|
||||
import { OAuth2FlowProxy } from '@/services/oauth2-flow-proxy.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProtectedResourceRegistry } from '@/services/protected-resource.registry';
|
||||
import type { WebhookRunOutcome } from '@/modules/engine-v2/webhook-response/webhook-outcome';
|
||||
import type { WebhookResponseWait } from '@/modules/engine-v2/webhook-response/webhook-response-registry.service';
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ export async function executeWorkflow(
|
|||
|
||||
const executionId = await activeExecutions.add(runData);
|
||||
|
||||
const { OwnershipService } = await import('@/services/ownership.service.js');
|
||||
const { OwnershipService } = await import('@n8n/backend-services');
|
||||
const { projectId, projectName } = await getWorkflowProjectDetailsSafe(
|
||||
Container.get(OwnershipService),
|
||||
workflowData.id,
|
||||
|
|
@ -423,7 +423,7 @@ export async function executeAgent(
|
|||
// `webhooks/*`, `scaling/job-processor`). Resolve it from the workflow's
|
||||
// owning project so the agent runs under the correct project scope.
|
||||
if (!projectId && additionalData.workflowId) {
|
||||
const { OwnershipService } = await import('@/services/ownership.service.js');
|
||||
const { OwnershipService } = await import('@n8n/backend-services');
|
||||
const ownershipService = Container.get(OwnershipService);
|
||||
const project = await ownershipService.getWorkflowProjectCached(additionalData.workflowId);
|
||||
projectId = project.id;
|
||||
|
|
@ -883,7 +883,7 @@ export async function getBase({
|
|||
// matching `getVariables`'s own pre-existing lookup below: an unresolvable owner
|
||||
// project fails execution setup, it isn't silently tolerated.
|
||||
if (!projectId && workflowId) {
|
||||
const { OwnershipService } = await import('@/services/ownership.service.js');
|
||||
const { OwnershipService } = await import('@n8n/backend-services');
|
||||
const project = await Container.get(OwnershipService).getWorkflowProjectCached(workflowId);
|
||||
projectId = project?.id;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import { VariablesService } from '@/environments.ee/variables/variables.service.
|
|||
import { ExecutionPersistence } from '@/executions/execution-persistence';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
|
||||
import { OwnershipService } from './services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
export { dropInvalidWorkflowGroups, makeGetNodeTypeForGrouping };
|
||||
export { getLastExecutedNodeData, getLastExecutedNodeRuns } from 'n8n-workflow';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { Project } from '@n8n/db';
|
|||
import { WorkflowEntity } from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
import { dropRedactionPolicy, getWorkflowProjectDetailsSafe } from '@/workflows/utils';
|
||||
|
||||
describe('dropRedactionPolicy', () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { EventService, InstanceWriteAccessService } from '@n8n/backend-services';
|
||||
import type {
|
||||
EventService,
|
||||
InstanceWriteAccessService,
|
||||
OwnershipService,
|
||||
} from '@n8n/backend-services';
|
||||
import type { GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import type {
|
||||
CreateExecutionPayload,
|
||||
|
|
@ -36,7 +40,6 @@ import { ForbiddenError } from '@n8n/errors';
|
|||
import type { ExecutionCrashService } from '@/executions/execution-crash.service';
|
||||
import type { IWorkflowErrorData } from '@/interfaces';
|
||||
import type { NodeTypes } from '@/node-types';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { TestWebhooks } from '@/webhooks/test-webhooks';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import type { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -15,11 +15,10 @@ import { WorkflowActivationError } from 'n8n-workflow';
|
|||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import type { CredentialsFinderService } from '@n8n/backend-services';
|
||||
import type { CredentialsFinderService, OwnershipService } from '@n8n/backend-services';
|
||||
import type { CredentialsService } from '@/credentials/credentials.service';
|
||||
import type { CredentialsPermissionChecker } from '@/executions/pre-execution-checks/credentials-permission-checker';
|
||||
import type { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import type { WorkflowMutationHooksProxy } from '@/workflows/workflow-mutation-hooks-proxy.service';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type { EventService, RoleService, OwnershipService } from '@n8n/backend-services';
|
||||
import type { GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import type {
|
||||
Transaction,
|
||||
|
|
@ -46,7 +46,6 @@ import type { DurableJobProvisioner } from '@/scheduling/durable-job-provisioner
|
|||
import type { PollTriggerJobRegistrar } from '@/scheduling/poll-trigger-node/poll-trigger-job-registrar';
|
||||
import type { ScheduleTriggerJobRegistrar } from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import type { WorkflowScheduledJobOwner } from '@/scheduling/workflow-scheduled-job-owner';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
|
||||
import type { TagService } from '@/services/tag.service';
|
||||
import type { WebhookService } from '@/webhooks/webhook.service';
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { TELEMETRY_EVENT } from '@n8n/telemetry';
|
|||
import type { NodeTypes } from '@/node-types';
|
||||
import type { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { PolicyViolationError } from '@/policy/policy-violation.error';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
import type { Telemetry } from '@/telemetry';
|
||||
import { WorkflowPublicationApplier } from '@/workflows/publication/workflow-publication-applier';
|
||||
import type { DurableJobProvisioner } from '@/scheduling/durable-job-provisioner';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
|||
import { PolicyViolationError } from '@/policy/policy-violation.error';
|
||||
import { DurableJobProvisioner } from '@/scheduling/durable-job-provisioner';
|
||||
import { WorkflowScheduledJobOwner } from '@/scheduling/workflow-scheduled-job-owner';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { formatNodeFailures } from '@/workflows/publication/format-node-failures';
|
||||
import { healNodeIds } from '@/workflows/publication/heal-node-ids';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import type { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import type { GlobalConfig } from '@n8n/config';
|
||||
import type { Project, WorkflowEntity } from '@n8n/db';
|
||||
import type { IDeferredPromise } from '@n8n/utils/promise/deferred-promise';
|
||||
|
|
@ -39,7 +39,6 @@ import type {
|
|||
ScheduleTriggerCollectionSession,
|
||||
ScheduleTriggerJobRegistrar,
|
||||
} from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { WorkflowPublisherService } from '@/workflows/workflow-publisher.service';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import type { WorkflowExecutionService } from '@/workflows/workflow-execution.service';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import { Time } from '@n8n/constants';
|
||||
import type { IWorkflowDb, PollerCursor, PollLeaseFence } from '@n8n/db';
|
||||
|
|
@ -39,7 +39,6 @@ import { ExecutionService } from '@/executions/execution.service';
|
|||
import { NodeTypes } from '@/node-types';
|
||||
import type { ScheduleTriggerCollectionSession } from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import { ScheduleTriggerJobRegistrar } from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import type { EngineV2ActiveTriggerEmit } from '@/workflows/triggers/engine-v2-active-triggers';
|
||||
import { EngineV2ActiveTriggers } from '@/workflows/triggers/engine-v2-active-triggers';
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type { Scope } from '@n8n/permissions';
|
|||
import { NodeApiError, NodeError, WorkflowActivationError } from 'n8n-workflow';
|
||||
import type { WorkflowSettings } from 'n8n-workflow';
|
||||
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
type RedactionMode = 'manual' | 'nonManual';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService, InstanceWriteAccessService } from '@n8n/backend-services';
|
||||
import { EventService, InstanceWriteAccessService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import type {
|
||||
Project,
|
||||
|
|
@ -49,7 +49,6 @@ import { FailedRunFactory } from '@/executions/failed-run-factory';
|
|||
import { SubworkflowPolicyChecker } from '@/executions/pre-execution-checks';
|
||||
import type { IWorkflowErrorData } from '@/interfaces';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { TestWebhooks } from '@/webhooks/test-webhooks';
|
||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import {
|
|||
|
||||
import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import { isCredSharingEnabled } from '@/constants/credential-sharing';
|
||||
import { CredentialsFinderService } from '@n8n/backend-services';
|
||||
import { CredentialsFinderService, OwnershipService } from '@n8n/backend-services';
|
||||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { EnterpriseCredentialsService } from '@/credentials/credentials.service.ee';
|
||||
import { CredentialsPermissionChecker } from '@/executions/pre-execution-checks/credentials-permission-checker';
|
||||
|
|
@ -41,7 +41,6 @@ import { BadRequestError, NotFoundError } from '@n8n/errors';
|
|||
import { TransferWorkflowError } from '@/errors/response-errors/transfer-workflow.error';
|
||||
import { extractAgentCredentialIds } from '@/modules/agents/utils/extract-agent-credential-ids';
|
||||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
import { WorkflowFinderService } from './workflow-finder.service';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { UpdateWorkflowHistoryVersionDto } from '@n8n/api-types';
|
||||
import type { WorkflowListPublicationStatus, WorkflowExecutionBlockCause } from '@n8n/api-types';
|
||||
import { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import type {
|
||||
User,
|
||||
|
|
@ -82,7 +82,6 @@ import { DurableJobProvisioner } from '@/scheduling/durable-job-provisioner';
|
|||
import { PollTriggerJobRegistrar } from '@/scheduling/poll-trigger-node/poll-trigger-job-registrar';
|
||||
import { ScheduleTriggerJobRegistrar } from '@/scheduling/schedule-trigger-node/schedule-trigger-job-registrar';
|
||||
import { WorkflowScheduledJobOwner } from '@/scheduling/workflow-scheduled-job-owner';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
import { TagService } from '@/services/tag.service';
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { OutboundHttp, SsrfBlockedIpError } from '@n8n/backend-network';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import {
|
||||
AuthenticatedRequest,
|
||||
|
|
@ -50,7 +50,6 @@ import { listQueryMiddleware } from '@/middlewares';
|
|||
import { userHasScopes } from '@/permissions.ee/check-access';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
import { NamingService } from '@/services/naming.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { UserManagementMailer } from '@/user-management/email';
|
||||
import * as utils from '@/utils';
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import { ExternalHooks } from '@/external-hooks';
|
|||
import { NodeTypes } from '@/node-types';
|
||||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { Push } from '@/push';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import * as WebhookHelpers from '@/webhooks/webhook-helpers';
|
||||
import { WebhookService } from '@/webhooks/webhook.service';
|
||||
import * as AdditionalData from '@/workflow-execute-additional-data';
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import { Push } from '@/push';
|
|||
import { PubSubEventBus } from '@/scaling/pubsub/pubsub.eventbus';
|
||||
import { DurableScheduler } from '@/scheduling/durable-scheduler';
|
||||
import { Server } from '@/server';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { ExecutionsPruningService } from '@/services/pruning/executions-pruning.service';
|
||||
import { WorkflowHistoryCompactionService } from '@/services/pruning/workflow-history-compaction.service';
|
||||
import { WorkflowStatisticsRollupService } from '@/services/workflow-statistics-rollup.service';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { v4 as uuid } from 'uuid';
|
|||
import { CredentialsPermissionChecker } from '@/executions/pre-execution-checks';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { WorkflowValidationService } from '@/workflows/workflow-validation.service';
|
||||
import { affixRoleToSaveCredential } from '@test-integration/db/credentials';
|
||||
import { createOwner, createUser } from '@test-integration/db/users';
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { DateTime } from 'luxon';
|
|||
import { PROJECT_ROOT, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import {
|
||||
createCredentials,
|
||||
getCredentialSharings,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { GLOBAL_OWNER_ROLE, UserRepository } from '@n8n/db';
|
|||
import { Container } from '@n8n/di';
|
||||
import validator from 'validator';
|
||||
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
|
||||
import { createUserShell } from './shared/db/users';
|
||||
import * as utils from './shared/utils/';
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import { ExecutionService } from '@/executions/execution.service';
|
|||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Push } from '@/push';
|
||||
import { WorkflowScheduledJobOwner } from '@/scheduling/workflow-scheduled-job-owner';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WorkflowPublicationOutboxConsumer } from '@/workflows/publication/workflow-publication-outbox-consumer';
|
||||
import { WorkflowService } from '@/workflows/workflow.service';
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ import { validateUser } from './shared/utils/users';
|
|||
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { ProvisioningService } from '@/modules/provisioning.ee/provisioning.service.ee';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { CHANGE_ROLE_ERROR_MESSAGES } from '@/services/user.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
|||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Push } from '@/push';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService } from '@n8n/backend-services';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { PublishedWorkflowTriggerDeactivator } from '@/workflows/publication/published-workflow-trigger-deactivator';
|
||||
import { WorkflowPublicationLifecycleLock } from '@/workflows/publication/workflow-publication-lifecycle-lock';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, OwnershipService } from '@n8n/backend-services';
|
||||
import {
|
||||
createWorkflowHistory,
|
||||
createWorkflowWithHistory,
|
||||
|
|
@ -25,7 +25,6 @@ import { ActiveWorkflowManager } from '@/active-workflow-manager';
|
|||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { Push } from '@/push';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { WorkflowPublicationOutboxConsumer } from '@/workflows/publication/workflow-publication-outbox-consumer';
|
||||
import { WorkflowPublicationApplier } from '@/workflows/publication/workflow-publication-applier';
|
||||
import { WorkflowPublicationReconciler } from '@/workflows/publication/workflow-publication-reconciler.service';
|
||||
|
|
|
|||
|
|
@ -33,9 +33,8 @@ import type { ExternalHooks } from '@/external-hooks';
|
|||
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { OwnershipService, RoleService } from '@n8n/backend-services';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WebhookService } from '@/webhooks/webhook.service';
|
||||
import { WorkflowHookContextService } from '@/workflow-hook-context.service';
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user