Skip to content

fix(install): make Windows pip fallback resilient to stderr under ErrorActionPreference=Stop (closes #1874)#1876

Open
danielmeppiel wants to merge 2 commits into
mainfrom
fix/issue-1874-pip-fallback-erroraction
Open

fix(install): make Windows pip fallback resilient to stderr under ErrorActionPreference=Stop (closes #1874)#1876
danielmeppiel wants to merge 2 commits into
mainfrom
fix/issue-1874-pip-fallback-erroraction

Conversation

@danielmeppiel

Copy link
Copy Markdown
Collaborator

TL;DR

Make the Windows pip fallback ignore non-fatal native stderr as a PowerShell terminating-error source while preserving the existing pip exit-code handling.

Problem

With $ErrorActionPreference = "Stop", PowerShell 5.1 can turn stderr redirected through 2>&1 from a native pip command into a terminating NativeCommandError / System.Management.Automation.RemoteException. That happens before the installer checks $LASTEXITCODE, so pip notices or warnings can make a successful fallback look failed.

Fix

Inside Install-ViaPip, save the current $ErrorActionPreference, set it to "Continue" only while invoking native pip, then restore it in finally. The captured output and non-zero exit-code behavior stay unchanged.

How to test

  • $HOME/.local/bin/uv run --extra dev pytest tests/unit/test_enterprise_bootstrap_installers.py -q
  • Mutation-break gate: removed the scoped guard and confirmed the new regression test fails, then restored it.
  • $HOME/.local/bin/uv run --extra dev ruff check src/ tests/ --quiet
  • $HOME/.local/bin/uv run --extra dev ruff format --check src/ tests/ --quiet

closes #1874

Prevent native pip stderr from becoming a terminating PowerShell error while preserving exit-code based failure handling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 22, 2026 08:24

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

This PR hardens the Windows install.ps1 pip fallback against PowerShell 5.1 cases where native-command stderr can be promoted to a terminating error when $ErrorActionPreference = "Stop", ensuring the fallback still relies on pip’s exit code as intended.

Changes:

  • Scope $ErrorActionPreference = "Continue" to the native pip invocation inside Install-ViaPip, restoring the previous value in a finally block.
  • Add a unit regression test that asserts the guard is present and ordered correctly around both pip invocation variants.
Show a summary per file
File Description
install.ps1 Wraps native pip execution with a scoped $ErrorActionPreference override and restoration to avoid stderr-triggered termination.
tests/unit/test_enterprise_bootstrap_installers.py Adds a regression test validating the new guard exists and is positioned correctly within Install-ViaPip.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 1

Comment on lines +174 to +177
text = _read_repo_file("install.ps1")
body = text.split("function Install-ViaPip {", 1)[1].split(
"function Write-ManualInstallHelp {", 1
)[0]
Record the enterprise PowerShell compatibility fix surfaced by the review panel so the release notes make the Windows installer hardening discoverable.

Addresses CEO follow-up from apm-review-panel for PR #1876.

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

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_now

Hardens the Windows install path so enterprise ErrorActionPreference=Stop environments no longer crash on benign pip stderr, closing a real-world enterprise compatibility gap.

cc @danielmeppiel @sergio-sisternes-epam -- a fresh advisory pass is ready for your review.

All active panelists converged on shipping this narrow fix. The implementation saves the previous $ErrorActionPreference, sets Continue only for native pip, restores in finally, and preserves exit-code handling. The regression trap is load-bearing: deleting the Continue guard makes the new test fail, then restoring the guard returns the suite to green. The CHANGELOG entry was folded during shepherding so the enterprise PowerShell compatibility fix is discoverable in release notes.

Aligned with: pragmatic_as_npm: pip fallback now survives strict PowerShell policies without user intervention; governed_by_policy: respects enterprise ErrorActionPreference=Stop instead of requiring users to weaken shell policy; multi_harness_multi_host: Windows install resilience closes a platform-parity gap.

Growth signal. Enterprise Windows compatibility fixes are high-signal for regulated environments. The CHANGELOG framing tells IT teams that APM respects their security posture rather than fighting it.

Panel summary

Persona B R N Takeaway
Python Architect 0 0 1 Clean save/restore guard around native pip invocation; no Python architecture surface touched. Ship.
CLI Logging Expert 0 0 1 The guard preserves proper exit-code diagnostics by preventing pip stderr noise from becoming a false terminating error.
DevX UX Expert 0 0 2 ErrorActionPreference guard is correct UX for pip stderr; no regression in the install command surface.
Supply Chain Security Expert 0 0 0 No supply-chain or security surface affected; change is purely PowerShell error-preference scoping around an unchanged pip invocation.
OSS Growth Hacker 0 0 1 Enterprise-friendly installer hardening removes a silent adoption blocker; release-note visibility was folded.
Test Coverage Expert 0 0 0 ErrorActionPreference guard in install.ps1 is defended by a static ordering-assertion test; coverage is adequate for this surface.

B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.

Top 3 follow-ups

  1. [Python Architect] Consider regex-based assertion in the static test to decouple from line ordering -- reduces future maintenance churn if the ErrorActionPreference block is refactored; current form is correct and passing.
  2. [DevX UX] Add mirror URL redaction in manual-install help output and enterprise-mode success breadcrumb -- polish for the enterprise install experience; outside this stderr terminating-error fix.
  3. [CLI Logging] Align Write-Host usage in install.ps1 with a consistent output helper style -- low-priority consistency pass; current output is functional and correct.

Recommendation

Merge as-is. The fix is minimal, mutation-validated, CI-green, and closes a reported enterprise regression. The remaining follow-ups are polish or hardening outside this PR's stated scope; track them separately if desired.

Folded in this run

  • (panel) Add CHANGELOG entry for enterprise PowerShell compatibility -- resolved in 0ec5927.

Copilot signals reviewed

  • Copilot review fetched twice; no inline comments were present to classify.

Deferred (out-of-scope follow-ups)

  • (panel) Redact embedded credentials in Write-ManualInstallHelp mirror URL output -- scope boundary: PR scope is the ErrorActionPreference pip fallback failure; this is a separate manual-help credential-redaction hardening pass.
  • (panel) Add enterprise mirror-mode success breadcrumb -- scope boundary: PR scope is a false terminating-error bug; this is broader installer UX messaging.
  • (panel) Refactor static test to regex-based structural matching -- scope boundary: current regression trap is passing and mutation-proven; this is future test-maintenance polish.
  • (panel) Align Write-Host remediation style with output helpers -- scope boundary: PR does not change remediation output styling.

Regression-trap evidence (mutation-break gate)

  • tests/unit/test_enterprise_bootstrap_installers.py::test_windows_pip_fallback_scopes_native_stderr_error_action_guard -- deleted $ErrorActionPreference = "Continue"; test FAILED as expected; guard restored.

Lint contract

uv run --extra dev ruff check src/ tests/ and uv run --extra dev ruff format --check src/ tests/ both silent. Full CI lint equivalent also passed locally (YAML I/O guard, file-length guard, raw relative_to guard, pylint R0801, auth-signals).

CI

GitHub checks green on 0ec592773b80a3425a507dd90a68b0bc54eb6f61: Lint, Build & Test Shard 1/2, gate, APM Self-Check, PR Binary Smoke, Coverage Combine, CodeQL, NOTICE Drift Check, Analyze (python/actions), and license/cla all passed (after 0 CI fix iterations).

Mergeability status

Captured from gh pr view 1876 --json mergeable,mergeStateStatus,statusCheckRollup immediately after the last push of this run.

PR head SHA CEO stance iters folds defers Copilot rounds CI mergeable mergeStateStatus notes
#1876 0ec5927 ship_now 1 1 4 2 green MERGEABLE BLOCKED awaiting maintainer review

Convergence

1 outer iteration; 2 Copilot rounds. Final panel verdict: ship_now.

Ready for maintainer review.


Full per-persona findings

Python Architect

  • [nit] Test asserts string ordering but is brittle to incidental refactors at tests/unit/test_enterprise_bootstrap_installers.py:183
    The test uses body.index() ordering of raw string literals. This is acceptable for a regression trap on a shell script but worth noting as a maintenance cost; a regex-based structural match would be more robust.

CLI Logging Expert

  • [nit] Fail-closed remediation line uses raw Write-Host instead of Write-Info at install.ps1:263
    The adjacent guidance line uses bare Write-Host. This is internally consistent with existing installer patterns and is not material to the PR scope.

DevX UX Expert

  • [nit] Manual install help leaks raw mirror URL without redaction at install.ps1:310
    Write-ManualInstallHelp prints $pypiIndexUrl verbatim if the mirror URL contains embedded credentials. This is pre-existing and outside the ErrorActionPreference fix.
    Suggested: Use Redact-UrlCredentials in a separate hardening PR.
  • [nit] No feedback when APM_NO_DIRECT_FALLBACK is active but everything succeeds
    A positive enterprise mirror mode breadcrumb could reassure admins, but this is a broader installer UX enhancement outside the stderr terminating-error fix.

Supply Chain Security Expert

No findings.

OSS Growth Hacker

  • [nit] The fix is story-shaped but invisible; consider a CHANGELOG entry calling out enterprise PowerShell compatibility
    Enterprise users running ErrorActionPreference=Stop are a high-value segment. This was folded into CHANGELOG.md.

Auth Expert -- inactive

Touched files are install.ps1 and tests/unit/test_enterprise_bootstrap_installers.py; no token management, credential resolution, host classification, git/HTTP auth headers, or remote-host fallback semantics changed.

Doc Writer -- inactive

No documentation-relevant surface touched before the folded CHANGELOG entry; no docs drift remains.

Test Coverage Expert

No findings.

Performance Expert -- inactive

Touched files are install.ps1 and tests/unit/test_enterprise_bootstrap_installers.py; no cache, transport, materialization, parallelism, benchmark, or performance claim changed.

This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.

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] Installation of v.0.21 failed on MS-managed Windows 11 PC. Even in running Terminal "as administrator"

2 participants