Skip to content

fix(migrate-auth-secret): exit cleanly when there are no 2FA records - #4394

Merged
Siumauricio merged 1 commit into
Dokploy:canaryfrom
ngenohkevin:fix/migrate-auth-secret-exit-on-empty
May 12, 2026
Merged

Siumauricio merged 1 commit into
Dokploy:canaryfrom
ngenohkevin:fix/migrate-auth-secret-exit-on-empty

Conversation

@ngenohkevin

Copy link
Copy Markdown
Contributor

Summary

Adds process.exit(0) to the empty-2FA-records branch of apps/dokploy/scripts/migrate-auth-secret.ts so the script terminates cleanly when there is nothing to migrate.

Currently the branch just returns from main(). Because the db import opens a Drizzle/pg connection pool with un-unref'd handles, Node's event loop never empties and the process hangs forever, even though every migration responsibility has completed.

This is the root cause documented in #4392 — the 0.29.3.sh security migration script runs this file via docker exec, then expects to continue and run the critical docker service update --secret-add ... --env-add BETTER_AUTH_SECRET_FILE=... --env-rm BETTER_AUTH_SECRET dokploy step. When this script hangs, the outer shell script hangs too (because of set -e + synchronous docker exec), and the dokploy service is never reconfigured to use the new secret. The dokploy-auth-secret Docker Secret is created but never mounted, so the instance silently stays vulnerable while the operator believes the patch was applied.

Closes #4392.

The change

One line:

 	if (records.length === 0) {
 		console.log("✅ No 2FA records found, nothing to migrate.");
-		return;
+		process.exit(0);
 	}

This matches:

  • The success branch a few lines below, which already calls process.exit(0).
  • The pattern in sibling scripts apps/dokploy/scripts/reset-password.ts and apps/dokploy/scripts/reset-2fa.ts, which both call process.exit(0) after their main work.

Test plan

I reproduced the hang on a real install before opening #4392:

  • Two production VPSes (Hetzner + Contabo, Debian 12, Docker Swarm single-replica)
  • Both started on Dokploy v0.29.2, both had SELECT COUNT(*) FROM two_factor = 0
  • Upgraded to v0.29.4, ran curl -sSL https://dokploy.com/security/0.29.3.sh | bash
  • On both, the script printed ✅ No 2FA records found, nothing to migrate. then hung; /proc/<pid>/wchan was ep_pol, ~140MB RSS, 11 threads — Node's event loop idle, never exiting
  • Manual workaround was to kill the node process and run the final docker service update myself; full diagnostics in Post-upgrade security script (0.29.3.sh) hangs in migrate-auth-secret when there are 0 two_factor records, leaving service unreconfigured #4392

With this patch, process.exit(0) causes Node to terminate the runtime immediately, releasing any open pg/Docker socket handles. The bash script's docker exec then returns 0, and execution continues to the docker service update --secret-add ... step the way it was meant to.

I have not stood up a full local Dokploy dev environment to re-run the entire 0.29.3.sh pipeline end-to-end against this branch — the fix is a single process.exit(0) call whose behavior is fully determined by the Node runtime, and the failing branch already prints its completion message before returning, so the new exit code is reached at exactly the same point that previously hung. Happy to do further testing if a maintainer wants something specific.

Out of scope, but flagged in #4392

There is a related issue with the outer shell script (0.29.3.sh) that this PR does not address: its early-exit idempotency check only verifies that the dokploy-auth-secret Docker Secret exists, not that the dokploy service spec actually mounts it and uses BETTER_AUTH_SECRET_FILE. A user whose first run hung after the secret was created will see ✅ Auth secret is already configured! on a re-run and bail out, despite the service still being unpatched. Worth tightening that check in the shell script (suggested patch in the issue), but it lives outside this repo so I haven't touched it here.

The empty-records branch of `main()` returned without calling
`process.exit(0)`, leaving the Drizzle Postgres connection pool
holding the event loop open. The `migrate-auth-secret` process
then hangs indefinitely after printing "No 2FA records found,
nothing to migrate." causing the upstream `0.29.3.sh` security
migration script (which calls this via `docker exec`) to never
reach its final `docker service update` step that mounts the new
Docker Secret. Operators end up with the new secret created but
the dokploy service still configured with the hardcoded
`BETTER_AUTH_SECRET`, while believing the migration completed.

Match the success branch a few lines below which already does
`process.exit(0)`, and the pattern used in sibling scripts
`reset-password.ts` and `reset-2fa.ts`.

Closes Dokploy#4392
@ngenohkevin
ngenohkevin requested a review from Siumauricio as a code owner May 12, 2026 18:36
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. bug Something isn't working labels May 12, 2026
@Siumauricio
Siumauricio merged commit a714e0f into Dokploy:canary May 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Post-upgrade security script (0.29.3.sh) hangs in migrate-auth-secret when there are 0 two_factor records, leaving service unreconfigured

2 participants