From 91ebf3b6f5937c72970ab1c3627880d01b3b3af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Ors=C3=A1g?= Date: Fri, 3 Apr 2026 01:09:28 +0200 Subject: [PATCH 01/13] fix: upgrade ssh2 from 1.15.0 to ^1.16.0 (util.isDate removed in Node.js v23+) --- packages/server/package.json | 2 +- pnpm-lock.yaml | 75 +++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 7fe2eaba0..ad7d8d48d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -80,7 +80,7 @@ "semver": "7.7.3", "shell-quote": "^1.8.1", "slugify": "^1.6.6", - "ssh2": "1.15.0", + "ssh2": "^1.16.0", "toml": "3.0.0", "ws": "8.16.0", "yaml": "2.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb61d48e3..18bcc7f2b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,10 +115,10 @@ importers: version: 2.0.30(zod@4.3.6) '@better-auth/api-key': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25)) '@better-auth/sso': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50))(better-call@2.0.2(zod@4.3.6)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25))(better-call@2.0.2(zod@4.3.6)) '@codemirror/autocomplete': specifier: ^6.18.6 version: 6.20.0 @@ -277,7 +277,7 @@ importers: version: 5.1.1 better-auth: specifier: 1.5.4 - version: 1.5.4(febde88eaf587188179e6ecc47119e50) + version: 1.5.4(219be630f7f6fef2e235cef94eaddc25) bl: specifier: 6.0.11 version: 6.0.11 @@ -527,10 +527,10 @@ importers: version: 5.9.3 vite-tsconfig-paths: specifier: 4.3.2 - version: 4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1)) + version: 4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)) vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) apps/schedules: dependencies: @@ -618,10 +618,10 @@ importers: version: 2.0.30(zod@4.3.6) '@better-auth/api-key': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424)) '@better-auth/sso': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934))(better-call@2.0.2(zod@4.3.6)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424))(better-call@2.0.2(zod@4.3.6)) '@better-auth/utils': specifier: 0.3.1 version: 0.3.1 @@ -660,7 +660,7 @@ importers: version: 5.1.1 better-auth: specifier: 1.5.4 - version: 1.5.4(334901c35c1fcda64bb596793b2e4934) + version: 1.5.4(8933545d763d3f096150f97f9213a424) better-call: specifier: 2.0.2 version: 2.0.2(zod@4.3.6) @@ -746,8 +746,8 @@ importers: specifier: ^1.6.6 version: 1.6.6 ssh2: - specifier: 1.15.0 - version: 1.15.0 + specifier: ^1.16.0 + version: 1.17.0 toml: specifier: 3.0.0 version: 3.0.0 @@ -763,7 +763,7 @@ importers: devDependencies: '@better-auth/cli': specifier: 1.4.21 - version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)) + version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1)) '@types/adm-zip': specifier: ^0.5.7 version: 0.5.7 @@ -4167,6 +4167,7 @@ packages: '@xmldom/xmldom@0.8.11': resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@xterm/addon-attach@0.10.0': resolution: {integrity: sha512-ES/XO8pC1tPHSkh4j7qzM8ajFt++u8KMvfRc9vKIbjHTDOxjl9IUVo+vcQgLn3FTCM3w2czTvBss8nMWlD83Cg==} @@ -7567,6 +7568,10 @@ packages: resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} engines: {node: '>=10.16.0'} + ssh2@1.17.0: + resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==} + engines: {node: '>=10.16.0'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -8581,21 +8586,21 @@ snapshots: '@balena/dockerignore@1.0.2': {} - '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934))': + '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 - better-auth: 1.5.4(334901c35c1fcda64bb596793b2e4934) + better-auth: 1.5.4(219be630f7f6fef2e235cef94eaddc25) zod: 4.3.6 - '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50))': + '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 - better-auth: 1.5.4(febde88eaf587188179e6ecc47119e50) + better-auth: 1.5.4(8933545d763d3f096150f97f9213a424) zod: 4.3.6 - '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1))': + '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1))': dependencies: '@babel/core': 7.29.0 '@babel/preset-react': 7.28.5(@babel/core@7.29.0) @@ -8607,7 +8612,7 @@ snapshots: '@mrleebo/prisma-ast': 0.13.1 '@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) '@types/pg': 8.16.0 - better-auth: 1.4.21(b1bc00b9e18c5e6af4e13b03fc4304ac) + better-auth: 1.4.21(db78b83f9b5449d160708cdf9d272aa3) better-sqlite3: 12.6.2 c12: 3.3.3 chalk: 5.6.2 @@ -8741,24 +8746,24 @@ snapshots: '@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) - '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934))(better-call@2.0.2(zod@4.3.6))': + '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25))(better-call@2.0.2(zod@4.3.6))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 - better-auth: 1.5.4(334901c35c1fcda64bb596793b2e4934) + better-auth: 1.5.4(219be630f7f6fef2e235cef94eaddc25) better-call: 2.0.2(zod@4.3.6) fast-xml-parser: 5.5.1 jose: 6.1.3 samlify: 2.10.2 zod: 4.3.6 - '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50))(better-call@2.0.2(zod@4.3.6))': + '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424))(better-call@2.0.2(zod@4.3.6))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 - better-auth: 1.5.4(febde88eaf587188179e6ecc47119e50) + better-auth: 1.5.4(8933545d763d3f096150f97f9213a424) better-call: 2.0.2(zod@4.3.6) fast-xml-parser: 5.5.1 jose: 6.1.3 @@ -12220,6 +12225,7 @@ snapshots: magic-string: 0.30.21 optionalDependencies: vite: 7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) + optional: true '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1))': dependencies: @@ -12228,7 +12234,6 @@ snapshots: magic-string: 0.30.21 optionalDependencies: vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) - optional: true '@vitest/pretty-format@4.0.18': dependencies: @@ -12433,7 +12438,7 @@ snapshots: before-after-hook@2.2.3: {} - better-auth@1.4.21(b1bc00b9e18c5e6af4e13b03fc4304ac): + better-auth@1.4.21(db78b83f9b5449d160708cdf9d272aa3): dependencies: '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0) '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)) @@ -12459,9 +12464,9 @@ snapshots: prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) + vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) - better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934): + better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25): dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))) @@ -12496,7 +12501,7 @@ snapshots: transitivePeerDependencies: - '@cloudflare/workers-types' - better-auth@1.5.4(febde88eaf587188179e6ecc47119e50): + better-auth@1.5.4(8933545d763d3f096150f97f9213a424): dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))) @@ -13085,7 +13090,7 @@ snapshots: debug: 4.4.3 readable-stream: 3.6.2 split-ca: 1.0.1 - ssh2: 1.15.0 + ssh2: 1.17.0 transitivePeerDependencies: - supports-color @@ -15731,6 +15736,14 @@ snapshots: cpu-features: 0.0.10 nan: 2.25.0 + ssh2@1.17.0: + dependencies: + asn1: 0.2.6 + bcrypt-pbkdf: 1.0.2 + optionalDependencies: + cpu-features: 0.0.10 + nan: 2.25.0 + stackback@0.0.2: {} standard-as-callback@2.1.0: {} @@ -16248,13 +16261,13 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-tsconfig-paths@4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1)): + vite-tsconfig-paths@4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: 7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript @@ -16273,6 +16286,7 @@ snapshots: jiti: 1.21.7 tsx: 4.16.2 yaml: 2.8.1 + optional: true vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1): dependencies: @@ -16288,7 +16302,6 @@ snapshots: jiti: 2.6.1 tsx: 4.16.2 yaml: 2.8.1 - optional: true vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1): dependencies: @@ -16327,6 +16340,7 @@ snapshots: - terser - tsx - yaml + optional: true vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1): dependencies: @@ -16365,7 +16379,6 @@ snapshots: - terser - tsx - yaml - optional: true w3c-keyname@2.2.8: {} From eafbd0353e067abfb289707fb44957fcc170dd52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Ors=C3=A1g?= Date: Sat, 4 Apr 2026 17:18:03 +0200 Subject: [PATCH 02/13] fix: strictly use ssh2 1.16.0 package --- apps/dokploy/package.json | 2 +- packages/server/package.json | 2 +- pnpm-lock.yaml | 84 ++++++++++++++++-------------------- 3 files changed, 38 insertions(+), 50 deletions(-) diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 09ec864c4..67478303b 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -145,7 +145,7 @@ "shell-quote": "^1.8.1", "slugify": "^1.6.6", "sonner": "^1.7.4", - "ssh2": "1.15.0", + "ssh2": "~1.16.0", "stripe": "17.2.0", "superjson": "^2.2.2", "swagger-ui-react": "^5.31.2", diff --git a/packages/server/package.json b/packages/server/package.json index ad7d8d48d..1f519b494 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -80,7 +80,7 @@ "semver": "7.7.3", "shell-quote": "^1.8.1", "slugify": "^1.6.6", - "ssh2": "^1.16.0", + "ssh2": "~1.16.0", "toml": "3.0.0", "ws": "8.16.0", "yaml": "2.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18bcc7f2b..daece688d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,10 +115,10 @@ importers: version: 2.0.30(zod@4.3.6) '@better-auth/api-key': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50)) '@better-auth/sso': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25))(better-call@2.0.2(zod@4.3.6)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50))(better-call@2.0.2(zod@4.3.6)) '@codemirror/autocomplete': specifier: ^6.18.6 version: 6.20.0 @@ -277,7 +277,7 @@ importers: version: 5.1.1 better-auth: specifier: 1.5.4 - version: 1.5.4(219be630f7f6fef2e235cef94eaddc25) + version: 1.5.4(febde88eaf587188179e6ecc47119e50) bl: specifier: 6.0.11 version: 6.0.11 @@ -411,8 +411,8 @@ importers: specifier: ^1.7.4 version: 1.7.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0) ssh2: - specifier: 1.15.0 - version: 1.15.0 + specifier: ~1.16.0 + version: 1.16.0 stripe: specifier: 17.2.0 version: 17.2.0 @@ -527,10 +527,10 @@ importers: version: 5.9.3 vite-tsconfig-paths: specifier: 4.3.2 - version: 4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)) + version: 4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1)) vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) apps/schedules: dependencies: @@ -618,10 +618,10 @@ importers: version: 2.0.30(zod@4.3.6) '@better-auth/api-key': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934)) '@better-auth/sso': specifier: 1.5.4 - version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424))(better-call@2.0.2(zod@4.3.6)) + version: 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934))(better-call@2.0.2(zod@4.3.6)) '@better-auth/utils': specifier: 0.3.1 version: 0.3.1 @@ -660,7 +660,7 @@ importers: version: 5.1.1 better-auth: specifier: 1.5.4 - version: 1.5.4(8933545d763d3f096150f97f9213a424) + version: 1.5.4(334901c35c1fcda64bb596793b2e4934) better-call: specifier: 2.0.2 version: 2.0.2(zod@4.3.6) @@ -746,8 +746,8 @@ importers: specifier: ^1.6.6 version: 1.6.6 ssh2: - specifier: ^1.16.0 - version: 1.17.0 + specifier: ~1.16.0 + version: 1.16.0 toml: specifier: 3.0.0 version: 3.0.0 @@ -763,7 +763,7 @@ importers: devDependencies: '@better-auth/cli': specifier: 1.4.21 - version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1)) + version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)) '@types/adm-zip': specifier: ^0.5.7 version: 0.5.7 @@ -7564,12 +7564,8 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} - ssh2@1.15.0: - resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==} - engines: {node: '>=10.16.0'} - - ssh2@1.17.0: - resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==} + ssh2@1.16.0: + resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} engines: {node: '>=10.16.0'} stackback@0.0.2: @@ -8586,21 +8582,21 @@ snapshots: '@balena/dockerignore@1.0.2': {} - '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25))': + '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 - better-auth: 1.5.4(219be630f7f6fef2e235cef94eaddc25) + better-auth: 1.5.4(334901c35c1fcda64bb596793b2e4934) zod: 4.3.6 - '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424))': + '@better-auth/api-key@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 - better-auth: 1.5.4(8933545d763d3f096150f97f9213a424) + better-auth: 1.5.4(febde88eaf587188179e6ecc47119e50) zod: 4.3.6 - '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1))': + '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(better-call@2.0.2(zod@4.3.6))(drizzle-kit@0.31.9)(jose@6.1.3)(kysely@0.28.11)(mongodb@7.1.0)(mysql2@3.15.3)(nanostores@1.1.1)(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1))': dependencies: '@babel/core': 7.29.0 '@babel/preset-react': 7.28.5(@babel/core@7.29.0) @@ -8612,7 +8608,7 @@ snapshots: '@mrleebo/prisma-ast': 0.13.1 '@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) '@types/pg': 8.16.0 - better-auth: 1.4.21(db78b83f9b5449d160708cdf9d272aa3) + better-auth: 1.4.21(b1bc00b9e18c5e6af4e13b03fc4304ac) better-sqlite3: 12.6.2 c12: 3.3.3 chalk: 5.6.2 @@ -8746,24 +8742,24 @@ snapshots: '@prisma/client': 5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)) prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) - '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25))(better-call@2.0.2(zod@4.3.6))': + '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934))(better-call@2.0.2(zod@4.3.6))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 - better-auth: 1.5.4(219be630f7f6fef2e235cef94eaddc25) + better-auth: 1.5.4(334901c35c1fcda64bb596793b2e4934) better-call: 2.0.2(zod@4.3.6) fast-xml-parser: 5.5.1 jose: 6.1.3 samlify: 2.10.2 zod: 4.3.6 - '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(8933545d763d3f096150f97f9213a424))(better-call@2.0.2(zod@4.3.6))': + '@better-auth/sso@1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(better-auth@1.5.4(febde88eaf587188179e6ecc47119e50))(better-call@2.0.2(zod@4.3.6))': dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 - better-auth: 1.5.4(8933545d763d3f096150f97f9213a424) + better-auth: 1.5.4(febde88eaf587188179e6ecc47119e50) better-call: 2.0.2(zod@4.3.6) fast-xml-parser: 5.5.1 jose: 6.1.3 @@ -12225,7 +12221,6 @@ snapshots: magic-string: 0.30.21 optionalDependencies: vite: 7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) - optional: true '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1))': dependencies: @@ -12234,6 +12229,7 @@ snapshots: magic-string: 0.30.21 optionalDependencies: vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) + optional: true '@vitest/pretty-format@4.0.18': dependencies: @@ -12438,7 +12434,7 @@ snapshots: before-after-hook@2.2.3: {} - better-auth@1.4.21(db78b83f9b5449d160708cdf9d272aa3): + better-auth@1.4.21(b1bc00b9e18c5e6af4e13b03fc4304ac): dependencies: '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0) '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1)) @@ -12464,9 +12460,9 @@ snapshots: prisma: 7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) + vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) - better-auth@1.5.4(219be630f7f6fef2e235cef94eaddc25): + better-auth@1.5.4(334901c35c1fcda64bb596793b2e4934): dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))) @@ -12501,7 +12497,7 @@ snapshots: transitivePeerDependencies: - '@cloudflare/workers-types' - better-auth@1.5.4(8933545d763d3f096150f97f9213a424): + better-auth@1.5.4(febde88eaf587188179e6ecc47119e50): dependencies: '@better-auth/core': 1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1) '@better-auth/drizzle-adapter': 1.5.4(@better-auth/core@1.5.4(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@2.0.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@5.22.0(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3)))(@types/pg@8.16.0)(better-sqlite3@12.6.2)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.18.0)(postgres@3.4.4)(prisma@7.4.1(@types/react@18.3.5)(better-sqlite3@12.6.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3))) @@ -13090,7 +13086,7 @@ snapshots: debug: 4.4.3 readable-stream: 3.6.2 split-ca: 1.0.1 - ssh2: 1.17.0 + ssh2: 1.16.0 transitivePeerDependencies: - supports-color @@ -15728,15 +15724,7 @@ snapshots: sqlstring@2.3.3: {} - ssh2@1.15.0: - dependencies: - asn1: 0.2.6 - bcrypt-pbkdf: 1.0.2 - optionalDependencies: - cpu-features: 0.0.10 - nan: 2.25.0 - - ssh2@1.17.0: + ssh2@1.16.0: dependencies: asn1: 0.2.6 bcrypt-pbkdf: 1.0.2 @@ -16261,13 +16249,13 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-tsconfig-paths@4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1)): + vite-tsconfig-paths@4.3.2(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1) + vite: 7.3.1(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript @@ -16286,7 +16274,6 @@ snapshots: jiti: 1.21.7 tsx: 4.16.2 yaml: 2.8.1 - optional: true vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1): dependencies: @@ -16302,6 +16289,7 @@ snapshots: jiti: 2.6.1 tsx: 4.16.2 yaml: 2.8.1 + optional: true vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@1.21.7)(tsx@4.16.2)(yaml@2.8.1): dependencies: @@ -16340,7 +16328,6 @@ snapshots: - terser - tsx - yaml - optional: true vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.10.13)(jiti@2.6.1)(tsx@4.16.2)(yaml@2.8.1): dependencies: @@ -16379,6 +16366,7 @@ snapshots: - terser - tsx - yaml + optional: true w3c-keyname@2.2.8: {} From 598fae0e92e5bd9941f78170d26ac6b6a088e9cc Mon Sep 17 00:00:00 2001 From: manalkaff Date: Sun, 19 Apr 2026 17:30:42 +0800 Subject: [PATCH 03/13] fix: filter requests by hostname instead of path The search filter on the Requests tab was incorrectly filtering by RequestPath instead of RequestHost, causing "filter by name" to match URL paths rather than hostnames. Updated the placeholder text to reflect the correct field being searched. Fixes #4249 --- apps/dokploy/components/dashboard/requests/requests-table.tsx | 2 +- packages/server/src/utils/access-log/utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/requests/requests-table.tsx b/apps/dokploy/components/dashboard/requests/requests-table.tsx index e804b065b..6f7406e19 100644 --- a/apps/dokploy/components/dashboard/requests/requests-table.tsx +++ b/apps/dokploy/components/dashboard/requests/requests-table.tsx @@ -185,7 +185,7 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => {
setSearch(event.target.value)} className="md:max-w-sm" diff --git a/packages/server/src/utils/access-log/utils.ts b/packages/server/src/utils/access-log/utils.ts index b89dc2ed2..9b472ee27 100644 --- a/packages/server/src/utils/access-log/utils.ts +++ b/packages/server/src/utils/access-log/utils.ts @@ -120,7 +120,7 @@ export function parseRawConfig( if (search) { parsedLogs = parsedLogs.filter((log) => - log.RequestPath.toLowerCase().includes(search.toLowerCase()), + log.RequestHost.toLowerCase().includes(search.toLowerCase()), ); } From c3fa638a566e77dc4d71d9b49de84a1942e1f824 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Tue, 21 Apr 2026 21:36:44 -0600 Subject: [PATCH 04/13] feat: enhance schedule management with permission checks and cloud restrictions - Added comprehensive permission checks for creating, updating, and deleting schedules based on user roles (owner/admin) and schedule types (server/dokploy-server). - Implemented restrictions for cloud users to prevent managing host-level schedules and changing schedule types. - Improved access control for server-level schedules to ensure users can only manage schedules associated with their organization. --- apps/dokploy/server/api/routers/schedule.ts | 261 +++++++++++++++++++- 1 file changed, 260 insertions(+), 1 deletion(-) diff --git a/apps/dokploy/server/api/routers/schedule.ts b/apps/dokploy/server/api/routers/schedule.ts index 144f7c74a..7da745b8e 100644 --- a/apps/dokploy/server/api/routers/schedule.ts +++ b/apps/dokploy/server/api/routers/schedule.ts @@ -7,19 +7,25 @@ import { updateScheduleSchema, } from "@dokploy/server/db/schema/schedule"; import { runCommand } from "@dokploy/server/index"; -import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission"; +import { + checkPermission, + checkServicePermissionAndAccess, + findMemberByUserId, +} from "@dokploy/server/services/permission"; import { createSchedule, deleteSchedule, findScheduleById, updateSchedule, } from "@dokploy/server/services/schedule"; +import { findServerById } from "@dokploy/server/services/server"; import { TRPCError } from "@trpc/server"; import { asc, desc, eq } from "drizzle-orm"; import { z } from "zod"; import { audit } from "@/server/api/utils/audit"; import { removeJob, schedule } from "@/server/utils/backup"; import { createTRPCRouter, protectedProcedure } from "../trpc"; + export const scheduleRouter = createTRPCRouter({ create: protectedProcedure .input(createScheduleSchema) @@ -29,6 +35,45 @@ export const scheduleRouter = createTRPCRouter({ await checkServicePermissionAndAccess(ctx, serviceId, { schedule: ["create"], }); + } else { + if (input.scheduleType === "dokploy-server" && IS_CLOUD) { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Host-level schedules are not available in the cloud version.", + }); + } + + await checkPermission(ctx, { schedule: ["create"] }); + + if ( + input.scheduleType === "server" || + input.scheduleType === "dokploy-server" + ) { + const member = await findMemberByUserId( + ctx.user.id, + ctx.session.activeOrganizationId, + ); + if (member.role !== "owner" && member.role !== "admin") { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Only owners and admins can manage server-level schedules.", + }); + } + } + + if (input.scheduleType === "server" && input.serverId) { + const targetServer = await findServerById(input.serverId); + if ( + targetServer.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } } const newSchedule = await createSchedule(input); @@ -57,12 +102,77 @@ export const scheduleRouter = createTRPCRouter({ .input(updateScheduleSchema) .mutation(async ({ input, ctx }) => { const existingSchedule = await findScheduleById(input.scheduleId); + + if ( + IS_CLOUD && + input.scheduleType && + input.scheduleType !== existingSchedule.scheduleType + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "Changing scheduleType is not allowed in the cloud version.", + }); + } + const serviceId = existingSchedule.applicationId || existingSchedule.composeId; if (serviceId) { await checkServicePermissionAndAccess(ctx, serviceId, { schedule: ["update"], }); + } else { + if (existingSchedule.scheduleType === "dokploy-server" && IS_CLOUD) { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Host-level schedules are not available in the cloud version.", + }); + } + + await checkPermission(ctx, { schedule: ["update"] }); + + if ( + existingSchedule.scheduleType === "server" || + existingSchedule.scheduleType === "dokploy-server" + ) { + const member = await findMemberByUserId( + ctx.user.id, + ctx.session.activeOrganizationId, + ); + if (member.role !== "owner" && member.role !== "admin") { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Only owners and admins can manage server-level schedules.", + }); + } + } + + if ( + existingSchedule.scheduleType === "server" && + existingSchedule.serverId + ) { + const targetServer = await findServerById(existingSchedule.serverId); + if ( + targetServer.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } + + if ( + existingSchedule.scheduleType === "dokploy-server" && + existingSchedule.userId && + existingSchedule.userId !== ctx.user.id + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You can only manage your own host-level schedules.", + }); + } } const updatedSchedule = await updateSchedule(input); @@ -107,6 +217,56 @@ export const scheduleRouter = createTRPCRouter({ await checkServicePermissionAndAccess(ctx, serviceId, { schedule: ["delete"], }); + } else { + if (scheduleItem.scheduleType === "dokploy-server" && IS_CLOUD) { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Host-level schedules are not available in the cloud version.", + }); + } + + await checkPermission(ctx, { schedule: ["delete"] }); + + if ( + scheduleItem.scheduleType === "server" || + scheduleItem.scheduleType === "dokploy-server" + ) { + const member = await findMemberByUserId( + ctx.user.id, + ctx.session.activeOrganizationId, + ); + if (member.role !== "owner" && member.role !== "admin") { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Only owners and admins can manage server-level schedules.", + }); + } + } + + if (scheduleItem.scheduleType === "server" && scheduleItem.serverId) { + const targetServer = await findServerById(scheduleItem.serverId); + if ( + targetServer.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } + + if ( + scheduleItem.scheduleType === "dokploy-server" && + scheduleItem.userId && + scheduleItem.userId !== ctx.user.id + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You can only manage your own host-level schedules.", + }); + } } await deleteSchedule(input.scheduleId); @@ -148,6 +308,30 @@ export const scheduleRouter = createTRPCRouter({ await checkServicePermissionAndAccess(ctx, input.id, { schedule: ["read"], }); + } else { + await checkPermission(ctx, { schedule: ["read"] }); + + if (input.scheduleType === "server") { + const targetServer = await findServerById(input.id); + if ( + targetServer.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } + + if ( + input.scheduleType === "dokploy-server" && + input.id !== ctx.user.id + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You can only list your own host-level schedules.", + }); + } } const where = { application: eq(schedules.applicationId, input.id), @@ -178,6 +362,31 @@ export const scheduleRouter = createTRPCRouter({ await checkServicePermissionAndAccess(ctx, serviceId, { schedule: ["read"], }); + } else { + await checkPermission(ctx, { schedule: ["read"] }); + + if (schedule.scheduleType === "server" && schedule.serverId) { + const targetServer = await findServerById(schedule.serverId); + if ( + targetServer.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this schedule.", + }); + } + } + + if ( + schedule.scheduleType === "dokploy-server" && + schedule.userId && + schedule.userId !== ctx.user.id + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this schedule.", + }); + } } return schedule; }), @@ -191,6 +400,56 @@ export const scheduleRouter = createTRPCRouter({ await checkServicePermissionAndAccess(ctx, serviceId, { schedule: ["create"], }); + } else { + if (scheduleItem.scheduleType === "dokploy-server" && IS_CLOUD) { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Host-level schedules are not available in the cloud version.", + }); + } + + await checkPermission(ctx, { schedule: ["create"] }); + + if ( + scheduleItem.scheduleType === "server" || + scheduleItem.scheduleType === "dokploy-server" + ) { + const member = await findMemberByUserId( + ctx.user.id, + ctx.session.activeOrganizationId, + ); + if (member.role !== "owner" && member.role !== "admin") { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Only owners and admins can manage server-level schedules.", + }); + } + } + + if (scheduleItem.scheduleType === "server" && scheduleItem.serverId) { + const targetServer = await findServerById(scheduleItem.serverId); + if ( + targetServer.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } + + if ( + scheduleItem.scheduleType === "dokploy-server" && + scheduleItem.userId && + scheduleItem.userId !== ctx.user.id + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You can only manage your own host-level schedules.", + }); + } } try { await runCommand(input.scheduleId); From f8c6c8f7ccee57ac16b5d13cba398a967b92706d Mon Sep 17 00:00:00 2001 From: sajdakabir Date: Wed, 22 Apr 2026 13:06:22 +0530 Subject: [PATCH 05/13] fix: stop leaking Drizzle SQL queries in webhook error responses (#4276) --- apps/dokploy/pages/api/deploy/[refreshToken].ts | 16 +++++++++++++--- .../pages/api/deploy/compose/[refreshToken].ts | 8 +++++--- apps/dokploy/pages/api/deploy/github.ts | 15 +++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/apps/dokploy/pages/api/deploy/[refreshToken].ts b/apps/dokploy/pages/api/deploy/[refreshToken].ts index 1a99c3a8e..bb6eb06d3 100644 --- a/apps/dokploy/pages/api/deploy/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/[refreshToken].ts @@ -12,6 +12,15 @@ import type { DeploymentJob } from "@/server/queues/queue-types"; import { myQueue } from "@/server/queues/queueSetup"; import { deploy } from "@/server/utils/deploy"; +/** + * Log a webhook handler error server-side without leaking its shape to the HTTP + * response. Drizzle errors carry the raw SQL query, column list and parameters, + * so we never forward the error object to the client. + */ +export const logWebhookError = (context: string, error: unknown) => { + console.error(context, error); +}; + /** * Helper function to get package_version from registry_package events */ @@ -262,14 +271,15 @@ export default async function handler( ); } } catch (error) { - res.status(400).json({ message: "Error deploying Application", error }); + logWebhookError("Error deploying Application:", error); + res.status(400).json({ message: "Error deploying Application" }); return; } res.status(200).json({ message: "Application deployed successfully" }); } catch (error) { - console.log(error); - res.status(400).json({ message: "Error deploying Application", error }); + logWebhookError("Error deploying Application:", error); + res.status(400).json({ message: "Error deploying Application" }); } } diff --git a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts index 640a2531d..85a379eb3 100644 --- a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts @@ -12,6 +12,7 @@ import { extractCommittedPaths, extractHash, getProviderByHeader, + logWebhookError, } from "../[refreshToken]"; export default async function handler( @@ -195,13 +196,14 @@ export default async function handler( ); } } catch (error) { - res.status(400).json({ message: "Error deploying Compose", error }); + logWebhookError("Error deploying Compose:", error); + res.status(400).json({ message: "Error deploying Compose" }); return; } res.status(200).json({ message: "Compose deployed successfully" }); } catch (error) { - console.log(error); - res.status(400).json({ message: "Error deploying Compose", error }); + logWebhookError("Error deploying Compose:", error); + res.status(400).json({ message: "Error deploying Compose" }); } } diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 4438366f6..293207198 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -17,7 +17,11 @@ import { applications, compose, github } from "@/server/db/schema"; import type { DeploymentJob } from "@/server/queues/queue-types"; import { myQueue } from "@/server/queues/queueSetup"; import { deploy } from "@/server/utils/deploy"; -import { extractCommitMessage, extractHash } from "./[refreshToken]"; +import { + extractCommitMessage, + extractHash, + logWebhookError, +} from "./[refreshToken]"; export default async function handler( req: NextApiRequest, @@ -197,10 +201,8 @@ export default async function handler( }); return; } catch (error) { - console.error("Error deploying applications on tag:", error); - res - .status(400) - .json({ message: "Error deploying applications on tag", error }); + logWebhookError("Error deploying applications on tag:", error); + res.status(400).json({ message: "Error deploying applications on tag" }); return; } } @@ -322,7 +324,8 @@ export default async function handler( } res.status(200).json({ message: `Deployed ${totalApps} apps` }); } catch (error) { - res.status(400).json({ message: "Error deploying Application", error }); + logWebhookError("Error deploying Application:", error); + res.status(400).json({ message: "Error deploying Application" }); } } else if (req.headers["x-github-event"] === "pull_request") { const prId = githubBody?.pull_request?.id; From 018e2b153e564cf9af163d47ce4a1ee409dfb848 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 24 Apr 2026 12:44:42 -0600 Subject: [PATCH 06/13] fix: add cross-org ownership checks to cluster, deployment, backup, and WebSocket endpoints Prevents owner/admin users of one organization from accessing servers, destinations, and Docker Swarm join tokens belonging to other organizations by validating organizationId on all endpoints that accept serverId or destinationId as direct input. - cluster: validate serverId org on getNodes, addWorker, addManager, removeWorker - deployment: validate serverId org on allByServer - backup: validate destinationId + serverId org on listBackupFiles - volume-backups: validate destinationId + serverId org on restoreVolumeBackupWithLogs - wss: validate server org on docker-container-logs, docker-container-terminal, listen-deployment, and terminal WebSocket handlers - auth: fix TypeScript type for API key metadata parsing --- apps/dokploy/server/api/routers/backup.ts | 19 +++++++++- apps/dokploy/server/api/routers/cluster.ts | 36 +++++++++++++++++-- apps/dokploy/server/api/routers/deployment.ts | 10 +++++- .../server/api/routers/volume-backups.ts | 20 ++++++++++- .../server/wss/docker-container-logs.ts | 5 +++ .../server/wss/docker-container-terminal.ts | 6 ++++ apps/dokploy/server/wss/listen-deployment.ts | 5 +++ apps/dokploy/server/wss/terminal.ts | 5 +++ packages/server/src/lib/auth.ts | 6 ++-- 9 files changed, 104 insertions(+), 8 deletions(-) diff --git a/apps/dokploy/server/api/routers/backup.ts b/apps/dokploy/server/api/routers/backup.ts index c3633b135..75bb60f2c 100644 --- a/apps/dokploy/server/api/routers/backup.ts +++ b/apps/dokploy/server/api/routers/backup.ts @@ -458,9 +458,26 @@ export const backupRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { try { const destination = await findDestinationById(input.destinationId); + if (destination.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this destination.", + }); + } + if (input.serverId) { + const targetServer = await findServerById(input.serverId); + if ( + targetServer.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } const rcloneFlags = getS3Credentials(destination); const bucketPath = `:s3:${destination.bucket}`; diff --git a/apps/dokploy/server/api/routers/cluster.ts b/apps/dokploy/server/api/routers/cluster.ts index afd8a0e92..dad67a3d0 100644 --- a/apps/dokploy/server/api/routers/cluster.ts +++ b/apps/dokploy/server/api/routers/cluster.ts @@ -11,6 +11,20 @@ import { audit } from "@/server/api/utils/audit"; import { getLocalServerIp } from "@/server/wss/terminal"; import { createTRPCRouter, withPermission } from "../trpc"; +const assertServerBelongsToOrg = async ( + serverId: string | undefined, + activeOrganizationId: string, +) => { + if (!serverId) return; + const targetServer = await findServerById(serverId); + if (targetServer.organizationId !== activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } +}; + export const clusterRouter = createTRPCRouter({ getNodes: withPermission("server", "read") .input( @@ -18,7 +32,11 @@ export const clusterRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + await assertServerBelongsToOrg( + input.serverId, + ctx.session.activeOrganizationId, + ); const docker = await getRemoteDocker(input.serverId); const workers: DockerNode[] = await docker.listNodes(); return workers; @@ -32,6 +50,10 @@ export const clusterRouter = createTRPCRouter({ }), ) .mutation(async ({ input, ctx }) => { + await assertServerBelongsToOrg( + input.serverId, + ctx.session.activeOrganizationId, + ); try { const drainCommand = `docker node update --availability drain ${input.nodeId}`; const removeCommand = `docker node rm ${input.nodeId} --force`; @@ -65,7 +87,11 @@ export const clusterRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + await assertServerBelongsToOrg( + input.serverId, + ctx.session.activeOrganizationId, + ); const docker = await getRemoteDocker(input.serverId); const result = await docker.swarmInspect(); const docker_version = await docker.version(); @@ -88,7 +114,11 @@ export const clusterRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + await assertServerBelongsToOrg( + input.serverId, + ctx.session.activeOrganizationId, + ); const docker = await getRemoteDocker(input.serverId); const result = await docker.swarmInspect(); const docker_version = await docker.version(); diff --git a/apps/dokploy/server/api/routers/deployment.ts b/apps/dokploy/server/api/routers/deployment.ts index 03cd3c935..6f3b1d1ae 100644 --- a/apps/dokploy/server/api/routers/deployment.ts +++ b/apps/dokploy/server/api/routers/deployment.ts @@ -16,6 +16,7 @@ import { checkServicePermissionAndAccess, findMemberByUserId, } from "@dokploy/server/services/permission"; +import { findServerById } from "@dokploy/server/services/server"; import { TRPCError } from "@trpc/server"; import { desc, eq } from "drizzle-orm"; import { z } from "zod"; @@ -52,7 +53,14 @@ export const deploymentRouter = createTRPCRouter({ }), allByServer: withPermission("deployment", "read") .input(apiFindAllByServer) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + const targetServer = await findServerById(input.serverId); + if (targetServer.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } return await findAllDeploymentsByServerId(input.serverId); }), allCentralized: withPermission("deployment", "read").query( diff --git a/apps/dokploy/server/api/routers/volume-backups.ts b/apps/dokploy/server/api/routers/volume-backups.ts index 5b50219d2..1f589d1e3 100644 --- a/apps/dokploy/server/api/routers/volume-backups.ts +++ b/apps/dokploy/server/api/routers/volume-backups.ts @@ -15,7 +15,9 @@ import { updateVolumeBackupSchema, volumeBackups, } from "@dokploy/server/db/schema"; +import { findDestinationById } from "@dokploy/server/services/destination"; import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission"; +import { findServerById } from "@dokploy/server/services/server"; import { execAsyncRemote, execAsyncStream, @@ -265,7 +267,23 @@ export const volumeBackupsRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .subscription(async ({ input }) => { + .subscription(async ({ input, ctx }) => { + const destination = await findDestinationById(input.destinationId); + if (destination.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this destination.", + }); + } + if (input.serverId) { + const targetServer = await findServerById(input.serverId); + if (targetServer.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } return observable((emit) => { const runRestore = async () => { try { diff --git a/apps/dokploy/server/wss/docker-container-logs.ts b/apps/dokploy/server/wss/docker-container-logs.ts index 159bedaae..ed4541558 100644 --- a/apps/dokploy/server/wss/docker-container-logs.ts +++ b/apps/dokploy/server/wss/docker-container-logs.ts @@ -85,6 +85,11 @@ export const setupDockerContainerLogsWebSocketServer = ( if (serverId) { const server = await findServerById(serverId); + if (server.organizationId !== session.activeOrganizationId) { + ws.close(); + return; + } + if (!server.sshKeyId) return; const client = new Client(); client diff --git a/apps/dokploy/server/wss/docker-container-terminal.ts b/apps/dokploy/server/wss/docker-container-terminal.ts index a2c242d95..e752c0651 100644 --- a/apps/dokploy/server/wss/docker-container-terminal.ts +++ b/apps/dokploy/server/wss/docker-container-terminal.ts @@ -61,6 +61,12 @@ export const setupDockerContainerTerminalWebSocketServer = ( try { if (serverId) { const server = await findServerById(serverId); + + if (server.organizationId !== session.activeOrganizationId) { + ws.close(); + return; + } + if (!server.sshKeyId) throw new Error("No SSH key available for this server"); diff --git a/apps/dokploy/server/wss/listen-deployment.ts b/apps/dokploy/server/wss/listen-deployment.ts index c39fa70b7..cd9eefed6 100644 --- a/apps/dokploy/server/wss/listen-deployment.ts +++ b/apps/dokploy/server/wss/listen-deployment.ts @@ -57,6 +57,11 @@ export const setupDeploymentLogsWebSocketServer = ( if (serverId) { const server = await findServerById(serverId); + if (server.organizationId !== session.activeOrganizationId) { + ws.close(); + return; + } + if (!server.sshKeyId) { ws.close(); return; diff --git a/apps/dokploy/server/wss/terminal.ts b/apps/dokploy/server/wss/terminal.ts index 00b0e2c2c..4825f7301 100644 --- a/apps/dokploy/server/wss/terminal.ts +++ b/apps/dokploy/server/wss/terminal.ts @@ -154,6 +154,11 @@ export const setupTerminalWebSocketServer = ( return; } + if (server.organizationId !== session.activeOrganizationId) { + ws.close(); + return; + } + const { ipAddress: host, port, username, sshKey, sshKeyId } = server; if (!sshKeyId) { diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 65dd1b01d..afbc57881 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -481,8 +481,10 @@ export const validateRequest = async (request: IncomingMessage) => { }; } - const organizationId = JSON.parse( - apiKeyRecord.metadata || "{}", + const organizationId = ( + JSON.parse(apiKeyRecord.metadata || "{}") as { + organizationId?: string; + } ).organizationId; if (!organizationId) { From 232ccc913967e28d58635a989a80cd77733d9f96 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 24 Apr 2026 12:47:51 -0600 Subject: [PATCH 07/13] feat: add organization-level authorization checks to WebSocket servers - Implemented checks in the WebSocket server setups for Docker container logs, terminal, and deployment logs to ensure users can only access resources associated with their active organization. - Enhanced security by closing WebSocket connections if the organization ID does not match the session's active organization ID. --- apps/dokploy/server/api/routers/cluster.ts | 66 ++++++++++++---------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/apps/dokploy/server/api/routers/cluster.ts b/apps/dokploy/server/api/routers/cluster.ts index dad67a3d0..3dc07935e 100644 --- a/apps/dokploy/server/api/routers/cluster.ts +++ b/apps/dokploy/server/api/routers/cluster.ts @@ -11,20 +11,6 @@ import { audit } from "@/server/api/utils/audit"; import { getLocalServerIp } from "@/server/wss/terminal"; import { createTRPCRouter, withPermission } from "../trpc"; -const assertServerBelongsToOrg = async ( - serverId: string | undefined, - activeOrganizationId: string, -) => { - if (!serverId) return; - const targetServer = await findServerById(serverId); - if (targetServer.organizationId !== activeOrganizationId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You don't have access to this server.", - }); - } -}; - export const clusterRouter = createTRPCRouter({ getNodes: withPermission("server", "read") .input( @@ -33,10 +19,15 @@ export const clusterRouter = createTRPCRouter({ }), ) .query(async ({ input, ctx }) => { - await assertServerBelongsToOrg( - input.serverId, - ctx.session.activeOrganizationId, - ); + if (input.serverId) { + const targetServer = await findServerById(input.serverId); + if (targetServer.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } const docker = await getRemoteDocker(input.serverId); const workers: DockerNode[] = await docker.listNodes(); return workers; @@ -50,10 +41,15 @@ export const clusterRouter = createTRPCRouter({ }), ) .mutation(async ({ input, ctx }) => { - await assertServerBelongsToOrg( - input.serverId, - ctx.session.activeOrganizationId, - ); + if (input.serverId) { + const targetServer = await findServerById(input.serverId); + if (targetServer.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } try { const drainCommand = `docker node update --availability drain ${input.nodeId}`; const removeCommand = `docker node rm ${input.nodeId} --force`; @@ -88,10 +84,15 @@ export const clusterRouter = createTRPCRouter({ }), ) .query(async ({ input, ctx }) => { - await assertServerBelongsToOrg( - input.serverId, - ctx.session.activeOrganizationId, - ); + if (input.serverId) { + const targetServer = await findServerById(input.serverId); + if (targetServer.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } const docker = await getRemoteDocker(input.serverId); const result = await docker.swarmInspect(); const docker_version = await docker.version(); @@ -115,10 +116,15 @@ export const clusterRouter = createTRPCRouter({ }), ) .query(async ({ input, ctx }) => { - await assertServerBelongsToOrg( - input.serverId, - ctx.session.activeOrganizationId, - ); + if (input.serverId) { + const targetServer = await findServerById(input.serverId); + if (targetServer.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You don't have access to this server.", + }); + } + } const docker = await getRemoteDocker(input.serverId); const result = await docker.swarmInspect(); const docker_version = await docker.version(); From 05f22edfe55ed675295ed71a0d0e4117cb49ecd6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 24 Apr 2026 12:53:03 -0600 Subject: [PATCH 08/13] chore: bump version to v0.29.2 in package.json --- apps/dokploy/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index c7622a3dc..d4064a188 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -1,6 +1,6 @@ { "name": "dokploy", - "version": "v0.29.1", + "version": "v0.29.2", "private": true, "license": "Apache-2.0", "type": "module", From b610f7aeffccbb6f841bcb73ec50a4b68733d152 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 24 Apr 2026 21:40:08 -0600 Subject: [PATCH 09/13] feat: implement invitation email functionality for organization creation - Added `sendInvitationEmail` function to send invitation emails when a new organization is created in the cloud environment. - Updated email template to enhance the invitation message and included a direct link for users to accept the invitation. - Refactored email sending logic in the user router to utilize the new invitation email rendering function. - Improved organization invitation email design for better user experience. --- .../server/api/routers/organization.ts | 20 +++- apps/dokploy/server/api/routers/user.ts | 32 +++--- .../server/src/emails/emails/invitation.tsx | 106 ++++++++++-------- packages/server/src/index.ts | 1 + packages/server/src/lib/auth.ts | 17 --- .../verification/send-verification-email.tsx | 36 ++++++ 6 files changed, 132 insertions(+), 80 deletions(-) diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index 2f9da6d71..51c1fec5d 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -1,5 +1,5 @@ import { db } from "@dokploy/server/db"; -import { IS_CLOUD } from "@dokploy/server/index"; +import { IS_CLOUD, sendInvitationEmail } from "@dokploy/server/index"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, exists } from "drizzle-orm"; import { nanoid } from "nanoid"; @@ -325,6 +325,24 @@ export const organizationRouter = createTRPCRouter({ }) .returning(); + if (IS_CLOUD && created) { + const host = + process.env.NODE_ENV === "development" + ? "http://localhost:3000" + : "https://app.dokploy.com"; + const inviteLink = `${host}/invitation?token=${created.id}`; + + const org = await db.query.organization.findFirst({ + where: eq(organization.id, orgId), + }); + + await sendInvitationEmail({ + email, + inviteLink, + organizationName: org?.name || "organization", + }); + } + await audit(ctx, { action: "create", resourceType: "organization", diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 63578b099..93b7e6cf6 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -9,12 +9,12 @@ import { getWebServerSettings, IS_CLOUD, removeUserById, + renderInvitationEmail, sendEmailNotification, sendResendNotification, updateUser, } from "@dokploy/server"; import { db } from "@dokploy/server/db"; -import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key"; import { account, apiAssignPermissions, @@ -29,6 +29,7 @@ import { hasPermission, resolvePermissions, } from "@dokploy/server/services/permission"; +import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; import { and, asc, eq, gt } from "drizzle-orm"; @@ -639,27 +640,26 @@ export const userRouter = createTRPCRouter({ ); try { - const htmlContent = ` -\t\t\t\t

You are invited to join ${organization?.name || "organization"} on Dokploy. Click the link to accept the invitation: Accept Invitation

-\t\t\t\t`; + const toEmail = currentInvitation?.email || ""; + const orgName = organization?.name || "organization"; + const subject = `You've been invited to join ${orgName} on Dokploy`; + const html = await renderInvitationEmail({ + email: toEmail, + inviteLink, + organizationName: orgName, + }); if (email) { await sendEmailNotification( - { - ...email, - toAddresses: [currentInvitation?.email || ""], - }, - "Invitation to join organization", - htmlContent, + { ...email, toAddresses: [toEmail] }, + subject, + html, ); } else if (resend) { await sendResendNotification( - { - ...resend, - toAddresses: [currentInvitation?.email || ""], - }, - "Invitation to join organization", - htmlContent, + { ...resend, toAddresses: [toEmail] }, + subject, + html, ); } } catch (error) { diff --git a/packages/server/src/emails/emails/invitation.tsx b/packages/server/src/emails/emails/invitation.tsx index 833b77286..dd075aecf 100644 --- a/packages/server/src/emails/emails/invitation.tsx +++ b/packages/server/src/emails/emails/invitation.tsx @@ -14,21 +14,18 @@ import { Text, } from "@react-email/components"; -export type TemplateProps = { - email: string; - name: string; -}; - -interface VercelInviteUserEmailProps { +interface InvitationEmailProps { inviteLink: string; toEmail: string; + organizationName: string; } export const InvitationEmail = ({ inviteLink, toEmail, -}: VercelInviteUserEmailProps) => { - const previewText = "Join to Dokploy"; + organizationName = "an organization", +}: InvitationEmailProps) => { + const previewText = `You've been invited to join ${organizationName} on Dokploy`; return ( @@ -44,50 +41,67 @@ export const InvitationEmail = ({ }, }} > - - -
+ + + {/* Header */} +
Dokploy
- - Join to Dokploy - - - Hello, - - - You have been invited to join Dokploy, a platform - that helps for deploying your apps to the cloud. - -
- + + {/* Body */} +
+ + You've been invited to join {organizationName} + + + You have been invited to join{" "} + {organizationName}{" "} + on Dokploy, the platform for deploying your apps to the cloud. + Click the button below to accept the invitation. + + + {/* CTA Button */} +
+ +
+ + + If the button above doesn't work, copy and paste the following + link into your browser: + + + {inviteLink} + +
+ + {/* Footer */} +
+
+ + This invitation was intended for{" "} + {toEmail}. This invite + was sent from{" "} + + Dokploy Cloud + + . If you were not expecting this invitation, you can safely + ignore this email. +
- - or copy and paste this URL into your browser:{" "} - - https://dokploy.com - - -
- - This invitation was intended for {toEmail}. This invite was sent - from dokploy.com. If you - were not expecting this invitation, you can ignore this email. If - you are concerned about your account's safety, please reply to - diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index e6fd0ba59..717c20246 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -108,6 +108,7 @@ export * from "./utils/notifications/docker-cleanup"; export * from "./utils/notifications/dokploy-restart"; export * from "./utils/notifications/server-threshold"; export * from "./utils/notifications/utils"; +export * from "./verification/send-verification-email"; export * from "./utils/process/execAsync"; export * from "./utils/process/spawnAsync"; export * from "./utils/providers/bitbucket"; diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index afbc57881..069be48cc 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -409,23 +409,6 @@ const { handler, api } = betterAuth({ enabled: true, maximumRolesPerOrganization: 10, }, - async sendInvitationEmail(data, _request) { - if (IS_CLOUD) { - const host = - process.env.NODE_ENV === "development" - ? "http://localhost:3000" - : "https://app.dokploy.com"; - const inviteLink = `${host}/invitation?token=${data.id}`; - - await sendEmail({ - email: data.email, - subject: "Invitation to join organization", - text: ` -

You are invited to join ${data.organization.name} on Dokploy. Click the link to accept the invitation: Accept Invitation

- `, - }); - } - }, }), ...(IS_CLOUD ? [ diff --git a/packages/server/src/verification/send-verification-email.tsx b/packages/server/src/verification/send-verification-email.tsx index 098789a2b..fe9cd6ee6 100644 --- a/packages/server/src/verification/send-verification-email.tsx +++ b/packages/server/src/verification/send-verification-email.tsx @@ -1,4 +1,5 @@ import { renderAsync } from "@react-email/components"; +import InvitationEmail from "../emails/emails/invitation"; import VerifyEmailTemplate from "../emails/emails/verify-email"; import { sendEmailNotification } from "../utils/notifications/utils"; @@ -51,3 +52,38 @@ export const sendVerificationEmail = async ({ text: html, }); }; + +export const renderInvitationEmail = async ({ + email, + inviteLink, + organizationName, +}: { + email: string; + inviteLink: string; + organizationName: string; +}) => { + return renderAsync( + InvitationEmail({ + inviteLink, + toEmail: email, + organizationName, + }), + ); +}; + +export const sendInvitationEmail = async ({ + email, + inviteLink, + organizationName, +}: { + email: string; + inviteLink: string; + organizationName: string; +}) => { + const html = await renderInvitationEmail({ email, inviteLink, organizationName }); + await sendEmail({ + email, + subject: `You've been invited to join ${organizationName} on Dokploy`, + text: html, + }); +}; From c41b69c925d88dab8dffc228882cf3a56a7a185d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 25 Apr 2026 03:40:50 +0000 Subject: [PATCH 10/13] [autofix.ci] apply automated fixes --- .../server/src/verification/send-verification-email.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/server/src/verification/send-verification-email.tsx b/packages/server/src/verification/send-verification-email.tsx index fe9cd6ee6..e6ae0250a 100644 --- a/packages/server/src/verification/send-verification-email.tsx +++ b/packages/server/src/verification/send-verification-email.tsx @@ -80,7 +80,11 @@ export const sendInvitationEmail = async ({ inviteLink: string; organizationName: string; }) => { - const html = await renderInvitationEmail({ email, inviteLink, organizationName }); + const html = await renderInvitationEmail({ + email, + inviteLink, + organizationName, + }); await sendEmail({ email, subject: `You've been invited to join ${organizationName} on Dokploy`, From e9fdc19b9615dfd6dc832e52b1fcda4e2e39cd86 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 24 Apr 2026 22:33:24 -0600 Subject: [PATCH 11/13] fix: fallback to DownstreamStatus when OriginStatus is 0 in requests table Closes #4250 --- apps/dokploy/components/dashboard/requests/columns.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/requests/columns.tsx b/apps/dokploy/components/dashboard/requests/columns.tsx index 997074fde..1cb8868cd 100644 --- a/apps/dokploy/components/dashboard/requests/columns.tsx +++ b/apps/dokploy/components/dashboard/requests/columns.tsx @@ -79,8 +79,8 @@ export const columns: ColumnDef[] = [ : log.RequestPath}
- - Status: {formatStatusLabel(log.OriginStatus)} + + Status: {formatStatusLabel(log.OriginStatus || log.DownstreamStatus)} Exec Time: {formatDuration(log.Duration)} From 09824facf8ffd826d96f5d35f966eb84ffdeaaf4 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 24 Apr 2026 22:34:48 -0600 Subject: [PATCH 12/13] refactor: improve Badge component formatting in requests table --- apps/dokploy/components/dashboard/requests/columns.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/requests/columns.tsx b/apps/dokploy/components/dashboard/requests/columns.tsx index 1cb8868cd..2ad2455ba 100644 --- a/apps/dokploy/components/dashboard/requests/columns.tsx +++ b/apps/dokploy/components/dashboard/requests/columns.tsx @@ -79,8 +79,11 @@ export const columns: ColumnDef[] = [ : log.RequestPath}
- - Status: {formatStatusLabel(log.OriginStatus || log.DownstreamStatus)} + + Status:{" "} + {formatStatusLabel(log.OriginStatus || log.DownstreamStatus)} Exec Time: {formatDuration(log.Duration)} From fb6b06f064b7eaa8e08878d5cfdea50ec3d774fa Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 24 Apr 2026 22:46:18 -0600 Subject: [PATCH 13/13] chore: add push trigger for version sync on tag creation --- .github/workflows/sync-version.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/sync-version.yml b/.github/workflows/sync-version.yml index be19a2bb1..5e8ccb706 100644 --- a/.github/workflows/sync-version.yml +++ b/.github/workflows/sync-version.yml @@ -3,6 +3,9 @@ name: Sync version to MCP and CLI repos on: release: types: [published] + push: + tags: + - 'v*' workflow_dispatch: jobs: