mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 05:29:44 +02:00
feat(core): Add credentialTypePolicy:manage as a separate permission (no-changelog) (#38855)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
6f2bc13984
commit
1b6b20c29e
|
|
@ -47,6 +47,7 @@ exports[`Scope Information > ensure scopes are defined correctly 1`] = `
|
|||
"credential:update",
|
||||
"credential:delete",
|
||||
"credential:list",
|
||||
"credentialTypePolicy:manage",
|
||||
"externalSecretsProvider:sync",
|
||||
"externalSecretsProvider:create",
|
||||
"externalSecretsProvider:read",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export const RESOURCES = {
|
|||
'manageInstance',
|
||||
...DEFAULT_OPERATIONS,
|
||||
] as const,
|
||||
credentialTypePolicy: ['manage'] as const,
|
||||
externalSecretsProvider: ['sync', ...DEFAULT_OPERATIONS] as const,
|
||||
externalSecret: ['list'] as const,
|
||||
eventBusDestination: ['test', ...DEFAULT_OPERATIONS] as const,
|
||||
|
|
@ -125,6 +126,7 @@ export const API_KEY_RESOURCES = {
|
|||
role: ['manage', 'manageProject', 'list', 'read'] as const,
|
||||
roleMappingRule: ['create', 'delete', 'list', 'update'] as const,
|
||||
nodeTypePolicy: ['manage'] as const,
|
||||
// TODO: add credentialTypePolicy:manage once a Public API endpoint consumes it.
|
||||
} as const;
|
||||
|
||||
export const GLOBAL_OWNER_ROLE_SLUG = 'global:owner';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
import { API_KEY_RESOURCES } from '@/constants.ee';
|
||||
import { GLOBAL_ADMIN_SCOPES, GLOBAL_OWNER_SCOPES } from '@/roles/scopes/global-scopes.ee';
|
||||
import {
|
||||
PERSONAL_PROJECT_OWNER_SCOPES,
|
||||
PROJECT_EDITOR_SCOPES,
|
||||
PROJECT_VIEWER_SCOPES,
|
||||
REGULAR_PROJECT_ADMIN_SCOPES,
|
||||
} from '@/roles/scopes/project-scopes.ee';
|
||||
import type { AuthPrincipal } from '@/types.ee';
|
||||
import { hasGlobalScope } from '@/utilities/has-global-scope.ee';
|
||||
|
||||
const principal = (slug: string, scopes: string[]): AuthPrincipal =>
|
||||
({
|
||||
role: { slug, scopes: scopes.map((scope) => ({ slug: scope })) },
|
||||
}) as unknown as AuthPrincipal;
|
||||
|
||||
describe('credentialTypePolicy:manage and nodeTypePolicy:manage are independent scopes', () => {
|
||||
it('a user granted only nodeTypePolicy:manage does not also gain credentialTypePolicy:manage', () => {
|
||||
expect(
|
||||
hasGlobalScope(
|
||||
principal('custom:node-policy-manager-only', ['nodeTypePolicy:manage']),
|
||||
'credentialTypePolicy:manage',
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('a user granted only credentialTypePolicy:manage does not also gain nodeTypePolicy:manage', () => {
|
||||
expect(
|
||||
hasGlobalScope(
|
||||
principal('custom:credential-policy-manager-only', ['credentialTypePolicy:manage']),
|
||||
'nodeTypePolicy:manage',
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credentialTypePolicy:manage default grants', () => {
|
||||
it('is granted to instance owners and admins', () => {
|
||||
expect(GLOBAL_OWNER_SCOPES).toContain('credentialTypePolicy:manage');
|
||||
expect(GLOBAL_ADMIN_SCOPES).toContain('credentialTypePolicy:manage');
|
||||
});
|
||||
|
||||
it('is granted to project admins, same as nodeTypePolicy:manage', () => {
|
||||
expect(REGULAR_PROJECT_ADMIN_SCOPES).toContain('credentialTypePolicy:manage');
|
||||
});
|
||||
|
||||
it('is not granted to personal project owners, editors, or viewers', () => {
|
||||
expect(PERSONAL_PROJECT_OWNER_SCOPES).not.toContain('credentialTypePolicy:manage');
|
||||
expect(PROJECT_EDITOR_SCOPES).not.toContain('credentialTypePolicy:manage');
|
||||
expect(PROJECT_VIEWER_SCOPES).not.toContain('credentialTypePolicy:manage');
|
||||
});
|
||||
});
|
||||
|
||||
describe('credentialTypePolicy:manage as an API key scope', () => {
|
||||
it('is not declared in API_KEY_RESOURCES yet, since no Public API endpoint consumes it', () => {
|
||||
expect(API_KEY_RESOURCES).not.toHaveProperty('credentialTypePolicy');
|
||||
});
|
||||
});
|
||||
|
|
@ -30,6 +30,7 @@ export const GLOBAL_OWNER_SCOPES: Scope[] = [
|
|||
'credential:connect',
|
||||
'credential:createEndUser',
|
||||
'credential:manageInstance',
|
||||
'credentialTypePolicy:manage',
|
||||
'community:register',
|
||||
'communityPackage:install',
|
||||
'communityPackage:uninstall',
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export const REGULAR_PROJECT_ADMIN_SCOPES: Scope[] = [
|
|||
'folder:move',
|
||||
'sourceControl:push',
|
||||
'nodeTypePolicy:manage',
|
||||
'credentialTypePolicy:manage',
|
||||
'dataTable:create',
|
||||
'dataTable:delete',
|
||||
'dataTable:read',
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ export const scopeInformation: Partial<Record<Scope, ScopeInformation>> = {
|
|||
displayName: 'Manage Node Type Policies',
|
||||
description: 'Allows managing which node types are available, on the instance or in a project.',
|
||||
},
|
||||
'credentialTypePolicy:manage': {
|
||||
displayName: 'Manage Credential Type Policies',
|
||||
description:
|
||||
'Allows managing which credential types are available, on the instance or in a project.',
|
||||
},
|
||||
'encryptionKey:manage': {
|
||||
displayName: 'Manage Encryption Keys',
|
||||
description: 'Allows listing and rotating instance encryption keys.',
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ describe('permissions', () => {
|
|||
community: {},
|
||||
communityPackage: {},
|
||||
credential: {},
|
||||
credentialTypePolicy: {},
|
||||
externalSecretsProvider: {},
|
||||
externalSecret: {},
|
||||
eventBusDestination: {},
|
||||
|
|
@ -113,6 +114,7 @@ describe('permissions', () => {
|
|||
share: true,
|
||||
update: true,
|
||||
},
|
||||
credentialTypePolicy: {},
|
||||
eventBusDestination: {
|
||||
list: true,
|
||||
test: true,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export const useRBACStore = defineStore(STORES.RBAC, () => {
|
|||
annotationTag: {},
|
||||
user: {},
|
||||
credential: {},
|
||||
credentialTypePolicy: {},
|
||||
variable: {},
|
||||
projectVariable: {},
|
||||
sourceControl: {},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user