






















@@ -172,6 +172,103 @@ describe("resolveCommandSecretRefsViaGateway", () => {
172172expect(readTalkProviderApiKey(result.resolvedConfig)).toBe("sk-live");
173173});
174174175+it("passes command provider overrides to gateway secret resolution", async () => {
176+callGateway.mockResolvedValueOnce({
177+assignments: [
178+{
179+path: TALK_TEST_PROVIDER_API_KEY_PATH,
180+pathSegments: [...TALK_TEST_PROVIDER_API_KEY_PATH_SEGMENTS],
181+value: "sk-live",
182+},
183+],
184+diagnostics: [],
185+});
186+const config = buildTalkTestProviderConfig({
187+source: "env",
188+provider: "default",
189+id: "TALK_API_KEY",
190+});
191+192+await resolveCommandSecretRefsViaGateway({
193+ config,
194+commandName: "infer web search",
195+targetIds: new Set(["talk.providers.*.apiKey"]),
196+providerOverrides: { webSearch: "tavily" },
197+});
198+199+expect(callGateway.mock.calls[0]?.[0]?.params).toEqual({
200+commandName: "infer web search",
201+targetIds: ["talk.providers.*.apiKey"],
202+providerOverrides: { webSearch: "tavily" },
203+});
204+});
205+206+it("applies provider overrides during unavailable-gateway local fallback", async () => {
207+const restoreDeps = commandSecretGatewayTesting.setDepsForTest({
208+collectConfigAssignments: ({ context }) => {
209+context.assignments.push({
210+path: "plugins.entries.google.config.webSearch.apiKey",
211+} as never);
212+},
213+resolveManifestContractOwnerPluginId: (params) =>
214+params.contract === "webSearchProviders" && params.value === "gemini"
215+ ? "google"
216+ : undefined,
217+});
218+const envKey = "WEB_SEARCH_GEMINI_OVERRIDE_LOCAL_FALLBACK";
219+await withEnvValue(envKey, "gemini-override-local-fallback-key", async () => {
220+try {
221+callGateway.mockRejectedValueOnce(new Error("gateway closed"));
222+const result = await resolveCommandSecretRefsViaGateway({
223+config: {
224+tools: {
225+web: {
226+search: {
227+provider: "brave",
228+apiKey: {
229+source: "env",
230+provider: "default",
231+id: "WEB_SEARCH_BRAVE_MISSING_LOCAL_FALLBACK",
232+},
233+},
234+},
235+},
236+plugins: {
237+entries: {
238+google: {
239+config: {
240+webSearch: {
241+apiKey: { source: "env", provider: "default", id: envKey },
242+},
243+},
244+},
245+},
246+},
247+} as unknown as OpenClawConfig,
248+commandName: "infer web search",
249+targetIds: new Set([
250+"tools.web.search.apiKey",
251+"plugins.entries.google.config.webSearch.apiKey",
252+]),
253+providerOverrides: { webSearch: "gemini" },
254+});
255+256+const googleWebSearchConfig = result.resolvedConfig.plugins?.entries?.google?.config as
257+| { webSearch?: { apiKey?: unknown } }
258+| undefined;
259+expect(result.resolvedConfig.tools?.web?.search?.provider).toBe("gemini");
260+expect(googleWebSearchConfig?.webSearch?.apiKey).toBe("gemini-override-local-fallback-key");
261+expect(result.targetStatesByPath["plugins.entries.google.config.webSearch.apiKey"]).toBe(
262+"resolved_local",
263+);
264+expect(result.targetStatesByPath["tools.web.search.apiKey"]).toBe("inactive_surface");
265+expectGatewayUnavailableLocalFallbackDiagnostics(result);
266+} finally {
267+restoreDeps();
268+}
269+});
270+});
271+175272it("enforces unresolved checks only for allowed paths when provided", async () => {
176273const restoreDeps = commandSecretGatewayTesting.setDepsForTest({
177274analyzeCommandSecretAssignmentsFromSnapshot: () =>
@@ -425,6 +522,36 @@ describe("resolveCommandSecretRefsViaGateway", () => {
425522});
426523});
427524525+it("falls back to local resolution for legacy web fetch SecretRefs when gateway is unavailable", async () => {
526+const envKey = "WEB_FETCH_FIRECRAWL_LEGACY_LOCAL_FALLBACK";
527+await withEnvValue(envKey, "legacy-firecrawl-local-fallback-key", async () => {
528+callGateway.mockRejectedValueOnce(new Error("gateway closed"));
529+const result = await resolveCommandSecretRefsViaGateway({
530+config: {
531+tools: {
532+web: {
533+fetch: {
534+provider: "firecrawl",
535+firecrawl: {
536+apiKey: { source: "env", provider: "default", id: envKey },
537+},
538+},
539+},
540+},
541+} as unknown as OpenClawConfig,
542+commandName: "infer web fetch",
543+targetIds: new Set(["tools.web.fetch.firecrawl.apiKey"]),
544+});
545+546+const resolvedFetch = result.resolvedConfig.tools?.web?.fetch as
547+| { firecrawl?: { apiKey?: unknown } }
548+| undefined;
549+expect(resolvedFetch?.firecrawl?.apiKey).toBe("legacy-firecrawl-local-fallback-key");
550+expect(result.targetStatesByPath["tools.web.fetch.firecrawl.apiKey"]).toBe("resolved_local");
551+expectGatewayUnavailableLocalFallbackDiagnostics(result);
552+});
553+});
554+428555it("marks web SecretRefs inactive when the web surface is disabled during local fallback", async () => {
429556const restoreDeps = commandSecretGatewayTesting.setDepsForTest({
430557collectConfigAssignments: ({ context }) => {
@@ -467,6 +594,7 @@ describe("resolveCommandSecretRefsViaGateway", () => {
467594} as OpenClawConfig,
468595commandName: "agent",
469596targetIds: new Set(["plugins.entries.google.config.webSearch.apiKey"]),
597+providerOverrides: { webSearch: "gemini" },
470598});
471599472600expect(result.hadUnresolvedTargets).toBe(false);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。