Skip to content

🚀 Release v0.28.2#3845

Merged
Siumauricio merged 11 commits intomainfrom
canary
Mar 1, 2026
Merged

🚀 Release v0.28.2#3845
Siumauricio merged 11 commits intomainfrom
canary

Conversation

@github-actions
Copy link
Copy Markdown

@github-actions github-actions bot commented Mar 1, 2026

This PR promotes changes from canary to main for version v0.28.2.

🔍 Changes Include:

  • Version bump to v0.28.2
  • All changes from canary branch

✅ Pre-merge Checklist:

  • All tests passing
  • Documentation updated
  • Docker images built and tested

🤖 This PR was automatically generated by GitHub Actions

Greptile Summary

This release PR (v0.28.2) promotes a set of canary fixes to main, covering GitHub OAuth hardening, a debug log cleanup, test mock updates, a getTrustedOrigins refactor with cloud caching, and a compose domain-writing behavioral change.

Key changes:

  • GitHub provider fix: Nullish coalescing operators prevent undefined from appearing in OAuth redirect URLs, and missing activeOrganization/session values now disable the setup button.
  • getTrustedOrigins refactor: Switches from the ORM relational API to a raw Drizzle join query and introduces a 30-minute in-memory cache for cloud mode. The cache has no explicit invalidation path, which could leave revoked trusted origins active for up to 30 minutes.
  • Compose domain writing: Removes the early no-op guard when domains is empty. Deployments with zero configured domains will now attempt to load and modify the compose file rather than silently skipping, which can cause a deployment failure if the compose file doesn't exist at that point in the pipeline.
  • Duplicate DB file: A new apps/dokploy/server/db/index.ts is added that mirrors packages/server/src/db/index.ts, potentially creating two independent PostgreSQL connection pools and omitting the schema re-export present in the original.

Confidence Score: 2/5

  • This PR has two medium-risk changes that could cause production regressions: the compose no-domain behavioral change may break deployments, and the new duplicate DB file risks double connection pools.
  • The writeDomainsToCompose behavior change (no-op → error/modify when domains is empty) and the duplicate db/index.ts creating a second connection pool are both substantive correctness risks that warrant verification before merging to main. The remaining changes (OAuth URL fix, log cleanup, test mocks, parallel fetch optimization) are clean and safe.
  • packages/server/src/utils/docker/domain.ts (behavior change on empty domains) and apps/dokploy/server/db/index.ts (duplicate DB connection pool).

Last reviewed commit: 8d56544

@github-actions github-actions bot requested a review from Siumauricio as a code owner March 1, 2026 05:07
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 1, 2026
@dosubot
Copy link
Copy Markdown

dosubot bot commented Mar 1, 2026

Related Documentation

Checked 7 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

11 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +1 to +38
import { dbUrl } from "@dokploy/server/db/constants";
import * as schema from "@dokploy/server/db/schema";
import { and, eq } from "drizzle-orm";
import { drizzle, type PostgresJsDatabase } from "drizzle-orm/postgres-js";
import postgres from "postgres";

export { and, eq };

type Database = PostgresJsDatabase<typeof schema>;
/**
* Evita problemas de redeclaración global en monorepos.
* No usamos `declare global`.
*/
const globalForDb = globalThis as unknown as {
db?: Database;
};

let dbConnection: Database;

if (process.env.NODE_ENV === "production") {
// En producción no usamos global cache
dbConnection = drizzle(postgres(dbUrl), {
schema,
});
} else {
// En desarrollo reutilizamos conexión para evitar múltiples conexiones
if (!globalForDb.db) {
globalForDb.db = drizzle(postgres(dbUrl), {
schema,
});
}

dbConnection = globalForDb.db;
}

export const db: Database = dbConnection;

export { dbUrl };
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate database connection pool

This new file is nearly identical to packages/server/src/db/index.ts and will create a second, independent postgres(dbUrl) connection pool pointing to the same database. In a monorepo, if both apps/dokploy and packages/server load their respective db/index.ts, you'll have two separate connection pools in the same process, which can double the number of open database connections and risk hitting PostgreSQL's max_connections limit.

Additionally, packages/server/src/db/index.ts exports the schema via export * from "./schema", whereas this new file does not. If any code that previously imported from @dokploy/server/db is redirected to this local file (e.g., via a tsconfig path alias), those schema type imports would silently break.

If the intent is to fix the HMR duplicate-connection issue in Next.js development mode, consider reusing the globalForDb singleton from the shared package rather than duplicating the entire module.

Comment on lines +120 to 147
const TRUSTED_ORIGINS_CACHE_TTL_MS = 30 * 60_000;
let trustedOriginsCache: { data: string[]; expiresAt: number } | null = null;

export const getTrustedOrigins = async () => {
const members = await db.query.member.findMany({
where: eq(member.role, "owner"),
with: {
user: true,
},
});
const runQuery = async () => {
const rows = await db
.select({ trustedOrigins: user.trustedOrigins })
.from(member)
.innerJoin(user, eq(member.userId, user.id))
.where(eq(member.role, "owner"));
return Array.from(new Set(rows.flatMap((r) => r.trustedOrigins ?? [])));
};

if (members.length === 0) {
return [];
if (IS_CLOUD) {
const now = Date.now();
if (trustedOriginsCache && now < trustedOriginsCache.expiresAt) {
return trustedOriginsCache.data;
}
const trustedOrigins = await runQuery();
trustedOriginsCache = {
data: trustedOrigins,
expiresAt: now + TRUSTED_ORIGINS_CACHE_TTL_MS,
};
return trustedOrigins;
}

const trustedOrigins = members.flatMap(
(member) => member.user.trustedOrigins || [],
);

return Array.from(new Set(trustedOrigins));
return runQuery();
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale cache with no invalidation path for trusted origins

The new 30-minute in-memory cache for IS_CLOUD is a good performance improvement, but trustedOriginsCache has no invalidation mechanism. If an owner's trustedOrigins are removed or changed (e.g., a user revokes a previously trusted domain), the old origins will continue to be accepted for up to 30 minutes. From a security standpoint, this means a revoked origin remains trusted throughout the cache TTL.

Consider either:

  • Exporting a clearTrustedOriginsCache() function and calling it from the relevant user-update service, or
  • Shortening the TTL for security-sensitive operations like origin trust validation.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 1, 2026

Additional Comments (1)

packages/server/src/utils/docker/domain.ts
Behavioral regression: empty domains array now modifies the compose file

Before this PR, writeDomainsToCompose had an early guard:

if (!domains.length) {
  return "";
}

This made the call a safe no-op when no domains were configured. Now that the guard is removed (and the matching domains.length === 0 check in addDomainToCompose is also removed), calling this function with an empty domains array will:

  1. Attempt to load the compose file from disk/remote.
  2. If the file doesn't exist, return an error shell script (echo "❌ Error: Compose file not found"; exit 1;) — potentially failing a deployment that previously succeeded silently.
  3. If the file does exist, modify it by injecting dokploy-network and write it back — a side-effect that was previously skipped.

Callers that passed an empty domains array expecting a no-op "" result (e.g., to build a shell command string) will now see different output. This is worth verifying against all call sites to confirm none rely on the old no-op behavior.

@Siumauricio Siumauricio merged commit d4719ec into main Mar 1, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated pr release size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant