Skip to content

fix(plugins): centralize explicit plugin scope handling#65298

Merged
vincentkoc merged 8 commits intomainfrom
feat/plugins-scope-semantics
Apr 12, 2026
Merged

fix(plugins): centralize explicit plugin scope handling#65298
vincentkoc merged 8 commits intomainfrom
feat/plugins-scope-semantics

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • Problem: explicit plugin scopes were still encoded ad hoc across loader/runtime/provider helpers, so [] vs undefined could drift back into the same behavior outside the first main-path fix.
  • Why it matters: when an explicitly empty scope widens to unscoped, OpenClaw can load far more plugin surface than the caller asked for.
  • What changed: added a shared plugin-scope helper and moved loader, provider, runtime metadata, and web-provider cache/scope handling onto it.
  • What did NOT change (scope boundary): no new activation behavior, no manifest contract changes, and no plugin API changes.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause (if applicable)

  • Root cause: explicit plugin scope semantics were duplicated in several helpers, and some call sites treated onlyPluginIds: [] the same as onlyPluginIds: undefined.
  • Missing detection / guardrail: we had coverage for one provider-path regression, but not for the shared loader/runtime/metadata/cache seams that still normalized empty scope away.
  • Contributing context (if known): provider narrowing landed incrementally, so the scope contract existed before the shared abstraction did.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/plugins/runtime/runtime-registry-loader.test.ts, src/plugins/runtime/metadata-registry-loader.test.ts, src/plugins/providers.test.ts, src/plugins/web-provider-resolution-shared.test.ts
  • Scenario the test should lock in: explicit empty plugin scopes stay scoped-empty through loaders, metadata snapshots, provider helpers, and web-provider cache/mapping helpers.
  • Why this is the smallest reliable guardrail: the bug is in normalization and scope forwarding, not full plugin execution.
  • Existing test that already covers this (if any): src/plugins/loader.runtime-registry.test.ts covers adjacent loader/runtime registry behavior.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

None.

Diagram (if applicable)

Before:
[explicit empty scope] -> [helper normalizes to unscoped] -> [broader plugin load]

After:
[explicit empty scope] -> [shared scope helper preserves empty scope] -> [no widening]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 22 / pnpm
  • Model/provider: N/A
  • Integration/channel (if any): plugin loader/runtime
  • Relevant config (redacted): default local plugin test config

Steps

  1. Request a provider/runtime/metadata load with onlyPluginIds: [].
  2. Observe whether downstream helpers treat that as explicit empty scope or unscoped.
  3. Run scoped regression tests and pnpm build.

Expected

  • Explicit empty scopes remain scoped-empty and do not widen plugin loading.

Actual

  • This PR preserves that behavior consistently across the touched helpers.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: explicit empty scope handling in runtime registry loading, metadata snapshots, provider helper filtering, web-provider cache keys, loader/runtime/provider regression suites.
  • Edge cases checked: undefined vs [], scoped-empty cache keys, helper set creation, explicit empty forwarding through metadata/runtime loaders.
  • What you did not verify: full repo pnpm test, remote CI, or third-party plugin ecosystems.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk:
    • Scope helper could subtly change existing undefined handling in hot paths.
    • Mitigation: kept undefined semantics intact, added explicit empty-scope regressions, and ran pnpm build because these are loader/runtime boundaries.

AI assistance

  • AI-assisted: yes
  • Local verification run: pnpm test:serial src/plugins/runtime/runtime-registry-loader.test.ts src/plugins/runtime/metadata-registry-loader.test.ts src/plugins/providers.test.ts src/plugins/web-provider-resolution-shared.test.ts
  • Additional local verification run: pnpm test:serial src/plugins/loader.test.ts src/plugins/loader.runtime-registry.test.ts src/plugins/provider-runtime.test.ts
  • Additional gates: pnpm lint -- src/plugins/plugin-scope.ts src/plugins/loader.ts src/plugins/providers.ts src/plugins/providers.runtime.ts src/plugins/runtime/runtime-registry-loader.ts src/plugins/runtime/metadata-registry-loader.ts src/plugins/provider-runtime.ts src/plugins/web-provider-resolution-shared.ts src/plugins/providers.test.ts src/plugins/runtime/runtime-registry-loader.test.ts src/plugins/runtime/metadata-registry-loader.test.ts src/plugins/web-provider-resolution-shared.test.ts, pnpm build

@vincentkoc vincentkoc self-assigned this Apr 12, 2026
@openclaw-barnacle openclaw-barnacle Bot added size: M maintainer Maintainer-authored PR labels Apr 12, 2026
@vincentkoc vincentkoc marked this pull request as ready for review April 12, 2026 10:52
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1c1a3efde

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return deps.mapRegistryProviders({
registry: runtimeRegistry,
onlyPluginIds: params.onlyPluginIds,
onlyPluginIds: loadOptions?.onlyPluginIds,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve onlyPluginIds when config is omitted

When resolveRuntimeWebProviders is called with config unset but an explicit onlyPluginIds scope, this path now drops the scope and returns providers from the full active runtime registry. loadOptions is intentionally undefined in that case, so onlyPluginIds: loadOptions?.onlyPluginIds becomes undefined and no filtering happens. This is a regression from the previous behavior (which filtered by params.onlyPluginIds) and can surface extra providers whenever callers rely on scoped runtime resolution without passing config.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 12, 2026

Greptile Summary

This PR centralizes explicit plugin scope handling into a new src/plugins/plugin-scope.ts helper and migrates loader, provider, runtime metadata, and web-provider cache/scope paths onto it. The core fix ensures that an explicitly empty onlyPluginIds: [] is preserved as a scoped-empty request rather than being widened to an unscoped load across all affected helpers.

Confidence Score: 5/5

Safe to merge — the scope helper is correctly designed, all changed paths preserve the undefined/[] distinction, and regression tests cover the key scenarios end-to-end.

No P0 or P1 findings. The normalizePluginIdScope / hasExplicitPluginIdScope / createPluginIdScopeSet helpers correctly distinguish undefined (unscoped) from [] (explicit empty). All callers — loader cache key, runtime-registry loader, metadata-registry loader, providers helpers, web-provider cache key, and mapRegistryProviders — consistently use these helpers. New tests lock in the explicit-empty behavior on every changed seam.

No files require special attention. The helper design and callsite usage are consistent throughout.

Reviews (1): Last reviewed commit: "Merge branch 'main' into feat/plugins-sc..." | Re-trigger Greptile

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 86797cb2c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugins/web-provider-resolution-shared.ts Outdated
@vincentkoc vincentkoc merged commit 6a189ee into main Apr 12, 2026
10 checks passed
@vincentkoc vincentkoc deleted the feat/plugins-scope-semantics branch April 12, 2026 15:16
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request Apr 27, 2026
* fix(plugins): centralize explicit plugin scope handling

* fix(plugins): preserve explicit empty web scopes

* fix(plugins): preserve runtime web provider scopes without config

* fix(plugins): preserve web provider runtime filtering

* fix(plugins): preserve scoped web runtime fallback

* fix(plugins): harden plugin scope normalization
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
* fix(plugins): centralize explicit plugin scope handling

* fix(plugins): preserve explicit empty web scopes

* fix(plugins): preserve runtime web provider scopes without config

* fix(plugins): preserve web provider runtime filtering

* fix(plugins): preserve scoped web runtime fallback

* fix(plugins): harden plugin scope normalization
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
* fix(plugins): centralize explicit plugin scope handling

* fix(plugins): preserve explicit empty web scopes

* fix(plugins): preserve runtime web provider scopes without config

* fix(plugins): preserve web provider runtime filtering

* fix(plugins): preserve scoped web runtime fallback

* fix(plugins): harden plugin scope normalization
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant