GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(lifecycle): keep pinned HTTP egress when only NO_PROXY is set by bodapatisaikrishna · Pull Request #3575 · microsoft/apm

Conversation

@bodapatisaikrishna

@bodapatisaikrishna bodapatisaikrishna commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Fixes #3574.

What

_environ_proxies_for() classified any truthy result of requests.utils.get_environ_proxies() as "corporate egress". With NO_PROXY exported but no proxy variables set — containers, CI runners, macOS shells — that result is a bare {'no': ...} mapping, which selects no proxy for any URL. Dispatch then took the corporate branch and ran on the unpinned capturing session instead of the resolve-and-pinned guarded session, silently dropping the DNS-pin defense, and the two TestHttpExecutor tests went red on every such host because they patch _get_guarded_session and expect it to be used:

FAILED tests/unit/test_lifecycle_executor_paths.py::TestHttpExecutor::test_public_url_dispatches_and_logs
FAILED tests/unit/test_lifecycle_executor_paths.py::TestHttpExecutor::test_batch_dispatch_drains_all_entries

CI never saw this because GitHub-hosted runners don't export NO_PROXY; the suite was red at main (0a71750c) for anyone who did.

Fix

The decision now re-uses requests' own proxy selection for the destination URL instead of truthiness:

raw = requests.utils.get_environ_proxies(url, no_proxy=None) or {}
if requests.utils.select_proxy(url, raw) is None:
    return {}
return raw
  • {'no': ...}-only environments return {} → direct egress on the resolve-and-pinned guarded session, as the docstring always promised.
  • Genuinely proxied environments (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY, scheme- or host-scoped) return the full env mapping unchanged, so the corporate-egress path behaves exactly as before — select_proxy returns the selected proxy for those, and the full mapping (not just the selection) is what requests needs to route the request.
  • Any resolution error still fails closed to {} (direct, pinned), as before.

Tests

New TestEnvironProxies class in tests/unit/test_lifecycle_executor_paths.py:

  1. test_no_proxy_only_mapping_is_direct_egress — a bare {'no': ...} mapping is direct egress.
  2. test_scheme_proxy_mapping_is_corporate_egress — a real scheme mapping is returned intact.
  3. test_resolution_error_fails_closed_to_direct — errors fail closed to {}.
  4. test_no_proxy_only_env_still_uses_guarded_session — end-to-end regression: with only NO_PROXY exported, execute_script must still dispatch on the (mocked) guarded session.

The getproxies source is patched rather than relying on ambient env so the tests stay hermetic on hosts whose system proxy configuration (e.g. macOS SCPreferences) would otherwise inject a mapping.

Verification

  • pytest tests/unit -p no:cacheprovider: 23584 passed, 44 skipped, 21 xfailed — the two previously failing tests now pass both with NO_PROXY exported and unset, and the new tests pass in both states.
  • ruff check and ruff format --check clean on both touched files.

The behavior change is intentionally narrow: the only hosts whose dispatch path changes are ones exporting NO_PROXY with no proxy variables set — hosts that today get the unpinned fallback the docstring says they shouldn't.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
bodapatisaikrishna added 2 commits November 7, 2026 15:27
@bodapatisaikrishna
fix(mcp): preserve declared self-defined server names containing slashes
0a71750
@bodapatisaikrishna
fix(lifecycle): keep pinned HTTP egress when only NO_PROXY is set
b82ddcc
_environ_proxies_for treated any truthy get_environ_proxies() result as
corporate egress, but with NO_PROXY exported and no proxy variables set
(containers, CI runners, macOS shells) that mapping is a bare {'no': ...}
entry which selects no proxy for any URL. Dispatch then ran on the
unpinned capturing session instead of the resolve-and-pinned guarded
session, silently dropping the DNS-pin defense, and two TestHttpExecutor
tests failed on every such host because they patch _get_guarded_session.

Confirm the classification with requests' own select_proxy() for the
destination URL: return the env mapping only when a proxy would actually
be used, and {} otherwise (direct egress on the pinned session). Add
regression tests for the no-proxy-only mapping, a genuine scheme mapping,
fail-closed error handling, and an end-to-end dispatch that must stay on
the guarded session when only NO_PROXY is exported.

Fixes microsoft#3574
@bodapatisaikrishna
bodapatisaikrishna requested review from Daniel Meppiel (danielmeppiel) and Sergio Sisternes (sergio-sisternes-epam) as code owners November 12, 2026 06:52
Copilot AI balanced review requested due to automatic review settings November 12, 2026 06:52
Copilot started reviewing on behalf of bodapatisaikrishna November 12, 2026 06:52
View session
Copilot AI reviewed Nov 12, 2026
View reviewed changes

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

🟡 Changes recommended

Reinstallation can leave legacy server entries and stale endpoints active, while proxy tests remain environment-dependent and the required architecture guard is unregistered.

3 open issues
  • Medium severity Migrate legacy basename keys when adopting full server names · New
  • Medium severity Disable proxy bypass checks in mapping-based proxy tests · New
  • Low severity Register config-key ownership in the architecture linter · New
What changed in this PR

This PR addresses #3574 by keeping HTTP lifecycle requests on the DNS-pinned session when no proxy applies. It also updates MCP adapters to preserve self-defined server names containing slashes.

Changes:

  • Use requests' destination-specific proxy selection instead of proxy-mapping truthiness.
  • Preserve self-defined MCP names through the shared configuration-key helper.
  • Add proxy-routing, MCP naming, and Kiro error-path regression tests.
File Description
tests/​unit/​test_scoped_mcp_server_names.py Adds self-defined name preservation, collision, and delegation tests.
tests/​unit/​test_lifecycle_executor_paths.py Adds proxy-classification and guarded-session regressions.
tests/​integration/​test_wave2_adapters_coverage.py Tests self-defined keys and Kiro fetch failures.
src/​apm_cli/​integration/​mcp_integrator.py Marks synthetic server metadata as self-defined.
src/​apm_cli/​core/​script_executors.py Checks whether a proxy actually applies before choosing egress.
src/​apm_cli/​adapters/​client/​opencode.py Passes server metadata to shared key selection.
src/​apm_cli/​adapters/​client/​kiro.py Recomputes the configuration key after fetching metadata.
src/​apm_cli/​adapters/​client/​hermes.py Passes server metadata to shared key selection.
src/​apm_cli/​adapters/​client/​gemini.py Replaces local key selection with the shared helper.
src/​apm_cli/​adapters/​client/​cursor.py Passes server metadata to shared key selection.
src/​apm_cli/​adapters/​client/​copilot.py Passes server metadata to shared key selection.
src/​apm_cli/​adapters/​client/​codex.py Passes server metadata to shared key selection.
src/​apm_cli/​adapters/​client/​claude.py Passes server metadata to shared key selection.
src/​apm_cli/​adapters/​client/​base.py Preserves declared names for self-defined servers.

Review effort: Balanced

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/apm_cli/adapters/client/base.py
Comment on lines +1341 to +1342
if server_info and (server_info.get("is_self_defined") or "_raw_stdio" in server_info):
return server_info.get("name") or server_url
Comment thread tests/unit/test_lifecycle_executor_paths.py
Comment on lines +179 to +180
def test_no_proxy_only_mapping_is_direct_egress(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr("requests.utils.getproxies", lambda: {"no": "127.0.0.1,localhost,::1"})
Comment thread tests/unit/test_scoped_mcp_server_names.py
Comment on lines +195 to +196
def test_static_guard_safe_installer_centralizes_naming_in_adapter():
"""SafeMCPInstaller must not duplicate self-defined config key resolution."""
@danielmeppiel Daniel Meppiel (danielmeppiel) mentioned this pull request Nov 12, 2026
[BUG] HTTP lifecycle dispatch treats a NO_PROXY-only environment as corporate egress and skips the resolve-and-pinned session #3574
Open

This branch has not been deployed

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

Reviewers

Copilot code review Copilot
Copilot review effort
Applies to this pull request for everyone.Learn more about Copilot code review.
Copilot left review comments
@danielmeppiel Daniel Meppiel (danielmeppiel) Awaiting requested review from danielmeppiel danielmeppiel is a code owner
@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) Awaiting requested review from sergio-sisternes-epam sergio-sisternes-epam is a code owner

At least 0 approving reviews are required to merge this pull request.

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

[BUG] HTTP lifecycle dispatch treats a NO_PROXY-only environment as corporate egress and skips the resolve-and-pinned session

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@bodapatisaikrishna
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.