Skip to content

fix(agents): tighten workspace file opens#66636

Merged
drobison00 merged 13 commits into
openclaw:mainfrom
eleqtrizit:423
Apr 14, 2026
Merged

fix(agents): tighten workspace file opens#66636
drobison00 merged 13 commits into
openclaw:mainfrom
eleqtrizit:423

Conversation

@eleqtrizit

Copy link
Copy Markdown
Contributor

Summary

  • Routes agents.files.get, agents.files.set, and workspace file listing through the existing root-scoped fs-safe helpers
  • Removes the separate path-resolution layer for allowlisted workspace files so the gateway uses the same open/read/write validation path everywhere

Changes

  • Replaced the hand-rolled workspace file resolver in src/gateway/server-methods/agents.ts with openFileWithinRoot, readFileWithinRoot, and writeFileWithinRoot
  • Updated src/infra/fs-safe.ts to resolve opened file real paths from the open file descriptor before falling back to the current path
  • Tightened the gateway tests to reject symlink aliases for allowlisted agent files and added an fs-safe regression that locks in the fd-first realpath behavior

Validation

  • Ran pnpm test src/gateway/server-methods/agents-mutate.test.ts
  • Ran pnpm test src/infra/fs-safe.test.ts
  • Ran pnpm check on the rebased branch

Notes

@greptile-apps

greptile-apps Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR tightens workspace file access in the agents gateway by routing agents.files.get and agents.files.set through the shared fs-safe helpers, and adds fd-first realpath resolution to openVerifiedLocalFile so a symlink swap between open(2) and realpath(3) can no longer redirect the validated path to a different inode. The agents.files.set bare-catch regression flagged in a prior review thread was addressed in a follow-up commit (149616372) that rethrows non-SafeOpenError errors, consistent with the agents.files.get and writeWorkspaceFileOrRespond patterns.

Confidence Score: 5/5

  • This PR is safe to merge; the prior P1 concern has been resolved and all remaining findings are P2 or lower.
  • The bare-catch regression in agents.files.set that allowed non-SafeOpenError OS errors to be swallowed was fixed in the final follow-up commit. The fd-first realpath addition is well-tested (race scenario verified in fs-safe.test.ts), and the symlink/hardlink gateway tests are comprehensive. No P0 or P1 issues remain.
  • No files require special attention.

Reviews (4): Last reviewed commit: "fix(agents): rethrow unexpected errors i..." | Re-trigger Greptile

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

Copy link
Copy Markdown

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: 53eb7ecc31

ℹ️ 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".

Comment thread USER.md Outdated
@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: L maintainer Maintainer-authored PR labels Apr 14, 2026
@eleqtrizit

Copy link
Copy Markdown
Contributor Author

@greptile review

@eleqtrizit

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ 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".

@drobison00

Copy link
Copy Markdown
Contributor

@greptile review
@codex review

Comment thread src/gateway/server-methods/agents.ts Outdated

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

Copy link
Copy Markdown

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: e82c07b679

ℹ️ 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".

Comment thread src/gateway/server-methods/agents.ts
@drobison00

Copy link
Copy Markdown
Contributor

@greptile review

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

Copy link
Copy Markdown

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: 149616372e

ℹ️ 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".

Comment thread src/gateway/server-methods/agents.ts
eleqtrizit and others added 4 commits April 14, 2026 13:56
Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.
The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.
@drobison00 drobison00 merged commit 472bcbb into openclaw:main Apr 14, 2026
38 of 42 checks passed
kvnkho pushed a commit to kvnkho/openclaw that referenced this pull request Apr 17, 2026
* fix(agents): tighten workspace file opens

* fix(agents): clarify symlink rejection tests

* fix(agents): surface unsafe identity reads

* fix(agents): use non-blocking opens for identity reads and write-mode probes

* fix(fssafe): restore symlink read identity check

* fix(worklog): append comment resolution status

* fix(fssafe): close afterOpen handle leaks

* fix(worklog): append comment resolution follow-up

* fix(worklog): drop internal user file

* fix(agents): rethrow unexpected errors in agents.files.get

* changelog: note agents.files fs-safe routing + fd-first realpath (openclaw#66636)

* fix(agents): rethrow unexpected errors in agents.files.set too

Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.

* test(agents): match fsStat/fsLstat mock signatures

The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
* fix(agents): tighten workspace file opens

* fix(agents): clarify symlink rejection tests

* fix(agents): surface unsafe identity reads

* fix(agents): use non-blocking opens for identity reads and write-mode probes

* fix(fssafe): restore symlink read identity check

* fix(worklog): append comment resolution status

* fix(fssafe): close afterOpen handle leaks

* fix(worklog): append comment resolution follow-up

* fix(worklog): drop internal user file

* fix(agents): rethrow unexpected errors in agents.files.get

* changelog: note agents.files fs-safe routing + fd-first realpath (openclaw#66636)

* fix(agents): rethrow unexpected errors in agents.files.set too

Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.

* test(agents): match fsStat/fsLstat mock signatures

The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
* fix(agents): tighten workspace file opens

* fix(agents): clarify symlink rejection tests

* fix(agents): surface unsafe identity reads

* fix(agents): use non-blocking opens for identity reads and write-mode probes

* fix(fssafe): restore symlink read identity check

* fix(worklog): append comment resolution status

* fix(fssafe): close afterOpen handle leaks

* fix(worklog): append comment resolution follow-up

* fix(worklog): drop internal user file

* fix(agents): rethrow unexpected errors in agents.files.get

* changelog: note agents.files fs-safe routing + fd-first realpath (openclaw#66636)

* fix(agents): rethrow unexpected errors in agents.files.set too

Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.

* test(agents): match fsStat/fsLstat mock signatures

The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* fix(agents): tighten workspace file opens

* fix(agents): clarify symlink rejection tests

* fix(agents): surface unsafe identity reads

* fix(agents): use non-blocking opens for identity reads and write-mode probes

* fix(fssafe): restore symlink read identity check

* fix(worklog): append comment resolution status

* fix(fssafe): close afterOpen handle leaks

* fix(worklog): append comment resolution follow-up

* fix(worklog): drop internal user file

* fix(agents): rethrow unexpected errors in agents.files.get

* changelog: note agents.files fs-safe routing + fd-first realpath (openclaw#66636)

* fix(agents): rethrow unexpected errors in agents.files.set too

Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.

* test(agents): match fsStat/fsLstat mock signatures

The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
* fix(agents): tighten workspace file opens

* fix(agents): clarify symlink rejection tests

* fix(agents): surface unsafe identity reads

* fix(agents): use non-blocking opens for identity reads and write-mode probes

* fix(fssafe): restore symlink read identity check

* fix(worklog): append comment resolution status

* fix(fssafe): close afterOpen handle leaks

* fix(worklog): append comment resolution follow-up

* fix(worklog): drop internal user file

* fix(agents): rethrow unexpected errors in agents.files.get

* changelog: note agents.files fs-safe routing + fd-first realpath (openclaw#66636)

* fix(agents): rethrow unexpected errors in agents.files.set too

Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.

* test(agents): match fsStat/fsLstat mock signatures

The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
* fix(agents): tighten workspace file opens

* fix(agents): clarify symlink rejection tests

* fix(agents): surface unsafe identity reads

* fix(agents): use non-blocking opens for identity reads and write-mode probes

* fix(fssafe): restore symlink read identity check

* fix(worklog): append comment resolution status

* fix(fssafe): close afterOpen handle leaks

* fix(worklog): append comment resolution follow-up

* fix(worklog): drop internal user file

* fix(agents): rethrow unexpected errors in agents.files.get

* changelog: note agents.files fs-safe routing + fd-first realpath (openclaw#66636)

* fix(agents): rethrow unexpected errors in agents.files.set too

Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.

* test(agents): match fsStat/fsLstat mock signatures

The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
* fix(agents): tighten workspace file opens

* fix(agents): clarify symlink rejection tests

* fix(agents): surface unsafe identity reads

* fix(agents): use non-blocking opens for identity reads and write-mode probes

* fix(fssafe): restore symlink read identity check

* fix(worklog): append comment resolution status

* fix(fssafe): close afterOpen handle leaks

* fix(worklog): append comment resolution follow-up

* fix(worklog): drop internal user file

* fix(agents): rethrow unexpected errors in agents.files.get

* changelog: note agents.files fs-safe routing + fd-first realpath (openclaw#66636)

* fix(agents): rethrow unexpected errors in agents.files.set too

Match the narrow-SafeOpenError catch pattern that agents.files.get
(commit 633b8f92) and writeWorkspaceFileOrRespond already use, so a
real OS error (ENOSPC, EACCES, EBUSY, ...) surfaces through normal
gateway error handling instead of being masked as
'unsafe workspace file'.

* test(agents): match fsStat/fsLstat mock signatures

The mock functions are declared as
  vi.fn(async (..._args: unknown[]) => Stats | null)
so mockImplementation callbacks must accept ...unknown[], not a
narrowed (filePath: string) argument. The narrower signature
works at runtime but trips tsgo's strict type check; switch to
args[0] unpacking so the callbacks match the hoisted mock shape.

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants