mirror of
https://github.com/psmux/psmux.git
synced 2026-06-19 09:46:56 +08:00
* test: refuse to run the destructive test runner outside a sandbox tests/run_all_tests.ps1 kills all psmux processes and wipes ~/.psmux (*.port, *.key, .psmux.conf, .psmuxrc) between tests. Run on a machine with a live psmux it silently destroys the user's running sessions and config. Gate it behind PSMUX_TEST_SANDBOX=1: the runner refuses (exit 2) with a clear explanation unless that opt-in is set. The Docker dev image sets the variable so the intended throwaway environment runs unchanged. Adds tests/test_runner_safety_gate.ps1, a static guard (it reads the runner, never executes it — safe anywhere, no binary needed) asserting the gate exists and appears before every destructive operation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: anchor safety-gate guard on the real env check, not a comment The static guard located the gate via the first textual occurrence of PSMUX_TEST_SANDBOX, which is the explanatory comment rather than the executable `if ($env:PSMUX_TEST_SANDBOX ...)` check. That made the guard satisfiable by a comment naming the variable placed before destructive code, even if the real gate sat below it. Anchor on the if-statement instead so the position check reflects the actual abort. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: guard kill-server in the safety-gate blacklist run_all_tests.ps1 calls `& $PSMUX kill-server` in Clean-Server before the Stop-Process cleanup, but the static guard did not list kill-server as a destructive operation. A regression that moved the sandbox gate below the kill-server call would have passed unnoticed. Add kill-server to the blacklist so the position check covers it too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: flag any pre-gate Remove-Item, not just ~/.psmux deletes The guard only recognised Remove-Item calls whose literal target was "$env:USERPROFILE\.psmux...". Delete paths are commonly built from other $env: vars, so a target-specific pattern would not see them as destructive and a pre-gate delete could slip through. Match Remove-Item broadly instead; almost nothing runs before the gate, so flagging any pre-gate delete is the safe default. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: match the safety gate and blacklist case-insensitively [regex]::Match defaults to case-sensitive, but PowerShell keywords, $env: lookups and cmdlet/command names are case-insensitive. Differently cased code such as `remove-item` or `STOP-PROCESS` would therefore have gone unnoticed by the guard. Pass RegexOptions::IgnoreCase to both the gate-anchor match and the destructive-operation matches so casing cannot change the verdict. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test: run the safety-gate guard from the PR smoke suite The static guard lived as a standalone script that no automated path invoked, so a removed or moved sandbox gate in run_all_tests.ps1 would not be caught on a PR. CI already runs test_smoke_pr.ps1, so call the guard from there: it only reads the runner (no binary or session), runs before the session work, and a non-zero exit is reported as a smoke failure. Per review discussion, wiring it into the smoke suite keeps the check on the existing automated path and gives it local coverage too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
psmux Docker Dev Environment
A Windows container with Rust (MSVC), Visual Studio Build Tools, and OpenSSH — ready to build and run psmux.
What's inside
| Component | Details |
|---|---|
| Base image | mcr.microsoft.com/powershell:windowsservercore-ltsc2022 |
| Rust | stable-x86_64-pc-windows-msvc via rustup |
| MSVC | Visual Studio Build Tools 2022 (cl.exe, link.exe) |
| SSH | OpenSSH Server on port 2222 (key-only auth, no passwords) |
| Shell | PowerShell 7 with auto-loaded VS dev environment |
| Git | MinGit for cloning repos |
Quick start
One command
pwsh -File docker\Run-PsmuxDev.ps1
This will:
- Generate an SSH key at
~/.ssh/psmux_docker_key(if not present) - Build the Docker image (first time only)
- Start the container with your public key injected
- Print the SSH command to connect
Manual steps
1. Build the image
cd docker
docker build -t psmux-dev .
Note: The build takes a while (~15-30 min) because it downloads and installs Visual Studio Build Tools. The resulting image is large (~15 GB). This is expected for Windows MSVC containers.
2. Run the container
# Generate SSH key (once)
ssh-keygen -t ed25519 -f ~/.ssh/psmux_docker_key -N "" -C "psmux-docker"
# Run with your public key
$pubkey = Get-Content ~/.ssh/psmux_docker_key.pub
docker run -d --name psmux-dev --isolation=hyperv `
-e "SSH_PUBLIC_KEY=$pubkey" `
psmux-dev
3. SSH in
$ip = docker inspect psmux-dev --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}"
ssh -i ~/.ssh/psmux_docker_key -p 2222 ContainerAdministrator@$ip
4. Build psmux
git clone https://github.com/psmux/psmux.git
cd psmux
cargo install --path .
psmux --version
SSH authentication
This container uses key-only SSH — no passwords. Your public key is passed in via the SSH_PUBLIC_KEY environment variable at container start. The Run-PsmuxDev.ps1 script handles this automatically.
You can also mount a public key file:
docker run -d --name psmux-dev --isolation=hyperv `
-v "$HOME\.ssh\id_ed25519.pub:C:\ssh_public_key" `
psmux-dev
Verifying the toolchain
After SSH-ing in, these should all work:
rustc --version
cargo --version
where cl
where link
Safety notes
- No passwords are used — SSH key auth only
- Container runs with Hyper-V isolation (full VM separation from host)
- SSH listens on port 2222 to avoid conflicts with host sshd
- Key is stored at
~/.ssh/psmux_docker_key(never inside the repo)
File layout
docker/
Dockerfile
README.md
Run-PsmuxDev.ps1 # Host-side: generates key, builds, runs, prints SSH command
Tools/
StartContainer.ps1 # Entrypoint: configures sshd with key auth, starts sshd
InstallAll.ps1 # Build-time: installs Rust, VS Build Tools, OpenSSH, Git
ImportVsDevEnv.ps1 # Loads VS dev environment (cl.exe, link.exe) into PowerShell
Profile/
Microsoft.PowerShell_profile.ps1 # Auto-loads Rust + MSVC env on every shell