diff --git a/.github/workflows/dokploy.yml b/.github/workflows/dokploy.yml index 1c228d27e..e30b5d06a 100644 --- a/.github/workflows/dokploy.yml +++ b/.github/workflows/dokploy.yml @@ -140,6 +140,7 @@ jobs: runs-on: ubuntu-latest outputs: version: ${{ steps.get_version.outputs.version }} + npm_version: ${{ steps.get_version.outputs.npm_version }} steps: - name: Checkout uses: actions/checkout@v4 @@ -151,6 +152,7 @@ jobs: run: | VERSION=$(node -p "require('./apps/dokploy/package.json').version") echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "npm_version=${VERSION#v}" >> $GITHUB_OUTPUT - name: Fetch install.sh run: | @@ -164,6 +166,7 @@ jobs: uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.get_version.outputs.version }} + target_commitish: ${{ github.sha }} name: ${{ steps.get_version.outputs.version }} generate_release_notes: true draft: false @@ -180,15 +183,18 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10.22.0 + - 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 + jq --arg v "${{ needs.generate-release.outputs.npm_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 @@ -196,55 +202,53 @@ jobs: 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 }}" \ + git commit -m "chore: bump version to ${{ needs.generate-release.outputs.npm_version }}" \ -m "Source: ${{ github.repository }}@${{ github.sha }}" \ --allow-empty git push - echo "✅ MCP repo synced to version ${{ needs.generate-release.outputs.version }}" + echo "✅ MCP repo synced to version ${{ needs.generate-release.outputs.npm_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 + jq --arg v "${{ needs.generate-release.outputs.npm_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 }}" \ + git commit -m "chore: bump version to ${{ needs.generate-release.outputs.npm_version }}" \ -m "Source: ${{ github.repository }}@${{ github.sha }}" \ --allow-empty git push - echo "✅ CLI repo synced to version ${{ needs.generate-release.outputs.version }}" + echo "✅ CLI repo synced to version ${{ needs.generate-release.outputs.npm_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 + jq --arg v "${{ needs.generate-release.outputs.npm_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 }}" \ + git commit -m "chore: bump version to ${{ needs.generate-release.outputs.npm_version }}" \ -m "Source: ${{ github.repository }}@${{ github.sha }}" \ --allow-empty git push - echo "✅ SDK repo synced to version ${{ needs.generate-release.outputs.version }}" + echo "✅ SDK repo synced to version ${{ needs.generate-release.outputs.npm_version }}" diff --git a/.github/workflows/hotfix-cherry-pick.yml b/.github/workflows/hotfix-cherry-pick.yml new file mode 100644 index 000000000..9632917d4 --- /dev/null +++ b/.github/workflows/hotfix-cherry-pick.yml @@ -0,0 +1,36 @@ +name: Hotfix Cherry-Pick + +on: + pull_request_target: + types: [closed, labeled] + +concurrency: + group: hotfix-to-main + cancel-in-progress: false + +jobs: + cherry-pick: + if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'hotfix') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout main + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + token: ${{ secrets.HOTFIX_PUSH_TOKEN }} + + - name: Cherry-pick fix to main + run: | + git config user.name "Dokploy Bot" + git config user.email "bot@dokploy.com" + SHA="${{ github.event.pull_request.merge_commit_sha }}" + if [ "$(git rev-list --parents -n1 "$SHA" | wc -w)" -gt 2 ]; then + git cherry-pick -x -m 1 "$SHA" + else + git cherry-pick -x "$SHA" + fi + git commit --amend -m "$(git log -1 --format=%B)" -m "[skip ci]" + git push origin main diff --git a/.github/workflows/hotfix-release.yml b/.github/workflows/hotfix-release.yml new file mode 100644 index 000000000..7e473b3d2 --- /dev/null +++ b/.github/workflows/hotfix-release.yml @@ -0,0 +1,28 @@ +name: Hotfix Release + +on: + workflow_dispatch: + +concurrency: + group: hotfix-to-main + cancel-in-progress: false + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout main + uses: actions/checkout@v4 + with: + ref: main + token: ${{ secrets.HOTFIX_PUSH_TOKEN }} + + - name: Bump patch version and push + run: | + git config user.name "Dokploy Bot" + git config user.email "bot@dokploy.com" + CURRENT=$(node -p "require('./apps/dokploy/package.json').version") + NEW=$(echo "$CURRENT" | awk -F. -v OFS=. '{$NF++; print}') + sed -i "s/\"version\": \"$CURRENT\"/\"version\": \"$NEW\"/" apps/dokploy/package.json + git commit -am "chore: release ${NEW}" + git push origin main diff --git a/.gitignore b/.gitignore index d531bab01..602556df8 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,7 @@ yarn-error.log* *.pem -.db \ No newline at end of file +.db + +.playwright-* +.credentials \ No newline at end of file diff --git a/apps/dokploy/__test__/api/api-key-name.test.ts b/apps/dokploy/__test__/api/api-key-name.test.ts new file mode 100644 index 000000000..677a52757 --- /dev/null +++ b/apps/dokploy/__test__/api/api-key-name.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from "vitest"; +import { API_KEY_NAME_MAX_LENGTH, apiKeyNameSchema } from "@/lib/api-keys"; + +describe("apiKeyNameSchema", () => { + it("rejects an empty name", () => { + const result = apiKeyNameSchema.safeParse(""); + expect(result.success).toBe(false); + }); + + it("accepts a name at the maximum length", () => { + const name = "a".repeat(API_KEY_NAME_MAX_LENGTH); + const result = apiKeyNameSchema.safeParse(name); + expect(result.success).toBe(true); + }); + + it("rejects a name over the maximum length instead of passing it to better-auth", () => { + const name = "a".repeat(API_KEY_NAME_MAX_LENGTH + 1); + const result = apiKeyNameSchema.safeParse(name); + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.issues[0]?.message).toBe( + `Name must be at most ${API_KEY_NAME_MAX_LENGTH} characters`, + ); + } + }); +}); diff --git a/apps/dokploy/__test__/backups/db-backup-restore-injection.test.ts b/apps/dokploy/__test__/backups/db-backup-restore-injection.test.ts new file mode 100644 index 000000000..d48644c95 --- /dev/null +++ b/apps/dokploy/__test__/backups/db-backup-restore-injection.test.ts @@ -0,0 +1,106 @@ +import { execSync } from "node:child_process"; +import { chmodSync, existsSync, rmSync, writeFileSync } from "node:fs"; +import { + getLibsqlBackupCommand, + getMariadbBackupCommand, + getMongoBackupCommand, + getMysqlBackupCommand, + getPostgresBackupCommand, +} from "@dokploy/server/utils/backups/utils"; +import { + getMariadbRestoreCommand, + getMongoRestoreCommand, + getMysqlRestoreCommand, + getPostgresRestoreCommand, +} from "@dokploy/server/utils/restore/utils"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; + +// A stub replacing the real `docker` binary. It ignores exec/-i/$CONTAINER_ID, +// exports the -e VAR=val pairs, and runs the inner `sh -c +