@@ -2100,6 +2100,68 @@ describe("codex command", () => {
21002100 } ) ;
21012101 } ) ;
21022102
2103+ it ( "rejects Computer Use installation from non-owner non-admin callers" , async ( ) => {
2104+ const installCodexComputerUse = vi . fn ( async ( ) => computerUseReadyStatus ( ) ) ;
2105+ const ctx = createContext (
2106+ "computer-use install --source attacker/marketplace --plugin untrusted" ,
2107+ undefined ,
2108+ { senderIsOwner : false , gatewayClientScopes : [ "operator.write" ] } ,
2109+ ) ;
2110+
2111+ const result = await handleCodexCommand ( ctx , {
2112+ deps : createDeps ( { installCodexComputerUse } ) ,
2113+ } ) ;
2114+
2115+ expectResultTextContains ( result , "Only an owner or operator.admin" ) ;
2116+ expect ( installCodexComputerUse ) . not . toHaveBeenCalled ( ) ;
2117+ } ) ;
2118+
2119+ it ( "keeps Computer Use status overrides read-only for non-owner callers" , async ( ) => {
2120+ const readCodexComputerUseStatus = vi . fn ( async ( ) => computerUseReadyStatus ( ) ) ;
2121+ const installCodexComputerUse = vi . fn ( async ( ) => computerUseReadyStatus ( ) ) ;
2122+ const ctx = createContext (
2123+ "computer-use status --source existing/source --marketplace-path /existing/marketplace --marketplace existing --plugin existing-plugin --mcp-server existing-server" ,
2124+ undefined ,
2125+ {
2126+ senderIsOwner : false ,
2127+ gatewayClientScopes : [ "operator.write" ] ,
2128+ } ,
2129+ ) ;
2130+
2131+ const result = await handleCodexCommand ( ctx , {
2132+ deps : createDeps ( { readCodexComputerUseStatus, installCodexComputerUse } ) ,
2133+ } ) ;
2134+
2135+ expectResultTextContains ( result , "Computer Use: ready" ) ;
2136+ expect ( readCodexComputerUseStatus ) . toHaveBeenCalledWith ( {
2137+ pluginConfig : undefined ,
2138+ forceEnable : true ,
2139+ overrides : {
2140+ marketplaceSource : "existing/source" ,
2141+ marketplacePath : "/existing/marketplace" ,
2142+ marketplaceName : "existing" ,
2143+ pluginName : "existing-plugin" ,
2144+ mcpServerName : "existing-server" ,
2145+ } ,
2146+ } ) ;
2147+ expect ( installCodexComputerUse ) . not . toHaveBeenCalled ( ) ;
2148+ } ) ;
2149+
2150+ it ( "allows operator.admin gateway callers to install Codex Computer Use" , async ( ) => {
2151+ const installCodexComputerUse = vi . fn ( async ( ) => computerUseReadyStatus ( ) ) ;
2152+ const ctx = createContext ( "computer-use install" , undefined , {
2153+ senderIsOwner : false ,
2154+ gatewayClientScopes : [ "operator.admin" ] ,
2155+ } ) ;
2156+
2157+ const result = await handleCodexCommand ( ctx , {
2158+ deps : createDeps ( { installCodexComputerUse } ) ,
2159+ } ) ;
2160+
2161+ expectResultTextContains ( result , "Computer Use: ready" ) ;
2162+ expect ( installCodexComputerUse ) . toHaveBeenCalledOnce ( ) ;
2163+ } ) ;
2164+
21032165 it ( "shows help when Computer Use option values are missing" , async ( ) => {
21042166 const installCodexComputerUse = vi . fn ( async ( ) => computerUseReadyStatus ( ) ) ;
21052167
0 commit comments