Skip to main content

Module exec

Module exec 

Source
Expand description

Running a program with a literal argument vector, bounded output, a deadline, a cancellation flag, and an optional anonymous stdin pipe.

§Why this exists instead of std::process::Command

Everything the WSL adapter does is “run wsl.exe with these exact arguments and read what it says”. Three properties of that sentence are load-bearing, and none of them is Command’s default:

  1. There is no shell. Not a cmd /c, not a bash -c, not a string that something downstream re-splits. CommandRequest holds a program and a Vec<OsString>, and that is the only shape it can hold — a distribution named Ubuntu & rm -rf / is one argument, everywhere, by construction.
  2. Output is bounded. Command::output reads until EOF. A hung child writing to stderr in a loop would then be an unbounded allocation in a service that is supposed to stay up. OutputLimits caps what is kept while still draining the pipe, because a child that is not drained blocks instead of finishing.
  3. The credential goes in through stdin and comes out nowhere. ChildInput::Piped holds its bytes in a secrecy::SecretBox, its Debug prints a length, and CommandRequest::refuse_payload_in_argv refuses to launch at all if the payload is a verbatim substring of the program path or of any argument. 03-security-and-lifecycle.md item 3 says the document “is absent from argv, environment, provider records, logs, errors, status JSON, temporary files and scheduled-task XML”; this module is where the argv and environment halves of that are enforced rather than reviewed.

§The environment half is enforced by absence

CommandRequest has no method that sets an environment variable, and HostCommandRunner makes no env call. That is deliberate and is the whole control: there is no API through which a caller could put a secret in the child’s environment, so there is no code path to audit for one. The child inherits this process’s environment unchanged, which is the same environment wsl.exe would have inherited from an operator’s shell.

§The seam

CommandRunner is the injection point. Production uses HostCommandRunner, which really spawns. Tests use ScriptedRunner, which answers from a table and records every request — including the stdin bytes, so that a test can assert a canary reached the child’s stdin and nothing else. Both are usable on every CI leg, which is what lets the Windows-shaped logic in this module be tested on Linux and macOS too.

Structs§

Cancellation
A flag a caller can raise to stop a running child early.
CommandOutput
What a child said and how it stopped.
CommandRequest
One program, one literal argument vector, and the bounds it runs under.
HostCommandRunner
Really spawns the program.
OutputLimits
How much of each stream is kept.
PipedInput
Bytes destined for a child’s stdin, which never appear anywhere else.
RecordedRequest
One request as ScriptedRunner saw it.
ScriptedRunner
A CommandRunner that answers from a table and records what it was asked.

Enums§

ChildInput
What the child sees on stdin.
Completion
How a child stopped.

Constants§

DEFAULT_STDERR_LIMIT
How much of stderr is kept. Smaller, because its only use is a diagnostic sentence in an error.
DEFAULT_STDOUT_LIMIT
How much of stdout is kept.
DEFAULT_TIMEOUT
How long a probe-shaped command is given before it is killed.

Traits§

CommandRunner
Runs a CommandRequest.