Skip to content

fix(runtime): match linux and node fs semantics for cwd, symlinks and rm - #2077

Open
eersnington wants to merge 2 commits into
mainfrom
fix/fs-cwd-symlinks-rm
Open

eersnington wants to merge 2 commits into
mainfrom
fix/fs-cwd-symlinks-rm

Conversation

@eersnington

Copy link
Copy Markdown
Member
  • process.chdir goes through a new process.chdir RPC. The kernel process table owns the cwd, like umask.
  • The sidecar resolves every relative guest fs path against that cwd at its one path entry point. A child process starts in the parent's cwd and resolves a relative cwd option against it.
  • fs.cp copies symlinks as links (dereference and verbatimSymlinks honored) and applies filter.
  • readdir({ withFileTypes: true }) types entries without following symlinks. The readdir payload carries the libuv dirent type.
  • fs.rm on a directory without recursive throws ERR_FS_EISDIR. Callback rm reuses rmSync.
Guest call Before After
chdir("/tmp/p"), then mkdirSync("out") creates /out creates /tmp/p/out
relative process.chdir("sub") ENOENT moves to /tmp/p/sub
readlink("/proc/self/cwd") after chdir spawn cwd current cwd
child spawn(..., { cwd: ".." }) from /tmp/p/sub runs in / runs in /tmp/p
cpSync(src, dst, { recursive: true }) with src/link -> ../dir copies the contents of dir dst/link -> <abs>/dir
dirent.isSymbolicLink() always false true for links
rmSync(dir) removes dir ERR_FS_EISDIR

process.chdir now goes through a process.chdir RPC that validates the target with the same mapping-aware stat as fs.stat and records it in the kernel process table, like umask. The sidecar resolves every relative JavaScript fs path against that cwd at its one path entry point, and a child spawn starts in, and resolves a relative cwd option against, the parent's kernel cwd. Relative fs calls no longer land in /, and /proc/<pid>/cwd and child processes follow chdir.
…ddir and rm

cp copies symlinks as links (honoring dereference and verbatimSymlinks) and applies the filter option, readdir Dirents report symlinks without following them, and rm on a directory without recursive throws ERR_FS_EISDIR. The sidecar readdir payload now carries the entry's libuv dirent type (file, directory or symlink) instead of a followed is-directory flag. Callback rm reuses rmSync instead of a second tree walk.
@railway-app

railway-app Bot commented Oct 23, 2026

Copy link
Copy Markdown

This PR was not deployed automatically as @eersnington does not have access to the Railway project.

In order to get automatic PR deploys, please add @eersnington to your workspace on Railway.

@github-actions

Copy link
Copy Markdown
Contributor

📟 Pip-Boy · 03ca715

📦 Packages · fresh npm install resolve, no lockfile · this PR vs base

No notable install size, dependency, or entrypoint changes across 6 packages.

All 6 packages · linux-x64-gnu
package (linux-x64-gnu) @latest base this PR Δ vs base packages
@rivet-dev/agentos-core 326.0 MB 326.0 MB 326.0 MB 0 10 (0)
@rivet-dev/agentos-node-pty 7.6 KB 18.0 KB 18.0 KB 0 1 (0)
@rivet-dev/agentos-posix 253.8 MB 253.8 MB 253.8 MB 0 7 (0)
@rivet-dev/agentos-runtime-core 253.8 MB 253.8 MB 253.8 MB 0 6 (0)
@rivet-dev/agentos-sandbox 363.7 MB 363.7 MB 363.7 MB 0 85 (0)
@rivet-dev/agentos-toolchain 130.8 KB 141.2 KB 141.2 KB 0 2 (0)

🧹 Rust dependencies · cargo deny + cargo shear

check new in this PR fixed existing on base
advisories ✅ 0 0 25
licenses ✅ 0 0 0
sources ✅ 0 0 0
bans ✅ 0 0 0
unused ✅ 0 0 16

🦀 Binaries · publish Dockerfiles, --release

Base: main@ae5e5cd, the merge base.

artifact npm @latest base this PR Δ vs base
agentos-native-sidecar linux-x64-gnu 143.8 MB 143.8 MB 143.9 MB +92.2 KB (+0.1%)

⏱ Timing

job wall time slowest step
zizmor 10s checkout · 3s
changes 24s checkout · 22s
footprint 1m34s Pack this commit · 31s
hygiene 57s checkout · 22s
native · linux-x64-gnu 13m15s Build with the publish Dockerfile · 12m55s
⏭ self-test — skipped
report 16s Write the comment and run summary · 5s
🔭 Full CI trace for this commit

One OpenTelemetry trace of CI and Pip-Boy for 03ca715: every job and step, with the sizes above attached. Run after CI finishes.

pnpm install --frozen-lockfile --filter 'pipboy...'
pnpm --filter pipboy pipboy trace --sha 03ca715c65f2ee1f9110d096f3db30e83fb78147

Add --otlp <url> to send it to any OTLP/HTTP collector.

Agent instruction: From a rivet-dev/agentos checkout, run the commands above, then read the trace file the last command prints. List the slowest jobs and steps and explain where CI time went.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant