mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
fix: correct git provider access check for existing deploys (#4570)
* 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>
This commit is contained in:
369
apps/dokploy/__test__/git-provider/git-provider-access.test.ts
Normal file
369
apps/dokploy/__test__/git-provider/git-provider-access.test.ts
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import {
|
||||||
|
canEditDeployGitSource,
|
||||||
|
getAccessibleGitProviderIds,
|
||||||
|
} from "@dokploy/server/services/git-provider";
|
||||||
|
|
||||||
|
const mockDb = vi.hoisted(() => ({
|
||||||
|
query: {
|
||||||
|
gitProvider: {
|
||||||
|
findMany: vi.fn(),
|
||||||
|
findFirst: vi.fn(),
|
||||||
|
},
|
||||||
|
member: {
|
||||||
|
findFirst: vi.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@dokploy/server/db", () => ({ db: mockDb }));
|
||||||
|
|
||||||
|
const mockHasValidLicense = vi.hoisted(() => vi.fn());
|
||||||
|
vi.mock("@dokploy/server/services/proprietary/license-key", () => ({
|
||||||
|
hasValidLicense: mockHasValidLicense,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ORG_ID = "org-1";
|
||||||
|
const USER_OWNER = "user-owner";
|
||||||
|
const USER_ADMIN = "user-admin";
|
||||||
|
const USER_MEMBER = "user-member";
|
||||||
|
const USER_MEMBER_2 = "user-member-2";
|
||||||
|
|
||||||
|
const providerOwned = {
|
||||||
|
gitProviderId: "gp-owned",
|
||||||
|
userId: USER_MEMBER,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
};
|
||||||
|
const providerShared = {
|
||||||
|
gitProviderId: "gp-shared",
|
||||||
|
userId: USER_OWNER,
|
||||||
|
sharedWithOrganization: true,
|
||||||
|
};
|
||||||
|
const providerPrivate = {
|
||||||
|
gitProviderId: "gp-private",
|
||||||
|
userId: USER_OWNER,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
};
|
||||||
|
const providerOtherMember = {
|
||||||
|
gitProviderId: "gp-other",
|
||||||
|
userId: USER_MEMBER_2,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const allProviders = [
|
||||||
|
providerOwned,
|
||||||
|
providerShared,
|
||||||
|
providerPrivate,
|
||||||
|
providerOtherMember,
|
||||||
|
];
|
||||||
|
|
||||||
|
function session(userId: string) {
|
||||||
|
return { userId, activeOrganizationId: ORG_ID };
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
mockDb.query.gitProvider.findMany.mockResolvedValue(allProviders);
|
||||||
|
mockHasValidLicense.mockResolvedValue(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getAccessibleGitProviderIds", () => {
|
||||||
|
describe("owner", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "owner",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns all org providers", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_OWNER));
|
||||||
|
expect(ids).toEqual(new Set(allProviders.map((p) => p.gitProviderId)));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes providers owned by other members", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_OWNER));
|
||||||
|
expect(ids.has(providerOwned.gitProviderId)).toBe(true);
|
||||||
|
expect(ids.has(providerOtherMember.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("admin", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "admin",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns all org providers", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_ADMIN));
|
||||||
|
expect(ids).toEqual(new Set(allProviders.map((p) => p.gitProviderId)));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes providers owned by other members — fixes issue #4469", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_ADMIN));
|
||||||
|
expect(ids.has(providerPrivate.gitProviderId)).toBe(true);
|
||||||
|
expect(ids.has(providerOtherMember.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("member without enterprise license", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [providerPrivate.gitProviderId],
|
||||||
|
});
|
||||||
|
mockHasValidLicense.mockResolvedValue(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can access their own provider", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerOwned.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can access shared providers", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerShared.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cannot access private providers of other users even if assigned (no license)", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerPrivate.gitProviderId)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cannot access providers of other members", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerOtherMember.gitProviderId)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("member with enterprise license", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockHasValidLicense.mockResolvedValue(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can access provider explicitly assigned to them", async () => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [providerPrivate.gitProviderId],
|
||||||
|
});
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerPrivate.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cannot access provider not assigned and not shared", async () => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerPrivate.gitProviderId)).toBe(false);
|
||||||
|
expect(ids.has(providerOtherMember.gitProviderId)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can access shared provider even without explicit assignment", async () => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerShared.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can access own provider regardless of assignments", async () => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerOwned.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cannot access provider of other member even with license but no assignment", async () => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerOtherMember.gitProviderId)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("member with no member record", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue(null);
|
||||||
|
mockHasValidLicense.mockResolvedValue(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("only returns own providers and shared ones", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerOwned.gitProviderId)).toBe(true);
|
||||||
|
expect(ids.has(providerShared.gitProviderId)).toBe(true);
|
||||||
|
expect(ids.has(providerPrivate.gitProviderId)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("enterprise license — member assigned to a provider they do not own", () => {
|
||||||
|
// getAccessibleGitProviderIds still returns the provider (member can connect NEW deploys)
|
||||||
|
it("member assigned to owner's private provider can USE the provider for new deploys", async () => {
|
||||||
|
mockHasValidLicense.mockResolvedValue(true);
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [providerPrivate.gitProviderId],
|
||||||
|
});
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerPrivate.gitProviderId)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("member NOT assigned to owner's private provider cannot use it at all", async () => {
|
||||||
|
mockHasValidLicense.mockResolvedValue(true);
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "member",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_MEMBER));
|
||||||
|
expect(ids.has(providerPrivate.gitProviderId)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("empty org", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDb.query.gitProvider.findMany.mockResolvedValue([]);
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({
|
||||||
|
role: "admin",
|
||||||
|
accessedGitProviders: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns empty set when org has no providers", async () => {
|
||||||
|
const ids = await getAccessibleGitProviderIds(session(USER_ADMIN));
|
||||||
|
expect(ids.size).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("canEditDeployGitSource", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
mockHasValidLicense.mockResolvedValue(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("owner", () => {
|
||||||
|
it("can edit deploy using any provider", async () => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({ role: "owner" });
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
providerPrivate.gitProviderId,
|
||||||
|
session(USER_OWNER),
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("admin", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({ role: "admin" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cannot edit deploy using owner's private provider (not shared)", async () => {
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue({
|
||||||
|
userId: USER_OWNER,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
});
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
providerPrivate.gitProviderId,
|
||||||
|
session(USER_ADMIN),
|
||||||
|
);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can edit deploy using a provider shared with the org", async () => {
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue({
|
||||||
|
userId: USER_OWNER,
|
||||||
|
sharedWithOrganization: true,
|
||||||
|
});
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
providerShared.gitProviderId,
|
||||||
|
session(USER_ADMIN),
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can edit deploy using their own provider", async () => {
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue({
|
||||||
|
userId: USER_ADMIN,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
});
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
"gp-admin-owned",
|
||||||
|
session(USER_ADMIN),
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("member", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDb.query.member.findFirst.mockResolvedValue({ role: "member" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can edit deploy using their own provider", async () => {
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue({
|
||||||
|
userId: USER_MEMBER,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
});
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
providerOwned.gitProviderId,
|
||||||
|
session(USER_MEMBER),
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can edit deploy using a provider shared with the org", async () => {
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue({
|
||||||
|
userId: USER_OWNER,
|
||||||
|
sharedWithOrganization: true,
|
||||||
|
});
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
providerShared.gitProviderId,
|
||||||
|
session(USER_MEMBER),
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cannot edit deploy using owner's private provider even with enterprise license and assignment", async () => {
|
||||||
|
// This is the key case: enterprise, provider del owner, no compartido,
|
||||||
|
// member tiene accessedGitProviders asignado — pero NO puede cambiar la branch del deploy del owner
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue({
|
||||||
|
userId: USER_OWNER,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
});
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
providerPrivate.gitProviderId,
|
||||||
|
session(USER_MEMBER),
|
||||||
|
);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cannot edit deploy using another member's private provider", async () => {
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue({
|
||||||
|
userId: USER_MEMBER_2,
|
||||||
|
sharedWithOrganization: false,
|
||||||
|
});
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
providerOtherMember.gitProviderId,
|
||||||
|
session(USER_MEMBER),
|
||||||
|
);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false if provider does not exist", async () => {
|
||||||
|
mockDb.query.gitProvider.findFirst.mockResolvedValue(null);
|
||||||
|
const result = await canEditDeployGitSource(
|
||||||
|
"nonexistent-id",
|
||||||
|
session(USER_MEMBER),
|
||||||
|
);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
deleteAllMiddlewares,
|
deleteAllMiddlewares,
|
||||||
findApplicationById,
|
findApplicationById,
|
||||||
findEnvironmentById,
|
findEnvironmentById,
|
||||||
findGitProviderById,
|
|
||||||
findProjectById,
|
findProjectById,
|
||||||
getAccessibleServerIds,
|
getAccessibleServerIds,
|
||||||
getApplicationStats,
|
getApplicationStats,
|
||||||
@@ -31,6 +30,7 @@ import {
|
|||||||
writeConfigRemote,
|
writeConfigRemote,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { db } from "@dokploy/server/db";
|
import { db } from "@dokploy/server/db";
|
||||||
|
import { canEditDeployGitSource } from "@dokploy/server/services/git-provider";
|
||||||
import {
|
import {
|
||||||
addNewService,
|
addNewService,
|
||||||
checkServiceAccess,
|
checkServiceAccess,
|
||||||
@@ -174,13 +174,11 @@ export const applicationRouter = createTRPCRouter({
|
|||||||
const gitProviderId = getGitProviderId();
|
const gitProviderId = getGitProviderId();
|
||||||
|
|
||||||
if (gitProviderId) {
|
if (gitProviderId) {
|
||||||
try {
|
const canEdit = await canEditDeployGitSource(
|
||||||
const gitProvider = await findGitProviderById(gitProviderId);
|
gitProviderId,
|
||||||
if (gitProvider.userId !== ctx.session.userId) {
|
ctx.session,
|
||||||
hasGitProviderAccess = false;
|
);
|
||||||
unauthorizedProvider = application.sourceType;
|
if (!canEdit) {
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
hasGitProviderAccess = false;
|
hasGitProviderAccess = false;
|
||||||
unauthorizedProvider = application.sourceType;
|
unauthorizedProvider = application.sourceType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
findComposeById,
|
findComposeById,
|
||||||
findDomainsByComposeId,
|
findDomainsByComposeId,
|
||||||
findEnvironmentById,
|
findEnvironmentById,
|
||||||
findGitProviderById,
|
|
||||||
findProjectById,
|
findProjectById,
|
||||||
findServerById,
|
findServerById,
|
||||||
getAccessibleServerIds,
|
getAccessibleServerIds,
|
||||||
@@ -34,6 +33,7 @@ import {
|
|||||||
updateDeploymentStatus,
|
updateDeploymentStatus,
|
||||||
} from "@dokploy/server";
|
} from "@dokploy/server";
|
||||||
import { db } from "@dokploy/server/db";
|
import { db } from "@dokploy/server/db";
|
||||||
|
import { canEditDeployGitSource } from "@dokploy/server/services/git-provider";
|
||||||
import {
|
import {
|
||||||
addNewService,
|
addNewService,
|
||||||
checkServiceAccess,
|
checkServiceAccess,
|
||||||
@@ -173,13 +173,11 @@ export const composeRouter = createTRPCRouter({
|
|||||||
const gitProviderId = getGitProviderId();
|
const gitProviderId = getGitProviderId();
|
||||||
|
|
||||||
if (gitProviderId) {
|
if (gitProviderId) {
|
||||||
try {
|
const canEdit = await canEditDeployGitSource(
|
||||||
const gitProvider = await findGitProviderById(gitProviderId);
|
gitProviderId,
|
||||||
if (gitProvider.userId !== ctx.session.userId) {
|
ctx.session,
|
||||||
hasGitProviderAccess = false;
|
);
|
||||||
unauthorizedProvider = compose.sourceType;
|
if (!canEdit) {
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
hasGitProviderAccess = false;
|
hasGitProviderAccess = false;
|
||||||
unauthorizedProvider = compose.sourceType;
|
unauthorizedProvider = compose.sourceType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,38 @@ export const updateGitProvider = async (
|
|||||||
.then((response) => response[0]);
|
.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: {
|
export const getAccessibleGitProviderIds = async (session: {
|
||||||
userId: string;
|
userId: string;
|
||||||
activeOrganizationId: string;
|
activeOrganizationId: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user