Skip to content

Conversation

@mfsiega
Copy link
Contributor

@mfsiega mfsiega commented Dec 4, 2025

Summary

Make sure we only resolve filepaths once, so we know that when we read them they haven't been changed to link somewhere else.

Related Linear tickets, Github issues, and Community forum posts

Review / Merge checklist

  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with release/backport (if the PR is an urgent fix that needs to be backported)

@codecov
Copy link

codecov bot commented Dec 4, 2025

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 11 files

Prompt for AI agents (all 1 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts">

<violation number="1" location="packages/core/src/execution-engine/node-execution-context/utils/file-system-helper-functions.ts:94">
P1: The try/catch block will not catch `ELOOP` errors because `createReadStream` opens files asynchronously. The error is emitted via the stream&#39;s `&#39;error&#39;` event, not thrown synchronously. You need to attach an error handler to the stream or use `fs.open()` with `O_NOFOLLOW` first, then create the stream from the fd.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

@n8n-assistant n8n-assistant bot added core Enhancement outside /nodes-base and /editor-ui n8n team Authored by the n8n team node/improvement New feature or request labels Dec 4, 2025
@currents-bot
Copy link

currents-bot bot commented Dec 4, 2025

E2E Tests: n8n tests passed after 10m 9s

🟢 573 · 🔴 0 · ⚪️ 43 · 🟣 4

View Run Details

Run Details

  • Project: n8n

  • Groups: 2

  • Framework: Playwright

  • Run Status: Passed

  • Commit: 7140e57

  • Spec files: 129

  • Overall tests: 616

  • Duration: 10m 9s

  • Parallelization: 9

Groups

GroupId Results Spec Files Progress
multi-main:ui 🟢 519 · 🔴 0 · ⚪️ 43 · 🟣 3 120 / 120
multi-main:ui:isolated 🟢 54 · 🔴 0 · ⚪️ 0 · 🟣 1 9 / 9


This message was posted automatically by currents.dev | Integration Settings

mfsiega and others added 2 commits December 4, 2025 21:16
…s/file-system-helper-functions.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
@blacksmith-sh

This comment has been minimized.

@mfsiega mfsiega force-pushed the cat-1852-resolve-file-path-once branch from 15a88a9 to 5dc9144 Compare December 5, 2025 10:07

try {
await fsAccess(filePath);
await fsAccess(resolvedFilePath);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note: the NodeJS docs say: Using fsPromises.access() to check for the accessibility of a file before calling fsPromises.open() is not recommended.. Rather you should just try to open the file, and handle any potential failure. We should think about fixing this, potentially in this PR; but it's a bit orthogonal to the issue at hand.

@mfsiega mfsiega requested a review from tomi December 5, 2025 10:50
@tomi tomi requested a review from Cadiac December 5, 2025 10:53
export async function isFilePathBlocked(filePath: string): Promise<boolean> {
const allowedPaths = getAllowedPaths();
let resolvedFilePath = '';
const resolvePath = async (path: PathLike): Promise<ResolvedFilePath> => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Rest of the functions in this file have been defined with function. Maybe we could keep it consistent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
}

const __brand = Symbol('brand');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or:

Suggested change
const __brand = Symbol('brand');
const __brand = Symbol('resolvedFilePath');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

new NodeOperationError(
node,
`The file "${String(resolvedFilePath)}" could not be opened.`,
{ level: 'warning' },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we attach the original error as cause?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. (I think this is what you meant?)

Comment on lines +704 to 708
resolvePath(path: PathLike): Promise<ResolvedFilePath>;
isFilePathBlocked(filePath: ResolvedFilePath): boolean;
createReadStream(filePath: ResolvedFilePath): Promise<Readable>;
getStoragePath(): string;
writeContentToFile(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add docs to all these functions with mention that "Use resolvePath to resolve the path"?

);
}
return await fsWriteFile(filePath, content, { encoding: 'binary', flag });
return await fsWriteFile(resolvedFilePath, content, { encoding: 'binary', flag });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this still have the issue? Can we make this so that fsWriteFile doesn't follow symlinks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! I think I'm handling the flags correctly here.

Cadiac
Cadiac previously approved these changes Dec 5, 2025
Copy link
Contributor

@Cadiac Cadiac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a smart way to solve this 👍

const resolvePath = async (path: PathLike): Promise<ResolvedFilePath> => {
try {
resolvedFilePath = await fsRealpath(filePath);
return (await fsRealpath(path)) as ResolvedFilePath; // apply brand, since we know it's resolved now
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branded types seem like a smart way to enforce this 👍

@blacksmith-sh

This comment has been minimized.

@mfsiega mfsiega requested review from Cadiac and tomi December 5, 2025 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Enhancement outside /nodes-base and /editor-ui n8n team Authored by the n8n team node/improvement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants