Skip to content

Drop host-filesystem nodes from the production node surface - #4743

Merged
georgi merged 1 commit into
mainfrom
claude/file-access-nodes-prod-sfo9ai
Aug 5, 2026
Merged

Drop host-filesystem nodes from the production node surface#4743
georgi merged 1 commit into
mainfrom
claude/file-access-nodes-prod-sfo9ai

Conversation

@georgi

@georgi georgi commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Problem

In production we don't want file-access nodes like the document file input.

The cloud profile (NODETOOL_ENV=production → cloud, unless NODETOOL_NODE_PROFILE=full) already curates the catalog down to the creative node set, but it whole-lists nodetool.input, nodetool.image, nodetool.audio, nodetool.video, and nodetool.model3d. The nodes inside those namespaces that read and write paths on the server's own disk therefore survived.

nodetool.input.DocumentFileInput is the one users hit first: a native file picker rendered in a browser tab that can only ever point at the container's filesystem, not the user's machine.

The matching HTTP surfaces are already refused in production — /api/files/local (file-api.ts:163), the workspace routes (workspace-api.ts:76), tRPC files.list (trpc/routers/files.ts:46). So these nodes were offering a picker that cannot pick and a run that cannot resolve.

Change

Collect the offenders in a new CLOUD_HOST_FILE_NODES and embed it in the existing CLOUD_NODE_DENYLIST (packages/protocol/src/cloud-profile.ts). applyCloudNodePolicy already unregisters denied types at bootstrap, so the palette, /api/nodes/metadata, and the runner all agree with no new mechanism.

Thirteen node types, all verified to exist in the registry (a typo here would be a silent no-op):

Path pickers nodetool.input.DocumentFileInput, FilePathInput, FolderPathInput
Audio LoadAudioFile, LoadAudioFolder, SaveAudioFile
Image LoadImageFile, LoadImageFolder, SaveImageFile
Video LoadVideoFile, SaveVideoFile
3D LoadModel3DFile, SaveModel3DFile

Assets stay. They're how the cloud moves files: the *Assets loaders, AssetFolderInput, DocumentInput, and the plain SaveImage/SaveAudio/SaveVideo/SaveModel3D savers are untouched, and a test pins that.

Why the list is written out rather than derived

Two shapes needed naming, and only one is visible in metadata:

  • Most declare a picker property (json_schema_extra: { type: "file_path" }) — detectable.
  • The rest (LoadAudioFile and friends) take a plain str prop and call fs in process(). Nothing in their metadata distinguishes them from any other string node.

So the list is explicit, and a registry-level drift guard covers the detectable half: a test asserts no node with a file/folder picker property survives the policy, so one added later inside an allowed namespace fails CI instead of shipping. I verified the guard actually fails by temporarily removing DocumentFileInput from the list — it caught it — then restored.

Nodes that use scratch files under os.tmpdir() (ffmpeg work in nodetool.video.* and nodetool.timeline.*) are not host file access and correctly stay; I checked each against its source rather than trusting an fs grep.

Scope

Self-hosted deployments running NODETOOL_NODE_PROFILE=full are unaffected, consistent with the rest of the cloud curation. I deliberately did not gate on bare NODETOOL_ENV=production, which would override that documented opt-out — say the word if you'd rather these nodes be gone on every production server regardless of profile.

No shipped example workflow references any of the removed nodes (checked). Existing user workflows in the cloud that contain one will now fail validation up front rather than at the node — those runs could not have resolved a host path anyway.

Testing

  • packages/protocol: 794 tests pass; added coverage that the host-file nodes are denied and their asset counterparts are kept.
  • packages/websocket node-registry-setup: 19 pass, including the new drift guard.
  • npm run lint passes; root npm run typecheck passes.

Two pre-existing environment failures, confirmed identical on a clean tree via git stash: electron's typecheck and 26 websocket test files fail to import because packages/websocket/dist and @nodetool-ai/dsl aren't built in this sandbox. All 1918 collected websocket tests pass.


Generated by Claude Code

The cloud profile already curates production down to the creative node
set, but it whole-lists `nodetool.input`, `nodetool.image`, and their
siblings — so the nodes that read and write paths on the server's own
disk survived. `nodetool.input.DocumentFileInput` is the one users hit
first: a file picker in a browser tab that can only point at the
container's filesystem, not theirs.

The matching HTTP surfaces are already refused in production
(`/api/files/local`, the workspace routes, tRPC `files.list`), so these
nodes offered a picker that cannot pick and a run that cannot resolve.

Collect them in CLOUD_HOST_FILE_NODES and embed that in the existing
CLOUD_NODE_DENYLIST, keeping the "no host filesystem in the cloud" rule
as one reviewable list rather than entries scattered by namespace. The
asset-store counterparts — the `*Assets` loaders, AssetFolderInput, and
the plain SaveImage/SaveAudio/SaveVideo savers — are untouched, since
assets are how the cloud moves files.

Two node shapes needed naming: those declaring a `file_path`/`folder_path
picker property, and those taking a plain string path and calling `fs` in
`process()`. Only the first is visible in metadata, so a registry-level
test asserts no picker survives the policy — a new one lands in CI rather
than in production. Nodes using scratch files under `os.tmpdir()`
(ffmpeg work in the video and timeline nodes) are not host file access
and stay.

Self-hosted deployments setting NODETOOL_NODE_PROFILE=full are
unaffected, as with the rest of the cloud curation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TfkxHL5wPA3ZPKAvie8rbh
@georgi
georgi enabled auto-merge (squash) August 5, 2026 21:36
@georgi
georgi merged commit ebd8d65 into main Aug 5, 2026
23 checks passed
@georgi
georgi deleted the claude/file-access-nodes-prod-sfo9ai branch August 5, 2026 22:00
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.

2 participants