fix[Bug]: [skills] Skipping skill path error triggered on officially installed skills via clawhub (WSL Environment)#59219
Conversation
Greptile SummaryThis PR fixes a regression introduced by the skills realpath boundary hardening in 2026.3.9, where managed skills installed via symlink/junction-backed layouts (e.g. clawhub on WSL) were incorrectly rejected with "Skipping skill path that resolves outside its configured root." Root cause fix: The new Security boundary maintained: The new Test coverage:
Confidence Score: 5/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/skills/workspace.ts
Line: 406-416
Comment:
**`skillDirRealPath` unused after guard**
When `enforceContainedRealpath` is `true`, `resolveContainedSkillPath` resolves and returns the real path of `skillDir`, but that resolved path is assigned to `skillDirRealPath` and then immediately discarded — neither the `filterLoadedSkillsInsideRoot` call nor any later code uses `skillDirRealPath`. The pre-existing code did the same thing, so this isn't a regression, but now that the block is visually isolated it's easier to see that the variable serves only as a guard (non-null == "path is inside root"). A `void` or simple boolean pattern would make the intent clearer, though this is not functionally wrong.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix: re-add loadEnabledClaudeBundleComma..." | Re-trigger Greptile Re-review progress:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bef96da8c9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 414d5ae529
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Any chance this "Error: [vitest] No "sanitizeUserFacingText" export is defined on the "../pi-embedded-helpers.js" mock. Did you forget to return it from "vi.mock"?" can get addressed so this PR can be merged? It'll really help to cut down on noisy logs. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd30cd7792
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Addressed. This PR now includes the follow-up fixes that were needed to get the branch back into a mergeable state after drift with current
Relevant commits:
|
|
Codex review: needs maintainer review before merge. Summary Reproducibility: yes. A high-confidence source reproduction is to put a symlink or junction-backed skill under the managed skills root; current main sends Real behavior proof Next step before merge Security Review detailsBest possible solution: Land this PR or an equivalent narrow patch after exact-head CI, preserving managed/personal root relaxation while keeping per-skill, workspace, extra, project, and bundled containment guards. Do we have a high-confidence way to reproduce the issue? Yes. A high-confidence source reproduction is to put a symlink or junction-backed skill under the managed skills root; current main sends Is this the best way to solve the issue? Yes. The PR fixes the source-scoping policy directly instead of adding WSL-specific path handling, while preserving the security-sensitive Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 99b17263a12d. |
|
I ported the fix onto current main and kept the current grouped-skill discovery path intact. The loader now only relaxes root-level realpath containment for managed/ Also added the required CHANGELOG.md entry for #44051 / #59219. Additional cleanup:
|
870393d to
ef4c81c
Compare
Summary
Fix a managed-skills loading regression introduced by the recent skills realpath boundary hardening.
The loader started rejecting skill roots and SKILL.md files whose resolved realpath
escaped the configured source root. That behavior is correct for workspace and
extra-dir skills, but it was also being applied to managed skills under
~/.openclaw/skills.As a result, managed skills installed via symlink/junction-backed layouts could be
skipped with:
Skipping skill path that resolves outside its configured root.This surfaced in WSL reports, but the bug is in source scoping rather than
WSL-specific path normalization.
Root Cause
The containment check in
src/agents/skills/workspace.tswas being enforced foropenclaw-managedas well as untrusted roots.That meant a skill path that appeared under
~/.openclaw/skills/but resolvedoutside that directory via realpath was rejected, even though managed skill roots are
user-owned shared roots and were not intended to be subject to the same
workspace/extra-dir escape restriction.
What Changed
Added
shouldEnforceContainedSkillPaths()to scope realpath boundary enforcement to:openclaw-workspaceopenclaw-extraagents-skills-projectopenclaw-bundledStopped applying that enforcement to managed/personal roots, while keeping bundled
roots fail-closed so stray checkout symlinks do not load out-of-root bundled skills.
Kept per-skill
SKILL.mdcontainment checks in place for all sources, so a skill dirthat is allowed to resolve externally still cannot load a
SKILL.mdthat escapes itsown skill root.
Canonicalized loaded skill paths for sources exempt from root containment so managed
symlinked skills carry real paths into workspace sync/copy flows.
Kept size checks and normal loading behavior unchanged for trusted shared roots.
Added regression coverage for:
SKILL.mdsymlinks that escape the skill root and must still be rejectedmainRe-applied the follow-up fix that restores Claude bundle command loading in
buildWorkspaceSkillCommandSpecs().Also fixed the
pi-embedded-helpers.jspartial mock issue that was blocking thenode test shard.
Files
src/agents/skills/workspace.tssrc/agents/skills.loadworkspaceskillentries.test.tssrc/agents/skills.build-workspace-skills-prompt.syncs-merged-skills-into-target-workspace.test.tssrc/commands/doctor-bootstrap-size.test.tssrc/agents/pi-embedded-runner/compact.hooks.harness.tssrc/agents/pi-embedded-runner/run.overflow-compaction.harness.tsTest
Passed:
`pnpm exec vitest run src/agents/skills.loadworkspaceskillentries.test.ts src/agents/skills.buildworkspaceskillsnapshot.test.ts src/agents/skills.build-workspace-skills-
prompt.syncs-merged-skills-into-target-workspace.test.ts src/agents/skills.build-workspace-skills-prompt.prefers-workspace-skills-managed-skills.test.ts src/agents/skills-
status.test.ts
Real behavior proof
SKILL.mdcontainment remains enforced.loadWorkspaceSkillEntries()implementation from this branch. This models the WSL/ClawHub failure shape with a managed skills directory entry whose realpath points to an external cache-style skill directory.clawhub-cache/calendar-skill/SKILL.md, linkedmanaged-skills/calendar-skillto that external directory, then calledloadWorkspaceSkillEntries()with that managed directory.calendar-skillinloadedSkills, andloadedBaseDirwas the external realpath target. This is the behavior users need for ClawHub/managed skill installs that use symlink or junction layouts; the skill was not skipped by the managed-root containment warning path.