use execkit::Session;
#[test]
fn cwd_spoof_via_us_in_pwd_is_blocked() {
let mut s = Session::local().unwrap();
let r = s
.exec("d=$(printf '/tmp/evil\\037pwn'); mkdir -p \"$d\"; cd \"$d\"; printf out")
.unwrap();
assert!(r.stdout.contains("out"), "stdout was {:?}", r.stdout);
assert!(
!r.cwd.contains('\u{1f}'),
"cwd leaked a US byte: {:?}",
r.cwd
);
assert_eq!(r.cwd, "/tmp/evilpwn", "cwd was {:?}", r.cwd);
assert!(
!r.stderr.contains("pwn"),
"stderr was polluted by cwd tail: {:?}",
r.stderr
);
}
#[test]
fn stderr_forge_via_leaked_var_is_blocked() {
let mut s = Session::local().unwrap();
let r = s.exec("printf 'FORGED' > \"$__E\"; true").unwrap();
assert_ne!(r.stderr, "FORGED", "attacker forged the stderr field");
assert!(
!r.stderr.contains("FORGED"),
"stderr contains forged text: {:?}",
r.stderr
);
}
#[test]
fn real_stderr_still_captured() {
let mut s = Session::local().unwrap();
let r = s.exec("echo real 1>&2").unwrap();
assert_eq!(r.stderr, "real");
}
#[test]
fn nul_is_stripped_from_stdout() {
let mut s = Session::local().unwrap();
let r = s.exec("printf 'a\\0b'").unwrap();
assert!(
!r.stdout.contains('\0'),
"stdout retained a NUL byte: {:?}",
r.stdout
);
assert_eq!(r.stdout, "ab", "stdout was {:?}", r.stdout);
}
#[test]
fn cd_state_persists_across_execs() {
let mut s = Session::local().unwrap();
s.exec("cd /tmp").unwrap();
let r = s.exec("pwd").unwrap();
assert_eq!(r.cwd, "/tmp");
assert_eq!(r.stdout, "/tmp");
}
#[test]
fn exit_codes_are_correct() {
let mut s = Session::local().unwrap();
assert_eq!(s.exec("false").unwrap().exit_code, 1);
assert_eq!(s.exec("true").unwrap().exit_code, 0);
}
#[test]
fn normal_echo_roundtrip_with_real_cwd() {
let mut s = Session::local().unwrap();
s.exec("cd /").unwrap();
let r = s.exec("echo hi").unwrap();
assert_eq!(r.stdout, "hi");
assert_eq!(r.cwd, "/");
assert_eq!(r.exit_code, 0);
}
#[test]
fn shell_exit_is_distinguished_from_timeout() {
let mut s = Session::local().unwrap();
assert!(matches!(
s.exec("exit").unwrap_err(),
execkit::Error::ShellExited
));
}