@@ -13,6 +13,10 @@ const mocks = vi.hoisted(() => ({
1313 authenticatePat : vi . fn ( ) ,
1414 createOrganization : vi . fn ( ) ,
1515 findManyProjects : vi . fn ( ) ,
16+ env : { SESSION_SECRET : "test-session-secret" , ORG_CREATION_API_ENABLED : "1" } as {
17+ SESSION_SECRET : string ;
18+ ORG_CREATION_API_ENABLED ?: string ;
19+ } ,
1620} ) ) ;
1721
1822vi . mock ( "~/services/rbac.server" , ( ) => ( {
@@ -25,9 +29,7 @@ vi.mock("~/db.server", () => ({
2529 prisma : { project : { findMany : mocks . findManyProjects } } ,
2630 $replica : { } ,
2731} ) ) ;
28- vi . mock ( "~/env.server" , ( ) => ( {
29- env : { SESSION_SECRET : "test-session-secret" , ORG_CREATION_API_ENABLED : "1" } ,
30- } ) ) ;
32+ vi . mock ( "~/env.server" , ( ) => ( { env : mocks . env } ) ) ;
3133vi . mock ( "~/models/organization.server" , ( ) => ( { createOrganization : mocks . createOrganization } ) ) ;
3234vi . mock ( "~/services/personalAccessToken.server" , ( ) => ( {
3335 updateLastAccessedAtIfStale : vi . fn ( ) ,
@@ -177,6 +179,22 @@ describe("creating an organization over the API", () => {
177179 expect ( result . body . slug ) . toBe ( "new-org" ) ;
178180 } ) ;
179181
182+ // The env gate runs before the capability gate, so an install with the API disabled tells
183+ // every caller the same thing: the route does not exist. A capped token must not learn from a
184+ // 403 that it would have been the only thing standing in its way.
185+ it ( "hides the route from a capped token when the API is disabled" , async ( ) => {
186+ mocks . env . ORG_CREATION_API_ENABLED = undefined ;
187+
188+ try {
189+ const result = await createOrg ( [ "read:all" ] ) ;
190+
191+ expect ( result . status ) . toBe ( 404 ) ;
192+ expect ( mocks . createOrganization ) . not . toHaveBeenCalled ( ) ;
193+ } finally {
194+ mocks . env . ORG_CREATION_API_ENABLED = "1" ;
195+ }
196+ } ) ;
197+
180198 it ( "still admits a token that carries the universal grant" , async ( ) => {
181199 const result = await createOrg ( [ "admin" ] ) ;
182200
0 commit comments