Skip to content

Commit 344710d

Browse files
committed
fix(webapp): resolve the org scoped to membership on the settings routes
The runtime-updates loader and the settings side-menu deployment gate both resolved the organization from the slug alone and relied on the RBAC authorization check to reject a non-member. Use the membership-scoped resolver instead, matching the Team settings loader: the ability check enforces the role, the membership filter is the tenant floor. An unresolved org yields no scope, which the dashboard route builder and the side-menu helper both already fail closed on.
1 parent d44da64 commit 344710d

2 files changed

Lines changed: 11 additions & 5 deletions

File tree

  • apps/webapp/app/routes
    • _app.orgs.$organizationSlug.settings.runtime-updates
    • _app.orgs.$organizationSlug.settings

apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.runtime-updates/route.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { NODE_RUNTIME_UPDATE_MAJOR } from "@trigger.dev/core/v3";
22
import { typedjson, useTypedLoaderData } from "remix-typedjson";
3-
import { resolveOrgIdFromSlug } from "~/models/organization.server";
3+
import { resolveOrgIdFromSlugForUser } from "~/models/organization.server";
44
import { listCurrentProductionProjectRuntimes } from "~/services/projectRuntimeUpdates.server";
55
import { dashboardLoader } from "~/services/routeBuilders/dashboardBuilder";
6+
import { getUserId } from "~/services/session.server";
67
import { pageMeta } from "~/utils/pageTitle";
78
import { OrganizationParamsSchema } from "~/utils/pathBuilder";
89
import { type ProjectRuntimeRow, RuntimeUpdatesPage } from "./RuntimeUpdatesPage";
@@ -12,8 +13,12 @@ export const meta = pageMeta("Projects");
1213
export const loader = dashboardLoader(
1314
{
1415
params: OrganizationParamsSchema,
15-
context: async (params) => {
16-
const organizationId = await resolveOrgIdFromSlug(params.organizationSlug);
16+
// Membership-scoped resolve, like the Team settings loader: the RBAC gate below enforces the
17+
// role, this is the tenant floor. An unresolved org yields no scope, which fails closed.
18+
context: async (params, request) => {
19+
const userId = await getUserId(request);
20+
if (!userId) return {};
21+
const organizationId = await resolveOrgIdFromSlugForUser(params.organizationSlug, userId);
1722
return organizationId ? { organizationId } : {};
1823
},
1924
authorization: {

apps/webapp/app/routes/_app.orgs.$organizationSlug.settings/route.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
OrganizationSettingsSideMenu,
1111
} from "~/components/navigation/OrganizationSettingsSideMenu";
1212
import { useOrganization } from "~/hooks/useOrganizations";
13-
import { resolveOrgIdFromSlug } from "~/models/organization.server";
13+
import { resolveOrgIdFromSlugForUser } from "~/models/organization.server";
1414
import { organizationHasProjectRuntimeUpdate } from "~/services/projectRuntimeUpdates.server";
1515
import { rbac } from "~/services/rbac.server";
1616
import { requireUserId } from "~/services/session.server";
@@ -29,7 +29,8 @@ async function canReadDeployments({
2929
userId: string;
3030
organizationSlug: string;
3131
}) {
32-
const organizationId = await resolveOrgIdFromSlug(organizationSlug);
32+
// Membership-scoped so the dot is never computed against an org the user is not in.
33+
const organizationId = await resolveOrgIdFromSlugForUser(organizationSlug, userId);
3334
if (!organizationId) {
3435
return false;
3536
}

0 commit comments

Comments
 (0)