@@ -377,6 +377,45 @@ describe("resolveCommandSecretRefsViaGateway", () => {
377377 }
378378 } ) ;
379379
380+ it ( "does not retry old gateways without forced active path support" , async ( ) => {
381+ const envKey = "WEB_SEARCH_FIRECRAWL_OLD_GATEWAY_ONLY" ;
382+ await withEnvValue ( envKey , undefined , async ( ) => {
383+ callGateway . mockRejectedValueOnce (
384+ new Error ( "secrets.resolve invalid request: invalid secrets.resolve params" ) ,
385+ ) ;
386+
387+ await expect (
388+ resolveCommandSecretRefsViaGateway ( {
389+ config : {
390+ tools : {
391+ web : {
392+ search : {
393+ provider : "exa" ,
394+ } ,
395+ } ,
396+ } ,
397+ plugins : {
398+ entries : {
399+ firecrawl : {
400+ config : {
401+ webSearch : {
402+ apiKey : { source : "env" , provider : "default" , id : envKey } ,
403+ } ,
404+ } ,
405+ } ,
406+ } ,
407+ } ,
408+ } as unknown as OpenClawConfig ,
409+ commandName : "infer web search" ,
410+ targetIds : new Set ( [ "plugins.entries.firecrawl.config.webSearch.apiKey" ] ) ,
411+ allowedPaths : new Set ( [ "plugins.entries.firecrawl.config.webSearch.apiKey" ] ) ,
412+ forcedActivePaths : new Set ( [ "plugins.entries.firecrawl.config.webSearch.apiKey" ] ) ,
413+ } ) ,
414+ ) . rejects . toThrow ( / d o e s n o t s u p p o r t c o m m a n d - s c o p e d s e c r e t r e s o l u t i o n / i) ;
415+ expect ( callGateway ) . toHaveBeenCalledTimes ( 1 ) ;
416+ } ) ;
417+ } ) ;
418+
380419 it ( "fails fast when gateway-backed resolution is unavailable" , async ( ) => {
381420 const envKey = "TALK_API_KEY_FAILFAST" ;
382421 const priorValue = process . env [ envKey ] ;
@@ -581,6 +620,37 @@ describe("resolveCommandSecretRefsViaGateway", () => {
581620 } ) ;
582621 } ) ;
583622
623+ it ( "keeps top-level web search SecretRefs on the direct local fallback path" , async ( ) => {
624+ const runtimeWebTools = await import ( "../secrets/runtime-web-tools.js" ) ;
625+ vi . mocked ( runtimeWebTools . resolveRuntimeWebTools ) . mockClear ( ) ;
626+ const envKey = "WEB_SEARCH_BRAVE_TOP_LEVEL_LOCAL_FALLBACK" ;
627+ await withEnvValue ( envKey , "brave-top-level-local-fallback-key" , async ( ) => {
628+ callGateway . mockRejectedValueOnce ( new Error ( "gateway closed" ) ) ;
629+ const result = await resolveCommandSecretRefsViaGateway ( {
630+ config : {
631+ tools : {
632+ web : {
633+ search : {
634+ provider : "exa" ,
635+ apiKey : { source : "env" , provider : "default" , id : envKey } ,
636+ } ,
637+ } ,
638+ } ,
639+ } as unknown as OpenClawConfig ,
640+ commandName : "infer web search" ,
641+ targetIds : new Set ( [ "tools.web.search.apiKey" ] ) ,
642+ forcedActivePaths : new Set ( [ "tools.web.search.apiKey" ] ) ,
643+ } ) ;
644+
645+ expect ( result . resolvedConfig . tools ?. web ?. search ?. apiKey ) . toBe (
646+ "brave-top-level-local-fallback-key" ,
647+ ) ;
648+ expect ( result . targetStatesByPath [ "tools.web.search.apiKey" ] ) . toBe ( "resolved_local" ) ;
649+ expect ( runtimeWebTools . resolveRuntimeWebTools ) . not . toHaveBeenCalled ( ) ;
650+ expectGatewayUnavailableLocalFallbackDiagnostics ( result ) ;
651+ } ) ;
652+ } ) ;
653+
584654 it ( "treats command-scoped web fetch fallback SecretRefs as active even when web search is disabled" , async ( ) => {
585655 const envKey = "WEB_FETCH_FIRECRAWL_SEARCH_FALLBACK_KEY" ;
586656 await withEnvValue ( envKey , "firecrawl-search-fallback-key" , async ( ) => {
0 commit comments