Skip to content

Commit 880060f

Browse files
steipeteleno23
andcommitted
fix(cli): preserve optional web fallback secrets
Co-authored-by: wuyangfan <1102042793@qq.com>
1 parent 1edd95b commit 880060f

11 files changed

Lines changed: 674 additions & 51 deletions

src/cli/capability-cli.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,7 @@ async function resolveLocalCapabilityRuntimeConfig(params: {
15731573
targetIds: Set<string>;
15741574
allowedPaths?: Set<string>;
15751575
forcedActivePaths?: Set<string>;
1576+
optionalActivePaths?: Set<string>;
15761577
config?: OpenClawConfig;
15771578
}): Promise<OpenClawConfig> {
15781579
const cfg = params.config ?? getRuntimeConfig();
@@ -1583,6 +1584,7 @@ async function resolveLocalCapabilityRuntimeConfig(params: {
15831584
targetIds: params.targetIds,
15841585
...(params.allowedPaths ? { allowedPaths: params.allowedPaths } : {}),
15851586
...(params.forcedActivePaths ? { forcedActivePaths: params.forcedActivePaths } : {}),
1587+
...(params.optionalActivePaths ? { optionalActivePaths: params.optionalActivePaths } : {}),
15861588
runtime: defaultRuntime,
15871589
autoEnable: true,
15881590
});
@@ -1606,6 +1608,9 @@ async function runWebSearchCommand(params: { query: string; provider?: string; l
16061608
...(scopedTargets.forcedActivePaths
16071609
? { forcedActivePaths: scopedTargets.forcedActivePaths }
16081610
: {}),
1611+
...(scopedTargets.optionalActivePaths
1612+
? { optionalActivePaths: scopedTargets.optionalActivePaths }
1613+
: {}),
16091614
config: rawConfig,
16101615
});
16111616
const result = await runWebSearch({
@@ -1639,6 +1644,9 @@ async function runWebFetchCommand(params: { url: string; provider?: string; form
16391644
...(scopedTargets.forcedActivePaths
16401645
? { forcedActivePaths: scopedTargets.forcedActivePaths }
16411646
: {}),
1647+
...(scopedTargets.optionalActivePaths
1648+
? { optionalActivePaths: scopedTargets.optionalActivePaths }
1649+
: {}),
16421650
config: rawConfig,
16431651
});
16441652
const resolved = resolveWebFetchDefinition({

src/cli/command-config-resolution.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export async function resolveCommandConfigWithSecrets<TConfig extends OpenClawCo
1313
mode?: CommandSecretResolutionMode;
1414
allowedPaths?: Set<string>;
1515
forcedActivePaths?: Set<string>;
16+
optionalActivePaths?: Set<string>;
1617
runtime?: RuntimeEnv;
1718
autoEnable?: boolean;
1819
env?: NodeJS.ProcessEnv;
@@ -28,6 +29,7 @@ export async function resolveCommandConfigWithSecrets<TConfig extends OpenClawCo
2829
...(params.mode ? { mode: params.mode } : {}),
2930
...(params.allowedPaths ? { allowedPaths: params.allowedPaths } : {}),
3031
...(params.forcedActivePaths ? { forcedActivePaths: params.forcedActivePaths } : {}),
32+
...(params.optionalActivePaths ? { optionalActivePaths: params.optionalActivePaths } : {}),
3133
});
3234
if (params.runtime) {
3335
for (const entry of diagnostics) {

src/cli/command-secret-gateway.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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(/does not support command-scoped secret resolution/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

Comments
 (0)