Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions apps/dokploy/__test__/api/no-session-error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ vi.mock("@dokploy/server/services/known-secrets", () => ({
resetKnownSecretMatcherCache: () => {},
}));

vi.mock("@/server/api/utils/super-session", async (original) => ({
...(await original<object>()),
enforceProcedureSuperSession: async () => {},
}));

const {
adminProcedure,
cliProcedure,
Expand Down
5 changes: 0 additions & 5 deletions apps/dokploy/__test__/api/no-session-polling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ vi.mock("@dokploy/server/services/known-secrets", () => ({
resetKnownSecretMatcherCache: () => {},
}));

vi.mock("@/server/api/utils/super-session", async (original) => ({
...(await original<object>()),
enforceProcedureSuperSession: async () => {},
}));

const {
createTRPCContext,
createTRPCRouter,
Expand Down
45 changes: 2 additions & 43 deletions apps/dokploy/__test__/docker/docker-router-security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const mocks = vi.hoisted(() => ({
assertLocalDockerContainerAccess: vi.fn(),
assertLocalDockerContainerOrSystemAccess: vi.fn(),
checkPermission: vi.fn(),
checkProtectedResourceAccess: vi.fn(),
containerKill: vi.fn(),
containerRemove: vi.fn(),
containerRestart: vi.fn(),
Expand Down Expand Up @@ -66,17 +65,7 @@ vi.mock("@/server/api/utils/local-docker-access", () => ({
mocks.assertLocalDockerContainerOrSystemAccess,
}));

vi.mock("@dokploy/server/services/super-password", async (importOriginal) => ({
...(await importOriginal<
typeof import("@dokploy/server/services/super-password")
>()),
checkProtectedResourceAccess: mocks.checkProtectedResourceAccess,
}));

const { dockerRouter } = await import("../../server/api/routers/docker");
const { getSuperSessionDenial } = await import(
"@dokploy/server/services/super-password"
);

const createCaller = (authMethod: "session" | "api-key" = "session") =>
dockerRouter.createCaller({
Expand Down Expand Up @@ -292,9 +281,6 @@ describe("docker router container file and event boundary", () => {
(ctx, containerId, permission) =>
mocks.assertLocalDockerContainerAccess(ctx, containerId, permission),
);
mocks.checkProtectedResourceAccess.mockResolvedValue(
"super-session-required",
);
});

const fileCalls = (
Expand Down Expand Up @@ -467,28 +453,7 @@ describe("docker router container file and event boundary", () => {
);
});

it("denies system container files without an open super session", async () => {
for (const call of fileCalls(createCaller())) {
const error = await call.run().then(
() => null,
(caught: unknown) => caught,
);
expect(error, call.name).toMatchObject({ code: "FORBIDDEN" });
expect(getSuperSessionDenial(error), call.name).toBe(
"super-session-required",
);
expect(call.sideEffect, call.name).not.toHaveBeenCalled();
}
expect(mocks.checkProtectedResourceAccess).toHaveBeenCalledWith({
userId: "user-1",
viaApiKey: false,
});
expect(mocks.audit).not.toHaveBeenCalled();
});

it("opens system container files for owners and admins with an open super session", async () => {
mocks.checkProtectedResourceAccess.mockResolvedValue(null);

it("opens system container files for owners and admins", async () => {
for (const call of fileCalls(createCaller())) {
await call.run();
expect(call.sideEffect, call.name).toHaveBeenCalledWith(
Expand All @@ -501,8 +466,7 @@ describe("docker router container file and event boundary", () => {
}
});

it("keeps members out even with an open super session", async () => {
mocks.checkProtectedResourceAccess.mockResolvedValue(null);
it("keeps members out of system container files", async () => {
mocks.findMemberByUserId.mockResolvedValue({ role: "member" });

for (const call of fileCalls(createCaller())) {
Expand All @@ -514,11 +478,6 @@ describe("docker router container file and event boundary", () => {
});

it("never opens system container files through an API key", async () => {
mocks.checkProtectedResourceAccess.mockImplementation(
async ({ viaApiKey }: { viaApiKey: boolean }) =>
viaApiKey ? "browser-session-required" : null,
);

for (const call of fileCalls(createCaller("api-key"))) {
await expect(call.run(), call.name).rejects.toMatchObject({
code: "FORBIDDEN",
Expand Down
35 changes: 14 additions & 21 deletions apps/dokploy/__test__/docker/docker-volume-router-security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const mocks = vi.hoisted(() => ({
audit: vi.fn(),
assertLocalDockerContainerAccess: vi.fn(),
checkPermission: vi.fn(),
checkProtectedResourceAccess: vi.fn(),
deleteVolumeFile: vi.fn(),
isLocalSystemDockerVolume: vi.fn(),
findMemberByUserId: vi.fn(),
Expand Down Expand Up @@ -46,34 +45,31 @@ vi.mock("@/server/api/utils/local-docker-access", () => ({
isLocalSystemDockerVolume: mocks.isLocalSystemDockerVolume,
}));

vi.mock("@dokploy/server/services/super-password", async (importOriginal) => ({
...(await importOriginal<
typeof import("@dokploy/server/services/super-password")
>()),
checkProtectedResourceAccess: mocks.checkProtectedResourceAccess,
}));

const { dockerVolumeRouter } = await import(
"../../server/api/routers/docker-volume"
);

const createCaller = () =>
const createCaller = (authMethod: "session" | "api-key" = "session") =>
dockerVolumeRouter.createCaller({
db: {},
req: {},
res: {},
session: {
userId: "user-1",
activeOrganizationId: "org-1",
...(authMethod === "api-key" ? { authMethod } : {}),
},
user: {
id: "user-1",
role: "member",
},
} as never);

const volumeCalls = (serverId?: string) => {
const caller = createCaller();
const volumeCalls = (
serverId?: string,
authMethod: "session" | "api-key" = "session",
) => {
const caller = createCaller(authMethod);
return [
{
name: "listVolumeFiles",
Expand Down Expand Up @@ -133,9 +129,6 @@ describe("docker volume router access boundary", () => {
mocks.listVolumeFiles.mockResolvedValue([]);
mocks.readVolumeFile.mockResolvedValue({ content: "" });
mocks.isLocalSystemDockerVolume.mockResolvedValue(false);
mocks.checkProtectedResourceAccess.mockResolvedValue(
"super-session-required",
);
});

it("denies non-admin volume file access and removal on the local host", async () => {
Expand Down Expand Up @@ -214,15 +207,17 @@ describe("docker volume router access boundary", () => {
});

describe("panel system volumes", () => {
const fileCalls = () =>
volumeCalls().filter((call) => call.name !== "removeVolume");
const fileCalls = (authMethod?: "session" | "api-key") =>
volumeCalls(undefined, authMethod).filter(
(call) => call.name !== "removeVolume",
);

beforeEach(() => {
mocks.isLocalSystemDockerVolume.mockResolvedValue(true);
});

it("denies local system volume files without an open super session", async () => {
for (const call of fileCalls()) {
it("never opens local system volume files through an API key", async () => {
for (const call of fileCalls("api-key")) {
await expect(call.run(), call.name).rejects.toMatchObject({
code: "FORBIDDEN",
});
Expand All @@ -231,9 +226,7 @@ describe("docker volume router access boundary", () => {
expect(mocks.isLocalSystemDockerVolume).toHaveBeenCalledWith("data");
});

it("opens local system volume files with an open super session", async () => {
mocks.checkProtectedResourceAccess.mockResolvedValue(null);

it("opens local system volume files for owners and admins", async () => {
for (const call of fileCalls()) {
await call.run();
expect(call.sideEffect, call.name).toHaveBeenCalled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe("local Docker system containers", () => {
mocks.getConfig.mockResolvedValue(container);
const assertSystemAccess = vi
.fn()
.mockRejectedValue(new Error("super session required"));
.mockRejectedValue(new Error("system access denied"));

await expect(
assertLocalDockerContainerOrSystemAccess(
Expand All @@ -97,7 +97,7 @@ describe("local Docker system containers", () => {
"write",
assertSystemAccess,
),
).rejects.toThrow("super session required");
).rejects.toThrow("system access denied");
expect(assertSystemAccess).toHaveBeenCalledTimes(1);

assertSystemAccess.mockResolvedValue(undefined);
Expand Down
Loading