Skip to content

fix(secrets): register secret targets for installed-origin plugins#104347

Merged
steipete merged 1 commit into
openclaw:mainfrom
ObliviateRickLin:fix/secret-target-installed-plugins-104320
Jul 21, 2026
Merged

fix(secrets): register secret targets for installed-origin plugins#104347
steipete merged 1 commit into
openclaw:mainfrom
ObliviateRickLin:fix/secret-target-installed-plugins-104320

Conversation

@ObliviateRickLin

Copy link
Copy Markdown
Contributor

What Problem This Solves

#104320 (P1, regression of #82621/#82798): the secret target registry built its plugin-derived entries from bundled-origin records only (target-registry-data.ts filtered record.origin === "bundled"). When the Exa web providers moved out of bundled origin into an installed plugin package, their config targets (plugins.entries.exa.config.webSearch.apiKey) vanished from the gateway's known-target registry — secrets.resolve rejects the CLI-discovered target with unknown target id, and infer web search fails on an unresolved SecretRef before provider I/O, even though the plugin is loaded, enabled, and secrets audit reports full resolvability.

Why This Change Was Made

Per the triage's best-solution shape ("build the known-target registry from active installed-plugin manifest metadata, while preserving plugin enablement, manifest-first laziness, strict allowed-path scoping, and provider-specific ownership"):

  • Web-provider and config-contract secret target entries now come from every active plugin manifest record, exactly as channel-contract entries already did (they never filtered by origin — the bundled-only filter on the other two families was the inconsistency).
  • Scoping is unchanged and stays manifest-owned: an entry is only created for a plugin that declares the web-provider contract and marks the config path sensitive in its own manifest hints, or declares the path in configContracts.secretInputs. A non-bundled origin cannot widen target paths beyond its own declared contracts, and no plugin runtime is loaded (metadata snapshot only — laziness preserved).
  • No hard-coded provider ids, no validation weakening: isKnownSecretTargetId remains a closed registry; the registry just covers what's actually installed.

User Impact

Users of installed (non-bundled) provider plugins with SecretRef-backed credentials — the Exa split being the shipped example — get working infer web search/web fetch credential resolution again instead of a hard INVALID_REQUEST from the gateway.

Evidence

Executed real-handler before/after (the issue's exact secrets.resolve params driven through the real createSecretsHandlers handler, with an installed-origin Exa manifest record in the metadata snapshot):

result
current main ok: falseINVALID_REQUEST: invalid secrets.resolve params: unknown target id "plugins.entries.exa.config.webSearch.apiKey" (byte-identical to the issue's report)
this PR ok: true — validation passes, resolution proceeds

Regression test (target-registry-data.current-snapshot.test.ts): an installed-origin (origin: "global") record with the web-search contract + sensitive hint + declared secretInput produces the registry entry and isKnownSecretTargetId accepts it. Fails on prior head with expected [ 'auth-profiles.api_key.key', …(37) ] to include 'plugins.entries.exa.config.webSearch.apiKey'.

Validation: full src/secrets suite 553/553; tsgo:core 0; oxlint/oxfmt clean.

Fixes #104320

🤖 Generated with Claude Code

https://claude.ai/code/session_01AJogTw4aGDiacwqju1uod6

@ObliviateRickLin
ObliviateRickLin requested a review from a team as a code owner July 11, 2026 09:22
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. labels Jul 11, 2026
@clawsweeper

clawsweeper Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 11, 2026, 6:11 AM ET / 10:11 UTC.

Summary
The PR makes manifest-derived web-provider and config-contract secret targets origin-independent and adds regression coverage for an installed-origin Exa target.

PR surface: Source +5, Tests +25. Total +30 across 2 files.

Reproducibility: yes. A real npm-installed Exa plugin reproduces current main's exact unknown-target gateway response, and the same setup on this head passes gateway validation and reaches provider handling.

Review metrics: none identified.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #104320
Summary: This PR is a focused, proof-positive candidate fix for the canonical installed-plugin regression; a later PR implements the same production change with substantially more test-only code.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Next step before merge

  • No automated repair is needed; the remaining action is ordinary maintainer landing review and duplicate-branch cleanup.

Security
Cleared: The patch adds no dependency or executable surface and keeps known targets constrained to each plugin's manifest-declared contracts, sensitive hints, and secret-input paths.

Review details

Best possible solution:

Land this focused manifest-scoped fix, preserve the real installed-plugin proof in the PR record, and close #104383 as the overlapping candidate unless maintainers narrowly extract a demonstrably necessary gateway regression test from it.

Do we have a high-confidence way to reproduce the issue?

Yes. A real npm-installed Exa plugin reproduces current main's exact unknown-target gateway response, and the same setup on this head passes gateway validation and reaches provider handling.

Is this the best way to solve the issue?

Yes. Using the canonical manifest metadata across plugin origins is the narrowest ownership-correct fix, matches the existing channel target pattern, avoids provider-specific IDs, and preserves separate activation and resolution constraints.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against c702719eda74.

Label changes

Label justifications:

  • P1: This PR fixes a released installed-provider SecretRef regression that blocks the affected command before provider I/O.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): Redacted terminal output from a real npm-installed Exa plugin shows current main rejecting the target, this head accepting it through the real gateway, and the CLI reaching provider-owned credential handling.
  • proof: sufficient: Contributor real behavior proof is sufficient. Redacted terminal output from a real npm-installed Exa plugin shows current main rejecting the target, this head accepting it through the real gateway, and the CLI reaching provider-owned credential handling.
Evidence reviewed

PR surface:

Source +5, Tests +25. Total +30 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 15 10 +5
Tests 1 25 0 +25
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 40 10 +30

What I checked:

  • Shipped regression source: Release v2026.6.11 builds web-provider and config-contract target entries only from records whose origin is bundled, so an installed Exa manifest cannot contribute its credential target. (src/secrets/target-registry-data.ts:508, e085fa1a3ffd)
  • Current-main rejection boundary: The gateway rejects any non-core target absent from the plugin-derived known-target registry before invoking secret resolution. (src/gateway/server-methods/secrets.ts:132, c702719eda74)
  • Sibling manifest ownership: Channel secret targets already enumerate all discovered plugin manifest records with channel contracts rather than restricting ownership to bundled origin. (src/secrets/target-registry-data.ts:107, c702719eda74)
  • Patch behavior: The reviewed head removes the origin filter for web-provider and config-contract entries while retaining contract, sensitive-hint, and manifest secret-input scoping. (src/secrets/target-registry-data.ts:505, 2e9ca5b37883)
  • Real installed-plugin proof: The contributor's redacted transcript uses an npm-installed Exa plugin reported as global and enabled: current main rejects the exact target, while this head accepts it through the real gateway and the CLI proceeds to provider-owned credential handling. (2e9ca5b37883)
  • Validation status: Core secrets quality, plugin/security boundaries, build, lint, production types, and the real-behavior-proof check pass on the reviewed head. (2e9ca5b37883)

Likely related people:

  • vincentkoc: The current secret target registry helpers and bundled-origin filter trace to Vincent Koc's commit bb65e79. (role: introduced behavior; confidence: high; commits: bb65e79ae9b1; files: src/secrets/target-registry-data.ts, src/gateway/server-methods/secrets.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-07-11T09:30:46.277Z sha 2e9ca5b :: needs real behavior proof before merge. :: none

@ObliviateRickLin

Copy link
Copy Markdown
Contributor Author

Live before/after with an actually installed Exa plugin (real gateway + real CLI)

Real setup, matching the issue's topology: fresh OPENCLAW_STATE_DIR, @openclaw/exa-plugin actually installed from npm (openclaw plugins install npm:@openclaw/exa-plugin — forced external, since a source tree still bundles exa), OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 to reproduce the release topology where exa is installed-origin only, exec SecretRef at plugins.entries.exa.config.webSearch.apiKey, tools.web.search.provider: "exa". openclaw plugins list --json reports exa origin: global, enabled: true; the gateway boots with http server listening (1 plugin: exa) — metadata discovery, gateway load, and command path are all the real installed package.

BEFORE — pristine main dist, the issue's exact secrets.resolve call:

$ openclaw gateway call secrets.resolve --params '{"commandName":"infer","targetIds":["plugins.entries.exa.config.webSearch.apiKey"],"forcedActivePaths":["plugins.entries.exa.config.webSearch.apiKey"],"providerOverrides":{"webSearch":"exa"}}'
Gateway call failed: GatewayClientRequestError: invalid secrets.resolve params: unknown target id "plugins.entries.exa.config.webSearch.apiKey"

(byte-identical to the issue's report)

AFTER — this PR's dist, identical setup and command:

Gateway call: secrets.resolve
{ "ok": true, "assignments": [], "diagnostics": [], "inactiveRefPaths": [] }

and the CLI path proceeds past the gate into provider selection and provider-side credential handling:

$ openclaw infer web search --provider exa --query "openclaw test"
web.search via local
provider: exa
outputs: 1
{"result":{"error":"missing_exa_api_key","message":"web_search (exa) needs an Exa API key. ..."}}

The remaining missing_exa_api_key is the provider's own credential lookup on this synthetic setup (no real key was configured for this proof) — the point the review gates on is that the gateway no longer rejects the installed plugin's target id, so validation → command resolution → provider I/O boundary are reached with the real installed package. No credential values appear anywhere in this transcript.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 11, 2026
@steipete steipete self-assigned this Jul 21, 2026
The secret target registry filtered plugin-derived entries to bundled-origin
records only, so when the Exa web providers moved into an installed plugin
package their config targets vanished: the gateway's isKnownSecretTargetId
rejected the CLI-discovered target and infer web search failed with an
unresolved SecretRef before provider I/O (regression of openclaw#82621/openclaw#82798).
Web-provider and config-contract entries now come from every active plugin
manifest record, matching what channel entries already did; entries stay
manifest-scoped (web-provider contract + sensitive hint, or declared
secretInput paths), so non-bundled origins cannot widen target paths beyond
their own declared contracts.

Fixes openclaw#104320
@steipete
steipete force-pushed the fix/secret-target-installed-plugins-104320 branch from 2e9ca5b to 9a700e8 Compare July 21, 2026 04:54
@clawsweeper

clawsweeper Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper status: review started.

I am starting a fresh review of this pull request: fix(secrets): register secret targets for installed-origin plugins This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@steipete
steipete merged commit 959a450 into openclaw:main Jul 21, 2026
117 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

vincentkoc added a commit that referenced this pull request Jul 21, 2026
* origin/main: (24 commits)
  fix(agents): keep compaction on live session model (#95713)
  fix(plugin-sdk): guard provider catalog live URL parsing against malformed responses (#109986)
  chore(cli): drop dead classifiers and single-use wrappers left by fallback removal (#112191)
  feat(ui): expand the lobster pet's random universe (#112073)
  chore(ci): audit dependency fingerprint exports (#112190)
  fix(ui): preserve graphemes in provider icons (#109509)
  fix(ui): align settings search with navigation rows (#112172)
  fix(agents): allow configless gateway rebind to activate standalone owner (#111841)
  fix(secrets): register secret targets for installed-origin plugins (#104347)
  improve(ui): show real machine identity in the place picker (#112162)
  fix: webChat scrollback history is too limited — older assistant replies and tool outputs disappear when scrolling… (#104250)
  test(ui): run DOM-free suites in Node (#112031)
  feat(nodes): make computer.act eligibility capability-based for desktop nodes (#112107)
  fix(apps): harden mobile gateway and watch state
  fix(ci): restore Z.AI API Platform validation (#112171)
  fix(ui): prevent Logs controls from overlapping (#112170)
  fix #95291: message tool fails to deliver files/images on Feishu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone (#95514)
  refactor(cli)!: remove automatic gateway→embedded fallback from openclaw agent (#112074)
  refactor: move provider transports into packages/ai behind a typed host port (#111669)
  fix(anthropic): complete transcript reverse-scan windows across short reads (#109431)
  ...
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 22, 2026
…penclaw#104347)

The secret target registry filtered plugin-derived entries to bundled-origin
records only, so when the Exa web providers moved into an installed plugin
package their config targets vanished: the gateway's isKnownSecretTargetId
rejected the CLI-discovered target and infer web search failed with an
unresolved SecretRef before provider I/O (regression of openclaw#82621/openclaw#82798).
Web-provider and config-contract entries now come from every active plugin
manifest record, matching what channel entries already did; entries stay
manifest-scoped (web-provider contract + sensitive hint, or declared
secretInput paths), so non-bundled origins cannot widen target paths beyond
their own declared contracts.

Fixes openclaw#104320
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: infer web search rejects installed Exa plugin SecretRef target as unknown

2 participants