Files
skz-sloptrap/tests/run_tests.sh
Samuel Aubertin c1e64bb4ef More tests
2025-11-27 16:12:22 +01:00

446 lines
12 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR=$(
cd "$(dirname "${BASH_SOURCE[0]}")/.." >/dev/null 2>&1
pwd -P
)
SLOPTRAP_BIN="$ROOT_DIR/sloptrap"
TEST_ROOT="$ROOT_DIR/tests"
if [[ ! -x $SLOPTRAP_BIN ]]; then
printf 'error: sloptrap launcher not found at %s\n' "$SLOPTRAP_BIN" >&2
exit 1
fi
failures=()
run_shellcheck() {
printf '==> shellcheck\n'
if ! command -v shellcheck >/dev/null 2>&1; then
record_failure "shellcheck: shellcheck binary not found in PATH"
return
fi
if ! shellcheck "$SLOPTRAP_BIN"; then
record_failure "shellcheck: lint errors detected"
fi
}
setup_stub_env() {
STUB_BIN=$(mktemp -d)
STUB_HOME=$(mktemp -d)
STUB_LOG=$(mktemp)
cat >"$STUB_BIN/podman" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [[ -z ${FAKE_PODMAN_LOG:-} ]]; then
printf 'FAKE_PODMAN_LOG is not set\n' >&2
exit 1
fi
verify_secret_mounts() {
local -a args=("$@")
if [[ -z ${SECRET_MASK_EXPECTED_TARGET:-} ]]; then
return 0
fi
local saw=0
local idx=0
while (( idx < ${#args[@]} )); do
local arg=${args[$idx]}
if [[ $arg == "--mount" ]]; then
((idx++))
if (( idx >= ${#args[@]} )); then
printf 'podman stub: --mount missing spec\n' >&2
return 1
fi
local spec=${args[$idx]}
local target=""
local source=""
IFS=',' read -r -a parts <<< "$spec"
for part in "${parts[@]}"; do
case $part in
target=*)
target=${part#target=}
;;
source=*)
source=${part#source=}
;;
esac
done
if [[ -n ${SECRET_MASK_EXPECTED_TARGET:-} && $target == "$SECRET_MASK_EXPECTED_TARGET" ]]; then
saw=1
if [[ -z $source || ! -f $source ]]; then
printf 'podman stub: masked source missing for %s\n' "$target" >&2
return 1
fi
if [[ -s $source ]]; then
printf 'podman stub: masked source leaked contents (%s)\n' "$source" >&2
return 1
fi
fi
fi
((idx++))
done
if [[ $saw -eq 0 ]]; then
printf 'podman stub: target %s not mounted\n' "${SECRET_MASK_EXPECTED_TARGET:-}" >&2
return 1
fi
return 0
}
if [[ ${1-} == "image" && ${2-} == "inspect" && ${FAKE_PODMAN_INSPECT_FAIL:-0} == 1 ]]; then
echo "FAKE PODMAN (fail): $*" >>"$FAKE_PODMAN_LOG"
exit 1
fi
if [[ ${SECRET_MASK_VERIFY:-0} == 1 && ${1-} == "run" ]]; then
if ! verify_secret_mounts "$@"; then
echo "FAKE PODMAN (secret-check failed): $*" >>"$FAKE_PODMAN_LOG"
exit 1
fi
fi
echo "FAKE PODMAN: $*" >>"$FAKE_PODMAN_LOG"
exit 0
EOF
chmod +x "$STUB_BIN/podman"
cat >"$STUB_BIN/curl" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [[ ${1-} == "-fsSL" ]]; then
cat <<'JSON'
{"assets":[{"name":"codex-x86_64-unknown-linux-gnu.tar.gz","digest":"sha256:feedface"}]}
JSON
exit 0
fi
if [[ ${1-} == "-Lso" ]]; then
if [[ $# -lt 3 ]]; then
echo "curl stub expected output path" >&2
exit 1
fi
output=$2
: >"$output"
exit 0
fi
printf 'curl stub encountered unsupported args: %s\n' "$*" >&2
exit 1
EOF
chmod +x "$STUB_BIN/curl"
cat >"$STUB_BIN/jq" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
while [[ $# -gt 0 ]]; do
case "$1" in
-r)
shift
continue
;;
*)
break
;;
esac
done
cat >/dev/null
printf 'sha256:feedface\n'
EOF
chmod +x "$STUB_BIN/jq"
cat >"$STUB_BIN/sha256sum" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [[ ${1-} == "-c" ]]; then
shift
if [[ ${1-} == "-" ]]; then
shift
cat >/dev/null
exit 0
fi
fi
printf 'sha256sum stub encountered unsupported args: %s\n' "$*" >&2
exit 1
EOF
chmod +x "$STUB_BIN/sha256sum"
cat >"$STUB_BIN/tar" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
dest=""
new_name="codex"
while [[ $# -gt 0 ]]; do
case "$1" in
-C)
shift
if [[ $# -eq 0 ]]; then
echo "tar stub missing directory for -C" >&2
exit 1
fi
dest=$1
;;
--transform=*)
transform=${1#--transform=}
transform=${transform#s/}
rest=${transform#*/}
new_name=${rest%%/*}
;;
esac
shift
done
[[ -n $dest ]] || dest="."
mkdir -p "$dest"
cat >"$dest/$new_name" <<'BIN'
#!/usr/bin/env bash
echo "fake codex"
BIN
chmod +x "$dest/$new_name"
EOF
chmod +x "$STUB_BIN/tar"
}
teardown_stub_env() {
rm -rf "${STUB_BIN:-}" "${STUB_HOME:-}"
rm -f "${STUB_LOG:-}"
}
record_failure() {
failures+=("$1")
}
run_mount_injection() {
local scenario_dir="$TEST_ROOT/mount_injection"
printf '==> mount_injection\n'
setup_stub_env
rm -rf "$scenario_dir/.sloptrap-ignores"
if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \
"$SLOPTRAP_BIN" "$scenario_dir" >/dev/null 2>&1; then
record_failure "mount_injection: sloptrap exited non-zero"
teardown_stub_env
return
fi
if ! grep -q -- "--mount type=bind" "$STUB_LOG"; then
record_failure "mount_injection: bind mount invocation missing"
fi
if grep -q -- "attack,source=/etc/passwd" "$STUB_LOG"; then
record_failure "mount_injection: unescaped mount key detected"
fi
if ! grep -q -- "attack\\\\,source\\\\=/etc/passwd" "$STUB_LOG"; then
record_failure "mount_injection: escaped mount key missing"
fi
if ! grep -q -- "FAKE PODMAN: build " "$STUB_LOG"; then
record_failure "mount_injection: image build path did not trigger"
fi
teardown_stub_env
}
run_root_target() {
local scenario_dir="$TEST_ROOT/root_target"
printf '==> root_target\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "root_target: expected rejection for project-root mask"
return
fi
}
run_symlink_escape() {
local scenario_dir="$TEST_ROOT/symlink_escape"
printf '==> symlink_escape\n'
local secret_path="$ROOT_DIR/secrets.txt"
touch "$secret_path"
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "symlink_escape: expected failure for symlink escape"
rm -f "$secret_path"
return
fi
rm -f "$secret_path"
}
run_manifest_injection() {
local scenario_dir="$TEST_ROOT/manifest_injection"
printf '==> manifest_injection\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "manifest_injection: expected rejection of bad make override"
return
fi
}
run_helper_symlink() {
local scenario_dir="$TEST_ROOT/helper_symlink"
printf '==> helper_symlink\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "helper_symlink: expected rejection when helper directory is a symlink"
fi
if "$SLOPTRAP_BIN" "$scenario_dir" clean >/dev/null 2>&1; then
record_failure "helper_symlink: expected rejection for clean when helper directory is a symlink"
fi
}
run_secret_mask() {
local scenario_dir="$TEST_ROOT/secret_mask"
printf '==> secret_mask\n'
setup_stub_env
local custom_workdir="/alt-workspace"
if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" \
FAKE_PODMAN_INSPECT_FAIL=1 SECRET_MASK_VERIFY=1 \
SECRET_MASK_EXPECTED_TARGET="${custom_workdir}/secret.txt" \
SLOPTRAP_WORKDIR="$custom_workdir" \
"$SLOPTRAP_BIN" "$scenario_dir" >/dev/null 2>&1; then
record_failure "secret_mask: masking check failed"
teardown_stub_env
return
fi
teardown_stub_env
}
run_resume_target() {
local scenario_dir="$TEST_ROOT/resume_target"
printf '==> resume_target\n'
setup_stub_env
local session_id="019a81b7-32d2-7622-8639-6698c6579625"
if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" \
"$SLOPTRAP_BIN" "$scenario_dir" resume "$session_id" >/dev/null 2>&1; then
record_failure "resume_target: sloptrap exited non-zero"
teardown_stub_env
return
fi
if ! grep -q -- "resume $session_id" "$STUB_LOG"; then
record_failure "resume_target: resume invocation missing"
fi
teardown_stub_env
}
run_codex_symlink_home() {
local scenario_dir
scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P)
printf '==> codex_symlink_home\n'
local tmp_home
tmp_home=$(mktemp -d)
ln -s /etc "$tmp_home/.codex"
if HOME="$tmp_home" "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "codex_symlink_home: expected rejection when ~/.codex is a symlink"
fi
rm -rf "$tmp_home"
}
run_root_directory_project() {
printf '==> root_directory_project\n'
local tmp_home
tmp_home=$(mktemp -d)
if HOME="$tmp_home" "$SLOPTRAP_BIN" --dry-run / >/dev/null 2>&1; then
record_failure "root_directory_project: expected rejection for '/' project root"
fi
rm -rf "$tmp_home"
}
run_shared_dir_override() {
local scenario_dir
scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P)
printf '==> shared_dir_override\n'
setup_stub_env
local bogus_shared
bogus_shared=$(mktemp -d)
if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" \
SLOPTRAP_SHARED_DIR="$bogus_shared" FAKE_PODMAN_INSPECT_FAIL=1 \
"$SLOPTRAP_BIN" "$scenario_dir" >/dev/null 2>&1; then
record_failure "shared_dir_override: sloptrap exited non-zero"
teardown_stub_env
rm -rf "$bogus_shared"
return
fi
if grep -q "$bogus_shared" "$STUB_LOG"; then
record_failure "shared_dir_override: respected SLOPTRAP_SHARED_DIR override"
fi
if ! grep -q -- "-v ${scenario_dir}:/workspace" "$STUB_LOG"; then
record_failure "shared_dir_override: missing expected project bind mount"
fi
teardown_stub_env
rm -rf "$bogus_shared"
}
run_packages_env_validation() {
local scenario_dir
scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P)
printf '==> packages_env_validation\n'
local tmp_home
tmp_home=$(mktemp -d)
if HOME="$tmp_home" SLOPTRAP_PACKAGES='curl";touch /tmp/pwn #' \
"$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "packages_env_validation: expected rejection of invalid SLOPTRAP_PACKAGES"
fi
rm -rf "$tmp_home"
}
run_abs_path_ignore() {
local scenario_dir="$TEST_ROOT/abs_path_ignore"
printf '==> abs_path_ignore\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "abs_path_ignore: expected rejection for anchored parent traversal entry"
fi
}
run_dotdot_ignore() {
local scenario_dir="$TEST_ROOT/dotdot_ignore"
printf '==> dotdot_ignore\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "dotdot_ignore: expected rejection for parent traversal entry"
fi
}
run_invalid_manifest_name() {
local scenario_dir="$TEST_ROOT/invalid_manifest_name"
printf '==> invalid_manifest_name\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "invalid_manifest_name: expected rejection for illegal name"
fi
}
run_invalid_manifest_sandbox() {
local scenario_dir="$TEST_ROOT/invalid_manifest_sandbox"
printf '==> invalid_manifest_sandbox\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "invalid_manifest_sandbox: expected rejection for sandbox mode"
fi
}
run_invalid_manifest_packages() {
local scenario_dir="$TEST_ROOT/invalid_manifest_packages"
printf '==> invalid_manifest_packages\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "invalid_manifest_packages: expected rejection for bad packages"
fi
}
run_invalid_allow_host_network() {
local scenario_dir="$TEST_ROOT/invalid_allow_host_network"
printf '==> invalid_allow_host_network\n'
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then
record_failure "invalid_allow_host_network: expected rejection for invalid value"
fi
}
run_shellcheck
run_mount_injection
run_root_target
run_symlink_escape
run_manifest_injection
run_helper_symlink
run_secret_mask
run_resume_target
run_codex_symlink_home
run_root_directory_project
run_shared_dir_override
run_packages_env_validation
run_abs_path_ignore
run_dotdot_ignore
run_invalid_manifest_name
run_invalid_manifest_sandbox
run_invalid_manifest_packages
run_invalid_allow_host_network
if [[ ${#failures[@]} -gt 0 ]]; then
printf '\nTest failures:\n'
for entry in "${failures[@]}"; do
printf ' - %s\n' "$entry"
done
exit 1
fi
printf '\nAll regression checks passed.\n'