Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions launch/core/platforms/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,49 @@
import uuid

import docker


# Do not inherit or invent a machine-local proxy route for evaluated Windows
# containers. Callers that need one can opt in explicitly through these names.
WINDOWS_CONTAINER_PROXY_ENV = "REPOLAUNCH_WINDOWS_CONTAINER_PROXY"
WINDOWS_CONTAINER_NO_PROXY_ENV = "REPOLAUNCH_WINDOWS_CONTAINER_NO_PROXY"
DEFAULT_WINDOWS_CONTAINER_NO_PROXY = "localhost,127.0.0.1,::1"


def build_windows_container_environment() -> dict[str, str]:
"""Build the task-container environment without a proxy by default.

A Windows evaluation container may be able to reach an external registry
directly even when a host-local proxy is stale or unreachable from process
isolation. Conversely, managed, regional, and enterprise environments may
require a proxy. Keep proxy propagation explicit rather than guessing from
host variables: callers can supply a container-reachable route through
``REPOLAUNCH_WINDOWS_CONTAINER_PROXY``. When configured, set both
conventional upper- and lower-case variables because Windows project
toolchains use both spellings.
"""
environment = {"TERM": "xterm-mono"}
proxy = os.environ.get(WINDOWS_CONTAINER_PROXY_ENV, "").strip()
if not proxy:
return environment

environment.update({
"HTTP_PROXY": proxy,
"HTTPS_PROXY": proxy,
"ALL_PROXY": proxy,
"http_proxy": proxy,
"https_proxy": proxy,
"all_proxy": proxy,
})
no_proxy = os.environ.get(
WINDOWS_CONTAINER_NO_PROXY_ENV,
DEFAULT_WINDOWS_CONTAINER_NO_PROXY,
).strip()
if no_proxy:
environment.update({"NO_PROXY": no_proxy, "no_proxy": no_proxy})
return environment


from docker.models.containers import Container


Expand Down Expand Up @@ -157,9 +200,7 @@ def _start_container(
stdin_open=True,
tty=True,
detach=True,
environment={
"TERM": "xterm-mono",
},
environment=build_windows_container_environment(),
working_dir=working_dir,
extra_hosts=extra_hosts,
volumes={
Expand Down
93 changes: 93 additions & 0 deletions tests/windows_container_proxy_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from __future__ import annotations

import os
import sys
import unittest
from pathlib import Path
from unittest import mock


ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from launch.core.platforms.windows import (
DEFAULT_WINDOWS_CONTAINER_NO_PROXY,
WINDOWS_CONTAINER_NO_PROXY_ENV,
WINDOWS_CONTAINER_PROXY_ENV,
build_windows_container_environment,
)


class WindowsContainerProxyTest(unittest.TestCase):
def test_default_does_not_inject_machine_local_proxy(self) -> None:
with mock.patch.dict(os.environ, {}, clear=True):
environment = build_windows_container_environment()

self.assertEqual(environment, {"TERM": "xterm-mono"})
self.assertNotIn("HTTP_PROXY", environment)
self.assertNotIn("http_proxy", environment)

def test_explicit_proxy_populates_common_toolchain_spellings(self) -> None:
proxy = "http://host.docker.internal:7897"
with mock.patch.dict(
os.environ,
{WINDOWS_CONTAINER_PROXY_ENV: proxy},
clear=True,
):
environment = build_windows_container_environment()

for key in (
"HTTP_PROXY",
"HTTPS_PROXY",
"ALL_PROXY",
"http_proxy",
"https_proxy",
"all_proxy",
):
self.assertEqual(environment[key], proxy)
self.assertEqual(environment["NO_PROXY"], DEFAULT_WINDOWS_CONTAINER_NO_PROXY)
self.assertEqual(environment["no_proxy"], DEFAULT_WINDOWS_CONTAINER_NO_PROXY)

def test_host_proxy_is_used_only_when_explicitly_selected(self) -> None:
host_proxy = "http://host.docker.internal:7897"
with mock.patch.dict(
os.environ,
{
"HTTP_PROXY": host_proxy,
"HTTPS_PROXY": host_proxy,
"ALL_PROXY": host_proxy,
},
clear=True,
):
environment = build_windows_container_environment()

self.assertEqual(environment, {"TERM": "xterm-mono"})
self.assertNotIn("HTTP_PROXY", environment)

with mock.patch.dict(
os.environ,
{WINDOWS_CONTAINER_PROXY_ENV: host_proxy},
clear=True,
):
environment = build_windows_container_environment()

self.assertEqual(environment["HTTP_PROXY"], host_proxy)
self.assertEqual(environment["HTTPS_PROXY"], host_proxy)

def test_explicit_no_proxy_overrides_default(self) -> None:
with mock.patch.dict(
os.environ,
{
WINDOWS_CONTAINER_PROXY_ENV: "http://proxy.example:8080",
WINDOWS_CONTAINER_NO_PROXY_ENV: "localhost,fakerepo",
},
clear=True,
):
environment = build_windows_container_environment()

self.assertEqual(environment["NO_PROXY"], "localhost,fakerepo")
self.assertEqual(environment["no_proxy"], "localhost,fakerepo")


if __name__ == "__main__":
unittest.main()