#!/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=() can_run_script_pty() { if ! command -v script >/dev/null 2>&1; then return 1 fi if ! script -q -c "true" /dev/null >/dev/null 2>&1; then return 1 fi return 0 } 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 if [[ " $* " == *" --format "* ]]; then printf 'fake-image-id\n' exit 0 fi 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 if [[ -x /usr/bin/sha256sum ]]; then exec /usr/bin/sha256sum "$@" 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:-}" } extract_embedded_helper() { local helper=$1 local output=$2 if ! awk -v helper="$helper" ' $0 ~ "^[[:space:]]*" helper "\\)$" { state=1; next } state == 1 && /cat <<'\''EOF'\''$/ { state=2; next } state == 2 && /^EOF$/ { exit } state == 2 { print } ' "$SLOPTRAP_BIN" >"$output"; then return 1 fi chmod +x "$output" } wait_for_path() { local path=$1 local attempts=${2:-100} while (( attempts > 0 )); do if [[ -e $path ]]; then return 0 fi sleep 0.1 ((attempts-=1)) done return 1 } 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_git_ignore_mask() { local scenario_dir="$ROOT_DIR" printf '==> git_ignore_mask\n' setup_stub_env if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ "$SLOPTRAP_BIN" --trust-capabilities "$scenario_dir" /dev/null 2>&1; then record_failure "git_ignore_mask: sloptrap exited non-zero" teardown_stub_env return fi if ! grep -q -- "--mount type=tmpfs,target=/workspace/.git" "$STUB_LOG"; then record_failure "git_ignore_mask: .git was not masked with tmpfs" 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_runtime_context_prompt() { local scenario_dir="$TEST_ROOT/capability_repo" printf '==> runtime_context_prompt\n' setup_stub_env if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ "$SLOPTRAP_BIN" --trust-capabilities "$scenario_dir" /dev/null 2>&1; then record_failure "runtime_context_prompt: sloptrap exited non-zero" teardown_stub_env return fi local login_line run_line login_line=$(grep "FAKE PODMAN: run " "$STUB_LOG" | head -n 1 || true) run_line=$(grep "FAKE PODMAN: run " "$STUB_LOG" | tail -n 1 || true) if [[ -z $run_line || $run_line != *"You are running inside sloptrap"* ]]; then record_failure "runtime_context_prompt: startup prompt missing from fresh run" fi if ! grep -q -- "name=capability-repo" "$STUB_LOG" \ || ! grep -q -- "enabled_capabilities=apt-install packet-capture" "$STUB_LOG" \ || ! grep -q -- "network_mode=host" "$STUB_LOG"; then record_failure "runtime_context_prompt: runtime summary missing manifest or capability state" fi if [[ -n $login_line && $login_line == *"You are running inside sloptrap"* ]]; then record_failure "runtime_context_prompt: login flow should not receive startup prompt" fi teardown_stub_env } run_sh_reexec() { local scenario_dir="$TEST_ROOT/capability_repo" printf '==> sh_reexec\n' setup_stub_env if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ sh "$SLOPTRAP_BIN" --trust-capabilities "$scenario_dir" /dev/null 2>&1; then record_failure "sh_reexec: sloptrap exited non-zero when launched via sh" teardown_stub_env return fi if ! grep -q -- "You are running inside sloptrap" "$STUB_LOG"; then record_failure "sh_reexec: startup prompt missing after sh re-exec" fi teardown_stub_env } run_resume_omits_runtime_context() { local scenario_dir="$TEST_ROOT/capability_repo" local session_id="019a81b7-32d2-7622-8639-6698c6579625" printf '==> resume_omits_runtime_context\n' setup_stub_env if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ "$SLOPTRAP_BIN" --trust-capabilities "$scenario_dir" resume "$session_id" /dev/null 2>&1; then record_failure "resume_omits_runtime_context: sloptrap exited non-zero" teardown_stub_env return fi if grep -q -- "You are running inside sloptrap" "$STUB_LOG"; then record_failure "resume_omits_runtime_context: resume should not receive startup prompt" fi if ! grep -q -- "codex --sandbox danger-full-access --ask-for-approval never resume $session_id" "$STUB_LOG"; then record_failure "resume_omits_runtime_context: resume invocation missing" fi teardown_stub_env } run_auth_file_mount() { local scenario_dir scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P) printf '==> auth_file_mount\n' setup_stub_env mkdir -p "$STUB_HOME/.codex" printf '{"access_token":"test"}\n' >"$STUB_HOME/.codex/auth.json" 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 "auth_file_mount: sloptrap exited non-zero" teardown_stub_env return fi if ! grep -q -- "-v ${STUB_HOME}/.codex/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then record_failure "auth_file_mount: missing auth file bind mount" fi if ! grep -q -- "-v ${STUB_HOME}/.codex/sloptrap/state/" "$STUB_LOG"; then record_failure "auth_file_mount: missing project state bind mount" fi teardown_stub_env } run_codex_home_override() { local scenario_dir codex_root scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P) printf '==> codex_home_override\n' setup_stub_env codex_root="$STUB_HOME/codex-root" mkdir -p "$codex_root" printf '{"access_token":"test"}\n' >"$codex_root/auth.json" if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" CODEX_HOME="$codex_root" SLOPTRAP_PREFER_CODEX_HOME=1 \ FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ "$SLOPTRAP_BIN" "$scenario_dir" /dev/null 2>&1; then record_failure "codex_home_override: sloptrap exited non-zero" teardown_stub_env return fi if ! grep -q -- "-v ${codex_root}/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then record_failure "codex_home_override: missing CODEX_HOME auth file mount" fi if ! grep -q -- "-v ${codex_root}/sloptrap/state/" "$STUB_LOG"; then record_failure "codex_home_override: missing CODEX_HOME project state bind mount" fi if grep -q -- "-v ${STUB_HOME}/.codex/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then record_failure "codex_home_override: should not fall back to HOME/.codex when CODEX_HOME is set" fi local first_run first_run=$(grep "FAKE PODMAN: run " "$STUB_LOG" | head -n 1 || true) if [[ -z $first_run || $first_run == *" login" ]]; then record_failure "codex_home_override: existing CODEX_HOME auth should avoid login target" fi teardown_stub_env } run_removed_nested_podman_manifest() { local scenario_dir output_log scenario_dir=$(mktemp -d) output_log=$(mktemp) printf '==> removed_nested_podman_manifest\n' cat >"$scenario_dir/.sloptrap" <<'EOF' name=removed-nested-podman capabilities=nested-podman EOF if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >/dev/null 2>&1; then record_failure "removed_nested_podman_manifest: expected nested-podman manifest rejection" fi if ! "$SLOPTRAP_BIN" --dry-run "$scenario_dir" >"$output_log" 2>&1; then if ! grep -q -- "capability 'nested-podman' was removed" "$output_log"; then record_failure "removed_nested_podman_manifest: missing explicit removal error" fi fi rm -f "$output_log" rm -rf "$scenario_dir" } run_project_state_isolation() { local scenario_a scenario_b scenario_a=$(cd "$TEST_ROOT/resume_target" && pwd -P) scenario_b=$(cd "$TEST_ROOT/secret_mask" && pwd -P) printf '==> project_state_isolation\n' setup_stub_env mkdir -p "$STUB_HOME/.codex" printf '{"access_token":"test"}\n' >"$STUB_HOME/.codex/auth.json" if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ "$SLOPTRAP_BIN" "$scenario_a" /dev/null 2>&1; then record_failure "project_state_isolation: first project run failed" teardown_stub_env return fi if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" \ "$SLOPTRAP_BIN" "$scenario_b" /dev/null 2>&1; then record_failure "project_state_isolation: second project run failed" teardown_stub_env return fi local -a codex_mounts=() mapfile -t codex_mounts < <( { grep "FAKE PODMAN: run " "$STUB_LOG" \ | grep -oE -- "-v [^ ]+:/codex:Z" \ | sed -e 's/^-v //' -e 's/:\/codex:Z$//' } || true ) if [[ ${#codex_mounts[@]} -lt 2 ]]; then record_failure "project_state_isolation: missing /codex state mounts" teardown_stub_env return fi if [[ ${codex_mounts[0]} == "${codex_mounts[1]}" ]]; then record_failure "project_state_isolation: projects reused same Codex state mount" fi if [[ ${codex_mounts[0]} != */.codex/sloptrap/state/* || ${codex_mounts[1]} != */.codex/sloptrap/state/* ]]; then record_failure "project_state_isolation: state mounts did not use sloptrap namespace" fi teardown_stub_env } run_auto_login_empty_auth() { local scenario_dir scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P) printf '==> auto_login_empty_auth\n' setup_stub_env mkdir -p "$STUB_HOME/.codex" : >"$STUB_HOME/.codex/auth.json" 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 "auto_login_empty_auth: sloptrap exited non-zero" teardown_stub_env return fi local first_run first_run=$(grep "FAKE PODMAN: run " "$STUB_LOG" | head -n 1 || true) if [[ -z $first_run || $first_run != *" login" ]]; then record_failure "auto_login_empty_auth: expected login before primary run" fi if ! grep -q -- "-v ${STUB_HOME}/.codex/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then record_failure "auto_login_empty_auth: missing auth file bind mount" 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_manifest_capabilities() { local scenario_dir="$TEST_ROOT/invalid_manifest_capabilities" printf '==> invalid_manifest_capabilities\n' if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" /dev/null 2>&1; then record_failure "invalid_manifest_capabilities: expected rejection for bad capabilities" 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_wizard_create_manifest() { local scenario_dir="$TEST_ROOT/wizard_empty" printf '==> wizard_create_manifest\n' if ! can_run_script_pty; then printf 'skipping wizard_create_manifest: script PTY support not available\n' return fi rm -f "$scenario_dir/.sloptrap" local input=$'\n\n\n\n' if ! printf '%s' "$input" | script -q -c "$SLOPTRAP_BIN \"$scenario_dir\" wizard" /dev/null >/dev/null 2>&1; then record_failure "wizard_create_manifest: wizard failed" return fi if [[ ! -f $scenario_dir/.sloptrap ]]; then record_failure "wizard_create_manifest: manifest not created" return fi if ! grep -qx "name=wizard_empty" "$scenario_dir/.sloptrap"; then record_failure "wizard_create_manifest: name default mismatch" fi if ! grep -qx "packages_extra=" "$scenario_dir/.sloptrap"; then record_failure "wizard_create_manifest: packages_extra mismatch" fi if ! grep -qx "capabilities=" "$scenario_dir/.sloptrap"; then record_failure "wizard_create_manifest: capabilities mismatch" fi if ! grep -qx "allow_host_network=false" "$scenario_dir/.sloptrap"; then record_failure "wizard_create_manifest: allow_host_network mismatch" fi } run_wizard_existing_defaults() { local scenario_dir="$TEST_ROOT/wizard_existing" printf '==> wizard_existing_defaults\n' if ! can_run_script_pty; then printf 'skipping wizard_existing_defaults: script PTY support not available\n' return fi local input=$'\n\n\n\n' if ! printf '%s' "$input" | script -q -c "$SLOPTRAP_BIN \"$scenario_dir\" wizard" /dev/null >/dev/null 2>&1; then record_failure "wizard_existing_defaults: wizard failed" return fi if ! grep -qx "name=custom-wizard" "$scenario_dir/.sloptrap"; then record_failure "wizard_existing_defaults: name not preserved" fi if ! grep -qx "packages_extra=make git" "$scenario_dir/.sloptrap"; then record_failure "wizard_existing_defaults: packages_extra not preserved" fi if ! grep -qx "capabilities=apt-install packet-capture" "$scenario_dir/.sloptrap"; then record_failure "wizard_existing_defaults: capabilities not preserved" fi if ! grep -qx "allow_host_network=true" "$scenario_dir/.sloptrap"; then record_failure "wizard_existing_defaults: allow_host_network not preserved" fi } run_wizard_build_trigger() { local scenario_dir="$TEST_ROOT/wizard_build" printf '==> wizard_build_trigger\n' if ! can_run_script_pty; then printf 'skipping wizard_build_trigger: script PTY support not available\n' return fi setup_stub_env rm -f "$scenario_dir/.sloptrap" local input=$'\n\n\n\n' if ! printf '%s' "$input" | script -q -c "env PATH=\"$STUB_BIN:$PATH\" HOME=\"$STUB_HOME\" FAKE_PODMAN_LOG=\"$STUB_LOG\" FAKE_PODMAN_INSPECT_FAIL=1 \"$SLOPTRAP_BIN\" \"$scenario_dir\"" /dev/null >/dev/null 2>&1; then record_failure "wizard_build_trigger: sloptrap failed" teardown_stub_env return fi if [[ ! -f $scenario_dir/.sloptrap ]]; then record_failure "wizard_build_trigger: manifest not created" fi if ! grep -q -- "FAKE PODMAN: build " "$STUB_LOG"; then record_failure "wizard_build_trigger: build not invoked after wizard" fi teardown_stub_env } run_capability_trust_required() { local scenario_dir="$TEST_ROOT/capability_repo" printf '==> capability_trust_required\n' setup_stub_env 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 "capability_trust_required: expected failure without trusted capabilities" fi teardown_stub_env } run_capability_profiles() { local scenario_dir="$TEST_ROOT/capability_repo" printf '==> capability_profiles\n' setup_stub_env if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ "$SLOPTRAP_BIN" --trust-capabilities "$scenario_dir" /dev/null 2>&1; then record_failure "capability_profiles: sloptrap exited non-zero" teardown_stub_env return fi if ! grep -q -- "CAPABILITY_PACKAGES=tcpdump" "$STUB_LOG"; then record_failure "capability_profiles: build arg for capability packages missing" fi if ! grep -q -- "FAKE PODMAN: build --quiet -t capability-repo-sloptrap-image -f .* --network host " "$STUB_LOG"; then record_failure "capability_profiles: build should inherit host networking" fi if ! grep -q -- "--cap-add NET_RAW" "$STUB_LOG"; then record_failure "capability_profiles: NET_RAW capability missing" fi if ! grep -q -- "--cap-add NET_ADMIN" "$STUB_LOG"; then record_failure "capability_profiles: NET_ADMIN capability missing" fi if ! grep -q -- "--cap-add SETUID" "$STUB_LOG"; then record_failure "capability_profiles: SETUID capability missing" fi if ! grep -q -- "--cap-add SETGID" "$STUB_LOG"; then record_failure "capability_profiles: SETGID capability missing" fi if ! grep -q -- "--cap-add CHOWN" "$STUB_LOG"; then record_failure "capability_profiles: CHOWN capability missing" fi if ! grep -q -- "--cap-add DAC_OVERRIDE" "$STUB_LOG"; then record_failure "capability_profiles: DAC_OVERRIDE capability missing" fi if ! grep -q -- "--cap-add FOWNER" "$STUB_LOG"; then record_failure "capability_profiles: FOWNER capability missing" fi if ! grep -q -- "--security-opt no-new-privileges" "$STUB_LOG"; then record_failure "capability_profiles: no-new-privileges missing" fi if grep -q -- "--read-only" "$STUB_LOG"; then record_failure "capability_profiles: apt profile should disable read-only rootfs" fi if grep -q -- "--user " "$STUB_LOG"; then record_failure "capability_profiles: capability-enabled run should not force --user" fi if ! grep -q -- "--userns=keep-id:uid=$(id -u),gid=$(id -g)" "$STUB_LOG"; then record_failure "capability_profiles: podman keep-id user namespace missing" fi if ! grep -q -- "SLOPTRAP_ACTIVE_CAPABILITIES=apt-install packet-capture" "$STUB_LOG"; then record_failure "capability_profiles: active capability environment missing" fi if ! grep -q -- "SLOPTRAP_HOST_UID=$(id -u)" "$STUB_LOG"; then record_failure "capability_profiles: host uid environment missing" fi if ! grep -q -- "SLOPTRAP_HOST_GID=$(id -g)" "$STUB_LOG"; then record_failure "capability_profiles: host gid environment missing" fi if ! grep -q -- "SLOPTRAP_HOST_USER=$(id -un)" "$STUB_LOG"; then record_failure "capability_profiles: host user environment missing" fi local state_root capability_dir state_root="$STUB_HOME/.codex/sloptrap/state" capability_dir=$(find "$state_root" -mindepth 2 -maxdepth 2 -type d -name capabilities | head -n 1 || true) if [[ -z $capability_dir ]]; then record_failure "capability_profiles: project capability state directory missing" fi teardown_stub_env } run_embedded_capability_helpers() { printf '==> embedded_capability_helpers\n' local temp_root helper_bin helper_dir workspace_dir capture_dir tool_log helper_pid temp_root=$(mktemp -d) helper_bin="$temp_root/bin" helper_dir="$temp_root/helper" workspace_dir="$temp_root/workspace" capture_dir="$temp_root/captures" tool_log="$temp_root/tool.log" helper_pid="" mkdir -p "$helper_bin" "$helper_dir/queue" "$workspace_dir/data" "$capture_dir" : >"$tool_log" if ! extract_embedded_helper "sloptrap-entrypoint" "$helper_bin/sloptrap-entrypoint" \ || ! extract_embedded_helper "sloptrap-helperd" "$helper_bin/sloptrap-helperd" \ || ! extract_embedded_helper "slop-apt" "$helper_bin/slop-apt" \ || ! extract_embedded_helper "slopcap" "$helper_bin/slopcap"; then record_failure "embedded_capability_helpers: failed to extract embedded helper scripts" rm -rf "$temp_root" return fi cat >"$helper_bin/apt-get" <<'EOF' #!/usr/bin/env bash set -euo pipefail printf 'apt-get %s\n' "$*" >>"$TEST_TOOL_LOG" exit 0 EOF cat >"$helper_bin/tcpdump" <<'EOF' #!/usr/bin/env bash set -euo pipefail printf 'tcpdump %s\n' "$*" >>"$TEST_TOOL_LOG" output="" prev="" for arg in "$@"; do if [[ $prev == "-w" ]]; then output=$arg break fi prev=$arg done if [[ -n $output ]]; then mkdir -p "$(dirname "$output")" : >"$output" fi exit 0 EOF cat >"$helper_bin/setpriv" <<'EOF' #!/usr/bin/env bash set -euo pipefail printf 'setpriv %s\n' "$*" >>"$TEST_TOOL_LOG" while [[ $# -gt 0 ]]; do case "$1" in --reuid|--regid) shift 2 ;; --clear-groups) shift ;; --) shift break ;; *) break ;; esac done exec "$@" EOF chmod +x "$helper_bin/apt-get" "$helper_bin/tcpdump" "$helper_bin/setpriv" if ! grep -q "chmod 711 \"\\\$helper_dir\"" "$helper_bin/sloptrap-entrypoint" \ || ! grep -q "chmod 1733 \"\\\$queue_dir\"" "$helper_bin/sloptrap-entrypoint"; then record_failure "embedded_capability_helpers: entrypoint did not expose helper queue to the dropped user" fi local autostart_helper_dir autostart_helper_dir="$temp_root/helper-autostart" if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$autostart_helper_dir" \ SLOPTRAP_ACTIVE_CAPABILITIES="apt-install packet-capture" \ SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \ SLOPTRAP_AUDIT_LOG="$temp_root/autostart-audit.log" \ SLOPTRAP_HOST_UID="$(id -u)" SLOPTRAP_HOST_GID="$(id -g)" \ "$helper_bin/slop-apt" install jq >/dev/null 2>&1; then record_failure "embedded_capability_helpers: slop-apt did not self-bootstrap the helper daemon" fi if [[ ! -r $autostart_helper_dir/helperd.pid ]]; then record_failure "embedded_capability_helpers: helper self-bootstrap did not create a pid file" else kill "$(cat "$autostart_helper_dir/helperd.pid")" >/dev/null 2>&1 || true wait "$(cat "$autostart_helper_dir/helperd.pid")" >/dev/null 2>&1 || true fi TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \ SLOPTRAP_ACTIVE_CAPABILITIES="apt-install packet-capture" \ SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \ SLOPTRAP_AUDIT_LOG="$temp_root/audit.log" "$helper_bin/sloptrap-helperd" >/dev/null 2>&1 & helper_pid=$! if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \ "$helper_bin/slop-apt" install jq >/dev/null 2>&1; then record_failure "embedded_capability_helpers: slop-apt failed against the embedded helper daemon" fi if ! grep -q -- 'apt-get install -y --no-install-recommends jq' "$tool_log"; then record_failure "embedded_capability_helpers: slop-apt did not reach apt-get install" fi local bad_apt_request bad_apt_request=$(mktemp -d "$helper_dir/queue/request.XXXXXX.req") printf 'apt-install\n' >"$bad_apt_request/op" printf '%s\n' '--allow-unauthenticated' >"$bad_apt_request/packages" if ! wait_for_path "$bad_apt_request/status"; then record_failure "embedded_capability_helpers: helper daemon did not answer the invalid apt request" elif [[ $(<"$bad_apt_request/status") != "2" ]]; then record_failure "embedded_capability_helpers: invalid apt request returned the wrong status" fi if [[ -s "$bad_apt_request/stderr" ]] && ! grep -q -- 'invalid package name' "$bad_apt_request/stderr"; then record_failure "embedded_capability_helpers: invalid apt request did not explain the rejection" fi if TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \ SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \ "$helper_bin/slopcap" capture --interface eth0 --output /tmp/escape.pcap >/dev/null 2>&1; then record_failure "embedded_capability_helpers: slopcap accepted an out-of-bounds output path" fi if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_HELPER_DIR="$helper_dir" \ SLOPTRAP_CAPTURE_DIR="$capture_dir" SLOPTRAP_WORKDIR="$workspace_dir" \ "$helper_bin/slopcap" capture --interface eth0 --filter 'tcp port 80' \ --output "$workspace_dir/capture.pcap" >/dev/null 2>&1; then record_failure "embedded_capability_helpers: slopcap failed for a workspace-local capture file" fi if ! grep -q -- "tcpdump -i eth0 -w $workspace_dir/capture.pcap -- tcp port 80" "$tool_log"; then record_failure "embedded_capability_helpers: slopcap did not invoke tcpdump with the expected guarded arguments" fi local bad_capture_request bad_capture_request=$(mktemp -d "$helper_dir/queue/request.XXXXXX.req") printf 'packet-capture\n' >"$bad_capture_request/op" printf 'eth0\n' >"$bad_capture_request/interface" printf '\n' >"$bad_capture_request/filter" printf '/tmp/escape.pcap\n' >"$bad_capture_request/output" printf '0\n' >"$bad_capture_request/stdout_mode" if ! wait_for_path "$bad_capture_request/status"; then record_failure "embedded_capability_helpers: helper daemon did not answer the invalid capture request" elif [[ $(<"$bad_capture_request/status") != "2" ]]; then record_failure "embedded_capability_helpers: invalid capture request returned the wrong status" fi if [[ -s "$bad_capture_request/stderr" ]] && ! grep -q -- 'output path must stay within' "$bad_capture_request/stderr"; then record_failure "embedded_capability_helpers: invalid capture request did not explain the rejection" fi if [[ -n $helper_pid ]]; then kill "$helper_pid" >/dev/null 2>&1 || true wait "$helper_pid" >/dev/null 2>&1 || true fi rm -rf "$temp_root" } run_make_install_single_file() { local scenario_dir="$TEST_ROOT/resume_target" printf '==> make_install_single_file\n' if ! command -v make >/dev/null 2>&1; then record_failure "make_install_single_file: make binary not found in PATH" return fi setup_stub_env local install_root install_dir installed_bin install_root=$(mktemp -d) install_dir="$install_root/bin" installed_bin="$install_dir/sloptrap" if ! make -C "$ROOT_DIR" install INSTALL_DIR="$install_dir" >/dev/null 2>&1; then record_failure "make_install_single_file: make install failed" teardown_stub_env rm -rf "$install_root" return fi if [[ ! -x $installed_bin ]]; then record_failure "make_install_single_file: installed launcher missing" fi local helper for helper in sloptrap-entrypoint sloptrap-helperd slop-apt slopcap; do if [[ -e $install_dir/$helper ]]; then record_failure "make_install_single_file: unexpected helper installed ($helper)" fi done if ! PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \ "$installed_bin" "$scenario_dir" /dev/null 2>&1; then record_failure "make_install_single_file: installed launcher failed" fi if ! grep -q -- "FAKE PODMAN: build " "$STUB_LOG"; then record_failure "make_install_single_file: installed launcher did not reach build path" fi if ! make -C "$ROOT_DIR" uninstall INSTALL_DIR="$install_dir" >/dev/null 2>&1; then record_failure "make_install_single_file: make uninstall failed" fi if [[ -e $installed_bin ]]; then record_failure "make_install_single_file: installed launcher not removed by uninstall" fi teardown_stub_env rm -rf "$install_root" } run_shellcheck run_mount_injection run_root_target run_symlink_escape run_manifest_injection run_helper_symlink run_secret_mask run_git_ignore_mask run_resume_target run_runtime_context_prompt run_sh_reexec run_resume_omits_runtime_context run_auth_file_mount run_codex_home_override run_project_state_isolation run_auto_login_empty_auth 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_manifest_capabilities run_invalid_allow_host_network run_removed_nested_podman_manifest run_wizard_create_manifest run_wizard_existing_defaults run_wizard_build_trigger run_capability_trust_required run_capability_profiles run_embedded_capability_helpers run_make_install_single_file 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'