-
Notifications
You must be signed in to change notification settings - Fork 12.3k
Open
Labels
coreAnything pertaining to core functionality of the application (opencode server stuff)Anything pertaining to core functionality of the application (opencode server stuff)
Description
Description
The try/catch in Filesystem.resolve() (introduced in #16651) catches all exceptions from realpathSync, not just ENOENT. Errors like EACCES (permission denied), ELOOP (too many symlink levels), and ENOTDIR (component is not a directory) are silently swallowed, and the function falls back to the unresolved path.
This means:
- An
EACCESon a symlink target silently resolves to the symlink path instead of surfacing the permission error - An
ELOOP(symlink cycle) silently resolves to the unresolvable symlink path instead of alerting the user - Both could lead to
Instance.provide()creating a context keyed on a non-canonical path, re-introducing the duplicate-instance class of bugs for those edge cases
The codebase already has an isEnoent() type guard at filesystem.ts:50 used elsewhere. The fix is to narrow the catch:
export function resolve(p: string): string {
const resolved = pathResolve(windowsPath(p))
try {
return normalizePath(realpathSync(resolved))
} catch (e) {
if (isEnoent(e)) return normalizePath(resolved)
throw e
}
}Steps to reproduce
- Create a symlink cycle:
ln -s a b && ln -s b a - Or create a symlink to a permission-denied directory
- Run
opencodefrom a path involving that symlink - Observe that the error is silently swallowed instead of surfaced
Operating System
All platforms
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
coreAnything pertaining to core functionality of the application (opencode server stuff)Anything pertaining to core functionality of the application (opencode server stuff)