Skip to content

fix: allow symlinked workspace write parents#85818

Merged
giodl73-repo merged 1 commit into
openclaw:mainfrom
giodl73-repo:fix-84696-symlink-write-parent
May 24, 2026
Merged

fix: allow symlinked workspace write parents#85818
giodl73-repo merged 1 commit into
openclaw:mainfrom
giodl73-repo:fix-84696-symlink-write-parent

Conversation

@giodl73-repo

Copy link
Copy Markdown
Contributor

Summary

  • Canonicalize workspace-only host write/edit paths through existing symlink directory parents before handing them to @openclaw/fs-safe.
  • Preserve the existing filesystem boundary by rejecting outside-workspace symlink parents and final-file symlink writes.
  • Add Linux regression coverage for write, edit, outside-workspace symlink rejection, and final-symlink rejection.

Fixes #84696.

Verification

  • OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 CI=1 node scripts/run-vitest.mjs src/agents/pi-tools.workspace-paths.test.ts src/agents/pi-tools.workspace-only-false.test.ts src/infra/fs-safe.test.ts src/agents/sandbox/fs-bridge.anchored-ops.test.ts
  • git diff --check HEAD~1 HEAD
  • corepack pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/agents/pi-tools.read.ts src/agents/pi-tools.workspace-paths.test.ts
  • corepack pnpm exec oxlint src/agents/pi-tools.read.ts src/agents/pi-tools.workspace-paths.test.ts
  • codex review --base origin/main -> no discrete regression identified
  • Testbox through Crabbox: provider blacksmith-testbox, id tbx_01ksb7fefnehdfdn2kme3h9d9w, Actions run https://github.com/openclaw/openclaw/actions/runs/26342424451, command pnpm check:changed, exit 0

Real behavior proof

Behavior addressed: workspace-only host write and edit now work through in-workspace symlink directory parents such as memory -> oc_system/memory instead of surfacing directory component must be a directory.

Real environment tested: WSL Ubuntu 24.04 durable checkout, branch fix-84696-symlink-write-parent, local head cb3394edd7; broad validation on Blacksmith Testbox through Crabbox.

Exact steps or command run after this patch: focused Vitest command above, diff/format/lint checks, Codex review, and Testbox pnpm check:changed via node scripts/crabbox-wrapper.mjs run --provider blacksmith-testbox ....

Evidence after fix: regression tests create real Linux symlink parents and prove write("memory/2026-05-20.md") and edit through memory/... land in the real target directory; companion tests prove outside-workspace symlink parents are rejected and final file symlinks are still not followed.

Observed result after fix: 7 focused test files passed with 98 tests; local static checks passed; Codex review found no discrete regression; Testbox pnpm check:changed passed with exit 0.

What was not tested: a live model-driven OpenClaw agent session after context compaction was not run; the failing filesystem/tool path is covered directly through the host write/edit tool operations and the broad changed gate.

@openclaw-barnacle openclaw-barnacle Bot added the agents Agent runtime and tooling label May 23, 2026
@openclaw-barnacle openclaw-barnacle Bot added size: S maintainer Maintainer-authored PR labels May 23, 2026
@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Latest ClawSweeper review: 2026-05-24 02:30 UTC / May 23, 2026, 10:30 PM ET.

Workflow note: Future ClawSweeper reviews update this same comment in place.

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.

PR Surface
Source +19, Tests +102, Docs +1. Total +122 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 1 22 3 +19
Tests 1 102 0 +102
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 125 3 +122

Summary
The PR canonicalizes workspace-only host write/edit paths through existing in-workspace symlink directory parents, adds Linux regression coverage, and records a changelog fix.

Reproducibility: yes. at source level: the linked report gives a concrete Linux memory -> oc_system/memory failure path, and current main sends the lexical symlink path into fs-safe writes before the PR changes that path. I did not run tests because this review is read-only.

PR rating
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Summary: Focused patch with strong proof and no blocking finding; the remaining gate is maintainer review of the filesystem-boundary policy.

Rank-up moves:

  • Have a maintainer review the symlink boundary assumptions before merge.
  • Rely on required checks for head 0443b85.
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.

Real behavior proof
Sufficient (terminal): The PR body provides after-fix WSL terminal-style proof, focused real symlink write/edit tests, negative boundary tests, and a Crabbox/Testbox changed-check run.

Risk before merge

  • This intentionally changes workspace-only filesystem boundary behavior: host write/edit will follow symlink directory parents only when their canonical target remains inside the workspace.
  • The PR body proof names an older local head, but the final force-push after the prior review changed only CHANGELOG.md; required checks should still be trusted on head 0443b85 before merge.

Maintainer options:

  1. Land after filesystem-boundary review (recommended)
    Merge after maintainers confirm that following only in-workspace symlink directory parents is the intended workspace-only policy and required checks pass on the current head.
  2. Ask for extra race coverage
    If maintainers want stronger assurance, request an additional symlink-rebind or nested-missing-parent test before merging.
  3. Pause if the policy is unsettled
    Keep the PR open until the owner decides whether workspace-only write/edit should treat in-workspace directory symlinks as transparent.

Next step before merge
This protected maintainer-labeled PR appears technically bounded, but the remaining action is human filesystem-boundary approval rather than an automated repair.

Security
Cleared: The diff is security-sensitive because it touches workspace file boundaries, but the reviewed path keeps lexical and canonical root checks and leaves final-write validation in fs-safe.

Review details

Best possible solution:

Land the bounded parent-canonicalization fix after maintainer filesystem-boundary review and current-head required checks, leaving the linked bug open until the merge closes it.

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

Yes, at source level: the linked report gives a concrete Linux memory -> oc_system/memory failure path, and current main sends the lexical symlink path into fs-safe writes before the PR changes that path. I did not run tests because this review is read-only.

Is this the best way to solve the issue?

Yes, with maintainer boundary approval: the patch keeps the lexical workspace check, canonicalizes only the existing parent, and still relies on fs-safe for final-file, hardlink, and outside-root enforcement.

Label justifications:

  • P2: The PR addresses a real but bounded agent filesystem write/edit bug with workarounds and limited blast radius.
  • merge-risk: 🚨 security-boundary: The diff intentionally changes how workspace-only filesystem tools traverse symlinked directory parents.
  • rating: 🐚 platinum hermit: Current PR rating is 🐚 platinum hermit because proof is 🦞 diamond lobster, patch quality is 🐚 platinum hermit, and Focused patch with strong proof and no blocking finding; the remaining gate is maintainer review of the filesystem-boundary policy.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body provides after-fix WSL terminal-style proof, focused real symlink write/edit tests, negative boundary tests, and a Crabbox/Testbox changed-check run.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix WSL terminal-style proof, focused real symlink write/edit tests, negative boundary tests, and a Crabbox/Testbox changed-check run.

Acceptance criteria:

  • OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 CI=1 node scripts/run-vitest.mjs src/agents/pi-tools.workspace-paths.test.ts src/agents/pi-tools.workspace-only-false.test.ts src/infra/fs-safe.test.ts src/agents/sandbox/fs-bridge.anchored-ops.test.ts
  • git diff --check HEAD~1 HEAD
  • corepack pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/agents/pi-tools.read.ts src/agents/pi-tools.workspace-paths.test.ts
  • corepack pnpm exec oxlint src/agents/pi-tools.read.ts src/agents/pi-tools.workspace-paths.test.ts

What I checked:

  • Current main failure surface: Current main converts workspace-only host write/edit targets with toRelativeWorkspacePath(root, absolutePath) and passes the lexical relative path into fsRoot(root).write(...), so a symlink directory parent is still visible to fs-safe writes. (src/agents/pi-tools.read.ts:887, 029472c6defd)
  • PR implementation: The PR changes the write and edit writeFile paths to call toCanonicalRelativeWorkspacePath, which first checks the lexical workspace boundary, canonicalizes the existing parent, and then rechecks the canonical target relative to the real workspace root. (src/agents/pi-tools.read.ts:891, 0443b850afb7)
  • Regression and boundary coverage: The PR adds Linux tests for writing and editing through an in-workspace symlink parent, plus negative tests for outside-workspace symlink parents and final-file symlink writes. (src/agents/pi-tools.workspace-paths.test.ts:227, 0443b850afb7)
  • Dependency contract: The repo pins @openclaw/fs-safe 0.2.7; its root write path resolves under the real root, rejects path-alias escapes, uses no-follow open flags for final writes, rejects hardlinks, and verifies the written file remains inside the root after write. (package.json:1814, 029472c6defd)
  • Current-head force-push check: The final force-push from 039743f to 0443b85 changed only CHANGELOG.md, so the source and regression-test proof from the prior reviewed source head still applies to the current PR head. (CHANGELOG.md:84, 0443b850afb7)
  • Feature history: History shows the workspace-only host write/edit behavior dates through the initial workspace-only guard work, later host write/edit workspaceOnly handling, and fs-safe hardening commits. (src/agents/pi-tools.read.ts:887, 172583972065)

Likely related people:

  • steipete: Peter Steinberger authored the initial optional workspace-only filesystem guards and later fs-safe/host-write hardening, and recently split these files into the current shape. (role: recent area contributor and boundary owner signal; confidence: high; commits: 5e7c3250cb16, e3385a65789b, 846f56642bbb; files: src/agents/pi-tools.read.ts, src/infra/fs-safe.ts, src/agents/pi-tools.workspace-paths.test.ts)
  • 大猫子: The squash commit for the host write/edit workspaceOnly=false fix directly modified createHostWriteOperations and createHostEditOperations, which are the paths this PR changes. (role: introduced adjacent host write/edit workspaceOnly behavior; confidence: medium; commits: 172583972065; files: src/agents/pi-tools.read.ts, src/agents/pi-tools.workspace-only-false.test.ts)
  • velvet-shark: The host write/edit workspaceOnly=false squash metadata records review by @velvet-shark, making them a plausible reviewer for this boundary-adjacent change. (role: reviewer of adjacent behavior; confidence: low; commits: 172583972065; files: src/agents/pi-tools.read.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 029472c6defd.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 23, 2026
@giodl73-repo giodl73-repo force-pushed the fix-84696-symlink-write-parent branch from cb3394e to 4a4b562 Compare May 23, 2026 21:22
@clawsweeper clawsweeper Bot added the P2 Normal backlog priority with limited blast radius. label May 23, 2026
@clawsweeper

clawsweeper Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Gilded Proofling

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: stacks clean commits.
Image traits: location green-check meadow; accessory review stamp; palette rose quartz and slate; mood patient; pose pointing at a small proof artifact; shell woven fiber shell; lighting soft studio lighting; background tiny artifact crates.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Gilded Proofling in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@giodl73-repo giodl73-repo force-pushed the fix-84696-symlink-write-parent branch from 4a4b562 to 039743f Compare May 23, 2026 23:22
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. label May 23, 2026
@giodl73-repo giodl73-repo force-pushed the fix-84696-symlink-write-parent branch from 039743f to 0443b85 Compare May 24, 2026 02:22
@giodl73-repo giodl73-repo merged commit 6b337ff into openclaw:main May 24, 2026
98 checks passed
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary 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]: write tool intermittently fails to follow symlinks — "directory component must be a directory"

2 participants