mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 13:39:44 +02:00
refactor(core): Move role services to backend services (no-changelog) (#39999)
This commit is contained in:
parent
8dc0ac8011
commit
577df7a23b
4
OWNERS
4
OWNERS
|
|
@ -28,6 +28,8 @@ packages/@n8n/config/ @n8n-io/catalysts
|
|||
packages/@n8n/backend-common/ @n8n-io/catalysts
|
||||
packages/@n8n/backend-network/ @n8n-io/catalysts
|
||||
packages/@n8n/backend-services/ @n8n-io/catalysts
|
||||
packages/@n8n/backend-services/src/services/role.service.ts @n8n-io/iam
|
||||
packages/@n8n/backend-services/src/services/role-cache.service.ts @n8n-io/iam
|
||||
packages/@n8n/backend-test-utils/ @n8n-io/catalysts
|
||||
packages/@n8n/di/ @n8n-io/catalysts
|
||||
packages/@n8n/errors/ @n8n-io/catalysts
|
||||
|
|
@ -155,8 +157,6 @@ packages/cli/src/controllers/e2e.controller.ts @n8n-io/qa-dx
|
|||
# CLI services
|
||||
packages/cli/src/services/jwt.service.ts @n8n-io/iam
|
||||
packages/cli/src/services/user.service.ts @n8n-io/iam
|
||||
packages/cli/src/services/role.service.ts @n8n-io/iam
|
||||
packages/cli/src/services/role-cache.service.ts @n8n-io/iam
|
||||
packages/cli/src/services/password.utility.ts @n8n-io/iam
|
||||
packages/cli/src/services/public-api-key.service.ts @n8n-io/iam
|
||||
packages/cli/src/services/security-settings.service.ts @n8n-io/iam
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@
|
|||
"@n8n/config": "workspace:*",
|
||||
"@n8n/constants": "workspace:*",
|
||||
"@n8n/decorators": "workspace:*",
|
||||
"@n8n/db": "workspace:*",
|
||||
"@n8n/di": "workspace:*",
|
||||
"@n8n/errors": "workspace:*",
|
||||
"@n8n/permissions": "workspace:*",
|
||||
"@n8n/utils": "workspace:*",
|
||||
"cache-manager": "catalog:",
|
||||
"express-openapi-validator": "5.5.3",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ export { UncacheableValueError } from './errors/cache-errors/uncacheable-value.e
|
|||
export { CacheService } from './services/cache/cache.service';
|
||||
export { RedisClientService } from './services/redis-client.service';
|
||||
export type { RedisClientType } from './services/redis.types';
|
||||
export { RoleCacheService, type RoleLoader } from './services/role-cache.service';
|
||||
export {
|
||||
RoleDeletionCheckProxy,
|
||||
type RoleDeletionChecker,
|
||||
} from './services/role-deletion-check-proxy.service';
|
||||
export { RoleService } from './services/role.service';
|
||||
export { UrlService } from './services/url.service';
|
||||
export {
|
||||
classifyRestError,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { RoleRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { staticRolesWithScope } from '@n8n/permissions';
|
||||
import type { MockedFunction } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { CacheService } from '@n8n/backend-services';
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { type CacheService } from '../cache/cache.service';
|
||||
import { RoleCacheService } from '../role-cache.service';
|
||||
|
||||
// Mock static function
|
||||
vi.mock('@n8n/permissions', async () => ({
|
||||
|
|
@ -17,11 +15,11 @@ vi.mock('@n8n/permissions', async () => ({
|
|||
|
||||
describe('RoleCacheService', () => {
|
||||
const cacheService = mock<CacheService>();
|
||||
const logger = mockInstance(Logger);
|
||||
const roleRepository = mockInstance(RoleRepository);
|
||||
const logger = mock<Logger>();
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
const staticRolesMock = staticRolesWithScope as MockedFunction<typeof staticRolesWithScope>;
|
||||
|
||||
const roleCacheService = new RoleCacheService(cacheService, logger);
|
||||
const roleCacheService = new RoleCacheService(cacheService, logger, roleRepository);
|
||||
|
||||
const mockRoleScopeMap = {
|
||||
project: {
|
||||
|
|
@ -49,7 +47,6 @@ describe('RoleCacheService', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.spyOn(Container, 'get').mockReturnValue(roleRepository);
|
||||
});
|
||||
|
||||
describe('getRolesWithAllScopes', () => {
|
||||
|
|
@ -186,7 +183,6 @@ describe('RoleCacheService', () => {
|
|||
|
||||
await roleCacheService.refreshCache();
|
||||
|
||||
expect(Container.get).toHaveBeenCalledWith(RoleRepository);
|
||||
expect(roleRepository.findAll).toHaveBeenCalledTimes(1);
|
||||
expect(cacheService.set).toHaveBeenCalledWith(
|
||||
'roles:scope-map',
|
||||
|
|
@ -3,7 +3,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
import {
|
||||
RoleDeletionCheckProxy,
|
||||
type RoleDeletionChecker,
|
||||
} from '@/services/role-deletion-check-proxy.service';
|
||||
} from '../role-deletion-check-proxy.service';
|
||||
|
||||
describe('RoleDeletionCheckProxy', () => {
|
||||
it('reports no blockers when no provider is registered', async () => {
|
||||
|
|
@ -1,23 +1,21 @@
|
|||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { EventService } from '../../events/event.service';
|
||||
import { RoleCacheService } from '../role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '../role-deletion-check-proxy.service';
|
||||
import { RoleService } from '../role.service';
|
||||
import type { CredentialsEntity, ScopesField, User } from '@n8n/db';
|
||||
import { RoleRepository, ScopeRepository } from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '@/services/role-deletion-check-proxy.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
describe('RoleService.addScopes', () => {
|
||||
const licenseState = mock<LicenseState>();
|
||||
const roleRepository = mockInstance(RoleRepository);
|
||||
const scopeRepository = mockInstance(ScopeRepository);
|
||||
const roleCacheService = mockInstance(RoleCacheService);
|
||||
const logger = mockInstance(Logger);
|
||||
const roleDeletionCheckProxy = mockInstance(RoleDeletionCheckProxy);
|
||||
const eventService = mockInstance(EventService);
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
const scopeRepository = mock<ScopeRepository>();
|
||||
const roleCacheService = mock<RoleCacheService>();
|
||||
const logger = mock<Logger>();
|
||||
const roleDeletionCheckProxy = mock<RoleDeletionCheckProxy>();
|
||||
const eventService = mock<EventService>();
|
||||
|
||||
const roleService = new RoleService(
|
||||
licenseState,
|
||||
|
|
@ -1,23 +1,22 @@
|
|||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { EventService } from '../../events/event.service';
|
||||
import { RoleCacheService } from '../role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '../role-deletion-check-proxy.service';
|
||||
import { RoleService } from '../role.service';
|
||||
import { RoleRepository, ScopeRepository } from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { NotFoundError } from '@n8n/errors';
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '@/services/role-deletion-check-proxy.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
describe('RoleService.getRoleAssignments and getRoleProjectMembers', () => {
|
||||
const licenseState = mock<LicenseState>();
|
||||
const roleRepository = mockInstance(RoleRepository);
|
||||
const scopeRepository = mockInstance(ScopeRepository);
|
||||
const roleCacheService = mockInstance(RoleCacheService);
|
||||
const logger = mockInstance(Logger);
|
||||
const roleDeletionCheckProxy = mockInstance(RoleDeletionCheckProxy);
|
||||
const eventService = mockInstance(EventService);
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
const scopeRepository = mock<ScopeRepository>();
|
||||
const roleCacheService = mock<RoleCacheService>();
|
||||
const logger = mock<Logger>();
|
||||
const roleDeletionCheckProxy = mock<RoleDeletionCheckProxy>();
|
||||
const eventService = mock<EventService>();
|
||||
|
||||
const roleService = new RoleService(
|
||||
licenseState,
|
||||
|
|
@ -1,26 +1,25 @@
|
|||
import type { CreateRoleDto, UpdateRoleDto } from '@n8n/api-types';
|
||||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { EventService } from '../../events/event.service';
|
||||
import { RoleCacheService } from '../role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '../role-deletion-check-proxy.service';
|
||||
import { RoleService } from '../role.service';
|
||||
import type { Role, Scope as DBScope } from '@n8n/db';
|
||||
import { RoleRepository, ScopeRepository } from '@n8n/db';
|
||||
import { MANDATORY_INSTANCE_SCOPES } from '@n8n/permissions';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { BadRequestError } from '@n8n/errors';
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '@/services/role-deletion-check-proxy.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
describe('RoleService custom role scope whitelist', () => {
|
||||
const licenseState = mock<LicenseState>();
|
||||
const roleRepository = mockInstance(RoleRepository);
|
||||
const scopeRepository = mockInstance(ScopeRepository);
|
||||
const roleCacheService = mockInstance(RoleCacheService);
|
||||
const logger = mockInstance(Logger);
|
||||
const roleDeletionCheckProxy = mockInstance(RoleDeletionCheckProxy);
|
||||
const eventService = mockInstance(EventService);
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
const scopeRepository = mock<ScopeRepository>();
|
||||
const roleCacheService = mock<RoleCacheService>();
|
||||
const logger = mock<Logger>();
|
||||
const roleDeletionCheckProxy = mock<RoleDeletionCheckProxy>();
|
||||
const eventService = mock<EventService>();
|
||||
|
||||
const roleService = new RoleService(
|
||||
licenseState,
|
||||
|
|
@ -1,22 +1,20 @@
|
|||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { EventService } from '../../events/event.service';
|
||||
import { RoleCacheService } from '../role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '../role-deletion-check-proxy.service';
|
||||
import { RoleService } from '../role.service';
|
||||
import { RoleRepository, ScopeRepository } from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from '@/services/role-deletion-check-proxy.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
describe('RoleService.rolesWithScope', () => {
|
||||
const licenseState = mock<LicenseState>();
|
||||
const roleRepository = mockInstance(RoleRepository);
|
||||
const scopeRepository = mockInstance(ScopeRepository);
|
||||
const roleCacheService = mockInstance(RoleCacheService);
|
||||
const logger = mockInstance(Logger);
|
||||
const roleDeletionCheckProxy = mockInstance(RoleDeletionCheckProxy);
|
||||
const eventService = mockInstance(EventService);
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
const scopeRepository = mock<ScopeRepository>();
|
||||
const roleCacheService = mock<RoleCacheService>();
|
||||
const logger = mock<Logger>();
|
||||
const roleDeletionCheckProxy = mock<RoleDeletionCheckProxy>();
|
||||
const eventService = mock<EventService>();
|
||||
|
||||
const roleService = new RoleService(
|
||||
licenseState,
|
||||
|
|
@ -39,11 +37,9 @@ describe('RoleService.rolesWithScope', () => {
|
|||
|
||||
const result = await roleService.rolesWithScope('project', 'project:read');
|
||||
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith(
|
||||
'project',
|
||||
['project:read'],
|
||||
undefined,
|
||||
);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith('project', [
|
||||
'project:read',
|
||||
]);
|
||||
expect(result).toEqual(mockRoles);
|
||||
});
|
||||
|
||||
|
|
@ -54,11 +50,7 @@ describe('RoleService.rolesWithScope', () => {
|
|||
|
||||
const result = await roleService.rolesWithScope('project', inputScopes);
|
||||
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith(
|
||||
'project',
|
||||
inputScopes,
|
||||
undefined,
|
||||
);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith('project', inputScopes);
|
||||
expect(result).toEqual(mockRoles);
|
||||
});
|
||||
|
||||
|
|
@ -68,7 +60,7 @@ describe('RoleService.rolesWithScope', () => {
|
|||
|
||||
const result = await roleService.rolesWithScope('project', []);
|
||||
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith('project', [], undefined);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith('project', []);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
@ -110,11 +102,10 @@ describe('RoleService.rolesWithScope', () => {
|
|||
'project:update',
|
||||
]);
|
||||
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith(
|
||||
'project',
|
||||
['project:read', 'project:update'],
|
||||
undefined,
|
||||
);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith('project', [
|
||||
'project:read',
|
||||
'project:update',
|
||||
]);
|
||||
expect(result).toEqual(mockRoles);
|
||||
});
|
||||
});
|
||||
|
|
@ -130,24 +121,15 @@ describe('RoleService.rolesWithScope', () => {
|
|||
await roleService.rolesWithScope('project', 'project:delete');
|
||||
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledTimes(3);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'credential',
|
||||
['credential:read'],
|
||||
undefined,
|
||||
);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'workflow',
|
||||
['workflow:execute'],
|
||||
undefined,
|
||||
);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
'project',
|
||||
['project:delete'],
|
||||
undefined,
|
||||
);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenNthCalledWith(1, 'credential', [
|
||||
'credential:read',
|
||||
]);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenNthCalledWith(2, 'workflow', [
|
||||
'workflow:execute',
|
||||
]);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenNthCalledWith(3, 'project', [
|
||||
'project:delete',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle mixed scope arrays', async () => {
|
||||
|
|
@ -161,11 +143,7 @@ describe('RoleService.rolesWithScope', () => {
|
|||
|
||||
const result = await roleService.rolesWithScope('project', mixedScopes);
|
||||
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith(
|
||||
'project',
|
||||
mixedScopes,
|
||||
undefined,
|
||||
);
|
||||
expect(roleCacheService.getRolesWithAllScopes).toHaveBeenCalledWith('project', mixedScopes);
|
||||
expect(result).toEqual(mockRoles);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { Time } from '@n8n/constants';
|
||||
import { RoleRepository } from '@n8n/db';
|
||||
import type { EntityManager } from '@n8n/db';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
import { Service } from '@n8n/di';
|
||||
import { staticRolesWithScope, type Scope } from '@n8n/permissions';
|
||||
|
||||
import { CacheService } from '@n8n/backend-services';
|
||||
import { CacheService } from './cache/cache.service';
|
||||
|
||||
type RoleInfo = {
|
||||
scopes: string[]; // array of scope slugs
|
||||
|
|
@ -29,6 +28,8 @@ interface RoleScopeMap {
|
|||
};
|
||||
}
|
||||
|
||||
export type RoleLoader = () => ReturnType<RoleRepository['findAll']>;
|
||||
|
||||
@Service()
|
||||
export class RoleCacheService {
|
||||
private static readonly CACHE_KEY = 'roles:scope-map';
|
||||
|
|
@ -37,15 +38,15 @@ export class RoleCacheService {
|
|||
constructor(
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly logger: Logger,
|
||||
private readonly roleRepository: RoleRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get all roles from database and build scope map
|
||||
*/
|
||||
private async buildRoleScopeMap(trx?: EntityManager): Promise<RoleScopeMap> {
|
||||
private async buildRoleScopeMap(loadRoles?: RoleLoader): Promise<RoleScopeMap> {
|
||||
try {
|
||||
const roleRepository = Container.get(RoleRepository);
|
||||
const roles = await roleRepository.findAll(trx);
|
||||
const roles = await (loadRoles?.() ?? this.roleRepository.findAll());
|
||||
|
||||
const roleScopeMap: RoleScopeMap = {};
|
||||
for (const role of roles) {
|
||||
|
|
@ -68,13 +69,13 @@ export class RoleCacheService {
|
|||
async getRolesWithAllScopes(
|
||||
namespace: 'global' | 'project' | 'credential' | 'workflow' | 'secretsProviderConnection',
|
||||
requiredScopes: Scope[],
|
||||
em?: EntityManager,
|
||||
loadRoles?: RoleLoader,
|
||||
): Promise<string[]> {
|
||||
if (requiredScopes.length === 0) return [];
|
||||
|
||||
// Get cached role map with refresh function
|
||||
const roleScopeMap = await this.cacheService.get<RoleScopeMap>(RoleCacheService.CACHE_KEY, {
|
||||
refreshFn: async () => await this.buildRoleScopeMap(em),
|
||||
refreshFn: async () => await this.buildRoleScopeMap(loadRoles),
|
||||
fallbackValue: undefined,
|
||||
});
|
||||
|
||||
|
|
@ -5,7 +5,6 @@ import type {
|
|||
} from '@n8n/api-types';
|
||||
import { CreateRoleDto } from '@n8n/api-types';
|
||||
import { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import {
|
||||
CredentialsEntity,
|
||||
SharedCredentials,
|
||||
|
|
@ -19,16 +18,10 @@ import {
|
|||
Scope as DBScope,
|
||||
ScopeRepository,
|
||||
GLOBAL_ADMIN_ROLE,
|
||||
isUniqueConstraintError,
|
||||
} from '@n8n/db';
|
||||
import type { EntityManager } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import type {
|
||||
Scope,
|
||||
Role as RoleDTO,
|
||||
AssignableProjectRole,
|
||||
AssignableGlobalRole,
|
||||
RoleNamespace,
|
||||
} from '@n8n/permissions';
|
||||
import type { Scope, Role as RoleDTO, RoleNamespace } from '@n8n/permissions';
|
||||
import {
|
||||
combineScopes,
|
||||
CUSTOM_ROLE_SCOPE_WHITELIST,
|
||||
|
|
@ -43,10 +36,16 @@ import {
|
|||
import { UnexpectedError, UserError } from 'n8n-workflow';
|
||||
|
||||
import { BadRequestError, NotFoundError } from '@n8n/errors';
|
||||
import { isUniqueConstraintError } from '@/response-helper';
|
||||
|
||||
import { RoleCacheService } from './role-cache.service';
|
||||
import { RoleCacheService, type RoleLoader } from './role-cache.service';
|
||||
import { RoleDeletionCheckProxy } from './role-deletion-check-proxy.service';
|
||||
import { EventService } from '../events/event.service';
|
||||
|
||||
declare module '../events/event.service' {
|
||||
interface EventMap {
|
||||
'custom-role-deleted': { userId: string; roleSlug: string };
|
||||
'custom-role-updated': { userId: string; roleSlug: string; scopes: string[] };
|
||||
}
|
||||
}
|
||||
|
||||
@Service()
|
||||
export class RoleService {
|
||||
|
|
@ -458,16 +457,18 @@ export class RoleService {
|
|||
async rolesWithScope(
|
||||
namespace: RoleNamespace,
|
||||
scopes: Scope | Scope[],
|
||||
trx?: EntityManager,
|
||||
loadRoles?: RoleLoader,
|
||||
): Promise<string[]> {
|
||||
if (!Array.isArray(scopes)) {
|
||||
scopes = [scopes];
|
||||
}
|
||||
// Get database roles from cache
|
||||
return await this.roleCacheService.getRolesWithAllScopes(namespace, scopes, trx);
|
||||
return loadRoles
|
||||
? await this.roleCacheService.getRolesWithAllScopes(namespace, scopes, loadRoles)
|
||||
: await this.roleCacheService.getRolesWithAllScopes(namespace, scopes);
|
||||
}
|
||||
|
||||
isRoleLicensed(role: AssignableProjectRole | AssignableGlobalRole) {
|
||||
isRoleLicensed(role: string) {
|
||||
// TODO: move this info into FrontendSettings
|
||||
|
||||
if (!isBuiltInRole(role)) {
|
||||
|
|
@ -33,7 +33,7 @@ import { NodeTypes } from '@/node-types';
|
|||
import { PostHogClient } from '@/posthog';
|
||||
import { PollJobProvider } from '@/scheduling/poll-trigger-node/poll-job-provider';
|
||||
import { JwtService } from '@/services/jwt.service';
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleCacheService } from '@n8n/backend-services';
|
||||
import { ShutdownService } from '@/shutdown/shutdown.service';
|
||||
import { TaskRunnerModule } from '@/task-runners/task-runner-module';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
import { EventService, UrlService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, RoleCacheService } from '@n8n/backend-services';
|
||||
import { HTML_NONCE_PLACEHOLDER, LICENSE_FEATURES } from '@n8n/constants';
|
||||
import {
|
||||
AuthRolesService,
|
||||
|
|
@ -42,7 +42,7 @@ import { Server } from '@/server';
|
|||
import { JwtService } from '@/services/jwt.service';
|
||||
import { ExecutionsPruningService } from '@/services/pruning/executions-pruning.service';
|
||||
import { WorkflowHistoryCompactionService } from '@/services/pruning/workflow-history-compaction.service';
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
|
||||
import { WorkflowStatisticsRollupService } from '@/services/workflow-statistics-rollup.service';
|
||||
import { WaitTracker } from '@/wait-tracker';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type { AuthenticatedRequest, Project } from '@n8n/db';
|
||||
import type { Role } from '@n8n/permissions';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { NotFoundError } from '@n8n/errors';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
|
||||
import { RoleController } from '../role.controller';
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type {
|
|||
RoleMembersResponse,
|
||||
RoleProjectMembersResponse,
|
||||
} from '@n8n/api-types';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { LICENSE_FEATURES } from '@n8n/constants';
|
||||
import { AuthenticatedRequest } from '@n8n/db';
|
||||
import {
|
||||
|
|
@ -33,7 +33,6 @@ import { Role as RoleDTO } from '@n8n/permissions';
|
|||
import { NotFoundError } from '@n8n/errors';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { assertCanManageRoleType, canReassignUsers } from '@/services/role-authorization';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
@RestController('/roles')
|
||||
export class RoleController {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import type { ExternalSecretsConfig } from '@/modules/external-secrets.ee/extern
|
|||
import type { SecretsProviderAccessCheckService } from '@/modules/external-secrets.ee/secret-provider-access-check.service.ee';
|
||||
import type { OwnershipService } from '@/services/ownership.service';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
describe('EnterpriseCredentialsService', () => {
|
||||
const sharedCredentialsRepository = mock<SharedCredentialsRepository>();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ 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 } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type {
|
||||
CredentialsRepository,
|
||||
ICredentialsDb,
|
||||
|
|
@ -65,7 +65,6 @@ 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 type { RoleService } from '@/services/role.service';
|
||||
|
||||
import { mockExistingCredential } from './credentials.test-data';
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type { CredentialSharingRole, ProjectRole, Scope } from '@n8n/permissions
|
|||
import type { EntityManager, FindOptionsWhere } from '@n8n/typeorm';
|
||||
import { In } from '@n8n/typeorm';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
/**
|
||||
* The credential scopes an instance role can hold without being allowed to use a
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { ExternalSecretsConfig } from '@/modules/external-secrets.ee/external-se
|
|||
import { SecretsProviderAccessCheckService } from '@/modules/external-secrets.ee/secret-provider-access-check.service.ee';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { CredentialConnectionStatusProxy } from './credential-connection-status-proxy';
|
||||
import { CredentialsFinderService } from './credentials-finder.service';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { CreateCredentialDto, CredentialConnectionStatus } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { Time } from '@n8n/constants';
|
||||
import {
|
||||
Project,
|
||||
|
|
@ -76,7 +76,6 @@ 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 { RoleService } from '@/services/role.service';
|
||||
|
||||
import { CredentialConnectionStatusProxy } from './credential-connection-status-proxy';
|
||||
import { CredentialDescriptionsService } from './credential-descriptions.service';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Container } from '@n8n/di';
|
|||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { EngineDataPlaneProxyService } from '@/services/engine-data-plane-proxy.service';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
import type { WorkflowSharingService } from '@/workflows/workflow-sharing.service';
|
||||
|
||||
import type { ExecutionCursor } from '../execution-cursor';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Container, Service } from '@n8n/di';
|
|||
import type { Scope } from '@n8n/permissions';
|
||||
|
||||
import { EngineDataPlaneProxyService } from '@/services/engine-data-plane-proxy.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
import { WorkflowSharingService } from '@/workflows/workflow-sharing.service';
|
||||
|
||||
import { hasPosition, type ExecutionCursor } from './execution-cursor';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { InstanceSettings } from 'n8n-core';
|
|||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { Push } from '@/push';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
import type { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
|
||||
import { AgentPushRecipientsService } from '../agent-push-recipients.service';
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import type { Push } from '@/push';
|
||||
import type { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { AgentPushRecipientsService } from '../agent-push-recipients.service';
|
||||
import { AgentUpdateBroadcaster } from '../agent-update-broadcaster';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { UserRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
@Service()
|
||||
export class AgentPushRecipientsService {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { RenameDataTableColumnDto } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { mockInstance, testModules } from '@n8n/backend-test-utils';
|
||||
import { ProjectRelationRepository, ProjectRepository, type User } from '@n8n/db';
|
||||
import { In } from '@n8n/typeorm';
|
||||
|
|
@ -21,7 +21,6 @@ import { DataTableNotFoundError } from '../errors/data-table-not-found.error';
|
|||
import { DataTableValidationError } from '../errors/data-table-validation.error';
|
||||
|
||||
import { ProjectNotFoundError, ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
describe('DataTableService', () => {
|
||||
let dataTableService: DataTableService;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { ProjectRelationRepository, User } from '@n8n/db';
|
|||
import { Service } from '@n8n/di';
|
||||
import { hasGlobalScope } from '@n8n/permissions';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { DataTableRepository } from './data-table.repository';
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type {
|
|||
UpdateDataTableRowDto,
|
||||
} from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { ProjectRelationRepository, ProjectRepository, type User } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import { hasGlobalScope, type Scope } from '@n8n/permissions';
|
||||
|
|
@ -48,7 +48,6 @@ import { DataTableValidationError } from './errors/data-table-validation.error';
|
|||
import { normalizeRows } from './utils/sql-utils';
|
||||
|
||||
import { ProjectNotFoundError, ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
@Service()
|
||||
export class DataTableService {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { Logger } from '@n8n/backend-common';
|
||||
import type {
|
||||
ProjectRelationRepository,
|
||||
RoleRepository,
|
||||
SharedCredentialsRepository,
|
||||
User,
|
||||
UserRepository,
|
||||
|
|
@ -9,7 +10,7 @@ import type { EntityManager } from '@n8n/typeorm';
|
|||
import type { Cipher } from 'n8n-core';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { SYSTEM_RESOLVER_ID } from '../../constants';
|
||||
import { DynamicCredentialUserEntry } from '../../database/entities/dynamic-credential-user-entry';
|
||||
|
|
@ -37,6 +38,7 @@ describe('CredentialConnectionStatusService', () => {
|
|||
const cipher = mock<Cipher>();
|
||||
const logger = mock<Logger>();
|
||||
const em = mock<EntityManager>();
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
|
||||
const service = new CredentialConnectionStatusService(
|
||||
repository,
|
||||
|
|
@ -46,6 +48,7 @@ describe('CredentialConnectionStatusService', () => {
|
|||
projectRelationRepository,
|
||||
cipher,
|
||||
logger,
|
||||
roleRepository,
|
||||
);
|
||||
|
||||
const CRED_ID = 'cred-1';
|
||||
|
|
@ -202,7 +205,7 @@ describe('CredentialConnectionStatusService', () => {
|
|||
expect(roleService.rolesWithScope).toHaveBeenCalledWith(
|
||||
'credential',
|
||||
'credential:connect',
|
||||
em,
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(sharedCredentialsRepository.findPairsWithCredentialAccess).toHaveBeenCalledWith(
|
||||
[{ credentialId: CRED_ID, userId: 'sharee-1' }],
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
CredentialsEntity,
|
||||
In,
|
||||
ProjectRelationRepository,
|
||||
RoleRepository,
|
||||
SharedCredentialsRepository,
|
||||
UserRepository,
|
||||
type User,
|
||||
|
|
@ -18,7 +19,7 @@ import type {
|
|||
UserConnection,
|
||||
} from '@/credentials/credential-connection-status-provider.interface';
|
||||
import { extractAccountIdentifierFromData } from '@/oauth/account-identifier';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { SYSTEM_RESOLVER_ID } from '../constants';
|
||||
import { DynamicCredentialUserEntry } from '../database/entities/dynamic-credential-user-entry';
|
||||
|
|
@ -54,6 +55,7 @@ export class CredentialConnectionStatusService implements ICredentialConnectionS
|
|||
private readonly projectRelationRepository: ProjectRelationRepository,
|
||||
private readonly cipher: Cipher,
|
||||
private readonly logger: Logger,
|
||||
private readonly roleRepository: RoleRepository,
|
||||
) {}
|
||||
|
||||
async findMyConnections(
|
||||
|
|
@ -214,7 +216,7 @@ export class CredentialConnectionStatusService implements ICredentialConnectionS
|
|||
const validCredRoles = await this.roleService.rolesWithScope(
|
||||
'credential',
|
||||
CREDENTIAL_RETAIN_SCOPE,
|
||||
em,
|
||||
async () => await this.roleRepository.findAll(em),
|
||||
);
|
||||
return await this.sharedCredentialsRepository.findPairsWithCredentialAccess(
|
||||
pairsToCheck,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import { ForbiddenError, NotFoundError } from '@n8n/errors';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { SecretsProviderAccessCheckService } from '../secret-provider-access-check.service.ee';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { SettingsRepository } from '@n8n/db';
|
|||
import { Service } from '@n8n/di';
|
||||
import { EXTERNAL_SECRETS_SYSTEM_ROLES_ENABLED_SETTING } from '@n8n/permissions';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
@Service()
|
||||
export class ExternalSecretsSettingsService {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { combineScopes, getAuthPrincipalScopes, hasGlobalScope } from '@n8n/perm
|
|||
|
||||
import { ForbiddenError, NotFoundError } from '@n8n/errors';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
@Service()
|
||||
export class SecretsProviderAccessCheckService {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ vi.mock('@n8n/ai-utilities', () => ({
|
|||
import type { Logger } from '@n8n/backend-common';
|
||||
import { INSTANCE_AI_NODE_USAGE_FLAG } from '@n8n/api-types';
|
||||
import type { OutboundHttp } from '@n8n/backend-network';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type { GlobalConfig } from '@n8n/config';
|
||||
import type {
|
||||
AiBuilderTemporaryWorkflowRepository,
|
||||
|
|
@ -63,7 +63,7 @@ import type { FolderService } from '@/services/folder.service';
|
|||
import type { InstanceWriteAccessService } from '@/services/instance-write-access.service';
|
||||
import { NodeResourceExplorerService } from '@/services/node-resource-explorer.service';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
|
||||
import type { TagService } from '@/services/tag.service';
|
||||
import type { Telemetry } from '@/telemetry';
|
||||
import type { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ vi.mock('@n8n/instance-ai', async () => {
|
|||
});
|
||||
|
||||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type { GlobalConfig } from '@n8n/config';
|
||||
import { GLOBAL_MEMBER_ROLE } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
|
|
@ -65,7 +65,7 @@ import type { DataTableService } from '@/modules/data-table/data-table.service';
|
|||
import type { InstanceWriteAccessService } from '@/services/instance-write-access.service';
|
||||
import type { NodeTypes } from '@/node-types';
|
||||
import type { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
|
||||
import type { OutboundHttp } from '@n8n/backend-network';
|
||||
import type { AiGatewayService } from '@/services/ai-gateway.service';
|
||||
import type { Telemetry } from '@/telemetry';
|
||||
|
|
|
|||
|
|
@ -1827,7 +1827,7 @@ import {
|
|||
} from '@n8n/errors';
|
||||
import type { License } from '@/license';
|
||||
import type { AiPreferenceService } from '@/services/ai-preference.service';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import type { OutboundHttp } from '@n8n/backend-network';
|
||||
import { ModuleRegistry } from '@n8n/backend-common';
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import {
|
|||
import type { AiGatewayConfigDto } from '@n8n/api-types';
|
||||
import { LicenseState, Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { OutboundHttp } from '@n8n/backend-network';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import { Time, TOOL_EXECUTOR_NODE_NAME } from '@n8n/constants';
|
||||
import type { User, ExecutionSummaries, EvaluationConfig } from '@n8n/db';
|
||||
|
|
@ -192,7 +192,7 @@ import { FolderService } from '@/services/folder.service';
|
|||
import { InstanceWriteAccessService } from '@/services/instance-write-access.service';
|
||||
import { NodeResourceExplorerService } from '@/services/node-resource-explorer.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { resolveBuiltinNodeDefinitionDirs } from '@/utils/node-definition-dirs';
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import type { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
import { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import { createFolder } from '@test-integration/db/folders';
|
||||
import { createTag } from '@test-integration/db/tags';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { LicenseState, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { EventService, UrlService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, RoleService } from '@n8n/backend-services';
|
||||
import { mockInstance, mockLogger } from '@n8n/backend-test-utils';
|
||||
import { ExecutionsConfig, GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import { ExecutionRepository, ProjectRepository, SharedWorkflowRepository, User } from '@n8n/db';
|
||||
|
|
@ -21,7 +21,7 @@ import { FolderFinderService } from '@/services/folder-finder.service';
|
|||
import { FolderService } from '@/services/folder.service';
|
||||
import { NodeResourceExplorerService } from '@/services/node-resource-explorer.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { INSTANCE_ACTIVITY_CONTEXT_FLAG } from '@n8n/api-types';
|
||||
import { LicenseState, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { EventService, UrlService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, RoleService } from '@n8n/backend-services';
|
||||
import { mockInstance, mockLogger } from '@n8n/backend-test-utils';
|
||||
import { EndpointsConfig, ExecutionsConfig, GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import {
|
||||
|
|
@ -49,7 +49,7 @@ import { FolderFinderService } from '@/services/folder-finder.service';
|
|||
import { FolderService } from '@/services/folder.service';
|
||||
import { NodeResourceExplorerService } from '@/services/node-resource-explorer.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
INSTANCE_ACTIVITY_CONTEXT_FLAG,
|
||||
} from '@n8n/api-types';
|
||||
import { LicenseState, ModuleRegistry, type Logger } from '@n8n/backend-common';
|
||||
import { EventService, UrlService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, RoleService } from '@n8n/backend-services';
|
||||
import { mockInstance, mockLogger } from '@n8n/backend-test-utils';
|
||||
import { EndpointsConfig, ExecutionsConfig, GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import {
|
||||
|
|
@ -42,7 +42,7 @@ import { FolderFinderService } from '@/services/folder-finder.service';
|
|||
import { FolderService } from '@/services/folder.service';
|
||||
import { NodeResourceExplorerService } from '@/services/node-resource-explorer.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
INSTANCE_ACTIVITY_CONTEXT_FLAG,
|
||||
} from '@n8n/api-types';
|
||||
import { LicenseState, Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { EventService, UrlService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, RoleService } from '@n8n/backend-services';
|
||||
import { ExecutionsConfig, GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import { ExecutionRepository, ProjectRepository, SharedWorkflowRepository, User } from '@n8n/db';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
|
|
@ -40,7 +40,7 @@ import { FolderFinderService } from '@/services/folder-finder.service';
|
|||
import { FolderService } from '@/services/folder.service';
|
||||
import { NodeResourceExplorerService } from '@/services/node-resource-explorer.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WorkflowRunner } from '@/workflow-runner';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import z from 'zod';
|
|||
|
||||
import type { CredentialsService } from '@/credentials/credentials.service';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
import type { Telemetry } from '@/telemetry';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ export class ProvisioningModule implements ModuleInterface {
|
|||
// Register the role-deletion checker so the core `RoleService` blocks
|
||||
// deleting a role still targeted by a mapping rule, without importing
|
||||
// this module.
|
||||
const { RoleDeletionCheckProxy } = await import(
|
||||
'@/services/role-deletion-check-proxy.service.js'
|
||||
);
|
||||
const { RoleDeletionCheckProxy } = await import('@n8n/backend-services');
|
||||
const { ProvisioningRoleDeletionChecker } = await import('./role-deletion-checker.ee.js');
|
||||
Container.get(RoleDeletionCheckProxy).registerProvider(
|
||||
Container.get(ProvisioningRoleDeletionChecker),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { RoleMappingRuleRepository } from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
|
||||
import type { RoleDeletionChecker } from '@/services/role-deletion-check-proxy.service';
|
||||
import type { RoleDeletionChecker } from '@n8n/backend-services';
|
||||
|
||||
import { ProvisioningService } from './provisioning.service.ee';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
GLOBAL_MEMBER_ROLE,
|
||||
type AuthIdentity,
|
||||
|
|
@ -10,7 +10,6 @@ import {
|
|||
} from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { UserService } from '@/services/user.service';
|
||||
|
||||
import type { TokenExchangeConfig } from '../../token-exchange.config';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
AuthIdentity,
|
||||
AuthIdentityRepository,
|
||||
|
|
@ -11,7 +11,6 @@ import { Service } from '@n8n/di';
|
|||
import { GLOBAL_OWNER_ROLE_SLUG, isBuiltInRole } from '@n8n/permissions';
|
||||
import { createHash } from 'node:crypto';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { UserService } from '@/services/user.service';
|
||||
|
||||
import { TokenExchangeConfig } from '../token-exchange.config';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import type {
|
|||
import { chunkIds } from '@n8n/db';
|
||||
import type { DataTableRepository } from '@/modules/data-table/data-table.repository';
|
||||
import type { CredentialsFinderService } from '@/credentials/credentials-finder.service';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { In, type FindManyOptions } from '@n8n/typeorm';
|
|||
import { CredentialsFinderService } from '@/credentials/credentials-finder.service';
|
||||
import { isCredSharingEnabled } from '@/constants/credential-sharing';
|
||||
import { DataTableRepository } from '@/modules/data-table/data-table.repository';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
import { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
|
||||
import { AgentUsageProviderProxy } from './agent-usage-provider-proxy.service';
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { WorkflowReviewAuthorizationService } from '../workflow-review-authoriza
|
|||
|
||||
import { NotFoundError } from '@n8n/errors';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
|
||||
const requestId = 'req-1';
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import type {
|
|||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
|
||||
import { WorkflowReviewAuthorizationService } from '../workflow-review-authorization.service';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { DecideWorkflowReviewRequestDto } from '@n8n/api-types';
|
||||
import type { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type {
|
||||
DbLockService,
|
||||
Project,
|
||||
|
|
@ -33,7 +33,7 @@ import { WorkflowReviewStateNotifier } from '../workflow-review-state-notifier.s
|
|||
import type { CollaborationService } from '@/collaboration/collaboration.service';
|
||||
import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from '@n8n/errors';
|
||||
import type { ProjectService } from '@/services/project.service.ee';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
|
||||
import type { WorkflowReviewPolicyService } from '@/services/workflow-review-policy.service';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import type { WorkflowService } from '@/workflows/workflow.service';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type {
|
|||
GetWorkflowReviewEligibleReviewersQueryDto,
|
||||
} from '@n8n/api-types';
|
||||
import type { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import { DbLock, User } from '@n8n/db';
|
||||
import type {
|
||||
AuthIdentity,
|
||||
|
|
@ -27,7 +27,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import type { CollaborationService } from '@/collaboration/collaboration.service';
|
||||
import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from '@n8n/errors';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
|
||||
import type { WorkflowReviewPolicyService } from '@/services/workflow-review-policy.service';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import type { WorkflowHistoryService } from '@/workflows/workflow-history/workflow-history.service';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { UpdateWorkflowReviewRequestVersionDto } from '@n8n/api-types';
|
||||
import type { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import { DbLock } from '@n8n/db';
|
||||
import type {
|
||||
DbLockService,
|
||||
|
|
@ -26,7 +26,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import type { CollaborationService } from '@/collaboration/collaboration.service';
|
||||
import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from '@n8n/errors';
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
|
||||
import type { WorkflowReviewPolicyService } from '@/services/workflow-review-policy.service';
|
||||
import type { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import type { WorkflowHistoryService } from '@/workflows/workflow-history/workflow-history.service';
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import {
|
|||
|
||||
import { NotFoundError } from '@n8n/errors';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
import { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
|
||||
import { resolveDecisionCapability } from './workflow-review-decision-policy';
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type {
|
|||
WorkflowReviewEligibleReviewersList,
|
||||
WorkflowReviewRequestSummary,
|
||||
} from '@n8n/api-types';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
DbLock,
|
||||
DbLockService,
|
||||
|
|
@ -24,7 +24,7 @@ import {
|
|||
import { Service } from '@n8n/di';
|
||||
|
||||
import { BadRequestError, ConflictError, NotFoundError } from '@n8n/errors';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import { WorkflowHistoryService } from '@/workflows/workflow-history/workflow-history.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
import {
|
||||
GLOBAL_MEMBER_ROLE,
|
||||
ProjectRepository,
|
||||
RoleRepository,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
CredentialsRepository,
|
||||
type User,
|
||||
type Role,
|
||||
} from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { type Scope } from '@n8n/permissions';
|
||||
import type { EntityManager } from '@n8n/typeorm';
|
||||
import type { Mock } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import { CredentialsFinderService } from '@/credentials/credentials-finder.service';
|
||||
import { NotFoundError } from '@n8n/errors';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { userHasScopes } from '../check-access';
|
||||
|
||||
|
|
@ -27,6 +30,7 @@ describe('userHasScopes', () => {
|
|||
let hasGlobalConnectAccessMock: Mock;
|
||||
let roleServiceMock: Mock;
|
||||
let mockQueryBuilder: any;
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
|
||||
beforeAll(() => {
|
||||
findByWorkflowMock = vi.fn();
|
||||
|
|
@ -92,6 +96,7 @@ describe('userHasScopes', () => {
|
|||
rolesWithScope: roleServiceMock,
|
||||
}),
|
||||
);
|
||||
Container.set(RoleRepository, roleRepository);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -169,6 +174,37 @@ describe('userHasScopes', () => {
|
|||
});
|
||||
|
||||
describe('RoleService integration', () => {
|
||||
it('should load roles through the supplied transaction manager', async () => {
|
||||
const credentialId = 'cred123';
|
||||
const entityManager = mock<EntityManager>();
|
||||
const sharedCredentialsRepository = mock<SharedCredentialsRepository>();
|
||||
entityManager.createQueryBuilder.mockReturnValue(mockQueryBuilder);
|
||||
entityManager.getRepository.mockReturnValue(sharedCredentialsRepository);
|
||||
sharedCredentialsRepository.findBy.mockResolvedValue([
|
||||
{
|
||||
credentialsId: credentialId,
|
||||
projectId: 'projectId',
|
||||
role: 'credential:custom',
|
||||
},
|
||||
] as never);
|
||||
roleRepository.findAll.mockResolvedValue([mock<Role>({ slug: 'credential:custom' })]);
|
||||
roleServiceMock.mockImplementation(
|
||||
async (_namespace, _scopes, loadRoles: () => Promise<Role[]>) =>
|
||||
(await loadRoles()).map(({ slug }) => slug),
|
||||
);
|
||||
|
||||
const result = await userHasScopes(
|
||||
{ id: 'userId', scopes: [], role: GLOBAL_MEMBER_ROLE } as unknown as User,
|
||||
['credential:read'],
|
||||
false,
|
||||
{ credentialId },
|
||||
entityManager,
|
||||
);
|
||||
|
||||
expect(roleRepository.findAll).toHaveBeenCalledWith(entityManager);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should use RoleService for credential role resolution', async () => {
|
||||
const credentialId = 'cred123';
|
||||
const mockRoles = ['credential:owner', 'custom:credential-admin'];
|
||||
|
|
@ -187,7 +223,7 @@ describe('userHasScopes', () => {
|
|||
|
||||
const result = await userHasScopes(user, scopes, false, { credentialId });
|
||||
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('credential', scopes, undefined);
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('credential', scopes);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
|
|
@ -209,7 +245,7 @@ describe('userHasScopes', () => {
|
|||
|
||||
const result = await userHasScopes(user, scopes, false, { workflowId });
|
||||
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('workflow', scopes, undefined);
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('workflow', scopes);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
|
|
@ -231,7 +267,7 @@ describe('userHasScopes', () => {
|
|||
|
||||
const result = await userHasScopes(user, scopes, false, { credentialId });
|
||||
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('credential', scopes, undefined);
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('credential', scopes);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
|
|
@ -273,7 +309,7 @@ describe('userHasScopes', () => {
|
|||
|
||||
await userHasScopes(user, ['credential:read'], false, { credentialId });
|
||||
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('credential', ['credential:read'], undefined);
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('credential', ['credential:read']);
|
||||
expect(roleServiceMock).not.toHaveBeenCalledWith('workflow', expect.anything());
|
||||
});
|
||||
|
||||
|
|
@ -292,7 +328,7 @@ describe('userHasScopes', () => {
|
|||
|
||||
await userHasScopes(user, ['workflow:execute'], false, { workflowId });
|
||||
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('workflow', ['workflow:execute'], undefined);
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('workflow', ['workflow:execute']);
|
||||
expect(roleServiceMock).not.toHaveBeenCalledWith('credential', expect.anything());
|
||||
});
|
||||
|
||||
|
|
@ -396,7 +432,7 @@ describe('userHasScopes', () => {
|
|||
|
||||
const result = await userHasScopes(user, scopes, false, { workflowId });
|
||||
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('workflow', scopes, undefined);
|
||||
expect(roleServiceMock).toHaveBeenCalledWith('workflow', scopes);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { ProjectRelationRepository, User } from '@n8n/db';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { ProjectScopeService } from '../project-scope.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
CredentialsRepository,
|
||||
Project,
|
||||
ProjectRepository,
|
||||
RoleRepository,
|
||||
SharedCredentials,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflow,
|
||||
|
|
@ -16,7 +17,7 @@ import { UnexpectedError } from 'n8n-workflow';
|
|||
|
||||
import { CredentialsFinderService } from '@/credentials/credentials-finder.service';
|
||||
import { NotFoundError } from '@n8n/errors';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
const INSTANCE_CREDENTIAL_MANAGEMENT_SCOPES = new Set<Scope>([
|
||||
'credential:read',
|
||||
|
|
@ -114,6 +115,13 @@ export async function userHasScopes(
|
|||
// Then find at least one of the above qualifying projects having one of
|
||||
// those resource roles over the resource being checked.
|
||||
const roleService = Container.get(RoleService);
|
||||
const loadRoles = entityManager
|
||||
? async () => await Container.get(RoleRepository).findAll(entityManager)
|
||||
: undefined;
|
||||
const rolesWithScope = async (namespace: 'credential' | 'workflow') =>
|
||||
loadRoles
|
||||
? await roleService.rolesWithScope(namespace, scopes, loadRoles)
|
||||
: await roleService.rolesWithScope(namespace, scopes);
|
||||
|
||||
if (credentialId) {
|
||||
const credentialRepo = entityManager
|
||||
|
|
@ -125,7 +133,7 @@ export async function userHasScopes(
|
|||
throw new NotFoundError(`Credential with ID "${credentialId}" not found.`);
|
||||
}
|
||||
|
||||
const validRoles = await roleService.rolesWithScope('credential', scopes, entityManager);
|
||||
const validRoles = await rolesWithScope('credential');
|
||||
|
||||
const hasValidRoles = credentials.some(
|
||||
(c) => userProjectIds.includes(c.projectId) && validRoles.includes(c.role),
|
||||
|
|
@ -150,7 +158,7 @@ export async function userHasScopes(
|
|||
throw new NotFoundError(`Workflow with ID "${workflowId}" not found.`);
|
||||
}
|
||||
|
||||
const validRoles = await roleService.rolesWithScope('workflow', scopes, entityManager);
|
||||
const validRoles = await rolesWithScope('workflow');
|
||||
|
||||
return workflows.some(
|
||||
(w) => userProjectIds.includes(w.projectId) && validRoles.includes(w.role),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { ProjectRelationRepository, type User } from '@n8n/db';
|
|||
import { Service } from '@n8n/di';
|
||||
import { hasGlobalScope, type Scope } from '@n8n/permissions';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
/**
|
||||
* Resolves the project roles, or the project IDs, that restrict a scope-aware query.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import type { CreateRoleDto } from '@n8n/api-types';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type { AuthenticatedRequest } from '@n8n/db';
|
||||
import type { Role } from '@n8n/permissions';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
|
||||
import { RolesPublicController } from '../roles.public.controller';
|
||||
|
||||
describe('RolesPublicController', () => {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
UpdateRolePublicDto,
|
||||
roleSlugParamSchema,
|
||||
} from '@n8n/api-types';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { LICENSE_FEATURES } from '@n8n/constants';
|
||||
import { AuthenticatedRequest } from '@n8n/db';
|
||||
import {
|
||||
|
|
@ -33,7 +33,6 @@ import type { Response } from 'express';
|
|||
|
||||
import { NotFoundError } from '@n8n/errors';
|
||||
import { assertCanManageRoleType, canReassignUsers } from '@/services/role-authorization';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
type PublicRoleNamespace = Extract<RoleNamespace, 'global' | 'project'>;
|
||||
const isPublicRole = (role: RoleDTO): role is RoleDTO & { roleType: PublicRoleNamespace } =>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import { CredentialsFinderService } from '@/credentials/credentials-finder.service';
|
||||
|
||||
import { RoleService } from '../role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
describe('CredentialsFinderService', () => {
|
||||
const roleService = mockInstance(RoleService);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { Folder, FolderRepository, User } from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { FolderFinderService } from '../folder-finder.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import type { ProjectRelation } from '@n8n/api-types';
|
||||
import type { Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
type Project,
|
||||
type ProjectRepository,
|
||||
type RoleRepository,
|
||||
type SharedCredentialsRepository,
|
||||
type SharedWorkflowRepository,
|
||||
type ProjectRelationRepository,
|
||||
|
|
@ -21,7 +22,6 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import type { OwnershipService } from '../ownership.service';
|
||||
import { ProjectService } from '../project.service.ee';
|
||||
import type { RoleService } from '../role.service';
|
||||
|
||||
import type { ICredentialConnectionStatusProvider } from '@/credentials/credential-connection-status-provider.interface';
|
||||
import { BadRequestError, ForbiddenError } from '@n8n/errors';
|
||||
|
|
@ -48,6 +48,7 @@ describe('ProjectService', () => {
|
|||
const eventService = mock<EventService>();
|
||||
const userManagementMailer = mock<UserManagementMailer>();
|
||||
const userRepository = mock<UserRepository>();
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
const user = mock<User>({ id: 'actor-user', role: mock({ slug: 'global:owner' }) });
|
||||
const projectService = new ProjectService(
|
||||
sharedWorkflowRepository,
|
||||
|
|
@ -63,6 +64,7 @@ describe('ProjectService', () => {
|
|||
eventService,
|
||||
userManagementMailer,
|
||||
userRepository,
|
||||
roleRepository,
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import {
|
||||
SettingsRepository,
|
||||
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from '@n8n/permissions';
|
||||
|
||||
import { InstanceRedactionEnforcementService } from '@/modules/redaction/instance-redaction-enforcement.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { SecuritySettingsService } from '@/services/security-settings.service';
|
||||
|
||||
describe('SecuritySettingsService', () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { InviteUsersRequestDto } from '@n8n/api-types';
|
||||
import { type EventService, UrlService } from '@n8n/backend-services';
|
||||
import { type EventService, UrlService, type RoleService } from '@n8n/backend-services';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import {
|
||||
|
|
@ -32,7 +32,6 @@ import { JwtService } from '../jwt.service';
|
|||
import type { OwnershipService } from '../ownership.service';
|
||||
import type { ProjectService } from '../project.service.ee';
|
||||
import type { PublicApiKeyService } from '../public-api-key.service';
|
||||
import type { RoleService } from '../role.service';
|
||||
|
||||
describe('UserService', () => {
|
||||
const globalConfig = mockInstance(GlobalConfig, {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { hasGlobalScope, type Scope } from '@n8n/permissions';
|
|||
import type { FindOptionsWhere } from '@n8n/typeorm';
|
||||
import { In } from '@n8n/typeorm';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
/**
|
||||
* Resolves folders by id for a user, enforcing access through the folder's home
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { CreateProjectDto, ProjectType, UpdateProjectDto } from '@n8n/api-types';
|
||||
import { LicenseState, Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
type User,
|
||||
FolderRepository,
|
||||
|
|
@ -8,6 +8,7 @@ import {
|
|||
ProjectRelation,
|
||||
ProjectRelationRepository,
|
||||
ProjectRepository,
|
||||
RoleRepository,
|
||||
ProjectIdConflictError,
|
||||
SharedCredentialsRepository,
|
||||
SharedWorkflowRepository,
|
||||
|
|
@ -37,7 +38,6 @@ import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from '@
|
|||
import { UserManagementMailer } from '@/user-management/email';
|
||||
|
||||
import { OwnershipService } from './ownership.service';
|
||||
import { RoleService } from './role.service';
|
||||
|
||||
const INSTANCE_ACCESS_ROLE_ERROR =
|
||||
"This user has access through their instance role. Project roles can't change their access in this project.";
|
||||
|
|
@ -100,6 +100,7 @@ export class ProjectService {
|
|||
private readonly eventService: EventService,
|
||||
private readonly userManagementMailer: UserManagementMailer,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly roleRepository: RoleRepository,
|
||||
) {}
|
||||
|
||||
private get workflowService() {
|
||||
|
|
@ -911,10 +912,11 @@ export class ProjectService {
|
|||
};
|
||||
|
||||
if (!hasGlobalScope(user, scopes, { mode: 'allOf' })) {
|
||||
// Use the same EntityManager as the project lookup (including when callers pass a
|
||||
// transaction manager). Otherwise role resolution can open a second pooled connection
|
||||
// while a transaction already holds a connection
|
||||
const projectRoles = await this.roleService.rolesWithScope('project', scopes, em);
|
||||
const projectRoles = await this.roleService.rolesWithScope(
|
||||
'project',
|
||||
scopes,
|
||||
async () => await this.roleRepository.findAll(em),
|
||||
);
|
||||
|
||||
where = {
|
||||
...where,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { RedactionFloor } from '@n8n/api-types';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import {
|
||||
SettingsRepository,
|
||||
SharedCredentialsRepository,
|
||||
|
|
@ -15,7 +15,6 @@ import type { DistributiveOmit } from '@n8n/utils/types';
|
|||
|
||||
import type { RelayEventMap, UserLike } from '@/events/maps/relay.event-map';
|
||||
import { InstanceRedactionEnforcementService } from '@/modules/redaction/instance-redaction-enforcement.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
/**
|
||||
* The writable subset of the security policy shared by the internal controller
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { RoleChangeRequestDto } from '@n8n/api-types';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { EventService, UrlService } from '@n8n/backend-services';
|
||||
import { EventService, UrlService, RoleService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import type { PublicUser } from '@n8n/db';
|
||||
import {
|
||||
|
|
@ -34,7 +34,6 @@ import { JwtService } from './jwt.service';
|
|||
import { OwnershipService } from './ownership.service';
|
||||
import { ProjectService } from './project.service.ee';
|
||||
import { PublicApiKeyService } from './public-api-key.service';
|
||||
import { RoleService } from './role.service';
|
||||
|
||||
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { BadRequestError, ForbiddenError, InternalServerError, NotFoundError } from '@n8n/errors';
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
/* eslint-disable @typescript-eslint/unbound-method -- vi mocks */
|
||||
import type {
|
||||
FolderRepository,
|
||||
RoleRepository,
|
||||
SharedWorkflow,
|
||||
SharedWorkflowRepository,
|
||||
WorkflowRepository,
|
||||
} from '@n8n/db';
|
||||
import type { EntityManager } from '@n8n/typeorm';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { WorkflowFinderService } from '../workflow-finder.service';
|
||||
|
||||
|
|
@ -22,16 +24,43 @@ function makeService(rows?: FolderRow[]) {
|
|||
const workflowRepository = mock<WorkflowRepository>();
|
||||
const folderRepository = mock<FolderRepository>();
|
||||
const roleService = mock<RoleService>();
|
||||
const roleRepository = mock<RoleRepository>();
|
||||
const service = new WorkflowFinderService(
|
||||
sharedWorkflowRepository,
|
||||
folderRepository,
|
||||
roleService,
|
||||
workflowRepository,
|
||||
roleRepository,
|
||||
);
|
||||
return { service, sharedWorkflowRepository, workflowRepository, folderRepository, roleService };
|
||||
return {
|
||||
service,
|
||||
sharedWorkflowRepository,
|
||||
workflowRepository,
|
||||
folderRepository,
|
||||
roleService,
|
||||
roleRepository,
|
||||
};
|
||||
}
|
||||
|
||||
describe('WorkflowFinderService', () => {
|
||||
it('loads roles through the supplied transaction manager', async () => {
|
||||
const { service, roleService, roleRepository } = makeService();
|
||||
const em = mock<EntityManager>();
|
||||
roleService.rolesWithScope.mockResolvedValue([]);
|
||||
roleRepository.findAll.mockResolvedValue([]);
|
||||
|
||||
await service.findWorkflowForUser(
|
||||
'workflow-1',
|
||||
{ id: 'user-1', role: { slug: 'global:member', scopes: [] } } as never,
|
||||
['workflow:read'],
|
||||
{ em },
|
||||
);
|
||||
|
||||
const loadRoles = roleService.rolesWithScope.mock.calls[0][2];
|
||||
await loadRoles?.();
|
||||
expect(roleRepository.findAll).toHaveBeenCalledWith(em);
|
||||
});
|
||||
|
||||
describe('findWorkflowIdsByFolder', () => {
|
||||
it('returns an empty map without querying when no folder ids are given', async () => {
|
||||
const { service, sharedWorkflowRepository } = makeService();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { Logger, LicenseState } from '@n8n/backend-common';
|
|||
import type { ProjectRelationRepository, SharedWorkflowRepository, UserRepository } from '@n8n/db';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
import type { RoleService } from '@/services/role.service';
|
||||
import type { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { WorkflowSharingService } from '../workflow-sharing.service';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import type { EventService } from '@n8n/backend-services';
|
||||
import { type EventService, type RoleService } from '@n8n/backend-services';
|
||||
import type { GlobalConfig, WorkflowsConfig } from '@n8n/config';
|
||||
import type {
|
||||
Project,
|
||||
|
|
@ -45,7 +45,7 @@ import type { PollTriggerJobRegistrar } from '@/scheduling/poll-trigger-node/pol
|
|||
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 { RoleService } from '@/services/role.service';
|
||||
|
||||
import type { TagService } from '@/services/tag.service';
|
||||
import type { WebhookService } from '@/webhooks/webhook.service';
|
||||
import * as WorkflowHelpers from '@/workflow-helpers';
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
import type { SharedWorkflow, User, WorkflowEntity, ListQuery } from '@n8n/db';
|
||||
import { SharedWorkflowRepository, FolderRepository, WorkflowRepository, chunkIds } from '@n8n/db';
|
||||
import {
|
||||
SharedWorkflowRepository,
|
||||
FolderRepository,
|
||||
WorkflowRepository,
|
||||
RoleRepository,
|
||||
chunkIds,
|
||||
} from '@n8n/db';
|
||||
import { Service } from '@n8n/di';
|
||||
import { hasGlobalScope, type Scope } from '@n8n/permissions';
|
||||
import type { EntityManager, FindOptionsWhere } from '@n8n/typeorm';
|
||||
import { In, IsNull } from '@n8n/typeorm';
|
||||
|
||||
import { userHasScopes } from '@/permissions.ee/check-access';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
export type FindWorkflowsForUserOptions = {
|
||||
filters?: {
|
||||
|
|
@ -31,6 +37,7 @@ export class WorkflowFinderService {
|
|||
private readonly folderRepository: FolderRepository,
|
||||
private readonly roleService: RoleService,
|
||||
private readonly workflowRepository: WorkflowRepository,
|
||||
private readonly roleRepository: RoleRepository,
|
||||
) {}
|
||||
|
||||
async findWorkflowForUser(
|
||||
|
|
@ -95,10 +102,15 @@ export class WorkflowFinderService {
|
|||
em?: EntityManager,
|
||||
): Promise<FindOptionsWhere<SharedWorkflow>> {
|
||||
if (hasGlobalScope(user, scopes, { mode: 'allOf' })) return {};
|
||||
const loadRoles = em ? async () => await this.roleRepository.findAll(em) : undefined;
|
||||
const rolesWithScope = async (namespace: 'project' | 'workflow') =>
|
||||
loadRoles
|
||||
? await this.roleService.rolesWithScope(namespace, scopes, loadRoles)
|
||||
: await this.roleService.rolesWithScope(namespace, scopes);
|
||||
|
||||
const [projectRoles, workflowRoles] = await Promise.all([
|
||||
this.roleService.rolesWithScope('project', scopes, em),
|
||||
this.roleService.rolesWithScope('workflow', scopes, em),
|
||||
rolesWithScope('project'),
|
||||
rolesWithScope('workflow'),
|
||||
]);
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from '@n8n/permissions';
|
||||
import { In } from '@n8n/typeorm';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
export type ShareWorkflowOptions =
|
||||
| { scopes: Scope[]; projectId?: string }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { UpdateWorkflowHistoryVersionDto } from '@n8n/api-types';
|
||||
import type { WorkflowListPublicationStatus } from '@n8n/api-types';
|
||||
import { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import { EventService } from '@n8n/backend-services';
|
||||
import { EventService, RoleService } from '@n8n/backend-services';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import type { User, ListQueryDb, Project, WorkflowFolderUnionFull, WorkflowHistory } from '@n8n/db';
|
||||
import {
|
||||
|
|
@ -71,7 +71,7 @@ import { ScheduleTriggerJobRegistrar } from '@/scheduling/schedule-trigger-node/
|
|||
import { WorkflowScheduledJobOwner } from '@/scheduling/workflow-scheduled-job-owner';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { WEBHOOK_CONFLICT_MESSAGE } from '@/webhooks/constants';
|
||||
import { WebhookService } from '@/webhooks/webhook.service';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { AuthRolesService, RoleRepository, type User } from '@n8n/db';
|
|||
import { Container } from '@n8n/di';
|
||||
import { PROJECT_OWNER_ROLE_SLUG } from '@n8n/permissions';
|
||||
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleCacheService } from '@n8n/backend-services';
|
||||
|
||||
import { createMemberWithApiKey } from './shared/db/users';
|
||||
import * as utils from './shared/utils/';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { CreateRoleDto, UpdateRoleDto } from '@n8n/api-types';
|
|||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import { type Role } from '@n8n/permissions';
|
||||
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
|
||||
import { cleanupRolesAndScopes } from '../shared/db/roles';
|
||||
import { createMember, createOwner } from '../shared/db/users';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import config from '@/config';
|
|||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { CredentialsTester } from '@/services/credentials-tester.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleCacheService } from '@n8n/backend-services';
|
||||
import { SecuritySettingsService } from '@/services/security-settings.service';
|
||||
import { UserManagementMailer } from '@/user-management/email';
|
||||
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ describe('CredentialsRepository', () => {
|
|||
const { CredentialsFinderService } = await import(
|
||||
'@/credentials/credentials-finder.service.js'
|
||||
);
|
||||
const { RoleService } = await import('@/services/role.service.js');
|
||||
const { RoleService } = await import('@n8n/backend-services');
|
||||
|
||||
const member = await createMember();
|
||||
const teamProject = await createTeamProject('test-project');
|
||||
|
|
@ -566,7 +566,7 @@ describe('CredentialsRepository', () => {
|
|||
const { CredentialsFinderService } = await import(
|
||||
'@/credentials/credentials-finder.service.js'
|
||||
);
|
||||
const { RoleService } = await import('@/services/role.service.js');
|
||||
const { RoleService } = await import('@n8n/backend-services');
|
||||
|
||||
const member = await createMember();
|
||||
const teamProject = await createTeamProject('test-project');
|
||||
|
|
@ -636,7 +636,7 @@ describe('CredentialsRepository', () => {
|
|||
const { CredentialsFinderService } = await import(
|
||||
'@/credentials/credentials-finder.service.js'
|
||||
);
|
||||
const { RoleService } = await import('@/services/role.service.js');
|
||||
const { RoleService } = await import('@n8n/backend-services');
|
||||
|
||||
const member = await createMember();
|
||||
|
||||
|
|
@ -723,7 +723,7 @@ describe('CredentialsRepository', () => {
|
|||
const { CredentialsFinderService } = await import(
|
||||
'@/credentials/credentials-finder.service.js'
|
||||
);
|
||||
const { RoleService } = await import('@/services/role.service.js');
|
||||
const { RoleService } = await import('@n8n/backend-services');
|
||||
|
||||
// Create two separate users
|
||||
const userA = await createMember();
|
||||
|
|
|
|||
|
|
@ -1132,7 +1132,7 @@ describe('WorkflowRepository', () => {
|
|||
const { createMember } = await import('../../shared/db/users.js');
|
||||
const { createTeamProject, linkUserToProject } = await import('@n8n/backend-test-utils');
|
||||
const { WorkflowSharingService } = await import('@/workflows/workflow-sharing.service.js');
|
||||
const { RoleService } = await import('@/services/role.service.js');
|
||||
const { RoleService } = await import('@n8n/backend-services');
|
||||
|
||||
const member = await createMember();
|
||||
const teamProject = await createTeamProject('test-project');
|
||||
|
|
@ -1270,7 +1270,7 @@ describe('WorkflowRepository', () => {
|
|||
const { createMember } = await import('../../shared/db/users.js');
|
||||
const { createTeamProject, linkUserToProject } = await import('@n8n/backend-test-utils');
|
||||
const { WorkflowSharingService } = await import('@/workflows/workflow-sharing.service.js');
|
||||
const { RoleService } = await import('@/services/role.service.js');
|
||||
const { RoleService } = await import('@n8n/backend-services');
|
||||
|
||||
const member = await createMember();
|
||||
|
||||
|
|
@ -1352,7 +1352,7 @@ describe('WorkflowRepository', () => {
|
|||
const { createMember } = await import('../../shared/db/users.js');
|
||||
const { createTeamProject, linkUserToProject } = await import('@n8n/backend-test-utils');
|
||||
const { WorkflowSharingService } = await import('@/workflows/workflow-sharing.service.js');
|
||||
const { RoleService } = await import('@/services/role.service.js');
|
||||
const { RoleService } = await import('@n8n/backend-services');
|
||||
|
||||
// Create two separate users
|
||||
const userA = await createMember();
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import { mock } from 'vitest-mock-extended';
|
|||
|
||||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { ExternalSecretsConfig } from '@/modules/external-secrets.ee/external-secrets.config';
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleCacheService } from '@n8n/backend-services';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { CredentialsTester } from '@/services/credentials-tester.service';
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ import { BadRequestError, NotFoundError } from '@n8n/errors';
|
|||
import { License } from '@/license';
|
||||
import { ProvisioningRoleDeletionChecker } from '@/modules/provisioning.ee/role-deletion-checker.ee';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleDeletionCheckProxy } from '@/services/role-deletion-check-proxy.service';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleDeletionCheckProxy, RoleService } from '@n8n/backend-services';
|
||||
|
||||
import {
|
||||
createRole,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Role, RoleRepository, Scope, ScopeRepository } from '@n8n/db';
|
|||
import { Container } from '@n8n/di';
|
||||
import type { Scope as ScopeType } from '@n8n/permissions';
|
||||
|
||||
import { RoleCacheService } from '@/services/role-cache.service';
|
||||
import { RoleCacheService } from '@n8n/backend-services';
|
||||
|
||||
/**
|
||||
* Creates a test role with given parameters
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import { NodeTypes } from '@/node-types';
|
|||
import { PolicyEnforcementService } from '@/policy/policy-enforcement.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { RoleService } from '@n8n/backend-services';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
import { WebhookService } from '@/webhooks/webhook.service';
|
||||
import { WorkflowHookContextService } from '@/workflow-hook-context.service';
|
||||
|
|
|
|||
|
|
@ -1813,6 +1813,9 @@ importers:
|
|||
'@n8n/constants':
|
||||
specifier: workspace:*
|
||||
version: link:../constants
|
||||
'@n8n/db':
|
||||
specifier: workspace:*
|
||||
version: link:../db
|
||||
'@n8n/decorators':
|
||||
specifier: workspace:*
|
||||
version: link:../decorators
|
||||
|
|
@ -1822,6 +1825,9 @@ importers:
|
|||
'@n8n/errors':
|
||||
specifier: workspace:*
|
||||
version: link:../errors
|
||||
'@n8n/permissions':
|
||||
specifier: workspace:*
|
||||
version: link:../permissions
|
||||
'@n8n/utils':
|
||||
specifier: workspace:*
|
||||
version: link:../utils
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user