fix(agents): expand tilde in tool file paths#33501
fix(agents): expand tilde in tool file paths#33501thomasxm wants to merge 2 commits intoopenclaw:mainfrom
Conversation
path.resolve() treats ~ as a literal directory name, so ~/file.txt resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add expandHomePrefix() before path.resolve() in all affected tool path resolution points: - Host write operations (mkdir, writeFile) in non-workspace mode - Host edit operations (readFile, writeFile, access) in non-workspace mode - toRelativePathInRoot() workspace boundary validator (affects all tools) - resolveWorkdir() for non-sandbox exec/bash working directory - parseSandboxBindMount() for Docker bind mount host paths The host read tool and sandbox tools already handled tilde via the upstream library's expandPath(). Closes openclaw#30669 Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
Greptile SummaryThis PR adds tilde ( All identified path resolution points are now covered:
Test coverage is comprehensive (11 new tests) covering write, edit, workdir, and bind-mount path expansion, plus workspace boundary validation and non-tilde path handling. Confidence Score: 5/5
Last reviewed commit: 861bc0a |
861bc0a to
707d036
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 861bc0a01a
ℹ️ 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".
src/agents/bash-tools.shared.ts
Outdated
| const expanded = path.resolve(expandHomePrefix(workdir, { home: homedir() })); | ||
| const stats = statSync(expanded); | ||
| if (stats.isDirectory()) { | ||
| return workdir; | ||
| return expanded; |
There was a problem hiding this comment.
Preserve relative workdir for node-host exec
Converting workdir to an absolute path here changes semantics for exec host=node: resolveWorkdir now turns a relative input like . into a gateway-local absolute path, and that value is forwarded as cwd to node execution (src/agents/bash-tools.exec.ts:401-405). On the node side, approval hardening requires the provided cwd to exist locally (src/node-host/invoke-system-run-plan.ts:77-90), so remote nodes with different filesystem layouts can start failing with SYSTEM_RUN_DENIED where relative workdir previously worked.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in f8c9e28. resolveWorkdir now only returns the absolute path when tilde was actually expanded (expanded \!== workdir); otherwise it returns the original workdir value, preserving relative paths like . for node-host exec.
Summary
path.resolve("~/file.txt")treats~as a literal directory name, resolving to<cwd>/~/file.txtinstead of/home/user/file.txtexpandHomePrefix(..., { home: os.homedir() })beforepath.resolve()at all affected tool path resolution points, ensuring~always expands to the real OS home (notOPENCLAW_HOME)fs-safe.test.tswhere a hardcoded Unix path/tmp/fake-home-testbroke on WindowsThis is a rebase of #30866 which was closed as a duplicate of #30431, but the two PRs have significantly different scope (see comparison below).
Why this is not a duplicate of #30431
normalizeToolParamsonly)writeHostFile(host write)readFile/access(host edit)resolveWorkdir()(bash/exec cwd)parseSandboxBindMount()(Docker bind mounts)toRelativeWorkspacePath)expandPath)os.tmpdir()instead of hardcoded/tmp)#30431 only adds tilde expansion in
normalizeToolParams, which handles thepathparameter normalization for read/write/edit tool inputs. However, several other code paths resolve file paths independently ofnormalizeToolParams:writeHostFile()— the shared host write helper usespath.resolve()directly without tilde expansionresolveWorkdir()inbash-tools.shared.ts— the working directory for exec/bash tools bypassesnormalizeToolParamsentirelyparseSandboxBindMount()insandbox/fs-paths.ts— Docker bind mount host paths like~/mydata:/data:rware parsed separatelyThese three paths would remain broken with only #30431 merged.
Path resolution points covered
writeHostFile()shared write helpermkdirnon-workspacereadFile/accessnon-workspacetoRelativeWorkspacePath()workspace boundaryexpandPath()resolveWorkdir()non-sandbox exec/bash workdirparseSandboxBindMount()Docker bind mount host pathexpandPath()expandPath()Test plan
~path creates file in home directorymkdirwith~creates directory in homereadFilewith~reads from homeaccesswith~checks home path~paths outside workspace root~paths inside workspace rootresolveWorkdir("~")returns home directoryresolveWorkdir("~/subdir")returns home subdirectoryresolveWorkdirfalls back with warning for nonexistent~subdirparseSandboxBindMount("~/mydata:/data:rw")expands host pathexpandHomePrefixtest uses platform-correct paths (Windows CI fix)Closes #30669
Related: #30782, #30788, #30744, #30770, #30756, #30753, #30752, #30747