diff --git a/src/__tests__/integration/api/workspaces-stakgraph.test.ts b/src/__tests__/integration/api/workspaces-stakgraph.test.ts index 5151e6edb6..066dc8aa61 100644 --- a/src/__tests__/integration/api/workspaces-stakgraph.test.ts +++ b/src/__tests__/integration/api/workspaces-stakgraph.test.ts @@ -115,7 +115,7 @@ const DEFAULT_DOCKERFILE = "FROM ghcr.io/stakwork/staklink-js:v0.1.2\nRUN echo 'original'"; const UPDATED_DOCKERFILE = "FROM node:20-alpine\nRUN echo 'updated'"; const DEFAULT_DOCKER_COMPOSE = - "version: '3.8'\nservices:\n app:\n build: ."; + "version: '3.8'\nnetworks:\n app_network:\n driver: bridge\nservices: {}"; const UPDATED_DOCKER_COMPOSE = "version: '3.9'\nservices:\n app:\n build: .\n ports:\n - '3000:3000'"; const DEFAULT_DEVCONTAINER = JSON.stringify({ diff --git a/src/app/api/orgs/[githubLogin]/canvas/[ref]/route.ts b/src/app/api/orgs/[githubLogin]/canvas/[ref]/route.ts index 1c8b4e85ea..b237cc16cc 100644 --- a/src/app/api/orgs/[githubLogin]/canvas/[ref]/route.ts +++ b/src/app/api/orgs/[githubLogin]/canvas/[ref]/route.ts @@ -20,9 +20,26 @@ function validateCanvasData(value: unknown): value is { return true; } -async function findOrg(githubLogin: string) { - return db.sourceControlOrg.findUnique({ - where: { githubLogin }, +/** + * Resolve the org by githubLogin while simultaneously verifying the caller + * has at least one workspace in it. Returns null when the org does not exist + * OR the user has no workspace there (both cases → 404 to avoid leaking + * whether the org exists at all). + */ +async function findOrgForUser(githubLogin: string, userId: string) { + return db.sourceControlOrg.findFirst({ + where: { + githubLogin, + workspaces: { + some: { + deleted: false, + OR: [ + { ownerId: userId }, + { members: { some: { userId, leftAt: null } } }, + ], + }, + }, + }, select: { id: true }, }); } @@ -48,7 +65,7 @@ export async function GET( } try { - const org = await findOrg(githubLogin); + const org = await findOrgForUser(githubLogin, userOrResponse.id); if (!org) { return NextResponse.json({ error: "Organization not found" }, { status: 404 }); } @@ -88,7 +105,7 @@ export async function PUT( return NextResponse.json({ error: "Invalid canvas data" }, { status: 400 }); } - const org = await findOrg(githubLogin); + const org = await findOrgForUser(githubLogin, userOrResponse.id); if (!org) { return NextResponse.json({ error: "Organization not found" }, { status: 404 }); } diff --git a/src/app/api/orgs/[githubLogin]/canvas/route.ts b/src/app/api/orgs/[githubLogin]/canvas/route.ts index 12cfe70baf..443ecc6731 100644 --- a/src/app/api/orgs/[githubLogin]/canvas/route.ts +++ b/src/app/api/orgs/[githubLogin]/canvas/route.ts @@ -16,9 +16,26 @@ function validateCanvasData(value: unknown): value is { return true; } -async function findOrg(githubLogin: string) { - return db.sourceControlOrg.findUnique({ - where: { githubLogin }, +/** + * Resolve the org by githubLogin while simultaneously verifying the caller + * has at least one workspace in it. Returns null when the org does not exist + * OR the user has no workspace there (both cases → 404 to avoid leaking + * whether the org exists at all). + */ +async function findOrgForUser(githubLogin: string, userId: string) { + return db.sourceControlOrg.findFirst({ + where: { + githubLogin, + workspaces: { + some: { + deleted: false, + OR: [ + { ownerId: userId }, + { members: { some: { userId, leftAt: null } } }, + ], + }, + }, + }, select: { id: true }, }); } @@ -45,7 +62,7 @@ export async function GET( } try { - const org = await findOrg(githubLogin); + const org = await findOrgForUser(githubLogin, userOrResponse.id); if (!org) { return NextResponse.json({ error: "Organization not found" }, { status: 404 }); } @@ -85,7 +102,7 @@ export async function PUT( return NextResponse.json({ error: "Invalid canvas data" }, { status: 400 }); } - const org = await findOrg(githubLogin); + const org = await findOrgForUser(githubLogin, userOrResponse.id); if (!org) { return NextResponse.json({ error: "Organization not found" }, { status: 404 }); } diff --git a/src/utils/devContainerUtils.ts b/src/utils/devContainerUtils.ts index 0e6c7c46c9..299900a671 100644 --- a/src/utils/devContainerUtils.ts +++ b/src/utils/devContainerUtils.ts @@ -334,19 +334,7 @@ export function dockerComposeContent() { networks: app_network: driver: bridge -services: - app: - build: - context: . - dockerfile: Dockerfile - volumes: - - ../..:/workspaces:cached - command: sleep infinity - networks: - - app_network - extra_hosts: - - "localhost:172.17.0.1" - - "host.docker.internal:host-gateway" +services: {} `; }