Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9f10f0f
fix(migrate-auth-secret): exit cleanly when there are no 2FA records
ngenohkevin May 12, 2026
a714e0f
Merge pull request #4394 from ngenohkevin/fix/migrate-auth-secret-exi…
Siumauricio May 12, 2026
754774e
feat(compose): add import from base64 in create service dropdown
Siumauricio May 12, 2026
63e33a2
[autofix.ci] apply automated fixes
autofix-ci[bot] May 12, 2026
7a568aa
Merge pull request #4395 from Dokploy/feat/import-compose-from-base64
Siumauricio May 12, 2026
f8fcf68
Enhance version synchronization workflow to include SDK repository
Siumauricio May 12, 2026
558d809
feat(deployment): add readLogs procedure to fetch deployment logs
Siumauricio May 13, 2026
aff200f
feat(deployment): add server access validation for deployment actions
Siumauricio May 13, 2026
67278d8
feat(organization): prevent inviting users with owner role
Siumauricio May 13, 2026
1fdbe87
feat(user): implement session cleanup on user update
Siumauricio May 13, 2026
a50f958
feat(settings): add copy button to server IP in web server settings (…
Siumauricio May 13, 2026
8d88a34
fix: copy Dokploy server IP when clicking server badge (#4390)
vadamk May 13, 2026
ef0cf9b
fix: responsive layout (#4391)
nhridoy May 13, 2026
6e342ee
fix: automatically converting username to lowercase both in creation …
Baker May 13, 2026
af8072d
fix: allow square brackets in zip path validation for Next.js dynamic…
Siumauricio May 22, 2026
b06138b
fix: prevent webhook deploy crash when commit data lacks modified fil…
Siumauricio May 22, 2026
f6e6e5c
fix: add type="button" to TooltipTrigger in form components to preven…
mixelburg May 22, 2026
34d38cf
fix: enable comment toggle shortcut in env variable editor (#4402) (#…
Siumauricio May 22, 2026
103e2f7
fix: add tls=true label for domains when certificateType is none (#40…
Siumauricio May 22, 2026
2f43f60
chore: update version to v0.29.5 in package.json
Siumauricio May 22, 2026
6675aa6
chore(deps): upgrade next to 16.2.6 (#4477)
jasael May 24, 2026
3f36ffd
add custom rclone destinations
kitwongpixel May 26, 2026
109b945
fix destination router imports
kitwongpixel May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/dokploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ jobs:
needs: [combine-manifests]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -160,3 +162,80 @@ jobs:
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

sync-version:
needs: [generate-release]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Sync version to MCP repository
run: |
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/mcp.git /tmp/mcp-repo
cd /tmp/mcp-repo
jq --arg v "${{ needs.generate-release.outputs.version }}" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json
npm install -g pnpm
pnpm install
pnpm run fetch-openapi
pnpm run generate
git config user.name "Dokploy Bot"
git config user.email "bot@dokploy.com"
git add -A
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.version }}" \
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
--allow-empty
git push
echo "✅ MCP repo synced to version ${{ needs.generate-release.outputs.version }}"
- name: Sync version to CLI repository
run: |
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/cli.git /tmp/cli-repo
cd /tmp/cli-repo
jq --arg v "${{ needs.generate-release.outputs.version }}" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json
cp ${{ github.workspace }}/openapi.json ./openapi.json
npm install -g pnpm
pnpm install
pnpm run generate
git config user.name "Dokploy Bot"
git config user.email "bot@dokploy.com"
git add -A
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.version }}" \
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
--allow-empty
git push
echo "✅ CLI repo synced to version ${{ needs.generate-release.outputs.version }}"
- name: Sync version to SDK repository
run: |
git clone https://x-access-token:${{ secrets.DOCS_SYNC_TOKEN }}@github.com/dokploy/sdk.git /tmp/sdk-repo
cd /tmp/sdk-repo
jq --arg v "${{ needs.generate-release.outputs.version }}" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json
cp ${{ github.workspace }}/openapi.json ./openapi.json
npm install -g pnpm
pnpm install
pnpm run generate
git config user.name "Dokploy Bot"
git config user.email "bot@dokploy.com"
git add -A
git commit -m "chore: bump version to ${{ needs.generate-release.outputs.version }}" \
-m "Source: ${{ github.repository }}@${{ github.sha }}" \
--allow-empty
git push
echo "✅ SDK repo synced to version ${{ needs.generate-release.outputs.version }}"
83 changes: 0 additions & 83 deletions .github/workflows/sync-version.yml

This file was deleted.

45 changes: 45 additions & 0 deletions apps/dokploy/__test__/compose/domain/labels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,51 @@ describe("createDomainLabels", () => {
);
});

it("should add tls=true for certificateType none on websecure entrypoint", async () => {
const noneDomain = {
...baseDomain,
https: true,
certificateType: "none" as const,
};
const labels = await createDomainLabels(appName, noneDomain, "websecure");
expect(labels).toContain(
"traefik.http.routers.test-app-1-websecure.tls=true",
);
// no cert resolver should be set when relying on a default/custom cert
expect(labels).not.toContain(
"traefik.http.routers.test-app-1-websecure.tls.certresolver=letsencrypt",
);
});

it("should not add tls=true for certificateType none on web entrypoint", async () => {
const noneDomain = {
...baseDomain,
https: true,
certificateType: "none" as const,
};
const labels = await createDomainLabels(appName, noneDomain, "web");
expect(labels).not.toContain(
"traefik.http.routers.test-app-1-web.tls=true",
);
});

it("should add tls=true for certificateType none on a custom https entrypoint", async () => {
const noneDomain = {
...baseDomain,
https: true,
customEntrypoint: "websecure-custom",
certificateType: "none" as const,
};
const labels = await createDomainLabels(
appName,
noneDomain,
"websecure-custom",
);
expect(labels).toContain(
"traefik.http.routers.test-app-1-websecure-custom.tls=true",
);
});

it("should handle different ports correctly", async () => {
const customPortDomain = { ...baseDomain, port: 3000 };
const labels = await createDomainLabels(appName, customPortDomain, "web");
Expand Down
41 changes: 41 additions & 0 deletions apps/dokploy/__test__/deploy/should-deploy.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { shouldDeploy } from "@dokploy/server";
import { describe, expect, it } from "vitest";

describe("shouldDeploy", () => {
it("should deploy when no watch paths are configured", () => {
expect(shouldDeploy(null, ["src/index.ts"])).toBe(true);
expect(shouldDeploy([], ["src/index.ts"])).toBe(true);
});

it("should deploy when watch paths match modified files", () => {
expect(shouldDeploy(["src/**"], ["src/index.ts"])).toBe(true);
expect(shouldDeploy(["apps/web/**"], ["apps/web/page.tsx"])).toBe(true);
});

it("should not deploy when watch paths do not match", () => {
expect(shouldDeploy(["src/**"], ["docs/readme.md"])).toBe(false);
});

it("should not throw when modified files contain non-string values", () => {
expect(() =>
shouldDeploy(["src/**"], ["src/index.ts", undefined, null] as any),
).not.toThrow();
expect(
shouldDeploy(["src/**"], ["src/index.ts", undefined, null] as any),
).toBe(true);
});

it("should not throw when modified files are undefined or null", () => {
expect(() => shouldDeploy(["src/**"], undefined)).not.toThrow();
expect(() => shouldDeploy(["src/**"], null)).not.toThrow();
expect(shouldDeploy(["src/**"], undefined)).toBe(false);
expect(shouldDeploy(["src/**"], null)).toBe(false);
});

it("should not throw when every modified file is non-string", () => {
expect(() =>
shouldDeploy(["src/**"], [undefined, undefined] as any),
).not.toThrow();
expect(shouldDeploy(["src/**"], [undefined, undefined] as any)).toBe(false);
});
});
50 changes: 49 additions & 1 deletion apps/dokploy/__test__/utils/backups.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { normalizeS3Path } from "@dokploy/server/utils/backups/utils";
import {
buildRcloneDestination,
getDestinationRoot,
getS3Credentials,
normalizeS3Path,
} from "@dokploy/server/utils/backups/utils";
import { describe, expect, test } from "vitest";

describe("normalizeS3Path", () => {
Expand Down Expand Up @@ -59,3 +64,46 @@ describe("normalizeS3Path", () => {
expect(normalizeS3Path("instance-backups")).toBe("instance-backups/");
});
});

describe("buildRcloneDestination", () => {
test("should append relative paths to remote roots", () => {
expect(buildRcloneDestination(":s3:bucket", "app/file.tar.gz")).toBe(
":s3:bucket/app/file.tar.gz",
);
expect(
buildRcloneDestination(":sftp,host=example.com:backups", "app"),
).toBe(":sftp,host=example.com:backups/app");
expect(buildRcloneDestination("remote/root/", "app")).toBe(
"remote/root/app",
);
});

test("should preserve bare roots when no path is provided", () => {
expect(buildRcloneDestination(":s3:bucket", "")).toBe(":s3:bucket");
expect(buildRcloneDestination("remote/root", "")).toBe("remote/root");
});
});

describe("custom destination helpers", () => {
const customDestination = {
provider: "Custom",
bucket: "backups",
endpoint: ":sftp,host=example.com:backups",
additionalFlags: ["--ssh-no-check-known-hosts"],
accessKey: "",
secretAccessKey: "",
region: "",
};

test("should use the endpoint as the destination root for custom remotes", () => {
expect(getDestinationRoot(customDestination)).toBe(
":sftp,host=example.com:backups",
);
});

test("should only return additional flags for custom destinations", () => {
expect(getS3Credentials(customDestination)).toEqual([
"--ssh-no-check-known-hosts",
]);
});
});
16 changes: 16 additions & 0 deletions apps/dokploy/__test__/wss/readValidDirectory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,20 @@ describe("readValidDirectory (path traversal)", () => {
it("returns false for empty string (resolves to cwd)", () => {
expect(readValidDirectory("")).toBe(false);
});

it("returns true for Next.js dynamic route paths with square brackets", () => {
expect(
readValidDirectory(
`${BASE}/applications/myapp/code/app/api/[id]/route.ts`,
),
).toBe(true);
expect(
readValidDirectory(`${BASE}/applications/myapp/code/pages/[slug].tsx`),
).toBe(true);
expect(
readValidDirectory(
`${BASE}/applications/myapp/code/app/[...catch]/page.tsx`,
),
).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export const ShowResources = ({ id, type }: Props) => {
<FormLabel>Memory Limit</FormLabel>
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger>
<TooltipTrigger type="button">
<InfoIcon className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
Expand Down Expand Up @@ -263,7 +263,7 @@ export const ShowResources = ({ id, type }: Props) => {
<FormLabel>Memory Reservation</FormLabel>
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger>
<TooltipTrigger type="button">
<InfoIcon className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
Expand Down Expand Up @@ -303,7 +303,7 @@ export const ShowResources = ({ id, type }: Props) => {
<FormLabel>CPU Limit</FormLabel>
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger>
<TooltipTrigger type="button">
<InfoIcon className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
Expand Down Expand Up @@ -343,7 +343,7 @@ export const ShowResources = ({ id, type }: Props) => {
<FormLabel>CPU Reservation</FormLabel>
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger>
<TooltipTrigger type="button">
<InfoIcon className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>
Expand Down Expand Up @@ -379,7 +379,7 @@ export const ShowResources = ({ id, type }: Props) => {
<FormLabel className="text-base">Ulimits</FormLabel>
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger>
<TooltipTrigger type="button">
<InfoIcon className="h-4 w-4 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent className="max-w-xs">
Expand Down
Loading