Skip to content

fix(scripts): convert editable file URLs portably - #490

Open
mohgupta-ship-it wants to merge 59 commits into
mainfrom
codex/fix-editable-file-url-conversion
Open

mohgupta-ship-it wants to merge 59 commits into
mainfrom
codex/fix-editable-file-url-conversion

Conversation

@mohgupta-ship-it

Copy link
Copy Markdown
Member

Summary

  • Convert editable-install file URLs with the standard platform path adapter.
  • Preserve the empty-authority delimiter so valid POSIX double-slash paths remain local on Python 3.14 while Windows drive URLs lose their extra leading slash.
  • Add portable regression coverage for both URL shapes.

This builds on #486 and preserves the original author attribution while closing the compatibility gap found during validation.

Fixes #485

Validation

  • make lint
  • make format-check
  • ruff check scripts/compare_scan_accuracy.py
  • Targeted path-conversion tests: 3 passed
  • Full Python 3.12 suite: 3,980 passed, 14 skipped, 4 xfailed
  • Python 3.14 standard-library conversion probe for empty-authority double-slash paths

Submitted by Codex on behalf of Mohit Gupta.

SanHsien and others added 3 commits September 6, 2026 17:24
A Windows file URL's path is "/C:/Users/...". Path() reads the leading
slash as a root, so unquote() produced "C:\C:\Users\..." and the
following resolve(strict=True) raised WinError 123. url2pathname is the
stdlib conversion for this and is identical to the old behavior on POSIX,
where the path has no drive letter to double.

test_runtime_probe_hashes_installed_and_editable_dependency_bytes already
covers this; it just never runs on a Windows host in CI. On Windows 11 /
Python 3.13 it fails before this change and passes after.

Fixes #485

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: SanHsien <34234698+SanHsien@users.noreply.github.com>
Keep empty-authority delimiters intact for POSIX double-slash paths while retaining correct Windows drive conversion.

Prepared by Codex on behalf of Mohit Gupta.

Signed-off-by: Mohit Gupta <mohgupta@nvidia.com>
Construct the empty-authority delimiter explicitly so Python patch releases feed the same path shape to url2pathname.

Prepared by Codex on behalf of Mohit Gupta.

Signed-off-by: Mohit Gupta <mohgupta@nvidia.com>
SanHsien added a commit to SanHsien/SkillSpector that referenced this pull request Sep 11, 2026
…VIDIA#524

Raise reviewed_pr_through to 527 and reviewed_issue_through to 524 in
tools/upstream_baseline.json (commit axis unchanged at 69dcdfb). Every
item gets a verdict in docs/DECISIONS.md: NVIDIA#493/NVIDIA#507/NVIDIA#508/NVIDIA#511 verified
via git merge-base --is-ancestor as already included through the
2.11.1/2.11.2 sync (including NVIDIA#521, which merged only into the still-
open NVIDIA#516 stack, not main); the remaining 27 items stay "wait for
upstream merge", none adopted now.

Two items get dedicated comparison notes per docs/DIVERGENCE.md's
static_runner.py and scripts/compare_scan_accuracy.py rows: NVIDIA#522 uses a
different env var name and different default/semantics than this
fork's SKILLSPECTOR_MAX_STATIC_SECONDS, so merging it cannot simply
delete the divergence row and needs a downstream env var migration
first; NVIDIA#490 extends this fork's own upstream PR NVIDIA#486 with a Python
3.14/POSIX edge case the fork's Windows environment does not hit, so
NVIDIA#486 is left untouched pending upstream's own resolution. NVIDIA#501-NVIDIA#505 and
NVIDIA#518 are also flagged as near-verbatim matches to this fork's existing
Windows test divergence rows, worth revisiting for row deletion once
merged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: SanHsien <34234698+SanHsien@users.noreply.github.com>

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[SkillSpector Review]

Changes requested at head ea42d8e0e0ca2fabf049345b3856fa166a3792d5.

  • scripts/compare_scan_accuracy.py:187: for an empty-authority URL whose parsed path begins with exactly //, the new branch prepends two more slashes. On supported pre-3.14 POSIX Python, url2pathname leaves those four slashes unchanged and Path.resolve() collapses them to a single root slash, losing the implementation-defined exactly-two-leading-slash path that was parsed. The test mocks url2pathname and asserts only its input, so it cannot catch the resulting path corruption. Use a version-independent conversion that preserves the parsed local path semantics on both POSIX and Windows, and test the actual converted/resolved result across supported Python versions rather than only a mocked argument.

No checks are reported and GitHub reports merge state BLOCKED; the code issue and missing required CI both block merge. This PR appears to supersede #486, so avoid landing both versions of the same fix.

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[SkillSpector Review]

Re-reviewed current head e3b5b16fa8b3bcc876770e911b42e39ee2f642da. I am withdrawing the previous path-corruption blocker: it relied on an incorrect assumption about urllib.request.url2pathname. CPython 3.12 and 3.13 deliberately remove the two empty-authority delimiter slashes from a ////path input, preserving the parsed //path; CPython 3.14 parses the same input as a local file: URL with empty authority and also preserves //path. The /C:/... form is likewise handed to the platform adapter so Windows can remove the drive-letter prefix slash.

The checked-in test pins both converter inputs and would fail if the standard-library adapter were bypassed, while the existing runtime probe continues to exercise editable dependency traversal and hashing. I found no remaining required change in the current two-file diff.

No hosted checks are reported and GitHub currently reports mergeStateStatus=BLOCKED, so this approval does not make the PR merge-ready.

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[SkillSpector Review]

Re-reviewed current head ce56485a4c4a243f36c4fa5f8f3ad54c25e7d585. The feature blobs remain identical to the reviewed implementation, and the previous empty-authority concern remains correctly withdrawn. A distinct supported-runtime regression remains for accepted file://localhost//… inputs on Python 3.14: the current delimiter repair covers only an empty authority, allowing the adapter to reinterpret the first path component as authority. Preserve the localhost double-leading path and add a real-adapter regression.

No required checks are attached, GitHub reports mergeStateStatus=BLOCKED, and this PR must also be coordinated with superseded #486.

# with "//". Build it explicitly because urlunsplit() normalizes this
# form differently across Python patch releases.
converter_input = parsed.path
if not parsed.netloc and converter_input.startswith("//"):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Preserve localhost double-leading paths

The accepted URL file://localhost//path reaches this branch with parsed.netloc == "localhost" and parsed.path == "//path", so the delimiter is not restored. On Python 3.14, url2pathname reparses that input as file://path (authority path); POSIX then raises URLError instead of resolving the local //path. The repository supports Python 3.14. Restore the delimiter for this accepted localhost form as well and add a regression that exercises the real adapter rather than only mocking its argument.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I checked this on the latest commit and can still reproduce the issue on Python 3.14: file://localhost//tmp/dep raises URLError instead of resolving the local path. Could we preserve // for localhost URLs too and add a regression test using the real converter?

@yashrajp22 yashrajp22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address the remaining localhost path issue discussed in the inline thread.

SanHsien added a commit to SanHsien/SkillSpector that referenced this pull request Sep 17, 2026
Brings the fork up to upstream main c13f70e; the version is still 2.11.2.

The fork history was squashed into one commit on 2026-09-13, so it
shares no merge-base with upstream and git merge refuses. The range
diff was applied with git apply -3 instead. The fork content equals
69dcdfb plus the registered divergences, so conflicts landed only on
those seven files; the other 116 applied cleanly. FORK.md now documents
this procedure.

Divergences, resolved by each row's rule:
- static_runner.py takes upstream NVIDIA#522
  (SKILLSPECTOR_MAX_STATIC_ANALYSIS_SECONDS_PER_ARTIFACT, default 300s).
  The fork's SKILLSPECTOR_MAX_STATIC_SECONDS override and its seven
  tests are removed. Downstream gates must use the upstream name when
  their pin moves.
- test_static_yara.py, test_build_context.py and test_input_handler.py
  take upstream (NVIDIA#501-NVIDIA#505, NVIDIA#518 fix the same Windows issues); 301
  passed on Windows, rows deleted.
- test_security_end_to_end.py: upstream's version still fails
  nine_case on Windows (YARA load and SC8 budgets stay hard-coded), so
  the relaxation helper is re-applied on top; row kept and rewritten.
- .gitignore keeps the fork block; README.md stays Traditional Chinese
  and the upstream README goes to README.en.md.

Two new Windows divergences from new upstream tests:
- tests/unit/test_cli.py: a file name containing a backslash is split
  into two path parts on Windows; skipped by a capability probe added to
  tests/platform_support.py.
- test_json_container_ownership.py: oversized payloads became test ids,
  which pytest copies into PYTEST_CURRENT_TEST, over Windows' 32,767
  character environment limit; short ids added, content unchanged.

Triage: 13 of PRs NVIDIA#528-NVIDIA#580 merged into upstream main and arrive here;
29 stay open (including NVIDIA#550, release 2.12.0). Upstream closed this
fork's PR NVIDIA#486 on 2026-09-15; NVIDIA#490 builds on it and is open.

Verified on Windows in fresh-process batches against this tree:
tests/unit 1563 passed, 29 skipped; tests/nodes 3822 passed, 11
skipped, 4 xfailed (plus test_json_container_ownership 71 passed after
the id fix); remaining tests 182 passed, 16 skipped;
test_security_end_to_end.py 98 passed. ruff check and format clean,
check_divergence OK (10 diverging, 10 registered), check_pin_bounds OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: SanHsien <34234698+SanHsien@users.noreply.github.com>

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[SkillSpector Review]

Re-reviewed exact head 457f94505a848b404a2b17d79d75d8facf372b1e. Every intervening commit only synchronizes main; the two PR-owned files and the current blocker are unchanged.

scripts/compare_scan_accuracy.py:186 restores the empty-authority delimiter only when parsed.netloc is empty. The accepted file://localhost//path form still reaches url2pathname() as //path; on Python 3.14 that is reparsed as an authority and raises URLError instead of resolving the local path. Preserve the double-leading local path for localhost too, and add a regression using the real adapter rather than only asserting a mocked argument. The existing unresolved inline thread contains the exact case.

No exact-head hosted checks are attached. The portability fix, regression, unresolved conversation, and BLOCKED merge state prevent approval.

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[SkillSpector Review]

Re-reviewed exact head 646ec6201aa231df5d593c310626d7c88093f5f2. The intervening commits only synchronize merged main changes through #575; both PR-owned blobs are byte-identical to the prior reviewed head.

The existing blocker remains at scripts/compare_scan_accuracy.py:186: delimiter restoration is limited to an empty authority. The accepted file://localhost//path form still passes //path to Python 3.14 url2pathname(), which reparses the first path component as an authority and raises URLError instead of resolving the local path. Preserve the double-leading local path for localhost too and add a regression using the real adapter rather than only asserting a mocked argument. The existing unresolved inline thread contains the exact case, so I have not duplicated it.

No exact-head hosted checks are attached. The portability fix, real-adapter regression, unresolved conversation, and BLOCKED merge state prevent approval.

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.

compare_scan_accuracy: editable-dependency file:// URL resolves to "C:\C:\..." on Windows

4 participants