Skip to content

python: remove implicit PATH fallback for CLI executable resolution - #2528

Draft
SteveSandersonMS wants to merge 1 commit into
mainfrom
copilot/2524-python-no-path-fallback
Draft

python: remove implicit PATH fallback for CLI executable resolution#2528
SteveSandersonMS wants to merge 1 commit into
mainfrom
copilot/2524-python-no-path-fallback

Conversation

@SteveSandersonMS

Copy link
Copy Markdown
Contributor

Summary

Part of #2524 (Consolidate runtime discovery, acquisition, and embedding). Removes the Python SDK's implicit fallback to PATH-based executable resolution, satisfying the required outcome:

Python does not implicitly select an executable through PATH; it uses the SDK-managed runtime or an explicitly configured path.

Background

Commit 05dd60e (#793) added a shutil.which(cli_path) fallback in CopilotClient._start_cli_server that runs whenever the resolved cli_path does not exist as a file. This let the SDK silently pick up an arbitrary same-named executable from the host PATH instead of using the runtime the SDK actually resolved (explicit path > COPILOT_CLI_PATH > SDK-managed download, see _resolve_runtime_entrypoint). #1934 flagged this explicitly for removal, and #2522/#2524 carry that forward.

I confirmed on latest main (0921029) and on the in-flight roji-unify-runtime-artifacts branch (#2505) that this fallback is unchanged in both — #2505 only changes how the runtime is downloaded/verified from GitHub Releases for Python/.NET/Go/Java, not this PATH-search behavior at process start, so this is not duplicating that work.

What changed

  • python/copilot/client.py: _start_cli_server now raises a clear RuntimeError when the resolved cli_path doesn't exist, instead of falling back to shutil.which. Removed the now-unused shutil import.
  • python/test_client.py: added a regression test that plants a same-named decoy executable on PATH and asserts it is never used when the configured path is missing.

Not in scope here (tracked separately on #2524)

Validation

  • ruff check / ruff format --check on changed files: pass.
  • ty check on copilot/client.py: pass.
  • pytest python/test_client.py python/test_cli_download.py: same 79 pre-existing environment-only failures as unmodified main (fake local CLI binary used for offline testing has no real e2e semantics); all path-resolution tests, including the new regression test, pass with zero new failures.

Closes #2524 once merged (remaining #2524 items tracked in the follow-up comment on that issue).

The runtime start path fell back to shutil.which(cli_path) whenever the
resolved cli_path did not exist as a file. This let the SDK implicitly
select an arbitrary same-named executable found on the host PATH instead
of failing when the SDK-managed runtime or an explicitly configured path
was not actually present, re-introducing the PATH-search behavior
originally added by 05dd60e that #2524 asks to remove.

Resolution order is unchanged (explicit path > COPILOT_CLI_PATH >
SDK-managed downloaded runtime, see _resolve_runtime_entrypoint); only the
undocumented PATH-search fallback at process start is removed. A missing
resolved path now raises a RuntimeError up front instead of silently
searching PATH.

Adds a regression test asserting that a same-named executable placed on
PATH is not used when the configured path does not exist.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review

This PR removes a shutil.which() fallback in the Python SDK's _start_cli_server, so that a missing resolved CLI path now raises RuntimeError immediately instead of silently falling back to searching PATH for a same-named executable (addressing #2524).

Checked for the same pattern in other SDKs:

  • Node.js (nodejs/src/client.ts): only checks existsSync(this.resolvedCliPath) and throws if missing — no PATH-search fallback.
  • .NET (dotnet/src/Client.cs): resolves the CLI via bundled runtime paths and File.Exists checks — no PATH-search fallback.
  • Go, Java, Rust: no LookPath/which-style fallback found anywhere in their client startup code.

None of the other five SDKs implement (or ever implemented) the vulnerable PATH-search fallback that this PR removes from Python. This change simply brings Python's behavior in line with the stricter, already-consistent behavior of the other SDKs — no other SDK needs a corresponding update.

✅ No cross-SDK consistency issues found.

Generated by SDK Consistency Review Agent for #2528 · copilot · sonnet50 · 25 AIC · ⌖ 11.9 AIC · ⊞ 9.7K ·

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

Labels

sdk/python sdk-v2 Work planned for Copilot SDK v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v2] Consolidate runtime discovery, acquisition, and embedding

1 participant