Skip to content

Make shell command resolution use Effect file metadata#3554

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/idiomatic-effect-patterns-8876
Draft

Make shell command resolution use Effect file metadata#3554
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/idiomatic-effect-patterns-8876

Conversation

@cursor

@cursor cursor Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Refactored the Effect-based command path resolver to use FileSystem.stat metadata and Option instead of a null sentinel plus synchronous node:fs access checks.
  • Added an Effect test that creates executable and non-executable command candidates through the platform FileSystem layer.

Why

This keeps command resolution inside the Effect FileSystem capability, making the path more mockable/testable via layers while preserving POSIX executable-bit behavior.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes
Open in Web View Automation 

Note

Make shell command resolution check POSIX execute mode bits via Effect file metadata

  • Replaces the prior canExecuteFile call in isExecutableFile with a stat-based check using FileSystem.File.Info mode bits, so executability is determined by POSIX user/group/other execute bits relative to the current process uid and gids.
  • Adds helpers canExecuteFileInfo, getCurrentUid, and getCurrentGids in shell.ts to encapsulate POSIX permission logic; root (uid 0) is always allowed.
  • Windows behavior remains extension-based and is unchanged.
  • Behavioral Change: on POSIX, files in PATH that lack an execute bit for the current user are now rejected even if they exist; previously such files may have been treated as executable.
📊 Macroscope summarized 092b804. 1 file reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jun 25, 2026
Comment on lines +53 to +65
function canExecuteFileInfo(info: FileSystem.File.Info): boolean {
if ((info.mode & POSIX_ANY_EXECUTE_MODE) === 0) return false;

const uid = getCurrentUid();
if (uid === 0) return true;
if (uid !== undefined && Option.isSome(info.uid)) {
return info.uid.value === uid
? (info.mode & POSIX_USER_EXECUTE_MODE) !== 0
: canExecuteFileInfoForGroups(info);
}

return canExecuteFileInfoForGroups(info) || (info.mode & POSIX_ANY_EXECUTE_MODE) !== 0;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High src/shell.ts:53

canExecuteFileInfo at line 64 treats a file as executable whenever any execute bit is set, even for unrelated users. A file with only the owner execute bit set (e.g., mode 0o100) incorrectly returns true for non-owners, causing isExecutableFile to report commands as available that the process cannot actually execute. This diverges from fs.accessSync(..., X_OK) behavior and leads to failed command resolution.

-function canExecuteFileInfo(info: FileSystem.File.Info): boolean {
-  if ((info.mode & POSIX_ANY_EXECUTE_MODE) === 0) return false;
-
-  const uid = getCurrentUid();
-  if (uid === 0) return true;
-  if (uid !== undefined && Option.isSome(info.uid)) {
-    return info.uid.value === uid
-      ? (info.mode & POSIX_USER_EXECUTE_MODE) !== 0
-      : canExecuteFileInfoForGroups(info);
-  }
-
-  return canExecuteFileInfoForGroups(info) || (info.mode & POSIX_ANY_EXECUTE_MODE) !== 0;
-}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/shared/src/shell.ts around lines 53-65:

`canExecuteFileInfo` at line 64 treats a file as executable whenever *any* execute bit is set, even for unrelated users. A file with only the owner execute bit set (e.g., mode `0o100`) incorrectly returns `true` for non-owners, causing `isExecutableFile` to report commands as available that the process cannot actually execute. This diverges from `fs.accessSync(..., X_OK)` behavior and leads to failed command resolution.

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

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant