From c5e364dbcb8a08f2323a422e3996a650fe02de6d Mon Sep 17 00:00:00 2001 From: Yash Kumar Date: Thu, 22 Oct 2026 20:30:53 +0530 Subject: [PATCH 1/3] fix(monitoring): gate host monitoring on docker access and let docker readers see disk usage --- .../components/dashboard/search-command.tsx | 21 ++++++++++++------- apps/dokploy/components/layouts/side.tsx | 6 ++++-- apps/dokploy/components/layouts/user-nav.tsx | 18 +++++++++------- apps/dokploy/pages/dashboard/monitoring.tsx | 17 ++++++++------- apps/dokploy/server/api/routers/settings.ts | 3 ++- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 2d066992a..5ff7eccab 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -60,6 +60,9 @@ export const SearchCommand = () => { enabled: !!session, }); const { data: isCloud } = api.settings.isCloud.useQuery(); + const { data: permissions } = api.user.getPermissions.useQuery(undefined, { + enabled: !!session, + }); React.useEffect(() => { const down = (e: KeyboardEvent) => { @@ -183,14 +186,16 @@ export const SearchCommand = () => { {!isCloud && ( <> - { - router.push("/dashboard/monitoring"); - setOpen(false); - }} - > - Monitoring - + {permissions?.monitoring.read && permissions?.docker.read && ( + { + router.push("/dashboard/monitoring"); + setOpen(false); + }} + > + Monitoring + + )} { router.push("/dashboard/traefik"); diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 9cbc187b6..c1037d6db 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -192,9 +192,11 @@ const MENU: Menu = { title: "Monitoring", url: "/dashboard/monitoring", icon: BarChartHorizontalBigIcon, - // Only enabled in non-cloud environments and if user has monitoring.read + // Host stats also need docker.read, which the stats socket requires isEnabled: ({ isCloud, permissions }) => - !isCloud && !!permissions?.monitoring.read, + !isCloud && + !!permissions?.monitoring.read && + !!permissions?.docker.read, }, { isSingle: true, diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index aa9747cfb..1a68544f6 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -87,14 +87,16 @@ export const UserNav = () => { {!isCloud ? ( <> - { - router.push("/dashboard/monitoring"); - }} - > - Monitoring - + {permissions?.monitoring.read && permissions?.docker.read && ( + { + router.push("/dashboard/monitoring"); + }} + > + Monitoring + + )} {permissions?.traefikFiles.read && ( { + getDockerDiskUsage: withPermission("docker", "read").query(async () => { if (IS_CLOUD) { return []; } From 8cac2d849dcc0aed4a0327de6f934b4ed755cc6e Mon Sep 17 00:00:00 2001 From: Yash Kumar Date: Thu, 22 Oct 2026 21:27:11 +0530 Subject: [PATCH 2/3] chore(monitoring): address review comments --- apps/dokploy/components/layouts/side.tsx | 2 +- apps/dokploy/pages/dashboard/monitoring.tsx | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index c1037d6db..430349867 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -192,7 +192,7 @@ const MENU: Menu = { title: "Monitoring", url: "/dashboard/monitoring", icon: BarChartHorizontalBigIcon, - // Host stats also need docker.read, which the stats socket requires + // Only enabled in non-cloud environments (product decision) and if user has monitoring.read and docker.read isEnabled: ({ isCloud, permissions }) => !isCloud && !!permissions?.monitoring.read && diff --git a/apps/dokploy/pages/dashboard/monitoring.tsx b/apps/dokploy/pages/dashboard/monitoring.tsx index ba0bf1956..17d55b080 100644 --- a/apps/dokploy/pages/dashboard/monitoring.tsx +++ b/apps/dokploy/pages/dashboard/monitoring.tsx @@ -113,9 +113,6 @@ export async function getServerSideProps( user: { id: user.id }, session: { activeOrganizationId: session?.activeOrganizationId || "" }, }; - // Host stats come from the docker stats socket, which requires docker.read. - // Checked separately because a member's "Access to Docker" is a legacy - // override that only applies when every requested resource has one. const canView = (await hasPermission(permissionCtx, { monitoring: ["read"] })) && (await hasPermission(permissionCtx, { docker: ["read"] })); From e7b640dddfc4d131caedd65c65b4c34c5695f686 Mon Sep 17 00:00:00 2001 From: Yash Kumar Date: Thu, 22 Oct 2026 22:14:03 +0530 Subject: [PATCH 3/3] refactor(monitoring): run host monitoring permission checks in parallel --- apps/dokploy/pages/dashboard/monitoring.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/pages/dashboard/monitoring.tsx b/apps/dokploy/pages/dashboard/monitoring.tsx index 17d55b080..b932b929a 100644 --- a/apps/dokploy/pages/dashboard/monitoring.tsx +++ b/apps/dokploy/pages/dashboard/monitoring.tsx @@ -113,9 +113,11 @@ export async function getServerSideProps( user: { id: user.id }, session: { activeOrganizationId: session?.activeOrganizationId || "" }, }; - const canView = - (await hasPermission(permissionCtx, { monitoring: ["read"] })) && - (await hasPermission(permissionCtx, { docker: ["read"] })); + const [canReadMonitoring, canReadDocker] = await Promise.all([ + hasPermission(permissionCtx, { monitoring: ["read"] }), + hasPermission(permissionCtx, { docker: ["read"] }), + ]); + const canView = canReadMonitoring && canReadDocker; if (!canView) { return {