mirror of
https://github.com/andwati/dokploy.git
synced 2026-10-25 22:42:18 +00:00
feat: enhance vault provider management and environment variable resolution
- Introduced support for project and environment assignments for vault providers, allowing for more granular access control. - Updated the vault provider schema to include assignments and modified related components to handle these changes. - Enhanced UI to display assignment status and allow users to manage project and environment associations effectively. - Added validation to ensure assignments reference valid projects and environments within the organization. - Updated tests to cover new functionality related to vault provider assignments and environment variable resolution.
This commit is contained in:
@@ -63,6 +63,15 @@ export const vaultProviderConfigSchema = z.discriminatedUnion("providerType", [
|
||||
|
||||
export type VaultProviderConfig = z.infer<typeof vaultProviderConfigSchema>;
|
||||
|
||||
export const vaultProviderAssignmentSchema = z.object({
|
||||
projectId: z.string().min(1),
|
||||
environmentIds: z.array(z.string().min(1)).default([]),
|
||||
});
|
||||
|
||||
export type VaultProviderAssignment = z.infer<
|
||||
typeof vaultProviderAssignmentSchema
|
||||
>;
|
||||
|
||||
export const vaultProvider = pgTable(
|
||||
"vault_provider",
|
||||
{
|
||||
@@ -73,6 +82,10 @@ export const vaultProvider = pgTable(
|
||||
name: text("name").notNull(),
|
||||
providerType: vaultProviderType("providerType").notNull(),
|
||||
config: jsonb("config").$type<VaultProviderConfig>().notNull(),
|
||||
assignments: jsonb("assignments")
|
||||
.$type<VaultProviderAssignment[]>()
|
||||
.notNull()
|
||||
.default([]),
|
||||
organizationId: text("organizationId")
|
||||
.notNull()
|
||||
.references(() => organization.id, { onDelete: "cascade" }),
|
||||
@@ -102,12 +115,14 @@ const createSchema = createInsertSchema(vaultProvider);
|
||||
export const apiCreateVaultProvider = createSchema.pick({}).extend({
|
||||
name: vaultProviderNameSchema,
|
||||
config: vaultProviderConfigSchema,
|
||||
assignments: z.array(vaultProviderAssignmentSchema),
|
||||
});
|
||||
|
||||
export const apiUpdateVaultProvider = createSchema.pick({}).extend({
|
||||
vaultProviderId: z.string().min(1),
|
||||
name: vaultProviderNameSchema,
|
||||
config: vaultProviderConfigSchema,
|
||||
assignments: z.array(vaultProviderAssignmentSchema),
|
||||
});
|
||||
|
||||
export const apiFindOneVaultProvider = z.object({
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
type apiCreateVaultProvider,
|
||||
projects,
|
||||
type VaultProviderAssignment,
|
||||
type VaultProviderConfig,
|
||||
vaultProvider,
|
||||
} from "@dokploy/server/db/schema";
|
||||
@@ -58,10 +60,44 @@ const isUniqueNameViolation = (error: unknown) =>
|
||||
error instanceof Error &&
|
||||
error.message.includes("vault_provider_org_name_idx");
|
||||
|
||||
const validateAssignments = async (
|
||||
assignments: VaultProviderAssignment[],
|
||||
organizationId: string,
|
||||
) => {
|
||||
const orgProjects = await db.query.projects.findMany({
|
||||
where: eq(projects.organizationId, organizationId),
|
||||
with: { environments: true },
|
||||
});
|
||||
for (const assignment of assignments) {
|
||||
const project = orgProjects.find(
|
||||
(p) => p.projectId === assignment.projectId,
|
||||
);
|
||||
if (!project) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Assignment references a project outside this organization",
|
||||
});
|
||||
}
|
||||
const environmentIds = new Set(
|
||||
project.environments.map((e) => e.environmentId),
|
||||
);
|
||||
for (const environmentId of assignment.environmentIds) {
|
||||
if (!environmentIds.has(environmentId)) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message:
|
||||
"Assignment references an environment outside the selected project",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const createVaultProvider = async (
|
||||
input: z.infer<typeof apiCreateVaultProvider>,
|
||||
organizationId: string,
|
||||
) => {
|
||||
await validateAssignments(input.assignments, organizationId);
|
||||
try {
|
||||
const newProvider = await db
|
||||
.insert(vaultProvider)
|
||||
@@ -69,6 +105,7 @@ export const createVaultProvider = async (
|
||||
name: input.name,
|
||||
providerType: input.config.providerType,
|
||||
config: input.config,
|
||||
assignments: input.assignments,
|
||||
organizationId,
|
||||
})
|
||||
.returning()
|
||||
@@ -105,6 +142,20 @@ export const findVaultProviderById = async (vaultProviderId: string) => {
|
||||
return provider;
|
||||
};
|
||||
|
||||
export const findVaultProviderInOrganization = async (
|
||||
vaultProviderId: string,
|
||||
organizationId: string,
|
||||
) => {
|
||||
const provider = await findVaultProviderById(vaultProviderId);
|
||||
if (provider.organizationId !== organizationId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not allowed to access this vault provider",
|
||||
});
|
||||
}
|
||||
return provider;
|
||||
};
|
||||
|
||||
export const findVaultProvidersByOrganizationId = async (
|
||||
organizationId: string,
|
||||
) => {
|
||||
@@ -118,9 +169,11 @@ export const updateVaultProvider = async (
|
||||
vaultProviderId: string,
|
||||
name: string,
|
||||
config: VaultProviderConfig,
|
||||
assignments: VaultProviderAssignment[],
|
||||
) => {
|
||||
const existing = await findVaultProviderById(vaultProviderId);
|
||||
const mergedConfig = mergeVaultProviderConfig(config, existing.config);
|
||||
await validateAssignments(assignments, existing.organizationId);
|
||||
|
||||
try {
|
||||
const updated = await db
|
||||
@@ -129,6 +182,7 @@ export const updateVaultProvider = async (
|
||||
name,
|
||||
providerType: mergedConfig.providerType,
|
||||
config: mergedConfig,
|
||||
assignments,
|
||||
})
|
||||
.where(eq(vaultProvider.vaultProviderId, vaultProviderId))
|
||||
.returning()
|
||||
|
||||
@@ -42,11 +42,7 @@ const getAccessToken = async (config: AzureConfig) => {
|
||||
return data.access_token;
|
||||
};
|
||||
|
||||
const readSecret = async (
|
||||
config: AzureConfig,
|
||||
token: string,
|
||||
name: string,
|
||||
) => {
|
||||
const readSecret = async (config: AzureConfig, token: string, name: string) => {
|
||||
const response = await vaultFetch(
|
||||
`${baseUrl(config)}/secrets/${encodeURIComponent(name)}?api-version=${API_VERSION}`,
|
||||
{ headers: { Authorization: `Bearer ${token}` } },
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user