WinRM command.Wait() and remotefs upload can hang forever on a dead session
- Dominant language
- Go
- Stars
- 53
- Forks
- 33
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 29
Description
## What
`protocol/winrm.(*command).Wait()` and `remotefs.(*winFile).command()` can block forever when the underlying WinRM session has silently died, with no way for a caller to bound the wait.
## Repro / Evidence
Observed on `Mirantis/launchpad`'s smoke-windows CI (rig v2 migration branch, PRODENG-3594): a Windows host reboots mid-test, the reconnect succeeds, and the very next remote-file-upload during MCR uninstall hangs for the remainder of the 60-minute test timeout. `panic: test timed out` produced a full goroutine dump. Two independent goroutines were stuck:
```
goroutine 8153 [select, 40 minutes]:
github.com/k0sproject/rig/v2/remotefs.(*winFile).command(...)
remotefs/winfile.go:252
github.com/k0sproject/rig/v2/remotefs.(*winFile).open(...)
remotefs/winfile.go:215
github.com/k0sproject/rig/v2/remotefs.(*WinFS).OpenFile(...)
remotefs/winfs.go:241
github.com/k0sproject/rig/v2/remotefs.copyAndVerifyUpload(...)
remotefs/upload.go:38
github.com/k0sproject/rig/v2/remotefs.Upload(...)
remotefs/upload.go:98
```
```
goroutine 7165 [sync.WaitGroup.Wait, 45 minutes]:
sync.(*WaitGroup).Wait(...)
github.com/k0sproject/rig/v2/protocol/winrm.(*command).Wait(...)
protocol/winrm/connection.go:291
github.com/k0sproject/rig/v2/cmd.(*waiterWrapper).Wait(...)
cmd/executor.go:235
github.com/k0sproject/rig/v2/remotefs.(*winFile).open.func2(...)
remotefs/winfile.go:203
```
## Root cause
- `winFile.command()` (`remotefs/winfile.go:228`) writes a request to the remote rigrcp helper's stdin, then `select`s on either the helper process exiting (`f.done`) or a response arriving (`resp`). Neither the write nor the select has any timeout. If the WinRM shell backing the helper process is dead, neither branch is ever satisfied.
- `command.Wait()` (`protocol/winrm/connection.go:287`) calls `c.wg.Wait()` then the underlying `masterzen/winrm` `Command.Wait()`, neither of which take a context or have an internal timeout. `StartProcess` already receives a `ctx` and uses it to start the command, but never threads it into `Wait()`, so a caller-supplied deadline on `ctx` has no effect on how long `Wait()` can block.
## Expected
A command/upload whose underlying WinRM session has died returns an error within a bounded time (or respects a caller-supplied context deadline), instead of blocking indefinitely.
## Actual
Both hang indefinitely; nothing bounds them.
## Environment
- `github.com/k0sproject/rig/v2 v2.1.0`
- WinRM transport, Windows Server 2019/2022/2025 targets
- Failure occurs specifically in the window right after a host reboot, before the previous WinRM session is confirmed dead.
Written by AI: claude-sonnet-5
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with protocol/winrm/connection.go, especially command.Wait and StartProcess, then inspect remotefs/winfile.go around winFile.command and open. Trace how the caller context is passed and how f.done and resp are handled when the WinRM session dies. Done means command and upload operations return a bounded error or honor the caller-supplied context deadline instead of hanging indefinitely.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100