Skip to content

Studio: expose Windows drive roots in the folder browser - #7082

Merged
danielhanchen merged 26 commits into
unslothai:mainfrom
gaurav0107:fix/6368-windows-drive-browse-roots
Jul 15, 2026
Merged

danielhanchen merged 26 commits into
unslothai:mainfrom
gaurav0107:fix/6368-windows-drive-browse-roots

Conversation

@gaurav0107

Copy link
Copy Markdown
Contributor

Summary

On Windows, Unsloth Studio's model-selection folder browser cannot navigate between drive letters: a user whose home is on C: cannot browse to D:/E: to pick a model directory. Navigation is bounded to the roots returned by _build_browse_allowlist(), which exposes Linux removable-media mounts via linux_run_media_mount_roots() but has no Windows analog, so only roots on the home drive are ever reachable (and a drive root's parent is itself, so the "up" control can't reach a drive picker).

Changes

  • Add windows_drive_roots() to studio/backend/utils/paths/external_media.py — a Windows-only companion to linux_run_media_mount_roots() that lists readable logical drive roots (C:\, D:\, ...). Absent/unreadable drives are skipped; returns [] off Windows.
  • Wire it into both browse-allowlist builders (hub/services/models/folder_browser.py and routes/models.py) and their suggestion-chip lists, next to the existing Linux loop, so other drives are both navigable and offered as quick-picks.

Tests

  • New studio/backend/tests/test_windows_external_drive_paths.py, mirroring the existing test_linux_external_media_paths.py platform-mock style: no-op off Windows, lists readable drives, skips absent/unreadable drives, ignores malformed letters, and dedupes.
  • Updated the legacy allowlist test's external_media stub to provide the new helper.
  • python -m pytest tests/test_windows_external_drive_paths.py tests/test_linux_external_media_paths.py (from studio/backend) → 31 passed.

Validation

  • ruff check (0.15.12, repo config), python -m compileall, and scripts/verify_import_hoist.py: all clean.
  • Change is additive and platform-guarded, so Linux/macOS behavior is unchanged.

Closes #6368

gaurav0107 and others added 2 commits July 12, 2026 00:16
The model-selection folder browser bounds navigation to the roots returned
by _build_browse_allowlist(), which exposed Linux removable-media mounts via
linux_run_media_mount_roots() but had no Windows analog. As a result a user
on C: could not browse to D:/E: to pick a model directory.

Add windows_drive_roots(), a Windows-only companion to
linux_run_media_mount_roots() that lists readable logical drive roots, and
wire it into both browse-allowlist builders and their suggestion chips so
other drives are both navigable and offered as quick-picks. The helper is a
no-op on Linux/macOS, so existing platforms are unaffected.

Closes unslothai#6368

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request adds support for Windows drive roots in the folder browser, allowing users to navigate between logical drives (such as C: and D:) on Windows. The changes integrate these drive roots into the folder browser's allowlist and suggestion chips, and include a new suite of unit tests. Feedback suggests optimizing the drive-probing logic by using GetLogicalDrives via ctypes to prevent synchronous blocking of the event loop on disconnected network drives, and updating the test stubs to mock this API for deterministic test execution on Windows hosts.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

I am having trouble creating individual review comments. Click here to see my feedback.

studio/backend/utils/paths/external_media.py (117-139)

medium

Probing all 26 drive letters synchronously on the event loop using os.path.isdir can cause severe performance bottlenecks on Windows. Specifically, if there are disconnected or offline network drives (UNC paths mapped to drive letters), os.path.isdir can block the thread for up to 30 seconds per drive, hanging the entire FastAPI backend.

To prevent this, we can query the active logical drives using GetLogicalDrives via ctypes first. This is an extremely fast, non-blocking OS-level call that allows us to skip probing non-existent or inactive drive letters entirely.

    if platform.system() != "Windows":
        return []

    # Query active logical drives on Windows to avoid slow timeouts or system dialogs
    # when probing non-existent, unmounted, or disconnected drives.
    bitmask = 0
    try:
        import ctypes
        bitmask = ctypes.windll.kernel32.GetLogicalDrives()
    except Exception:
        pass

    roots: list[Path] = []
    seen: set[str] = set()
    for letter in drive_letters:
        letter = letter.strip().rstrip(":").upper()
        if len(letter) != 1 or letter not in string.ascii_uppercase:
            continue
        if bitmask:
            drive_idx = ord(letter) - ord("A")
            if not (bitmask & (1 << drive_idx)):
                continue
        root_text = f"{letter}:\\"
        try:
            if not os.path.isdir(root_text):
                continue
        except OSError:
            continue
        if not os.access(root_text, os.R_OK):
            continue
        key = os.path.normcase(root_text)
        if key in seen:
            continue
        seen.add(key)
        roots.append(Path(root_text))
    return roots

studio/backend/tests/test_windows_external_drive_paths.py (11-17)

medium

When running unit tests on a Windows host, the real GetLogicalDrives API will be called and return the host's actual drive layout, which will conflict with the stubbed existing_drives and cause the tests to fail. We should mock GetLogicalDrives in _stub_windows to ensure tests are completely deterministic across all platforms.

def _stub_windows(monkeypatch, existing_drives):
    """Simulate Windows exposing only *existing_drives* (e.g. {"C", "D"}) as
    readable drive roots, so the test does not depend on the host's real FS."""
    monkeypatch.setattr(external_media.platform, "system", lambda: "Windows")
    present = {f"{d.upper()}:\\" for d in existing_drives}
    monkeypatch.setattr(external_media.os.path, "isdir", lambda p: str(p) in present)
    monkeypatch.setattr(external_media.os, "access", lambda p, _mode: str(p) in present)

    # Also mock GetLogicalDrives if running on a Windows host to prevent real drives from interfering
    try:
        import ctypes
        if hasattr(ctypes, "windll"):
            mask = sum(1 << (ord(d.upper()) - ord("A")) for d in existing_drives)
            monkeypatch.setattr(ctypes.windll.kernel32, "GetLogicalDrives", lambda: mask)
    except Exception:
        pass

@gaurav0107
gaurav0107 marked this pull request as ready for review July 11, 2026 18:50
…n test

Add an allowlist integration test mirroring the Linux side's
test_legacy_browse_allowlist_includes_linux_run_media_mounts: it extracts
_build_browse_allowlist from routes/models.py, stubs external_media so
windows_drive_roots() yields a fake drive root, and asserts that root becomes
browsable through the built allowlist. Proves the wiring, not just the helper.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58aa8e3d00

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread studio/backend/routes/models.py Outdated
_add(Path.home())
for p in linux_run_media_mount_roots():
_add(p)
for p in windows_drive_roots():

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fix drive-root descendants in legacy browser

When /api/models/browse-folders runs on Windows, this new allowlist root is stored as D:\; _is_path_inside_allowlist() later checks descendants with target_real.startswith(root_real + os.sep), which becomes D:\\, so a child such as D:\models is rejected after _match_browse_child resolves it. The suggestion can open the drive root, but clicking any subfolder under that drive root returns 403 in this route; handle root paths with a trailing separator or use commonpath as the hub browser does.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Confirmed and kept fixed in af0cc8b. _is_path_inside_allowlist now uses os.path.splitdrive + os.path.commonpath, so a drive root (D:) authorizes its descendants (D:\models) via component-wise containment instead of a string prefix. Covered by test_windows_external_drive_paths.py (drive-root descendant, cross-drive, case-insensitive).

Resolve active logical drives from GetLogicalDrives() before probing each
letter with os.path.isdir. Probing a drive letter mapped to a disconnected
network share can otherwise block the async backend for tens of seconds per
letter. The call degrades gracefully (falls back to probing all letters) when
ctypes/windll is unavailable, so behavior is unchanged on Linux/macOS. Tests
override the bitmask source to stay deterministic on real Windows hosts.
@gaurav0107

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Addressed the drive-probing concern: windows_drive_roots() now resolves active drives via GetLogicalDrives() first (_active_windows_drive_bitmask()) and only os.path.isdir-probes letters that are actually mounted, so a disconnected network drive letter can't hang the backend. It falls back to probing all letters when ctypes/windll is unavailable (no change on Linux/macOS), and the tests override the bitmask source so they stay deterministic on real Windows hosts too.

pre-commit-ci Bot and others added 2 commits July 11, 2026 18:56
routes/models.py _is_path_inside_allowlist() checked descendants with
startswith(root_real + os.sep). A drive root ("D:\") already ends in a
separator, so the prefix became "D:\\" and a child like "D:\models" was
rejected with 403 after the browser opened the drive root. Only append a
separator when the root does not already end in one. folder_browser.py already
uses commonpath and was unaffected. Adds a regression test covering the
separator-terminated-root descendant case.
@gaurav0107

Copy link
Copy Markdown
Contributor Author

Good catch on the descendant check. Fixed in _is_path_inside_allowlist(): it now only appends a separator when the root doesn't already end in one, so children of a drive root (D:\models) are no longer 403'd after opening D:\. Added a regression test for the separator-terminated-root case. (folder_browser.py already used commonpath and wasn't affected.)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c58a449fd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if key in seen:
continue
seen.add(key)
roots.append(Path(root_text))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the system-prefix denylist when adding drive roots

When Windows exposes C: (or whichever drive hosts SystemRoot/ProgramFiles), this returns the whole drive root and both browse allowlists add it directly. I checked routes/models.py::_resolve_browse_target and hub/services/models/folder_browser.py::_resolve_browse_target: after this root matches they only block credential/config components, while storage/studio_db.py and hub/storage/scan_folders.py explicitly reject SystemRoot/ProgramFiles, so requests like /api/models/browse-folders?path=C:\Windows or the hub equivalent can now enumerate directories that the existing scan-folder policy denies. Filter those denied prefixes during browsing, or avoid adding system-drive roots wholesale.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good catch, fixed in af0cc8b. Instead of filtering at drive-root construction, both browse resolvers now re-apply the system-prefix denylist through a new is_denied_system_path() in storage/studio_db.py and hub/storage/scan_folders.py, mirroring add_scan_folder (including the /run/media carve-out and Windows normcase). C:\Windows and C:\Program Files are refused on descent while C:\ stays browseable, and they are also hidden from the listing and chips. Covered by test_browse_denylist.py.

Comment thread studio/backend/routes/models.py Outdated
Comment on lines +1290 to +1291
root_prefix = root_real if root_real.endswith(os.sep) else root_real + os.sep
if target_real == root_real or target_real.startswith(root_prefix):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep POSIX root registrations from unlocking every child

On POSIX, when the legacy browse allowlist contains / (for example from an existing scan_folders row, since storage.studio_db.add_scan_folder does not reject the filesystem root), this new prefix becomes /, so every absolute path now passes _is_path_inside_allowlist. Before this change the descendant prefix was //, which only allowed browsing / itself; now /etc, /proc, etc. can be entered through /api/models/browse-folders even though those prefixes are otherwise denied by the scan-folder policy. Special-case Windows drive roots instead of any separator-terminated root.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Correct, fixed in af0cc8b. _is_path_inside_allowlist now special-cases a bare POSIX filesystem root (empty splitdrive and dirname == path): it matches / itself but does not authorize descendants, so /etc is no longer reachable via a / scan-folder row. The browse-time denylist is a second gate for stale rows, and add_scan_folder now also rejects registering the filesystem root. Regression tests in test_browse_denylist.py.

danielhanchen and others added 2 commits July 12, 2026 10:49
Exposing whole Windows drive roots (and any legacy-registered filesystem root)
widened the browse allowlist above system directories, but the browse
resolvers only re-applied the credential/config denylist, not the
_denied_path_prefixes() system-dir denylist that scan-folder registration
enforces. That let browse-folders enumerate C:\Windows, C:\Program Files,
/etc and /proc.

- Add is_denied_system_path() to both storage modules and enforce it in both
  browse resolvers (legacy routes/models.py and hub folder_browser.py), on each
  resolved child and on the final target, keeping the /run/media carve-out.
- Rework the legacy _is_path_inside_allowlist to use splitdrive + commonpath so
  a Windows drive root authorizes its descendants while a bare POSIX / does not,
  and to compare case-insensitively like the hub browser.
- Reject the filesystem root in the legacy add_scan_folder, matching the hub.
- Hide denied system dirs from browse listings and suggestion chips.
- Add tests/test_browse_denylist.py and update the external-media path tests.
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: e0614fcc92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

danielhanchen added a commit to danielhanchen/unsloth-staging-2 that referenced this pull request Jul 12, 2026
Per-OS unit suites (ubuntu/macos run the POSIX-oriented tests; windows runs the
cross-platform drive-root suite), a real Windows GetLogicalDrives + system-denylist
integration on windows-latest, and a before/after security probe showing the
/etc-via-/ hole existed before the fix and is closed after.
The browse-time denylist tests used real /etc and tmp_path locations; on macOS
tmp lives under the (legitimately denied) /private/var and /etc resolves to
/private/etc, so three tests failed there. Pin the platform / use a tmp-based
denied prefix so they assert the same behavior on Linux, macOS and Windows.
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

1 similar comment
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 12, 2026
@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 12, 2026
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 5536da702e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The _is_path_inside_allowlist guard that stops a legacy-registered '/' scan
folder from authorizing every absolute path lived only in the legacy browser.
The hub browser used commonpath without it, so a stale '/' row let it descend
into /var, /root, /home -- which the system-directory denylist (/proc /sys /dev
/etc /boot /run) does not cover, while the legacy browser blocked them. Mirror
the legacy guard so both browsers treat '/' identically.

Also resolve each directory entry before the denylist check in both listing
loops, so a symlink or junction pointing into a denied dir is hidden instead of
rendered as a row that 403s on descent. Adds legacy-vs-hub parity tests.
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc8f2cb68c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread studio/backend/storage/studio_db.py Outdated
Comment on lines +959 to +960
if os.path.dirname(normalized) == normalized:
raise ValueError("The filesystem root cannot be registered")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allow UNC share roots to be registered

On Windows, a UNC share root such as \\nas\models also satisfies os.path.dirname(normalized) == normalized, so this new guard rejects it as a filesystem root. That blocks users whose model directory is the root of a network share from adding it through /api/models/scan-folders, even though it is not above local system directories like C:\Windows; please distinguish bare drive/filesystem roots from UNC share roots.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks. I did try exactly this: a carve-out that allowed a bare UNC share root while still rejecting C:\ and /. The follow-up review found it was only half-complete though. \\nas\models\ with its usual trailing separator was still rejected, and even once registered the share root was unbrowsable because ntpath.commonpath raises for the no-trailing-separator form that realpath stores. Fully supporting a bare share root means adding UNC-specific normalization to the security-critical containment path, which I cannot validate off Windows, so I reverted to rejecting it consistently with C:\ and /. Registering a subdirectory of the share (for example \\nas\models\gguf) still works and browses normally, which covers the real use case.

danielhanchen added a commit to danielhanchen/unsloth-staging-2 that referenced this pull request Jul 14, 2026
…y pass on macOS

test_browse_folders_route.py exercises allowlist containment and the file-vs-directory guard, not the system-directory denylist. On macOS pytest tmp_path resolves under /private/var, a denied prefix, so _resolve_browse_target 403s the fixture dirs before the containment logic runs (4 failures). Add an autouse fixture that makes is_denied_system_path inert in this file; the denylist keeps its own coverage in test_browse_denylist.py.
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 14, 2026
@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 14, 2026
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

1 similar comment
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea09a31fe6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread studio/backend/storage/studio_db.py Outdated
Comment on lines +956 to +957
if os.path.dirname(normalized) == normalized:
raise ValueError("The filesystem root cannot be registered")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not reject UNC share roots as filesystem roots

On Windows, a UNC share root such as \\nas\models also satisfies ntpath.dirname(normalized) == normalized, so this new guard rejects a readable network share root before the existing denylist logic runs. That blocks users from registering a share root that was valid before and does not expose local drive system directories; the same guard was added in hub/storage/scan_folders.py, so both scan-folder endpoints need the narrower check (e.g. only POSIX / and drive roots like C:\).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fixed in 1983329. The register guard now calls is_local_filesystem_root, which still rejects a bare local root (/ or C:) but exempts a UNC share root (\server\share): it has no denied system dirs under it and was registerable before this guard was added. Applied to both the legacy (studio_db.py) and hub (scan_folders.py) browsers through one shared helper, with a parametrized ntpath/posixpath regression test.

Comment on lines +150 to +151
thread = threading.Thread(target = _probe, args = (path,), daemon = True)
thread.start()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid accumulating timed-out drive probe threads

When a disconnected mapped drive makes os.path.isdir() block past _DRIVE_PROBE_TIMEOUT_S, this code returns without joining the daemon thread, but both browse endpoints call windows_drive_roots() on every folder request. Repeated navigation with one stale mapping can therefore spawn another stuck probe thread per request until the OS calls eventually return, causing unbounded thread buildup even though each individual request times out promptly; cache/serialize in-flight probes or otherwise avoid starting a fresh thread for the same hung drive each time.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Leaving this as is. A probe that blocks on a disconnected mapping is bounded by the OS: roughly 21s to abandon a TCP connect to an unreachable host, or the SMB SessTimeout (default about 60s) at the session layer, after which the daemon thread returns and exits. Stuck threads therefore self-drain to a steady state of about browse_rate times that timeout rather than growing without limit, and the returned root set is already correct because a timed-out drive is dropped. Running the isdir check in a bounded worker thread is the recommended mitigation for the redirector stall, so the current design is intentional.

@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 14, 2026
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

1 similar comment
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1983329e9b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if _pathmod.dirname(path) != path:
return False
drive, _ = _pathmod.splitdrive(path)
return drive[:2] not in ("\\\\", "//")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject device-prefixed drive roots as local roots

When a Windows path uses the Win32 device prefix (\\?\C:\ or \\.\C:\), ntpath.splitdrive() returns a drive beginning with \\, so this UNC carve-out treats it as non-local even though it is a local drive root. In that scenario add_scan_folder() accepts the root as a scan folder; once it is in the browse allowlist, paths like \\?\C:\Windows are contained by that root and also miss the normal C:\Windows denylist prefix, so the system-directory block can be bypassed.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fixed in 3911798. is_local_filesystem_root now collapses the Windows device / extended-length prefix before classifying, so \?\C:\ and \.\C:\ are judged as the C:\ drive root and rejected, while \?\UNC\server\share still maps to the \server\share share root and stays registerable. Added parametrized ntpath cases for both forms.

Comment on lines +164 to +165
thread = threading.Thread(target = _probe, args = (path,), daemon = True)
thread.start()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound accumulated drive-probe threads

When a mapped drive stays hung longer than the timeout, each /browse-folders request starts a fresh daemon thread for that drive and returns without joining or cancelling it. With a disconnected network drive and repeated folder-browser navigation, these stuck probes accumulate until the OS calls eventually return, so the request timeout still allows unbounded thread/resource growth in the server process.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Leaving this as is, same as the earlier thread on this function. A probe that blocks on a disconnected mapping is bounded by the OS: roughly 21s to abandon a TCP connect to an unreachable host, or the SMB SessTimeout (default about 60s) at the session layer, after which the daemon thread returns and exits. Stuck threads therefore self-drain to a steady state of about browse_rate times that timeout rather than growing without bound, and the returned root set is already correct because a timed-out drive is dropped. Running the isdir check in a bounded worker thread is the recommended mitigation for the redirector stall, so I would rather not add a module-level probe cache and its locking to the hot browse path.

# match; do not let it authorize arbitrary descendants.
continue
try:
if os.path.commonpath([target_real, root_real]) == root_real:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve UNC share roots when checking containment

When a registered Windows UNC share is stored as \\server\share (no trailing slash), ntpath.commonpath(["\\server\share\models", "\\server\share"]) raises ValueError, so this containment check returns false and browsing any child of the newly allowed UNC root 403s. This regresses the commit's UNC-share exception unless the user happens to register the share with a trailing separator.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fixed in 3911798. os.path.commonpath raises 'can't mix absolute and relative' on a bare \server\share, so _is_path_inside_allowlist now detects a UNC share root (drive set, empty splitdrive tail) and authorizes its descendants with a boundary-safe prefix test on the normcased realpath. Applied to both the legacy and hub browsers, with a parametrized test that a registered share authorizes its children but not a sibling share or a different volume.

@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 14, 2026
@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 14, 2026
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

1 similar comment
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac525776f6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +35 to +38
if path[:4].lower() in ("\\\\?\\", "\\\\.\\"):
rest = path[4:]
path = "\\\\" + rest[4:] if rest[:4].lower() == "unc\\" else rest
if _pathmod.dirname(path) != path:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep volume GUID roots classified as local roots

When a Windows path uses a volume/device root such as \\?\Volume{GUID}\, this prefix-stripping turns it into Volume{GUID}\, so _pathmod.dirname(path) != path and is_local_filesystem_root() returns False. add_scan_folder() can then accept a whole local volume even though drive roots are supposed to be rejected; because the denylist only matches drive-letter paths like C:\Windows, browsing that registered volume can expose system directories on the OS volume. Treat \\?\Volume.../\\.\Volume... as local filesystem roots before stripping or add an explicit volume-GUID case.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fixed in 86355eb. is_local_filesystem_root now resolves the device namespace fully: after a \?\ or \.\ prefix, a bare volume specifier with no further component (a drive letter C: or a Volume{GUID}) is a local volume root and rejected, while \?\UNC\server\share still maps to the \server\share share root and stays registerable. Added parametrized \?\Volume{GUID}\ and deep extended-length path cases.

@unslothai unslothai deleted a comment from chatgpt-codex-connector Bot Jul 14, 2026
@danielhanchen

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 86355eba77

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@oobabooga

Copy link
Copy Markdown
Member

Tested this on a real Windows runner via a throwaway CI run on my fork: https://github.com/oobabooga/unsloth/actions/runs/29367849225. windows_drive_roots() picked up the runner's real C: and D:. Browsing C:\ hid Windows and Program Files, descent into C:\Windows 403'd, the drive chip appeared, and registering C:\ was rejected in both browsers. 8.3 aliases (PROGRA~1) resolve to their denied long form, \?\ device-namespace requests are refused, and your mocked Windows tests pass on the real host too.

On POSIX nothing moved: a before/after harness over 27 containment cases shows zero drift from the commonpath rewrite, and 470 tests pass locally. One note: the Linux-simulation suites fail on a Windows host because their fixture paths hit the real os.path. CI runs them on ubuntu only, so nothing blocks; a skipif(os.sep != "/") can land separately.

LGTM. @danielhanchen good to merge on my end.

@danielhanchen
danielhanchen merged commit dc65638 into unslothai:main Jul 15, 2026
43 checks passed
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.

[Bug] Model Selection Directory browser does not allow changing the drive letter and navigating from C: to D: to E: etc

3 participants