Skip to content

fix(plugins): enforce minimum host versions for installable plugins#52094

Merged
vincentkoc merged 7 commits intomainfrom
fix/plugin-min-host-version
Mar 22, 2026
Merged

fix(plugins): enforce minimum host versions for installable plugins#52094
vincentkoc merged 7 commits intomainfrom
fix/plugin-min-host-version

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • Problem: peer dependency metadata was not a real compatibility gate for plugins that now depend on new openclaw/plugin-sdk/* subpaths.
  • Why it matters: older hosts could still install these plugins and then fail later at load/runtime, while unpublished peer floors also created avoidable CI/package-manager churn.
  • What changed: added explicit openclaw.install.minHostVersion metadata, enforce it during plugin install and manifest loading, and added guardrails/tests plus manifest coverage for affected installable plugins.
  • What did NOT change (scope boundary): this PR does not change npm peer resolution behavior or plugin publish strategy.

Change Type (select all)

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

Scope (select all touched areas)

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

Linked Issue/PR

User-visible / Behavior Changes

  • Plugin install now fails early when a plugin declares openclaw.install.minHostVersion above the running host version.
  • Manifest loading now skips incompatible already-installed plugins with a diagnostic instead of letting them fail later at runtime.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (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 install + manifest loading
  • Relevant config (redacted): none

Steps

  1. Create a plugin package with openclaw.install.minHostVersion above the running host version.
  2. Run the plugin install path or load the plugin from discovery.
  3. Verify install/load fails early with an explicit host-version message.

Expected

  • Incompatible hosts are rejected before runtime import failures.

Actual

  • This branch does that and keeps compatible hosts working.

Evidence

  • 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: targeted plugin install rejection, manifest-registry skip/diagnostic, bundled manifest validation, guardrail coverage for affected manifests.
  • Edge cases checked: invalid minHostVersion syntax, future stricter floors (>=...) still accepted by the guardrail, direct-install packages without npmSpec metadata (irc, twitch, voice-call).
  • What you did not verify: manual end-to-end install on an actually older released OpenClaw binary.

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.

Compatibility / Migration

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

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert this PR or remove the new openclaw.install.minHostVersion fields from affected plugin manifests.
  • Files/config to restore: src/plugins/install.ts, src/plugins/manifest-registry.ts, affected extensions/*/package.json manifests.
  • Known bad symptoms reviewers should watch for: compatible plugins being rejected due to malformed or overly strict minHostVersion metadata.

Risks and Mitigations

  • Risk: a plugin manifest could declare an incorrect floor and become unloadable.
    • Mitigation: install/load validation is covered by tests, bundled manifest validation, and the new guardrail test.

AI-assisted: yes. Tested locally with pnpm test -- src/plugins/min-host-version.test.ts src/plugins/install.test.ts src/plugins/manifest-registry.test.ts src/plugins/install-min-host-version-guardrails.test.ts test/release-check.test.ts, pnpm build, and pnpm check.

@vincentkoc vincentkoc self-assigned this Mar 22, 2026
@openclaw-barnacle openclaw-barnacle Bot added channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: googlechat Channel integration: googlechat channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nextcloud-talk Channel integration: nextcloud-talk channel: nostr Channel integration: nostr channel: tlon Channel integration: tlon channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser extensions: memory-lancedb Extension: memory-lancedb scripts Repository scripts channel: feishu Channel integration: feishu channel: twitch Channel integration: twitch channel: irc size: M maintainer Maintainer-authored PR labels Mar 22, 2026
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@vincentkoc vincentkoc reopened this Mar 22, 2026
@vincentkoc vincentkoc marked this pull request as ready for review March 22, 2026 05:18
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: c5e59c77f3

ℹ️ 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 extensions/irc/package.json
Comment thread src/plugins/min-host-version.ts Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 22, 2026

Greptile Summary

This PR adds a minHostVersion compatibility gate for installable plugins, preventing older hosts from loading plugins that depend on newer openclaw/plugin-sdk/* subpaths. The mechanism is clean and consistent: a new min-host-version.ts module encapsulates all parsing and checking logic behind a discriminated-union result type, and both the install path (installPluginFromPackageDir) and the manifest-loading path (loadPluginManifestRegistry) enforce the constraint early.

Key highlights:

  • Three distinct failure kinds (invalid, unknown_host_version, incompatible) give callers precise error messaging and allow the registry to emit warn rather than error when the host version is simply unknown (dev builds).
  • vi.unstubAllEnvs() added to install.test.ts beforeEach prevents env stubs from bleeding across test cases.
  • The hasNpmSpec guard in bundled-extension-manifest.ts correctly allows irc, twitch, and voice-call to declare minHostVersion without an npmSpec.
  • The install-min-host-version-guardrails.test.ts file provides a regression safety net that reads real manifests from disk, ensuring the version floor is never silently dropped.

Confidence Score: 5/5

  • PR is safe to merge; all install and manifest-load paths are correctly gated with good test coverage.
  • The core logic is correct and well-tested across all entry points. The two remaining observations (an unreachable defensive branch in checkMinHostVersion and an unused exported constant MIN_HOST_VERSION_PREFIX) are non-blocking style issues that do not affect correctness or safety. The prior concern about unknown host versions is addressed with a distinct unknown_host_version kind and a warn-level diagnostic in the registry.
  • No files require special attention.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/plugins/min-host-version.ts
Line: 74-77

Comment:
**Unreachable dead code branch**

`parseSemver(requirement.minimumLabel)` is guaranteed to succeed here because `parseMinHostVersionRequirement` already validates it at line 36–38 before returning a non-null `requirement`. The error branch at line 75–77 can never be reached. Consider removing it to avoid giving the impression this is a realistic fallback:

```suggestion
  const minimumSemver = parseSemver(requirement.minimumLabel);
  if (!isAtLeast(currentSemver, minimumSemver!)) {
```

Or, if you want to keep the defensive check, add a comment explaining why it is there even though the value was pre-validated.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/plugins/min-host-version.ts
Line: 3

Comment:
**Exported constant is never consumed**

`MIN_HOST_VERSION_PREFIX` is declared and exported but is not imported or used anywhere in the codebase. If it is not part of the public API surface, removing it avoids dead exports and removes any confusion about whether callers should rely on it.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "Merge branch 'main' into fix/plugin-min-..." | Re-trigger Greptile

Comment thread src/plugins/min-host-version.ts
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@vincentkoc vincentkoc reopened this Mar 22, 2026
Comment thread src/plugins/min-host-version.ts Outdated
Comment thread src/plugins/min-host-version.ts Outdated
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: 50c06e92bb

ℹ️ 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/min-host-version.ts Outdated
Comment thread scripts/lib/bundled-extension-manifest.ts Outdated
@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Mar 22, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🔵 Low minHostVersion guardrails bypass when PluginCandidate lacks packageManifest

1. 🔵 minHostVersion guardrails bypass when PluginCandidate lacks packageManifest

Property Value
Severity Low
CWE CWE-693
Location src/plugins/manifest-registry.ts:355-358

Description

loadPluginManifestRegistry enforces openclaw.install.minHostVersion using candidate.packageManifest, but some discovery paths create candidates without populating packageManifest.

As a result, a plugin that does have package.json metadata (including openclaw.install.minHostVersion) can still be loaded on an incompatible host when it is discovered/declared as a file-based plugin candidate (e.g., config loadPaths pointing directly to an entry file, or directories containing loose plugin entry files). In those cases candidate.packageManifest is undefined, checkMinHostVersion returns { ok: true }, and the plugin is not version-gated.

Impact:

  • Defeats the intended compatibility/guardrail enforcement.
  • Can lead to loading plugins on unsupported hosts, potentially causing runtime crashes (DoS) or undefined behavior.

Vulnerable code:

const minHostVersionCheck = checkMinHostVersion({
  currentVersion: currentHostVersion,
  minHostVersion: candidate.packageManifest?.install?.minHostVersion,
});

Why this is reachable:

  • In discoverFromPath, when the configured path is a file, addCandidate is called without reading/parsing a sibling package.json, so packageManifest remains unset.
  • In discoverInDirectory, when a plugin is discovered as a file entry, addCandidate is also called without a package manifest.

Recommendation

Ensure minHostVersion is derived from a trusted on-disk package.json whenever one exists for the candidate, instead of relying solely on candidate.packageManifest.

Options:

  1. Harden registry loading: if candidate.packageManifest is missing, attempt to read ${candidate.packageDir ?? candidate.rootDir}/package.json safely and extract openclaw.install.minHostVersion.

  2. Harden discovery: when creating file-based candidates, read/parse package.json from the file’s directory (if present) and populate candidate.packageManifest.

Example (option 1 — registry-side fallback):

import fs from "node:fs";
import path from "node:path";
import { getPackageManifestMetadata, type PackageManifest } from "./manifest.js";

function tryLoadPackageMetadata(dir: string): OpenClawPackageManifest | undefined {
  const p = path.join(dir, "package.json");
  if (!fs.existsSync(p)) return undefined;
  const raw = JSON.parse(fs.readFileSync(p, "utf-8")) as PackageManifest;
  return getPackageManifestMetadata(raw);
}

const packageMeta = candidate.packageManifest ?? tryLoadPackageMetadata(candidate.packageDir ?? candidate.rootDir);
const minHostVersionCheck = checkMinHostVersion({
  currentVersion: currentHostVersion,
  minHostVersion: packageMeta?.install?.minHostVersion,
});

Also consider treating an unreadable/invalid package.json as a diagnostic and possibly not silently skipping guardrails when the file exists but can’t be parsed.


Analyzed PR: #52094 at commit b434dda

Last updated on: 2026-03-22T16:36:48Z

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: 1248607cc9

ℹ️ 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/manifest-registry.ts
@vincentkoc vincentkoc merged commit 3ce5a83 into main Mar 22, 2026
56 of 58 checks passed
@vincentkoc vincentkoc deleted the fix/plugin-min-host-version branch March 22, 2026 16:12
MaheshBhushan pushed a commit to MaheshBhushan/openclaw that referenced this pull request Mar 22, 2026
…penclaw#52094)

* fix(plugins): enforce min host versions

* fix(plugins): tighten min host version validation

* chore(plugins): trim dead min host version code

* fix(plugins): handle malformed min host metadata

* fix(plugins): key manifest cache by host version
frankekn pushed a commit to artwalker/openclaw that referenced this pull request Mar 23, 2026
…penclaw#52094)

* fix(plugins): enforce min host versions

* fix(plugins): tighten min host version validation

* chore(plugins): trim dead min host version code

* fix(plugins): handle malformed min host metadata

* fix(plugins): key manifest cache by host version
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 24, 2026
…penclaw#52094)

* fix(plugins): enforce min host versions

* fix(plugins): tighten min host version validation

* chore(plugins): trim dead min host version code

* fix(plugins): handle malformed min host metadata

* fix(plugins): key manifest cache by host version

(cherry picked from commit 3ce5a83)
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 24, 2026
…penclaw#52094)

* fix(plugins): enforce min host versions

* fix(plugins): tighten min host version validation

* chore(plugins): trim dead min host version code

* fix(plugins): handle malformed min host metadata

* fix(plugins): key manifest cache by host version

(cherry picked from commit 3ce5a83)
furaul pushed a commit to furaul/openclaw that referenced this pull request Mar 24, 2026
…penclaw#52094)

* fix(plugins): enforce min host versions

* fix(plugins): tighten min host version validation

* chore(plugins): trim dead min host version code

* fix(plugins): handle malformed min host metadata

* fix(plugins): key manifest cache by host version
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…penclaw#52094)

* fix(plugins): enforce min host versions

* fix(plugins): tighten min host version validation

* chore(plugins): trim dead min host version code

* fix(plugins): handle malformed min host metadata

* fix(plugins): key manifest cache by host version
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…penclaw#52094)

* fix(plugins): enforce min host versions

* fix(plugins): tighten min host version validation

* chore(plugins): trim dead min host version code

* fix(plugins): handle malformed min host metadata

* fix(plugins): key manifest cache by host version
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: feishu Channel integration: feishu channel: googlechat Channel integration: googlechat channel: irc channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nextcloud-talk Channel integration: nextcloud-talk channel: nostr Channel integration: nostr channel: tlon Channel integration: tlon channel: twitch Channel integration: twitch channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser extensions: memory-lancedb Extension: memory-lancedb maintainer Maintainer-authored PR scripts Repository scripts size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant