Skip to content

fix(server): quote S3 path in backup retention rclone commands - #5568

Closed
sx4im wants to merge 2 commits into
Dokploy:canaryfrom
sx4im:fix/backup-retention-quote-s3-path
Closed

sx4im wants to merge 2 commits into
Dokploy:canaryfrom
sx4im:fix/backup-retention-quote-s3-path

Conversation

@sx4im

@sx4im sx4im commented Oct 2, 2026 •

Copy link
Copy Markdown

What broke

keepLatestNBackups (the retention cleanup that runs after every backup, on the panel server and on remote servers) built its rclone lsf and rclone delete shell commands with the S3 destination path interpolated unquoted. Every other rclone invocation in the codebase double-quotes the destination.

Root cause

Backup prefixes are free-form user input (schema: z.string().min(1)), so a prefix containing spaces or other shell-special characters made the shell split the path into multiple arguments. rclone then received a wrong path, and since the function swallows its own errors (try/catch -> console.error), the retention cleanup failed silently instead of pruning old backups.

Related to #4354, which reports backup failures when the backup name/prefix contains certain characters.

What changed

  • Extracted the command construction into a pure exported getKeepLatestNBackupsCommand in packages/server/src/utils/backups/utils.ts.
  • Double-quoted the S3 path in both the rclone lsf and rclone delete commands, keeping the xargs {} placeholder inside the quotes so substituted paths stay a single argument.
  • keepLatestNBackups now uses the builder; its behavior is otherwise unchanged.

Verification

  • New regression test apps/dokploy/__test__/backups/keep-latest-n-backups.test.ts (5 tests): runs the generated pipeline through a real shell with a stub rclone that records its argv. Before the fix, the two space-in-prefix tests failed (path split into two arguments); after the fix, all 5 pass.
  • Full backup suite: 43/43 pass (38 pre-existing + 5 new).
  • tsc --noEmit clean in packages/server; Biome check clean on touched files.

RetriggerConfidence Score: 5/5

The PR appears safe to merge.

What we checked:

  • Space in a prefix splits the path: Both generated paths are quoted, and the new tests check the arguments received by the listing and deletion commands.

Summary

Backup retention now quotes the S3 path in both rclone commands, keeping prefixes with spaces together. The command builder is reused by local and remote cleanup and covered by shell-based regression tests.

  • Checks both listing and deletion paths with space-containing prefixes.
  • Keeps the existing retention rules, including skipping cleanup when the keep count is zero.

Reviews (1) · Last reviewed commit: "fix(server): quote S3 path in backup ret..."

keepLatestNBackups interpolated the backup S3 path unquoted into the
rclone lsf/delete shell commands. Backup prefixes are free-form user
input, so a prefix with spaces or other shell-special characters made
the shell split the path and the retention cleanup silently failed.

Quote the path in both commands, keeping the xargs {} placeholder
inside the quotes so substituted paths stay a single argument.
Extracted the command builder into getKeepLatestNBackupsCommand for
testability; keepLatestNBackups behavior is unchanged.
@sx4im
sx4im requested a review from Siumauricio as a code owner October 2, 2026 17:57
@sx4im sx4im closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant