[Request]: Document shell evaluation in container machine run and consider an argv-preserving mode
- Dominant language
- Swift
- Stars
- 49.9k
- Forks
- 1.8k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 22
Description
### Feature or enhancement request details
### Summary
`container machine run [] [ ...]` looks like an argv-preserving interface, but the guest concatenates the supplied command and arguments and evaluates them through the user's shell:
```sh
exec "${USER_SHELL:-${SHELL}}" -c "$*"
```
This behavior appears intentional: it is described in
https://github.com/apple/container/blob/4dfa3d49d910f1a024359de7e4aa4fa9be649e20/Sources/Plugins/MachineAPIServer/Resources/init#L11-L15 and covered by integration tests including `testRunWithEnvironment`, `testRunCommandInShell`, and `testRunCommandExitCode`:
https://github.com/apple/container/blob/4dfa3d49d910f1a024359de7e4aa4fa9be649e20/Tests/IntegrationTests/Machine/TestCLIMachineRuntimeSerial.swift#L179
https://github.com/apple/container/blob/4dfa3d49d910f1a024359de7e4aa4fa9be649e20/Tests/IntegrationTests/Machine/TestCLIMachineRuntimeSerial.swift#L240
https://github.com/apple/container/blob/4dfa3d49d910f1a024359de7e4aa4fa9be649e20/Tests/IntegrationTests/Machine/TestCLIMachineRuntimeSerial.swift#L254
The issue is that `container machine run --help` only describes the operands as:
```text
Command to run (default: login shell)
Command arguments
```
It does not mention that they are joined and evaluated as shell code. This can reasonably be mistaken for argv-preserving behavior, especially by wrapper or automation authors familiar with interfaces such as `docker exec`.
### Reproduction and comparison with `docker exec`
```console
# A single argument containing spaces
$ container machine run -n my-machine -- printf ':%s:' 'one two three'
:one::two::three:
$ docker exec my-container printf ':%s:' 'one two three'
:one two three:
# Command substitution inside an argument
$ container machine run -n my-machine -- printf ':%s:' 'x=$(id -u)'
:x=501:
$ docker exec my-container printf ':%s:' 'x=$(id -u)'
:x=$(id -u):
```
`docker exec` preserves the argument boundaries and does not evaluate `$(id -u)`. Shell evaluation occurs only when a shell is explicitly requested, for example:
```console
$ docker exec my-container sh -c 'printf ":%s:" "x=$(id -u)"'
:x=0:
```
This matches the documented `docker exec` contract: `COMMAND` must be an executable, and shell processing requires an explicit `sh -c`: https://docs.docker.com/reference/cli/docker/container/exec/
Runtime reproduction was reconfirmed on container 1.1.0 (build 5973b9c) on 2026-07-16. The same implementation is present on current `main` (4dfa3d4, source-checked 2026-07-16). The Docker comparison above was verified locally with Docker Engine 27.4.0 and `alpine:latest`.
### Why this matters
For a user who controls the complete command line, this grants no new capability. The concern is downstream code that forwards untrusted data as an argument while assuming argv semantics; a value such as `$(...)` is then evaluated as code in the guest.
### Requested changes
1. Document that the command and arguments are joined into a single command string and evaluated by the shell configured for the execution user inside the guest, including expansion, substitution, and redirection.
2. Consider adding an explicit opt-in argv-preserving mode, such as `--exec` or `--no-shell`, while retaining the current shell behavior for compatibility.
### Code of Conduct
- [x] I agree to follow this project's Code of Conduct
Contributor guide
Research direction
Read the shell invocation in Sources/Plugins/MachineAPIServer/Resources/init and the integration coverage in Tests/IntegrationTests/Machine/TestCLIMachineRuntimeSerial.swift, especially testRunWithEnvironment, testRunCommandInShell, and testRunCommandExitCode. Document that arguments are joined and evaluated by the guest user's shell, then assess the requested argv-preserving mode and define its behavior and tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- shell, swift
- Domain
- cli, documentation
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100