fix: strip credentials from service-level API responses (#4564)

* fix: strip credentials from service-level API responses

Registry passwords and S3 destination credentials were being returned
in service `.one` tRPC endpoints to any user with service-level read
access. Reported by Nihon Kohden Corporation security team.

- Strip registry `password` from `findApplicationById` via Drizzle `columns: { password: false }`
- Strip destination `accessKey`/`secretAccessKey` from all DB service finders (postgres, mysql, mariadb, mongo, libsql, compose, backup, volume-backups)
- Add `findRegistryByIdWithCredentials` for internal use only
- Builders and upload utils now load registry credentials by ID at execution time
- `createRollback` enriches `fullContext` with registry credentials before persisting to DB so rollback execution has what it needs
- Remove `findApplicationByIdWithCredentials` and `ApplicationNestedWithCredentials` — no longer needed
- Backup execution utils load full destination via `findDestinationById` at runtime instead of reading from the joined relation

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Mauricio Siu
2026-06-06 17:45:24 -06:00
committed by GitHub
parent f35f3064e9
commit c968a2755e
22 changed files with 169 additions and 82 deletions

View File

@@ -1,3 +1,4 @@
import { findRegistryByIdWithCredentials } from "@dokploy/server/services/registry";
import type { InferResultType } from "@dokploy/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import { getRegistryTag, uploadImageRemoteCommand } from "../cluster/upload";
@@ -28,9 +29,9 @@ export type ApplicationNested = InferResultType<
security: true;
redirects: true;
ports: true;
registry: true;
buildRegistry: true;
rollbackRegistry: true;
registry: { columns: { password: false } };
buildRegistry: { columns: { password: false } };
rollbackRegistry: { columns: { password: false } };
deployments: true;
environment: { with: { project: true } };
}
@@ -121,8 +122,8 @@ export const mechanizeDockerContainer = async (
application.environment.env,
);
const image = getImageName(application);
const authConfig = getAuthConfig(application);
const image = await getImageName(application);
const authConfig = await getAuthConfig(application);
const docker = await getRemoteDocker(application.serverId);
const settings: CreateServiceOptions = {
@@ -190,7 +191,7 @@ export const mechanizeDockerContainer = async (
}
};
const getImageName = (application: ApplicationNested) => {
const getImageName = async (application: ApplicationNested) => {
const { appName, sourceType, dockerImage, registry, buildRegistry } =
application;
const imageName = `${appName}:latest`;
@@ -199,18 +200,18 @@ const getImageName = (application: ApplicationNested) => {
}
if (registry) {
const registryTag = getRegistryTag(registry, imageName);
return registryTag;
const r = await findRegistryByIdWithCredentials(registry.registryId);
return getRegistryTag(r, imageName);
}
if (buildRegistry) {
const registryTag = getRegistryTag(buildRegistry, imageName);
return registryTag;
const r = await findRegistryByIdWithCredentials(buildRegistry.registryId);
return getRegistryTag(r, imageName);
}
return imageName;
};
export const getAuthConfig = (application: ApplicationNested) => {
export const getAuthConfig = async (application: ApplicationNested) => {
const {
registry,
buildRegistry,
@@ -222,23 +223,21 @@ export const getAuthConfig = (application: ApplicationNested) => {
if (sourceType === "docker") {
if (username && password) {
return {
password,
username,
serveraddress: registryUrl || "",
};
return { password, username, serveraddress: registryUrl || "" };
}
} else if (registry) {
const r = await findRegistryByIdWithCredentials(registry.registryId);
return {
password: registry.password,
username: registry.username,
serveraddress: registry.registryUrl,
password: r.password,
username: r.username,
serveraddress: r.registryUrl,
};
} else if (buildRegistry) {
const r = await findRegistryByIdWithCredentials(buildRegistry.registryId);
return {
password: buildRegistry.password,
username: buildRegistry.username,
serveraddress: buildRegistry.registryUrl,
password: r.password,
username: r.username,
serveraddress: r.registryUrl,
};
}