fix: resolve Tavily SecretRefs in agent tools#97827
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 14, 2026, 8:46 PM ET / July 15, 2026, 00:46 UTC. Summary PR surface: Source +66, Tests +178. Total +244 across 8 files. Reproducibility: yes. at source level: strict Tavily normalization throws before its environment fallback, while applying Tool Search defaults before runtime-snapshot selection clones the authored SecretRef and loses snapshot identity. The PR also provides exact-head terminal proof of the Tavily path. Review metrics: 2 noteworthy metrics.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Refresh the adopted branch onto current main, rerun the focused Tavily and agent-tool regressions plus the exact-head type gate, land it as the canonical two-layer fix, then retire the narrower duplicate PR and let the linked issue close after merge. Do we have a high-confidence way to reproduce the issue? Yes, at source level: strict Tavily normalization throws before its environment fallback, while applying Tool Search defaults before runtime-snapshot selection clones the authored SecretRef and loses snapshot identity. The PR also provides exact-head terminal proof of the Tavily path. Is this the best way to solve the issue? Yes. The Tavily resolver follows the existing inspect-mode credential-boundary pattern, while the shared helper fixes the second root cause once for both agent-tool entry points instead of adding another provider-specific workaround. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 210340fe937b. Label changesLabel justifications:
Evidence reviewedPR surface: Source +66, Tests +178. Total +244 across 8 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (23 earlier review cycles; latest 8 shown)
|
81526f4 to
860c0ad
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review |
|
Maintainer landing proof for
Known proof gap: no successful search with a real Tavily credential; live proof deliberately used a generated invalid key to avoid handling a real secret while still proving provider execution. |
|
Merged via squash.
|
Fixes #95109
Summary
env:*:TAVILY_API_KEYref can use the documentedprocess.env.TAVILY_API_KEYfallback.Root Cause
There were two related Tavily SecretRef failures at different ownership layers.
params.config. Whenparams.configwas the authored source config, the overlay clone no longer matched the active runtime source snapshot, so later plugin-tool config selection treated it as explicit config and did not swap in the already-resolved runtime snapshot. Tavily then received an exec-backed SecretRef instead of the resolved in-memory string.extensions/tavily/src/config.tscalled strict normalization onplugins.entries.tavily.config.webSearch.apiKey; an unresolved env SecretRef threw beforeprocess.env.TAVILY_API_KEYcould be read.RCA proof:
src/agents/embedded-agent-runner/run/attempt.tsandsrc/agents/harness/tool-surface-bridge.tsapplied Tool Search defaults before runtime snapshot selection.src/agents/tool-runtime-config.tsand reuses it.extensions/tavily/src/config.tsused strict SecretRef normalization ahead of the env fallback, which matches theUnresolvedSecretInputErrorin Tavily plugin throws UnresolvedSecretInputError before falling back to process.env #95109.resolveSecretInputStringstrict mode throws on unresolved refs; inspect mode returns ref metadata so the plugin can allow only the matching env fallback and block file/exec/wrong-env refs.What Problem This Solves
Users with Tavily configured through resolved runtime SecretRefs can use agent-visible Tavily tools without the Tool Search overlay reintroducing unresolved source SecretRefs.
Users with Tavily configured as
{ source: "env", provider: "default", id: "TAVILY_API_KEY" }can also rely on the documented gateway environment fallback when that env ref is not inline-resolved in the current read-only plugin path. Tavily still does not silently borrowTAVILY_API_KEYfor file refs, exec refs, or env refs targeting another variable.Why This Change Was Made
The agent runtime now chooses the applicable resolved runtime snapshot before applying local Tool Search defaults. That keeps run-local config overlays in memory, preserves the authored SecretRef in source config, and avoids storing plaintext credentials.
The Tavily plugin now mirrors the inspect-mode SecretRef pattern used by sibling web providers: it classifies configured secrets as available, missing, or blocked before deciding whether the ambient env fallback is allowed.
User Impact
Agent-visible Tavily tools can use exec/file/env SecretRefs that have already been resolved into the active runtime snapshot.
Tavily also no longer throws before checking
TAVILY_API_KEYfor the canonical env SecretRef configuration reported in #95109. Explicit non-env Tavily SecretRefs remain fail-closed if unavailable.Real behavior proof
Behavior fixed: Tool Search runtime config now carries resolved in-memory Tavily API key values to agent/plugin tools while the source config keeps the authored SecretRef; Tavily's plugin-local resolver now allows the matching env SecretRef fallback without weakening file/exec/wrong-env credential boundaries.
Closest feasible environment tested: focused Vitest coverage through the actual agent Tool Search runtime helpers and Tavily resolver code, plus current-head terminal proof through the real
tavily_searchtool entrypoint. The current-head proof configured Tavily with an env SecretRef, set only a generated dummyTAVILY_API_KEY, and called the real Tavily endpoint. Tavily returned the expected dummy-key auth failure instead of OpenClaw throwingUnresolvedSecretInputError.Current-head Tavily env SecretRef proof:
Focused regression output:
Observed after behavior:
env:*:TAVILY_API_KEYSecretRef fromprocess.env.TAVILY_API_KEYinstead of throwing first.tavily_searchtool path reaches Tavily with the resolved dummy env key and receives a Tavily auth error, proving provider execution was reached.TAVILY_API_KEY.Evidence
Current-head real behavior proof:
Focused tests:
node scripts/run-vitest.mjs extensions/tavily/src/config.test.ts src/agents/harness/tool-surface-bridge.test.ts src/agents/openclaw-tools.browser-plugin.integration.test.ts # Test Files 3 passed (3); Tests 18 passed (18)Formatting, lint, whitespace:
Autoreview:
Requested update command:
oc-update # pushed commit 1b921e49532 first, then oc-update completed; health check passed on attempt 2/3GitHub CI:
Verification
tavily_searchcall againsthttps://api.tavily.com/searchreached Tavily and returned 401 instead ofUnresolvedSecretInputError.node scripts/run-vitest.mjs extensions/tavily/src/config.test.ts src/agents/harness/tool-surface-bridge.test.ts src/agents/openclaw-tools.browser-plugin.integration.test.tspnpm exec oxfmt --check --threads=1 ...node scripts/run-oxlint.mjs ...git diff --check.agents/skills/autoreview/scripts/autoreview --mode localoc-update1b921e49532747c9031dc98096179f90fc3fb6b9What was not tested
oc-updatedoctor/security warnings, including local skill/tooling/security-audit findings, were not repaired by this PR.AI Assistance
AI-assisted with Codex. I understand the change: it keeps the active resolved runtime snapshot as the base config for agent Tool Search overlays and direct plugin tools, and it repairs Tavily's plugin-local env SecretRef fallback without allowing unrelated configured credential refs to be silently replaced by ambient env state.