fix: preserve Docker ACP stdio input

This commit is contained in:
Bryan Helmkamp 2026-05-11 13:56:16 -04:00
parent cd8a968b4a
commit eb42ec642e
No known key found for this signature in database

View file

@ -758,6 +758,7 @@ fn docker_controlled_shell_command(command: &str, stop_file: &str, pid_file: &st
stop_file={stop_file}; \
pid_file={pid_file}; \
user_command={command}; \
exec 3<&0; \
rm -f \"$pid_file\"; \
if [ -e \"$stop_file\" ]; then \
rm -f \"$stop_file\" \"$pid_file\"; \
@ -772,11 +773,12 @@ fi; \
kill -KILL \"-$child\" 2>/dev/null || kill -KILL \"$child\" 2>/dev/null || true; \
) & watcher=$!; \
if command -v setsid >/dev/null 2>&1; then \
setsid /bin/bash -lc \"$user_command\" & \
setsid /bin/bash -lc \"$user_command\" <&3 & \
else \
/bin/bash -lc \"$user_command\" & \
/bin/bash -lc \"$user_command\" <&3 & \
fi; \
child=$!; \
exec 3<&-; \
echo \"$child\" > \"$pid_file\"; \
wait \"$child\"; \
status=$?; \
@ -1868,8 +1870,10 @@ mod tests {
reason = "unit test reads an in-memory tar entry synchronously"
)]
use std::io::Read as _;
use std::process::Stdio;
use std::time::Duration;
use tokio::io::AsyncWriteExt as _;
use tokio::process::Command;
use super::*;
@ -2017,6 +2021,45 @@ mod tests {
);
}
#[tokio::test]
async fn controlled_shell_command_preserves_stdin_for_user_command() {
let tempdir = tempfile::tempdir().expect("tempdir should be created");
let stop_file = tempdir.path().join("stop");
let pid_file = tempdir.path().join("pid");
let stop_file = stop_file.to_string_lossy().into_owned();
let pid_file = pid_file.to_string_lossy().into_owned();
let command = docker_controlled_shell_command("cat", &stop_file, &pid_file);
let mut child = Command::new("/bin/bash")
.arg("-lc")
.arg(command)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.kill_on_drop(true)
.spawn()
.expect("controlled shell command should spawn");
let mut stdin = child
.stdin
.take()
.expect("controlled shell command stdin should be piped");
stdin
.write_all(b"abc\n")
.await
.expect("stdin should be written");
drop(stdin);
let output = time::timeout(Duration::from_secs(5), child.wait_with_output())
.await
.expect("controlled shell command should not hang")
.expect("controlled shell command should run");
assert!(
output.status.success(),
"controlled shell command should exit successfully: {output:?}"
);
assert_eq!(output.stdout, b"abc\n");
}
#[tokio::test]
async fn controlled_shell_command_skips_user_command_when_stop_already_requested() {
let tempdir = tempfile::tempdir().expect("tempdir should be created");