Skip to content

fix: materialize artifacts in the user's own temp folder - #947

Open
wan9chi wants to merge 1 commit into
mainfrom
claude/user-temp-artifacts
Open

wan9chi wants to merge 1 commit into
mainfrom
claude/user-temp-artifacts

Conversation

@wan9chi

@wan9chi wan9chi commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Motivation

vp run writes the fspy preload library and the vt_client_napi addon to the fspy and vt_client_napi folders in the system temp directory. On Linux that directory is /tmp, which every user shares, so those folders belong to whoever ran vp run first. Another user running a different version can't write there, so their tracked tasks fail to start. Running the same version, they use files the first user could replace.

vp run --json, the next PR in this stack, writes its JSON Schema the same way, which is where this came up.

Changes

  • vt_materialized_artifact::user_temp_dir(name) returns a folder in the system temp directory that only the current user can write to:
    • On Unix, {temp}/{name}-{uid}, created with mode 0700. An existing path must be a directory, not a symlink, that the current user owns and that nobody else can write to; otherwise it's an error. On macOS, the temp directory is already per user, so only the folder name changes.
    • On Windows, {temp}\{name}, since the temp directory is already the user's own.
  • fspy and the vt_client_napi addon materialize there.
  • Materialize::at no longer resets the mode of an existing file. That chmod followed symlinks, and with a folder nobody else can write to, there's no drift to fix. Only executables get an explicit mode (0755). Other files keep the 0600 that new temp files get.

🤖 Generated with Claude Code


Note

Medium Risk
Changes where security-sensitive embedded binaries (fspy preload, NAPI addon) are written and adds Unix permission checks that must be correct for runs to start safely on multi-user systems.

Overview
On Linux shared /tmp, helper files that vp run materializes (fspy’s preload library and the vt_client_napi addon) no longer land in world-visible folders like /tmp/fspy. They now use user_temp_dir, which creates {temp}/{name}-{uid} with mode 0700 on Unix and rejects symlinks or directories other users can write to; Windows keeps {temp}\{name} because the temp dir is already per-user.

fspy and napi_client_path call that helper instead of manually creating shared temp subdirs. Materialize::at assumes the target directory is user-private: it stops reconciling modes on existing files (avoiding chmod through symlinks) and only sets 0755 when creating new executable artifacts; other new files stay at the temp file default (0600).

Unit tests cover directory creation, symlink rejection, and world-writable directory rejection on Unix.

Reviewed by Cursor Bugbot for commit dd39680. Bugbot is set up for automated code reviews on this repo. Configure here.

On Linux, `vp run` wrote the fspy preload library and the
`vt_client_napi` addon to `/tmp/fspy` and `/tmp/vt_client_napi`, which
belong to whoever created them first. Another user running a different
version couldn't write there, and the same version used files the first
user could replace.

- `vt_materialized_artifact::user_temp_dir` returns `{temp}/{name}-{uid}`
  on Unix, created with mode 0o700. An existing path has to be a
  directory, not a symlink, owned by the current user and not writable
  by anyone else. On Windows, the temp folder is already the user's own,
  so it returns `{temp}\{name}`.
- `Materialize::at` no longer reconciles an existing file's mode, which
  followed symlinks: no one else can write to the folder. Only
  executables get an explicit mode, 0o755.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wan9chi
wan9chi force-pushed the claude/user-temp-artifacts branch from 2c464cf to dd39680 Compare November 6, 2026 01:31
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown

fspy benchmark

linux

dynamic/launch             change  +1.17%  [ -3.67% ..  +4.79%]  overhead   +59.94%
dynamic/access             change  +0.39%  [ -3.62% ..  +5.66%]  overhead   +22.39%
dynamic/access-relative    change  +0.62%  [ -2.69% ..  +3.29%]  overhead   +67.37%
dynamic/access-contended   change  +0.36%  [ -4.37% ..  +5.33%]  overhead   +39.35%
static/launch              change  +0.40%  [ -3.47% ..  +4.12%]  overhead  +199.31%
static/access              change  +0.30%  [ -0.80% ..  +2.20%]  overhead +1459.16%
static/access-relative     change  -0.42%  [ -1.71% ..  +1.22%]  overhead +1964.39%
static/access-contended    change  +0.13%  [ -0.79% ..  +0.78%]  overhead +1546.47%

macos

dynamic/launch             change  +0.10%  [ -5.30% ..  +5.25%]  overhead  +248.69%
dynamic/access             change  -0.37%  [ -4.94% ..  +2.17%]  overhead    +1.44%
dynamic/access-relative    change  +1.23%  [ -2.63% ..  +4.76%]  overhead  +250.55%
dynamic/access-contended   change  +0.56%  [ -1.97% ..  +3.57%]  overhead    +2.77%

windows

dynamic/launch             change  -0.18%  [ -2.33% ..  +1.92%]  overhead   +31.09%
dynamic/access             change  +0.00%  [ -0.62% ..  +0.83%]  overhead    +1.25%
dynamic/access-relative    change  +0.00%  [ -0.41% ..  +0.62%]  overhead    +1.44%
dynamic/access-contended   change  +0.00%  [ -0.59% ..  +0.98%]  overhead    +1.39%

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