@@ -11,7 +11,7 @@ import {
1111} from "~/services/apiAuth.server" ;
1212import { rbac } from "~/services/rbac.server" ;
1313
14- type EnvironmentScopedResource = "envvars" | "apiKeys" | "deployments" ;
14+ type EnvironmentScopedResource = "envvars" | "apiKeys" | "deployments" | "branches" ;
1515
1616type EnvironmentScopedAuthentication =
1717 | { ok : true ; authentication : AuthenticationResult }
@@ -112,11 +112,11 @@ const RESOURCE_LABELS: Record<EnvironmentScopedResource, string> = {
112112 envvars : "environment variables" ,
113113 apiKeys : "API keys" ,
114114 deployments : "deployments" ,
115+ branches : "branches" ,
115116} ;
116117
117118/**
118- * Env-tier RBAC for environment-scoped API routes (env vars, and the endpoints
119- * that hand out an environment's secret credentials).
119+ * Env-tier RBAC for environment-scoped API routes.
120120 *
121121 * Machine credentials (an environment's API key) are authorized by the
122122 * ability returned by the RBAC bearer controller. A personal
@@ -145,11 +145,13 @@ export async function authorizePatEnvironmentAccess({
145145 organizationId : string ;
146146 projectId : string ;
147147 envType : RuntimeEnvironmentType ;
148- resource : EnvironmentScopedResource ;
148+ resource : EnvironmentScopedResource | EnvironmentScopedResource [ ] ;
149149 action : "read" | "write" ;
150150 // Controller ability for API-key credentials. Absent for PAT/OAT callers.
151151 ability ?: RbacAbility ;
152152} ) : Promise < Response | undefined > {
153+ const resources = Array . isArray ( resource ) ? resource : [ resource ] ;
154+ const resourceLabel = RESOURCE_LABELS [ resources [ 0 ] ?? "branches" ] ;
153155 const bearer = request . headers
154156 . get ( "Authorization" )
155157 ?. replace ( / ^ B e a r e r / , "" )
@@ -159,12 +161,12 @@ export async function authorizePatEnvironmentAccess({
159161 // Machine API keys are authorized by their controller ability. Root keys and
160162 // ungranted additional keys are permissive; granted keys are restricted.
161163 if ( authType === "apiKey" ) {
162- if ( ability ?. can ( action , { type : resource } ) ) {
164+ if ( resources . some ( ( candidate ) => ability ?. can ( action , { type : candidate } ) ) ) {
163165 return undefined ;
164166 }
165167 return json (
166168 {
167- error : `You don't have permission to access this environment's ${ RESOURCE_LABELS [ resource ] } .` ,
169+ error : `You don't have permission to access this environment's ${ resourceLabel } .` ,
168170 } ,
169171 { status : 403 }
170172 ) ;
@@ -183,10 +185,10 @@ export async function authorizePatEnvironmentAccess({
183185 return json ( { error : userAuth . error } , { status : userAuth . status } ) ;
184186 }
185187
186- if ( ! userAuth . ability . can ( action , { type : resource , envType } ) ) {
188+ if ( ! resources . some ( ( candidate ) => userAuth . ability . can ( action , { type : candidate , envType } ) ) ) {
187189 return json (
188190 {
189- error : `You don't have permission to access this environment's ${ RESOURCE_LABELS [ resource ] } .` ,
191+ error : `You don't have permission to access this environment's ${ resourceLabel } .` ,
190192 } ,
191193 { status : 403 }
192194 ) ;
0 commit comments