Status: Open
Priority: High
Component: lib/wsl/scripts/setup-proxy-negotiate.sh, lib/wsl/proxy.ps1
Depends on: SC-036a
Parent: SC-036
Summary:
As a developer picking Negotiate mode, I want the setup to install krb5-user and px-proxy through a temporary authenticated proxy so that the Kerberos tooling is available on disk before Kerberos is configured — without leaking Basic-auth credentials into any process environment.
Description:
Implements Phase 1 of the four-phase Negotiate workflow (see SC-036). After this slice, which px and which kinit succeed inside the target distro; Kerberos is not yet configured and px is not yet running.
This phase has a chicken-and-egg problem: installing the Kerberos stack needs a working authenticated proxy, but the authenticating proxy (px) is what we are trying to install. Solution: temporarily point apt and pip at the company proxy with Basic-auth creds. The key security constraint (from the SC-036 threat model) is that Basic-auth credentials must never be exported to the shell environment — AI coding agents running in the same WSL session can read /proc/*/environ of any process owned by the same user.
Credential handling during bootstrap:
- apt: creds live in
/etc/apt/apt.conf.d/99proxy(root-owned, 644). Same pattern as SC-007 Basic mode. apt reads its config; no env var needed. - pip/pipx: write a temporary
~/.config/pip/pip.confwith[global] proxy = http://user:pass@host:portbeforepipx install px-proxy, then deletepip.confafter the install succeeds. pip reads from config; no env var needed. - Never exported: at no point does this script run
export HTTP_PROXY=.... The Basic-auth URL does not enter any process env.
Scope Decisions:
- Creds in config files only (no
export HTTP_PROXY): preserves the Negotiate threat model even during bootstrap. Cost: ~5 extra lines of shell to write + deletepip.conf. pipx, notpip3: Ubuntu 24.04+ enforces PEP 668; system-levelpip3 installis blocked.- Marker transition: write
negotiate-bootstrapto/etc/wsl-manager/proxy-modeat the start of Phase 1 (notnegotiate— full Negotiate state is reached only after SC-036d). SC-036e's--removetreatsnegotiate-bootstrapandnegotiateidentically for teardown purposes. - Stop before krb5.conf/px.ini: this slice must not touch Kerberos config, must not start px, must not run
kinit. Those belong to SC-036c. - Idempotent re-run: if re-invoked, re-read the Basic-auth creds via prompt, overwrite
apt.conf.d/99proxy, re-runapt install(no-op if already installed), re-runpipx install(no-op if already installed), re-runpipx ensurepath.
Acceptance Criteria:
-
setup-proxy-negotiate.shprompts (via the PS1 caller, not the shell) for temporary Basic-auth credentials used during bootstrap -
setup-proxy-negotiate.shwrites/etc/apt/apt.conf.d/99proxywith the Basic-auth-embedded proxy URL (root-owned) -
setup-proxy-negotiate.shwrites a temporary~/.config/pip/pip.confwith the Basic-auth URL in[global] proxy; deletes it after the pip install step succeeds (even on failure viatrap) -
setup-proxy-negotiate.shnever setsHTTP_PROXY,HTTPS_PROXY,http_proxy, orhttps_proxyin its own environment or exports them to children -
apt-get update && apt-get install -y krb5-user pipxsucceeds through the apt-config-embedded proxy -
pipx install px-proxysucceeds, using the temppip.conffor proxy access -
pipx ensurepathruns so that~/.local/binis in PATH for future shells - After successful run:
/etc/wsl-manager/proxy-modecontainsnegotiate-bootstrap;~/.local/bin/pxexists;kinitis on PATH - Temp
pip.confdoes not exist after successful run - Script is idempotent: a second run updates the apt proxy with fresh creds and leaves the tools as-is
- Pester unit test covers the PS1 credential-prompt branch for Negotiate bootstrap (mocking the shell invocation)
- All existing tests continue to pass
Technical Notes:
pipx install px-proxypulls thepx-proxypackage; per the SC-036Verifiednote,px --test --auth=NEGOTIATEpassed on the user's system after this install, so no GSSAPI extras are required here.- Suggested
pip.confwriter:mkdir -p "$TARGET_HOME/.config/pip" cat > "$TARGET_HOME/.config/pip/pip.conf" <<EOF [global] proxy = $BASIC_PROXY_URL EOF trap 'rm -f "$TARGET_HOME/.config/pip/pip.conf"' EXIT