mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-10-15 13:21:11 +00:00
bbde5ebbc3
Reaching a server implied being able to open an SSH root shell on it: the /terminal websocket only checked that the server was in the caller's accessible set, so granting a server to a developer necessarily granted root on it. Add a server.terminal action, assignable on custom roles, and require it on the remote-server terminal websocket on top of server access. Owner/admin keep it through the enterprise bypass; the local host terminal stays owner/admin only. A migration grants server.terminal to existing custom roles that already have server.read, which is the permission that surfaces the terminal today, so current setups keep working. Roles without a server entry are left alone. Note: server.create still implies root execution (server.update persists server.command and server.setup runs it over SSH), reflected in the Create description in the role editor.
207 lines
6.7 KiB
TypeScript
207 lines
6.7 KiB
TypeScript
import { createAccessControl } from "better-auth/plugins/access";
|
|
|
|
/**
|
|
* Dokploy Access Control Statements
|
|
*
|
|
* Defines all resources and their possible actions across the platform.
|
|
* The first 5 (organization, member, invitation, team, ac) are better-auth defaults
|
|
* used internally by the organization plugin.
|
|
* The rest are Dokploy-specific resources.
|
|
*
|
|
* Enterprise-only resources (only assignable via custom roles):
|
|
* deployment, envVars, server, registry, certificate, backup, domain, logs, monitoring
|
|
*/
|
|
export const statements = {
|
|
// better-auth organization plugin defaults
|
|
organization: ["update", "delete"],
|
|
member: ["read", "create", "update", "delete"],
|
|
invitation: ["create", "cancel"],
|
|
team: ["create", "update", "delete"],
|
|
ac: ["create", "read", "update", "delete"],
|
|
|
|
// Dokploy core resources (free tier)
|
|
project: ["create", "delete"],
|
|
service: ["create", "read", "delete"],
|
|
environment: ["create", "read", "delete"],
|
|
docker: ["read"],
|
|
sshKeys: ["read", "create", "delete"],
|
|
gitProviders: ["read", "create", "delete"],
|
|
traefikFiles: ["read", "write"],
|
|
api: ["read"],
|
|
|
|
// Enterprise-only resources (custom roles only)
|
|
volume: ["read", "create", "delete"],
|
|
deployment: ["read", "create", "cancel"],
|
|
envVars: ["read", "write"],
|
|
projectEnvVars: ["read", "write"],
|
|
environmentEnvVars: ["read", "write"],
|
|
server: ["read", "create", "delete", "terminal"],
|
|
registry: ["read", "create", "delete"],
|
|
certificate: ["read", "create", "update", "delete"],
|
|
backup: ["read", "create", "update", "delete", "restore"],
|
|
volumeBackup: ["read", "create", "update", "delete", "restore"],
|
|
schedule: ["read", "create", "update", "delete"],
|
|
domain: ["read", "create", "delete"],
|
|
destination: ["read", "create", "delete"],
|
|
notification: ["read", "create", "update", "delete"],
|
|
tag: ["read", "create", "update", "delete"],
|
|
logs: ["read"],
|
|
monitoring: ["read"],
|
|
auditLog: ["read"],
|
|
vaultProvider: ["read", "create", "update", "delete"],
|
|
dnsProvider: ["read", "create", "update", "delete"],
|
|
} as const;
|
|
|
|
/**
|
|
* Enterprise-only resources. For static roles (owner/admin/member),
|
|
* permission checks on these resources are bypassed — they only apply
|
|
* when using custom roles with an enterprise license.
|
|
*/
|
|
export const enterpriseOnlyResources = new Set<string>([
|
|
"volume",
|
|
"deployment",
|
|
"envVars",
|
|
"projectEnvVars",
|
|
"environmentEnvVars",
|
|
"server",
|
|
"registry",
|
|
"certificate",
|
|
"backup",
|
|
"volumeBackup",
|
|
"schedule",
|
|
"domain",
|
|
"destination",
|
|
"notification",
|
|
"tag",
|
|
"logs",
|
|
"monitoring",
|
|
"auditLog",
|
|
"vaultProvider",
|
|
"dnsProvider",
|
|
]);
|
|
|
|
export const ac = createAccessControl(statements);
|
|
|
|
/**
|
|
* Owner role — full access to everything
|
|
*/
|
|
export const ownerRole = ac.newRole({
|
|
organization: ["update", "delete"],
|
|
member: ["read", "create", "update", "delete"],
|
|
invitation: ["create", "cancel"],
|
|
team: ["create", "update", "delete"],
|
|
ac: ["create", "read", "update", "delete"],
|
|
project: ["create", "delete"],
|
|
service: ["create", "read", "delete"],
|
|
environment: ["create", "read", "delete"],
|
|
docker: ["read"],
|
|
sshKeys: ["read", "create", "delete"],
|
|
gitProviders: ["read", "create", "delete"],
|
|
traefikFiles: ["read", "write"],
|
|
api: ["read"],
|
|
volume: ["read", "create", "delete"],
|
|
deployment: ["read", "create", "cancel"],
|
|
envVars: ["read", "write"],
|
|
projectEnvVars: ["read", "write"],
|
|
environmentEnvVars: ["read", "write"],
|
|
server: ["read", "create", "delete", "terminal"],
|
|
registry: ["read", "create", "delete"],
|
|
certificate: ["read", "create", "update", "delete"],
|
|
backup: ["read", "create", "update", "delete", "restore"],
|
|
volumeBackup: ["read", "create", "update", "delete", "restore"],
|
|
schedule: ["read", "create", "update", "delete"],
|
|
domain: ["read", "create", "delete"],
|
|
destination: ["read", "create", "delete"],
|
|
notification: ["read", "create", "update", "delete"],
|
|
tag: ["read", "create", "update", "delete"],
|
|
logs: ["read"],
|
|
monitoring: ["read"],
|
|
auditLog: ["read"],
|
|
vaultProvider: ["read", "create", "update", "delete"],
|
|
dnsProvider: ["read", "create", "update", "delete"],
|
|
});
|
|
|
|
/**
|
|
* Admin role — same as owner but cannot delete the organization
|
|
*/
|
|
export const adminRole = ac.newRole({
|
|
organization: ["update"],
|
|
member: ["read", "create", "update", "delete"],
|
|
invitation: ["create", "cancel"],
|
|
team: ["create", "update", "delete"],
|
|
ac: ["create", "read", "update", "delete"],
|
|
project: ["create", "delete"],
|
|
service: ["create", "read", "delete"],
|
|
environment: ["create", "read", "delete"],
|
|
docker: ["read"],
|
|
sshKeys: ["read", "create", "delete"],
|
|
gitProviders: ["read", "create", "delete"],
|
|
traefikFiles: ["read", "write"],
|
|
api: ["read"],
|
|
volume: ["read", "create", "delete"],
|
|
deployment: ["read", "create", "cancel"],
|
|
envVars: ["read", "write"],
|
|
projectEnvVars: ["read", "write"],
|
|
environmentEnvVars: ["read", "write"],
|
|
server: ["read", "create", "delete", "terminal"],
|
|
registry: ["read", "create", "delete"],
|
|
certificate: ["read", "create", "update", "delete"],
|
|
backup: ["read", "create", "update", "delete", "restore"],
|
|
volumeBackup: ["read", "create", "update", "delete", "restore"],
|
|
schedule: ["read", "create", "update", "delete"],
|
|
domain: ["read", "create", "delete"],
|
|
destination: ["read", "create", "delete"],
|
|
notification: ["read", "create", "update", "delete"],
|
|
tag: ["read", "create", "update", "delete"],
|
|
logs: ["read"],
|
|
monitoring: ["read"],
|
|
auditLog: ["read"],
|
|
vaultProvider: ["read", "create", "update", "delete"],
|
|
dnsProvider: ["read", "create", "update", "delete"],
|
|
});
|
|
|
|
/**
|
|
* Member role (free tier) — read-only base permissions.
|
|
* Members can read projects/services/environments they have access to,
|
|
* but cannot create, delete, or access admin resources.
|
|
* Enterprise resources are not available to the base member role.
|
|
*/
|
|
export const memberRole = ac.newRole({
|
|
organization: [],
|
|
member: [],
|
|
invitation: [],
|
|
team: [],
|
|
ac: ["read"],
|
|
project: [],
|
|
service: ["read"],
|
|
environment: ["read"],
|
|
docker: [],
|
|
sshKeys: [],
|
|
gitProviders: [],
|
|
traefikFiles: [],
|
|
api: [],
|
|
// Service-level enterprise resources — member can do everything within services they have access to
|
|
volume: ["read", "create", "delete"],
|
|
deployment: ["read", "create", "cancel"],
|
|
envVars: ["read", "write"],
|
|
projectEnvVars: ["read", "write"],
|
|
environmentEnvVars: ["read", "write"],
|
|
backup: ["read", "create", "update", "delete", "restore"],
|
|
volumeBackup: ["read", "create", "update", "delete", "restore"],
|
|
schedule: ["read", "create", "update", "delete"],
|
|
domain: ["read", "create", "delete"],
|
|
logs: ["read"],
|
|
monitoring: ["read"],
|
|
// Org-level enterprise resources — member cannot manage these
|
|
server: [],
|
|
registry: [],
|
|
certificate: [],
|
|
destination: [],
|
|
notification: [],
|
|
tag: ["read"],
|
|
auditLog: [],
|
|
// Members need provider/secret names for env editor autocomplete; values are never exposed
|
|
vaultProvider: ["read"],
|
|
dnsProvider: [],
|
|
});
|