Skip to content

Commit bbf86c8

Browse files
committed
fix(webapp): close two RBAC scope gaps from review
Add writableEnvironmentIds to the env vars page loader data type so the create form sees write access rather than an undefined field. Guard the prompt action on a resolved org before its per-intent ability checks, since it has no top-level authorization block and so skips the builder fail-closed.
1 parent fd6d0bf commit bbf86c8

2 files changed

Lines changed: 11 additions & 1 deletion

File tree

  • apps/webapp/app/routes
    • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables
    • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ export type EnvironmentVariablesPageLoaderData = {
114114
vercelIntegration: PageVercelIntegration | null;
115115
// Environment ids whose env vars the current role can read.
116116
accessibleEnvironmentIds: string[];
117+
// Environment ids whose env vars the current role can write (create/edit/delete).
118+
writableEnvironmentIds: string[];
117119
};
118120

119121
export const environmentVariablesRouteId =

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,17 @@ export const action = dashboardAction(
130130
return organizationId ? { organizationId } : {};
131131
},
132132
},
133-
async ({ request, params, user, ability }) => {
133+
async ({ request, params, user, ability, context }) => {
134134
const { organizationSlug, projectParam, envParam, promptSlug } = params;
135135

136+
// This action checks permissions per intent inline (below) rather than via
137+
// a top-level authorization block, so the builder's fail-closed scope guard
138+
// doesn't run. Enforce it here: without a resolved org the inline
139+
// ability.can checks would evaluate an unscoped ability.
140+
if (!context.organizationId) {
141+
return json({ error: "Unauthorized" }, { status: 403 });
142+
}
143+
136144
const project = await findProjectBySlug(organizationSlug, projectParam, user.id);
137145
if (!project) return json({ error: "Project not found" }, { status: 404 });
138146

0 commit comments

Comments
 (0)