Skip to content

"Create Services" permission incorrectly required for domain service selection and environment editing #4052

@nizepart

Description

@nizepart

To Reproduce

Bug Description

A member user with access to a project/service should not need the "Create Services" permission to:

  1. Select a service name in the domain configuration form (compose services)
  2. Edit environment variables on database services and compose services

Currently, both operations fail with "Permission denied" unless the user has "Create Services" (canCreateServices) enabled, even though these are read/edit operations, not service creation.

Root Cause

1. compose.loadServices requires service: ["create"] instead of service: ["read"]

File: apps/dokploy/server/api/routers/compose.ts (line ~277-283)

loadServices: protectedProcedure
    .input(apiFetchServices)
    .query(async ({ input, ctx }) => {
        await checkServicePermissionAndAccess(ctx, input.composeId, {
            service: ["create"],  // BUG: should be service: ["read"]
        });
        return await loadServices(input.composeId, input.type);
    }),

This endpoint is called by the domain form (handle-domain.tsx) to populate the service name dropdown when adding/editing a domain on a compose service. Loading services from a compose file is a read-only operation — it just parses the YAML and returns Object.keys(composeData.services).

Impact: When a member user without "Create Services" permission opens the domain form for a compose service, the service name dropdown fails to load.

2. Database/Compose env editing uses update mutation which requires service: ["create"]

Files:

  • apps/dokploy/server/api/routers/postgres.tsupdate checks { service: ["create"] }
  • apps/dokploy/server/api/routers/mysql.ts — same
  • apps/dokploy/server/api/routers/mariadb.ts — same
  • apps/dokploy/server/api/routers/redis.ts — same
  • apps/dokploy/server/api/routers/mongo.ts — same
  • apps/dokploy/server/api/routers/compose.tsupdate checks { service: ["create"] }

The ShowEnvironment component (show-enviroment.tsx) saves environment variables by calling the generic update mutation (e.g., api.postgres.update, api.compose.update). These all check { service: ["create"] }.

However, the frontend gates the Save button using envVars.write:

const canWrite = permissions?.envVars.write ?? false;
// ...
{canWrite && <Button>Save</Button>}

This is a mismatch — the UI shows the button based on envVars.write, but the backend requires service: ["create"].

Note: The application service type has a dedicated saveEnvironment endpoint that correctly checks { envVars: ["write"] }, but database and compose services do not use it — they go through the generic update mutation.

Why This Happens (Permission Flow for Members)

  1. The memberRole in access-control.ts only has service: ["read"] (not "create")
  2. When checkPermission is called with { service: ["create"] }, role.authorize() fails
  3. It falls back to getLegacyOverrides, which maps canCreateServices to service.create
  4. So a member needs canCreateServices = true to pass any { service: ["create"] } check

Enterprise-only resources like domain and envVars have a bypass for static roles, but service is a core resource without this bypass.

Steps to Reproduce

  1. Create a member user
  2. Grant them access to a project with a compose service (via the Projects modal)
  3. Do NOT enable "Create Services" permission
  4. Log in as that member user
  5. Navigate to the compose service -> Domains tab
  6. Try to add a domain — the service name dropdown will fail to load
  7. Navigate to environment settings for any database/compose service
  8. Try to edit and save environment variables — it will fail with "Permission denied"

Current vs. Expected behavior

Expected Behavior

  • Domain service selection: A member with read access to the service should be able to load the service list in the domain form
  • Environment editing: A member should be able to edit environment variables based on the envVars.write permission, not service.create

Suggested Fix

  1. Change compose.loadServices permission from { service: ["create"] } to { service: ["read"] }
  2. For database/compose environment editing, either:
    • Add dedicated saveEnvironment endpoints (like the application router already has) that check { envVars: ["write"] }
    • Or change the update mutation permission check to use a more appropriate permission when only env field is being updated

Provide environment information

Operating System:
  OS: N/A (code-level bug, not environment-specific)
  Arch: N/A
Dokploy version: v0.28.8
VPS Provider: N/A
What applications/services are you trying to deploy?
  N/A — this is a permission system bug affecting member users.
  The issue is in the tRPC router permission checks, not specific to any deployment.

Which area(s) are affected? (Select all that apply)

Application

Are you deploying the applications where Dokploy is installed or on a remote server?

Same server where Dokploy is installed

Additional context

No response

Will you send a PR to fix it?

Maybe, need help

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions