feat: enhance vault provider access control and environment variable handling

- Updated the environment autocomplete component to include projectId and environmentId in vault secret fetching logic.
- Added authorization checks in the vault provider router to ensure users have access to the specified project and environment.
- Modified the vault provider schema to include projectId and optional environmentId for better validation.
- Improved error handling for unauthorized access and invalid vault provider assignments.
This commit is contained in:
Mauricio Siu
2026-08-10 16:41:08 -06:00
parent ce717a3de6
commit 9747e832ac
4 changed files with 47 additions and 3 deletions
@@ -85,9 +85,13 @@ export const useEnvCompletionSource = ({
const vaultSecret = /^vault\.([a-zA-Z0-9_-]+)\.([^}\n]*)$/.exec(inner);
if (vaultSecret) {
const provider = providers?.find((p) => p.name === vaultSecret[1]);
if (!provider) return null;
if (!provider || !projectId) return null;
const names = await utils.vaultProvider.listSecretNames
.fetch({ vaultProviderId: provider.vaultProviderId })
.fetch({
vaultProviderId: provider.vaultProviderId,
projectId,
environmentId,
})
.catch(() => [] as string[]);
return {
from: innerFrom + `vault.${vaultSecret[1]}.`.length,
@@ -176,6 +180,14 @@ export const useEnvCompletionSource = ({
return null;
},
[providers, projectEnv, environmentEnv, includeShared, utils],
[
providers,
projectEnv,
environmentEnv,
includeShared,
projectId,
environmentId,
utils,
],
);
};
@@ -2,6 +2,7 @@ import {
createVaultProvider,
findVaultProviderInOrganization,
findVaultProvidersByOrganizationId,
isVaultProviderAssigned,
listVaultProviderSecretNames,
maskVaultProviderConfig,
mergeVaultProviderConfig,
@@ -9,6 +10,7 @@ import {
testVaultProviderConnection,
updateVaultProvider,
} from "@dokploy/server";
import { findMemberByUserId } from "@dokploy/server/services/permission";
import { TRPCError } from "@trpc/server";
import { audit } from "@/server/api/utils/audit";
import {
@@ -129,6 +131,34 @@ export const vaultProviderRouter = createTRPCRouter({
input.vaultProviderId,
ctx.session.activeOrganizationId,
);
if (ctx.user.role !== "owner" && ctx.user.role !== "admin") {
const { accessedProjects } = await findMemberByUserId(
ctx.user.id,
ctx.session.activeOrganizationId,
);
if (!accessedProjects.includes(input.projectId)) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this project",
});
}
}
if (
!isVaultProviderAssigned(
provider.assignments,
input.projectId,
input.environmentId,
)
) {
throw new TRPCError({
code: "FORBIDDEN",
message:
"This vault provider is not enabled for the given project/environment",
});
}
return await listVaultProviderSecretNames(provider.config);
}),
});
@@ -140,4 +140,6 @@ export const apiTestVaultProvider = z.object({
export const apiListVaultSecretNames = z.object({
vaultProviderId: z.string().min(1),
projectId: z.string().min(1),
environmentId: z.string().optional(),
});
Binary file not shown.