mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-21 07:05:21 +02:00
* fix: use canEditDeployGitSource for git provider access on existing deploys Replaces the simple userId ownership check with a new canEditDeployGitSource function that correctly handles all role/sharing scenarios. Owner always has access; admin and member only if they own the provider or it is shared with the org — being assigned via accessedGitProviders (enterprise) only grants permission to connect new deploys, not to edit the git source of existing ones. Adds 26 unit tests covering owner, admin, member (with/without enterprise license), shared providers, and the key regression case from issue #4469. * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
122 lines
3.4 KiB
TypeScript
122 lines
3.4 KiB
TypeScript
import { db } from "@dokploy/server/db";
|
|
import { gitProvider, member } from "@dokploy/server/db/schema";
|
|
import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { and, eq } from "drizzle-orm";
|
|
|
|
export type GitProvider = typeof gitProvider.$inferSelect;
|
|
|
|
export const removeGitProvider = async (gitProviderId: string) => {
|
|
const result = await db
|
|
.delete(gitProvider)
|
|
.where(eq(gitProvider.gitProviderId, gitProviderId))
|
|
.returning();
|
|
|
|
return result[0];
|
|
};
|
|
|
|
export const findGitProviderById = async (gitProviderId: string) => {
|
|
const result = await db.query.gitProvider.findFirst({
|
|
where: eq(gitProvider.gitProviderId, gitProviderId),
|
|
});
|
|
|
|
if (!result) {
|
|
throw new TRPCError({
|
|
code: "NOT_FOUND",
|
|
message: "Git Provider not found",
|
|
});
|
|
}
|
|
return result;
|
|
};
|
|
|
|
export const updateGitProvider = async (
|
|
gitProviderId: string,
|
|
input: Partial<GitProvider>,
|
|
) => {
|
|
return await db
|
|
.update(gitProvider)
|
|
.set({
|
|
...input,
|
|
})
|
|
.where(eq(gitProvider.gitProviderId, gitProviderId))
|
|
.returning()
|
|
.then((response) => response[0]);
|
|
};
|
|
|
|
// Returns true if the user can edit the git source configuration of an existing
|
|
// deploy that is connected to the given provider.
|
|
// Owner/admin: always yes.
|
|
// Member: only if they own the provider or it's shared with the org.
|
|
// Being in accessedGitProviders only grants permission to connect NEW deploys,
|
|
// not to modify the git config of an existing deploy owned by someone else.
|
|
export const canEditDeployGitSource = async (
|
|
gitProviderId: string,
|
|
session: { userId: string; activeOrganizationId: string },
|
|
): Promise<boolean> => {
|
|
const { userId, activeOrganizationId } = session;
|
|
|
|
const memberRecord = await db.query.member.findFirst({
|
|
where: and(
|
|
eq(member.userId, userId),
|
|
eq(member.organizationId, activeOrganizationId),
|
|
),
|
|
columns: { role: true },
|
|
});
|
|
|
|
if (memberRecord?.role === "owner") return true;
|
|
|
|
const provider = await db.query.gitProvider.findFirst({
|
|
where: eq(gitProvider.gitProviderId, gitProviderId),
|
|
columns: { userId: true, sharedWithOrganization: true },
|
|
});
|
|
|
|
if (!provider) return false;
|
|
|
|
return provider.userId === userId || provider.sharedWithOrganization;
|
|
};
|
|
|
|
export const getAccessibleGitProviderIds = async (session: {
|
|
userId: string;
|
|
activeOrganizationId: string;
|
|
}): Promise<Set<string>> => {
|
|
const { userId, activeOrganizationId } = session;
|
|
|
|
const allOrgProviders = await db.query.gitProvider.findMany({
|
|
where: eq(gitProvider.organizationId, activeOrganizationId),
|
|
columns: {
|
|
gitProviderId: true,
|
|
userId: true,
|
|
sharedWithOrganization: true,
|
|
},
|
|
});
|
|
|
|
const memberRecord = await db.query.member.findFirst({
|
|
where: and(
|
|
eq(member.userId, userId),
|
|
eq(member.organizationId, activeOrganizationId),
|
|
),
|
|
columns: { accessedGitProviders: true, role: true },
|
|
});
|
|
|
|
if (memberRecord?.role === "owner" || memberRecord?.role === "admin") {
|
|
return new Set(allOrgProviders.map((p) => p.gitProviderId));
|
|
}
|
|
|
|
const licensed = await hasValidLicense(activeOrganizationId);
|
|
const assignedSet = licensed
|
|
? new Set(memberRecord?.accessedGitProviders ?? [])
|
|
: new Set<string>();
|
|
|
|
const result = new Set<string>();
|
|
for (const p of allOrgProviders) {
|
|
if (
|
|
p.userId === userId ||
|
|
p.sharedWithOrganization ||
|
|
assignedSet.has(p.gitProviderId)
|
|
) {
|
|
result.add(p.gitProviderId);
|
|
}
|
|
}
|
|
return result;
|
|
};
|