Skip to content

fix: correctly evaluate path containment at filesystem root - #1296

Open
awhite0030 wants to merge 3 commits into
Nano-Collective:mainfrom
awhite0030:fix-ispathinside-root-11412373045009628762
Open

awhite0030 wants to merge 3 commits into
Nano-Collective:mainfrom
awhite0030:fix-ispathinside-root-11412373045009628762

Conversation

@awhite0030

@awhite0030 awhite0030 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Description

Root cause: isPathInside improperly appends a path separator path.sep to normalizedRoot before evaluating if normalizedTarget starts with it. When the root is a filesystem root, the normalized string already ends with a path separator, creating a doubled separator (e.g. // or C:\\\), causing containment checks to fail.
Fix: Conditionally append path.sep only if normalizedRoot doesn't already end with one, ensuring paths are evaluated correctly under root folders.
Validation:

./validate.sh .

Resulted in passing all validation checks, including a new test asserting containment within the filesystem root (/ and C:\).

Fixes #1240

Fixes #1240

Type of Change

  • Bug fix
  • Documentation update

Changeset

  • Added a changeset (pnpm changeset) describing this change for the changelog

Docs-only or internal chores need no changeset (or run pnpm changeset --empty to note that intentionally).

Testing

Automated Tests

  • New features include passing tests in .spec.ts/tsx files
  • All existing tests pass (pnpm test:all completes successfully)
  • Tests cover both success and error scenarios

Manual Testing

  • Tested with Ollama
  • Tested with OpenRouter
  • Tested with OpenAI-compatible API
  • Tested MCP integration (if applicable)

Checklist

  • If this was for an open issue, I was assigned to it
  • Code follows project style guidelines
  • Self-review completed
  • Documentation updated (if needed)
  • No breaking changes (or clearly documented)
  • Appropriate logging added using structured logging (see CONTRIBUTING.md)

actions-user and others added 3 commits September 12, 2026 02:32
Fix path containment check when checking paths within a project root that
is the filesystem root (like `/` or `C:\`).

This caused valid files within the workspace root to be rejected because
the duplicated path separator evaluated incorrectly in `startsWith`.
@github-actions

Copy link
Copy Markdown
Contributor

nc-review: needs work — 2 blocking, 2 nits

@awhite0030 — there is a blocking item below.

The fix to isPathInside for the filesystem-root edge case is correct and well-targeted, and the new test exercises the exact reproduction from issue #1240. However the PR only patches one site: the same root + path.sep pattern is duplicated in isValidFilePath (source/utils/path-validation.ts:87) and inline in source/tools/search-file-contents.tsx:57, and the issue explicitly names search_file_contents as failing. With root = /, search_file_contents still rejects every in-project path with the same 'escapes project directory' error. The isValidFilePath site also still rejects absolute paths under root = / (different code path, different error message, same root cause). The fix is correct as a unit; it does not fully resolve the issue.

🔴 blocking · completeness · source/tools/search-file-contents.tsx:57

The same root + path.sep pattern the PR fixes in isPathInside is reimplemented inline here:

if (searchPath !== root && !searchPath.startsWith(root + path.sep)) {
    return `Error: Path escapes project directory: ${args.path}`;
}

With root === '/', root + path.sep === '//', so every in-project search path fails containment — exactly the bug the issue (#1240) reports for search_file_contents. The PR does not touch this file, so the user-visible symptom for that tool remains after merging. Replace the inline check with the (now-fixed) isPathInside from @/utils/path-validation so the two stay in sync, or apply the same endsWith(path.sep) guard here.

🔴 blocking · completeness · source/utils/path-validation.ts:87

isValidFilePath contains the identical bug the PR fixes in isPathInside a few lines below:

const root = path.resolve(containmentRoot);
const abs = path.resolve(filePath);
return abs === root || abs.startsWith(root + path.sep);

With containmentRoot === '/', this returns false for every absolute path under root (e.g. /etc/passwd does not start with //), so resolveFilePath rejects absolute paths with Invalid file path: ... even though they are inside the project. resolveFilePath calls isValidFilePath before isPathInside, so the user-facing flow is still broken for absolute paths under root = /. Apply the same endsWith(path.sep) prefix guard, or — better — collapse both checks onto isPathInside so this drift cannot recur.

⚪ nit · tests · source/utils/path-validation.spec.ts:310

The new test covers the POSIX filesystem-root case (resolve('/')) but the Windows branch is gated behind if (sep === '\'), so on the Linux/macOS CI it never runs. That is the only platform on which path.resolve does anything interesting for the bug (it always produces '/' on POSIX regardless of input), so the test is correct on POSIX. Worth flagging only because a maintainer who later edits the test might delete the Windows arm as dead code without realising it is the only thing covering C:\; consider an explicit t.skip on POSIX or an AVA test.if predicate with a comment explaining the asymmetry.

⚪ nit · scope · badges/stars.svg:1

The diff modifies badges/stars.svg and the other badge SVGs. At minimum the stars badge embeds the contributor's fork URL (https://github.com/awhite0030/nanocoder/stargazers) rather than the upstream org's. These badge updates are unrelated to the fix and look like an accidental commit of stats-bot output from the contributor's fork checkout. Not blocking on its own, but the stars-badge URL in particular should not land on main.


🔴 blocking · 🟠 a reviewer would ask for a change · ⚪ optional

Automated code review — correctness, security, design, tests, plus duplicates and scope. A human still decides; this is not a substitute for review and is not exhaustive. The required status checks separately cover lint, formatting, types, unused dependencies, the test suite and the build. This bot never merges. Maintainers can rerun with /re-review.

@github-actions github-actions Bot added the agent:needs-work nc-review found blocking findings label Sep 14, 2026
@will-lamerton

Copy link
Copy Markdown
Member

Can you take a look at the bot comments and merge conflicts please @awhite0030 :)

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

Labels

agent:needs-work nc-review found blocking findings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] isPathInside() fails path containment when project root is filesystem or drive root (/ or C:\)

3 participants