Skip to content

Latest commit

 

History

History
157 lines (141 loc) · 9.22 KB

File metadata and controls

157 lines (141 loc) · 9.22 KB

← Back to Backlog

[SC-007] ✅ DONE - Add setup-proxy action to wsl-manager with automatic proxy detection

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:

  1. User launches wsl-manager setup-proxy <distro> (or selects from menu)
  2. Install-WslProxy dot-sources tools/proxy/setProxy.ps1 (in library mode) to access its detection functions
  3. Auto-detect: Calls Get-InternetSettingsFromRegistry + Get-ProxyFromPac to resolve proxy from PAC/registry
  4. Credentials: Asks user whether they want to provide credentials — if yes, prompts via Get-ProxyCredentialsFromUser
  5. Manual fallback: If no PAC/AutoConfigURL found, prompts user to either enter host:port manually or choose "no proxy (DIRECT)"
  6. Configures the target WSL distro with resolved settings

Ordering context:

  • setup-proxy runs after setup-user but before setup-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.ps1 functions via dot-sourcing (not module import)
  • Library mode guard: Rename SETPROXY_TEST_MODE env var in setProxy.ps1 to SETPROXY_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_PROXY all get the same value
  • NO_PROXY: Fallback to localhost,127.0.0.1
  • apt proxy: Write /etc/apt/apt.conf.d/99proxy with Acquire::http::Proxy and Acquire::https::Proxy
  • Docker runtime proxy: Write ~/.docker/config.json proxies.default unconditionally (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_MODE to SETPROXY_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.ps1 with $env:SETPROXY_LIBRARY_MODE = '1' (restores after)
  • Calls Get-InternetSettingsFromRegistry to check for PAC
  • If PAC exists: calls Get-ProxyFromPac to 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:port or 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.sh via Invoke-WslDistroScript
  • For DIRECT: calls setup-proxy.sh with a --remove flag to clean up proxy configs

Bash script — scripts/setup-proxy.sh:

  • Args: --proxy-url <url>, --no-proxy <list>, --username <user>, --remove
  • --remove flag: 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 as install-podman.sh)
  • All user-home files written under $TARGET_HOME, not /root; ownership set with chown $TARGET_USER:$TARGET_USER
  • Idempotent: uses marker comments (# BEGIN wsl-manager proxy / # END wsl-manager proxy) for managed blocks, replaces on re-run
  • Configures:
    1. $TARGET_HOME/.bashrc — managed block with all 6 exports (HTTPS_PROXY, HTTP_PROXY, https_proxy, http_proxy, NO_PROXY, no_proxy)
    2. /etc/apt/apt.conf.d/99proxy — full file replacement (idempotent by nature, owned by root) with Acquire::http::Proxy and Acquire::https::Proxy
    3. $TARGET_HOME/.docker/config.json — write proxies.default block unconditionally, chown to target user (pre-stages before Docker install)
    4. $TARGET_HOME/.config/containers/containers.conf — write [engine] env block unconditionally, chown to target user (pre-stages before Podman install)

wsl-manager.ps1:

  • Add setup-proxy to ValidateSet and Invoke-WslManager switch
  • Add Invoke-SetupProxy + Invoke-SetupProxyInteractive following 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.ps1 guard renamed from SETPROXY_TEST_MODE to SETPROXY_LIBRARY_MODE
  • Auto-detects proxy from PAC/registry via dot-sourced setProxy.ps1 functions
  • Asks user whether they want to provide proxy credentials; prompts if yes
  • When no PAC detected, prompts user to enter host:port or choose "no proxy (DIRECT)"
  • When PAC resolves to DIRECT, offers "no proxy" confirmation
  • DIRECT / "no proxy" removes managed proxy blocks from distro (--remove flag)
  • .bashrc exports all 6 proxy variables using managed block with marker comments
  • All proxy vars get the same value
  • NO_PROXY / no_proxy fallback to localhost,127.0.0.1
  • /etc/apt/apt.conf.d/99proxy written with Acquire::http::Proxy and Acquire::https::Proxy
  • ~/.docker/config.json written with proxies.default (unconditional, pre-staged before Docker install)
  • ~/.config/containers/containers.conf written 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.md updated with proxy setup step in the workflow
  • All existing tests continue to pass

Technical Notes:

  • .bashrc managed block pattern (same approach as install-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%40ss for p@ss) — Get-ProxyCredentialsFromUser handles 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 }

← Back to Backlog