Skip to content

fix(deps): harden local-dep display against Windows repo_url leak and over-eager hash stripping#2175

Closed
danielmeppiel wants to merge 1 commit into
mainfrom
danielmeppiel-finish-v0250-fix-review
Closed

fix(deps): harden local-dep display against Windows repo_url leak and over-eager hash stripping#2175
danielmeppiel wants to merge 1 commit into
mainfrom
danielmeppiel-finish-v0250-fix-review

Conversation

@danielmeppiel

@danielmeppiel danielmeppiel commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

TL;DR

Two verified pre-merge follow-ups to the v0.25.0 local-dependency display hardening (PR #2173, now merged). Both leaked or corrupted the user-facing local-dependency identity in apm deps list/tree output. Fixed TDD-first; no behavior change for the common relative-path case.

Problem (WHY)

PR #2173 hardened local-dep display but two edge cases still leak/corrupt identity:

  1. Windows-path repo_url pollution. A Windows-form declared path parsed on POSIX (C:\packages\pkg) leaves the drive letter and backslashes embedded in the parsed repo_url (_local/C:\packages\pkg), because PurePosixPath("C:\\...").name treats backslashes as ordinary characters. _dep_display_name fell back to that polluted repo_url for absolute paths, leaking host filesystem structure into user-facing output.

  2. Over-eager orphan hash stripping. _resolve_scope_deps stripped the hash segment from every scanned _local/<12hex>/pkg slot name. A legitimately declared/mapped slot whose logical key happens to look hashed was corrupted into _local/pkg and masked, instead of being reported under its true logical identity.

Approach (WHAT)

  1. Derive a hash-free _local/<basename> from local_path for absolute declared paths, via a new _local_basename helper that routes drive/UNC/backslash paths through PureWindowsPath and everything else through PurePosixPath. Relative local_path stays verbatim; a missing local_path still falls back to repo_url. get_unique_key is still never called for local deps.

  2. Gate the hash-strip in the scan loop on a confirmed orphan (a slot with no lockfile mapping to a logical key). Declared/mapped slots keep their logical name verbatim. Orphan detection still runs on the raw physical identity, so detection accuracy is unchanged.

Implementation (HOW)

  • src/apm_cli/commands/deps/cli.py: add _local_basename; rework _dep_display_name local branch; compute is_orphaned before the scan try and apply _logical_local_display only when orphaned.
  • tests/unit/commands/test_deps_cli_helpers.py: real DependencyReference.parse(r"C:\packages\pkg") -> LockedDependency -> _dep_display_name regression (asserts no drive/backslashes); declared-hashed-slot preservation test (asserts _local/<12hex>/pkg is preserved, not orphaned). Both were RED before the fix.

Trade-offs

Detection intentionally uses PureWindowsPath heuristics (backslash or drive) rather than importing the heavier path resolver -- keeps this a bounded release patch with no new cross-cutting abstraction.

Validation evidence

Check Result
New RED->GREEN unit tests 2 new, RED confirmed then GREEN
test_deps_cli_helpers.py 25 passed
Related deps modules (local_deps, deps_utils, list_tree_info, wave6, deps_cli_coverage) 282 passed
test_transitive_chain_e2e.py (binary shim) 4 passed
ruff check / ruff format --check clean
auth-signals lint clean
pylint R0801 10.00/10
ASCII-only additions verified

How to test

uv run --extra dev pytest tests/unit/commands/test_deps_cli_helpers.py -q

Does not merge or move any tags.

… over-eager hash stripping

Two verified follow-ups to the v0.25.0 local-dependency display hardening
(PR #2173), both leaking or corrupting the user-facing local-dep identity.

1) Windows-path repo_url pollution. A Windows-form declared path parsed on
   POSIX (`C:\packages\pkg`) leaves the drive and backslashes embedded in
   `repo_url` (`_local/C:\packages\pkg`). `_dep_display_name` fell back to
   that polluted `repo_url` for absolute paths, leaking host structure.
   Derive a hash-free `_local/<basename>` from `local_path` instead, via a
   new `_local_basename` helper that routes drive/UNC/backslash paths through
   PureWindowsPath and everything else through PurePosixPath. Relative paths
   stay verbatim; a missing `local_path` still falls back to `repo_url`.

2) Over-eager orphan hash stripping. `_resolve_scope_deps` stripped the hash
   segment from every scanned `_local/<12hex>/pkg` name, corrupting a
   legitimately declared/mapped slot into `_local/pkg` and masking it. Gate
   the strip on a CONFIRMED orphan (no lockfile mapping): declared/mapped
   slots keep their logical name verbatim. Orphan detection still runs on the
   raw physical identity.

TDD: added a real parse -> LockedDependency -> display regression and a
declared-hashed-slot preservation test (both RED before the fix). Existing
true-orphan and read-failure guards stay green.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4c5a1ddc-ce71-4a10-b527-8796df88975e
Copilot AI review requested due to automatic review settings July 12, 2026 12:42

Copilot AI 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.

Pull request overview

Hardens apm deps list / apm deps tree local-dependency display to avoid leaking Windows-path artifacts (drive letters/backslashes) into user-facing output and to prevent incorrectly stripping hash-like segments from declared local dependency identities.

Changes:

  • Add _local_basename() and update _dep_display_name() so absolute local paths render as _local/<basename> (derived from local_path) instead of falling back to potentially polluted repo_url.
  • Refine _resolve_scope_deps() to strip _local/<12hex>/... hash segments only for confirmed orphan slots (no lockfile mapping), preserving legitimately hashed logical keys.
  • Add unit regressions covering Windows-path repo_url pollution and declared hashed-slot preservation.
Show a summary per file
File Description
src/apm_cli/commands/deps/cli.py Implements cross-platform local basename derivation and gates hash stripping to confirmed orphans during deps scan/display.
tests/unit/commands/test_deps_cli_helpers.py Adds regression tests for Windows-path pollution and for preserving declared hashed local slot identities.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Low

@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

Superseded by #2174, which already landed both round-3 fixes in d73e6ac. v0.25.0 has been published from that commit; no additional patch is needed.

@danielmeppiel danielmeppiel deleted the danielmeppiel-finish-v0250-fix-review branch July 12, 2026 13:14
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.

2 participants