Status: Done (2026-03-02)
Priority: Urgent
Component: tools/proxy/setProxy.ps1 (existing, rename guard), tools/pslib/wsl/lib/proxy.ps1 (new), tools/pslib/wsl/scripts/setup-proxy.sh (new), tools/pslib/wsl/wsl-manager.ps1
Related: FEAT-002 (Podman setup — .bashrc pattern), FEAT-001 (Docker setup)
Summary:
As a developer in a corporate environment with an authenticating proxy, I want wsl-manager setup-proxy to automatically detect my proxy settings and configure all proxy settings inside my WSL distro so that apt, Docker, Podman, and general shell traffic all route through the proxy without manual configuration.
Key design change: Instead of requiring a separate setProxy.ps1 run to populate env vars, setup-proxy dot-sources setProxy.ps1 as a library and calls its detection functions directly. The user never needs to run setProxy.ps1 manually.
Workflow:
- User launches
wsl-manager setup-proxy <distro>(or selects from menu) Install-WslProxydot-sourcestools/proxy/setProxy.ps1(in library mode) to access its detection functions- Auto-detect: Calls
Get-InternetSettingsFromRegistry+Get-ProxyFromPacto resolve proxy from PAC/registry - Credentials: Asks user whether they want to provide credentials — if yes, prompts via
Get-ProxyCredentialsFromUser - Manual fallback: If no PAC/AutoConfigURL found, prompts user to either enter
host:portmanually or choose "no proxy (DIRECT)" - Configures the target WSL distro with resolved settings
Ordering context:
setup-proxyruns aftersetup-userbut beforesetup-docker/setup-podman- Docker and Podman are NOT installed yet at this point — proxy configs are pre-staged unconditionally
- When Docker/Podman are installed later, they pick up the existing proxy configs automatically
Proxy detection flow (in Install-WslProxy):
dot-source setProxy.ps1 (library mode)
│
├─ PAC detected (AutoConfigURL in registry)
│ ├─ PAC resolves to proxy URL → use that URL
│ └─ PAC resolves to DIRECT → offer "no proxy" confirmation
│
└─ No PAC detected
└─ Prompt user: enter host:port manually OR choose "no proxy (DIRECT)"
│
├─ If proxy URL resolved → ask if credentials needed, prompt if yes
└─ If DIRECT → skip credentials, remove proxy configs from distro
Scope Decisions:
- Proxy detection: Reuse
setProxy.ps1functions via dot-sourcing (not module import) - Library mode guard: Rename
SETPROXY_TEST_MODEenv var insetProxy.ps1toSETPROXY_LIBRARY_MODE— when set, script exposes functions without executing main logic - Credentials: Always ask user whether they want to provide credentials — if yes, prompt for username/password via
Get-ProxyCredentialsFromUser - DIRECT option: When PAC returns DIRECT or no PAC is available, user can choose "no proxy" which clears/removes proxy configs from the distro
- All proxy vars reuse same value:
HTTP_PROXY,https_proxy,http_proxy,HTTPS_PROXYall get the same value - NO_PROXY: Fallback to
localhost,127.0.0.1 - apt proxy: Write
/etc/apt/apt.conf.d/99proxywithAcquire::http::ProxyandAcquire::https::Proxy - Docker runtime proxy: Write
~/.docker/config.jsonproxies.defaultunconditionally (pre-stages config before Docker install) - Podman runtime proxy: Write
~/.config/containers/containers.conf[engine]env unconditionally (pre-stages config before Podman install)
Implementation:
tools/proxy/setProxy.ps1 changes:
- Rename env var guard from
SETPROXY_TEST_MODEtoSETPROXY_LIBRARY_MODE - No other changes — all detection functions already exist and are reusable
PowerShell side — lib/proxy.ps1:
Install-WslProxy -DistroName- Dot-sources
tools/proxy/setProxy.ps1with$env:SETPROXY_LIBRARY_MODE = '1'(restores after) - Calls
Get-InternetSettingsFromRegistryto check for PAC - If PAC exists: calls
Get-ProxyFromPacto resolve proxy URL- If DIRECT: asks user to confirm "no proxy" or enter manual proxy
- If proxy resolved: uses that URL
- If no PAC: prompts user to enter
host:portor choose "no proxy (DIRECT)" - Asks user whether they want to provide credentials; if yes, calls
Get-ProxyCredentialsFromUser - Builds final proxy URL:
http://user:encodedPass@host:port - Gets default user via
Get-WslDefaultUser - Calls
scripts/setup-proxy.shviaInvoke-WslDistroScript - For DIRECT: calls
setup-proxy.shwith a--removeflag to clean up proxy configs
Bash script — scripts/setup-proxy.sh:
- Args:
--proxy-url <url>,--no-proxy <list>,--username <user>,--remove --removeflag: removes all managed proxy blocks and files (idempotent cleanup)- Runs as root, follows exit code convention (0 success / 1 prereq failure / 2 config failure / 3 verification failure / 4 argument error)
- Resolves user home:
TARGET_HOME=$(eval echo "~$TARGET_USER")(same pattern asinstall-podman.sh) - All user-home files written under
$TARGET_HOME, not/root; ownership set withchown $TARGET_USER:$TARGET_USER - Idempotent: uses marker comments (
# BEGIN wsl-manager proxy/# END wsl-manager proxy) for managed blocks, replaces on re-run - Configures:
$TARGET_HOME/.bashrc— managed block with all 6 exports (HTTPS_PROXY,HTTP_PROXY,https_proxy,http_proxy,NO_PROXY,no_proxy)/etc/apt/apt.conf.d/99proxy— full file replacement (idempotent by nature, owned by root) withAcquire::http::ProxyandAcquire::https::Proxy$TARGET_HOME/.docker/config.json— writeproxies.defaultblock unconditionally,chownto target user (pre-stages before Docker install)$TARGET_HOME/.config/containers/containers.conf— write[engine]env block unconditionally,chownto target user (pre-stages before Podman install)
wsl-manager.ps1:
- Add
setup-proxytoValidateSetandInvoke-WslManagerswitch - Add
Invoke-SetupProxy+Invoke-SetupProxyInteractivefollowing existing pattern - Interactive menu:
[X] Setup proxy (corporate)— placed between Podman and Remove - Menu key
[X](proXy) to avoid conflicts with existing keys
Acceptance Criteria:
-
wsl-manager setup-proxy <distro>command works - Interactive menu option
[X] Setup proxy (corporate)works -
setProxy.ps1guard renamed fromSETPROXY_TEST_MODEtoSETPROXY_LIBRARY_MODE - Auto-detects proxy from PAC/registry via dot-sourced
setProxy.ps1functions - Asks user whether they want to provide proxy credentials; prompts if yes
- When no PAC detected, prompts user to enter
host:portor choose "no proxy (DIRECT)" - When PAC resolves to DIRECT, offers "no proxy" confirmation
- DIRECT / "no proxy" removes managed proxy blocks from distro (
--removeflag) -
.bashrcexports all 6 proxy variables using managed block with marker comments - All proxy vars get the same value
-
NO_PROXY/no_proxyfallback tolocalhost,127.0.0.1 -
/etc/apt/apt.conf.d/99proxywritten withAcquire::http::ProxyandAcquire::https::Proxy -
~/.docker/config.jsonwritten withproxies.default(unconditional, pre-staged before Docker install) -
~/.config/containers/containers.confwritten with[engine]env (unconditional, pre-staged before Podman install) - Idempotent — safe to re-run with new credentials (managed blocks replaced, files overwritten)
- All user-home files owned by target user, not root
- Exit codes follow convention (0/1/2/3/4)
- Unit tests for
lib/proxy.ps1(Pester) -
docs/wsl-manager.mdupdated with proxy setup step in the workflow - All existing tests continue to pass
Technical Notes:
.bashrcmanaged block pattern (same approach asinstall-podman.sh):# BEGIN wsl-manager proxy export HTTPS_PROXY="http://user:pass@proxy:8080" export HTTP_PROXY="http://user:pass@proxy:8080" export https_proxy="http://user:pass@proxy:8080" export http_proxy="http://user:pass@proxy:8080" export NO_PROXY="localhost,127.0.0.1,.corp.example.com" export no_proxy="localhost,127.0.0.1,.corp.example.com" # END wsl-manager proxy
/etc/apt/apt.conf.d/99proxy:Acquire::http::Proxy "http://user:pass@proxy:8080"; Acquire::https::Proxy "http://user:pass@proxy:8080";~/.docker/config.json(merge-safe — preserve existing keys):{ "proxies": { "default": { "httpProxy": "http://user:pass@proxy:8080", "httpsProxy": "http://user:pass@proxy:8080", "noProxy": "localhost,127.0.0.1" } } }~/.config/containers/containers.conf:[engine] env = ["https_proxy=http://user:pass@proxy:8080", "http_proxy=http://user:pass@proxy:8080", "no_proxy=localhost,127.0.0.1"]
- Credentials are URL-encoded in the proxy URL (e.g.,
p%40ssforp@ss) —Get-ProxyCredentialsFromUserhandles encoding - Dot-sourcing pattern for library mode:
$env:SETPROXY_LIBRARY_MODE = '1' try { . "$PSScriptRoot/../../../proxy/setProxy.ps1" } finally { Remove-Item Env:\SETPROXY_LIBRARY_MODE -ErrorAction SilentlyContinue }