Skip to content

Commit

Permalink
test: script to run integration tests as {user,root} and from /{home,…
Browse files Browse the repository at this point in the history
…tmp}
  • Loading branch information
desbma-s1n committed Sep 28, 2023
1 parent afc5b78 commit 0dfe73f
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 14 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ tempfile = { version = "3.7.0", default-features = false }
[dev-dependencies]
assert_cmd = { version = "2.0.12", default-features = false, features = ["color", "color-auto"] }
fastrand = { version = "2.0.0", default-features = false, features = ["std"] }
nix = { version = "0.26.2", default-features = false, features = ["user"] }
predicates = { version = "3.0.3", default-features = false, features = ["color"] }
pretty_assertions = { version = "1.4.0", default-features = false, features = ["std"] }

[features]
# for benchmarks only
nightly = []
# for tests only
as-root = []

[package.metadata.deb]
name = "shh"
Expand Down
42 changes: 42 additions & 0 deletions test-all
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash -eux

readonly TEST_ARGS="$@"

# auto cleanup
at_exit() {
[ "${TMP_DIR:-}" ] && rm -Rf "${TMP_DIR}"
}
trap at_exit EXIT

readonly TMP_DIR=$(mktemp -d /tmp/$(basename -- $0).XXXXXXXXXX)

if ! pwd | grep -q '^/home/'
then
echo 'This script should be run from /home' >&2
exit 1
fi

#
# runs test in current dir
#

# unit tests + integration tests
cargo test ${TEST_ARGS}

# integration tests as root
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER='sudo -E' cargo test --features as-root --test '*' ${TEST_ARGS}

#
# runs test in /tmp
#

cp -Ra . "${TMP_DIR}"
pushd "${TMP_DIR}"

# unit tests + integration tests
cargo test --test '*' ${TEST_ARGS}

# integration tests as root
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER='sudo -E' cargo test --features as-root --test '*' ${TEST_ARGS}

popd
132 changes: 118 additions & 14 deletions tests/cl.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
//! Command line tests
use std::env;

use nix::unistd::Uid;

use assert_cmd::{assert::OutputAssertExt, Command};
use predicates::prelude::*;

//
// Important: these tests assume they are run from a dir under /home, so we don't test for ProtectHome=xxx
// option values, because they are affected by that.
// See test_resolve_protect_home for unit test covering that option.
// Important: these tests have expectations strongly linked to the the environment they run on.
// For example binary may run lib from ${RUSTUP_HOME}/toolchains/stable-x86_64-unknown-linux-gnu/lib/
// Hence, they are not truly portabe, and are conditionnaly enabled using feature flags or runtime
// tests.
//

#[test]
Expand All @@ -18,7 +23,18 @@ fn run_true() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if !Uid::effective().is_root() && env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -39,7 +55,18 @@ fn run_write_dev_null() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() && !env::current_exe().unwrap().starts_with("/home") {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -60,7 +87,18 @@ fn run_ls_dev() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if !Uid::effective().is_root() && env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=").not())
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -81,7 +119,18 @@ fn run_ls_proc() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if !Uid::effective().is_root() && env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -102,7 +151,18 @@ fn run_read_kallsyms() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if !Uid::effective().is_root() && env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=").not())
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -123,7 +183,18 @@ fn run_ls_modules() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if !Uid::effective().is_root() && env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=").not())
Expand All @@ -136,7 +207,7 @@ fn run_ls_modules() {
}

#[test]
#[ignore] // needs to be run as root
#[cfg_attr(not(feature = "as-root"), ignore)]
fn run_dmesg() {
Command::cargo_bin(env!("CARGO_PKG_NAME"))
.unwrap()
Expand All @@ -145,7 +216,18 @@ fn run_dmesg() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if !Uid::effective().is_root() && env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=").not())
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -158,7 +240,9 @@ fn run_dmesg() {
}

#[test]
#[cfg_attr(feature = "as-root", ignore)]
fn run_systemctl() {
assert!(!Uid::effective().is_root());
Command::cargo_bin(env!("CARGO_PKG_NAME"))
.unwrap()
.args(["run", "--", "systemctl", "--user"])
Expand All @@ -167,7 +251,11 @@ fn run_systemctl() {
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("ProtectHome=read-only\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(if env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -191,7 +279,18 @@ fn run_ss() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=strict\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains(
if Uid::effective().is_root() {
"ProtectHome=tmpfs\n"
} else {
"ProtectHome=read-only\n"
}
).count(1))
.stdout(if !Uid::effective().is_root() && env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand All @@ -212,7 +311,12 @@ fn run_mmap_wx() {
.assert()
.success()
.stdout(predicate::str::contains("ProtectSystem=full\n").count(1))
.stdout(predicate::str::contains("PrivateTmp=true\n").count(1))
.stdout(predicate::str::contains("ProtectHome=read-only\n").count(1))
.stdout(if env::current_exe().unwrap().starts_with("/tmp") {
predicate::str::contains("PrivateTmp=true\n").count(0)
} else {
predicate::str::contains("PrivateTmp=true\n").count(1)
})
.stdout(predicate::str::contains("PrivateDevices=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelTunables=true\n").count(1))
.stdout(predicate::str::contains("ProtectKernelModules=true\n").count(1))
Expand Down

0 comments on commit 0dfe73f

Please sign in to comment.