Compare commits
2 Commits
f9d8234e23
...
7630e7edba
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7630e7edba | ||
|
|
c1e64bb4ef |
@@ -9,6 +9,14 @@ sloptrap runs the OpenAI Codex CLI inside a container with a predictable and loc
|
||||
|
||||
> Tip: set `SLOPTRAP_CONTAINER_ENGINE=<engine>` if you need to override the default Podman requirement.
|
||||
|
||||
### macOS setup
|
||||
|
||||
sloptrap targets GNU userland. On macOS, install the GNU tools via Homebrew and the launcher will prepend their `gnubin` paths automatically:
|
||||
|
||||
```
|
||||
brew install coreutils gnu-tar jq
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Place `sloptrap` somewhere on your PATH/shared drive (the helper Dockerfile and Codex binary are bundled and downloaded automatically).
|
||||
|
||||
173
sloptrap
173
sloptrap
@@ -2,7 +2,57 @@
|
||||
# sloptrap
|
||||
set -euo pipefail
|
||||
|
||||
require_cmd() { command -v "$1" >/dev/null 2>&1 || error "'$1' is required"; }
|
||||
IS_MAC=false
|
||||
if [[ $(uname -s 2>/dev/null) == "Darwin" ]]; then
|
||||
IS_MAC=true
|
||||
mac_gnu_bins=(
|
||||
/opt/homebrew/opt/coreutils/libexec/gnubin
|
||||
/usr/local/opt/coreutils/libexec/gnubin
|
||||
/opt/homebrew/opt/gnu-tar/libexec/gnubin
|
||||
/usr/local/opt/gnu-tar/libexec/gnubin
|
||||
)
|
||||
for bin_dir in "${mac_gnu_bins[@]}"; do
|
||||
[[ -d $bin_dir ]] || continue
|
||||
case ":$PATH:" in
|
||||
*":$bin_dir:"*)
|
||||
;;
|
||||
*)
|
||||
path_head=${PATH%%:*}
|
||||
path_rest=""
|
||||
if [[ $PATH == *:* ]]; then
|
||||
path_rest=${PATH#*:}
|
||||
fi
|
||||
case "$path_head" in
|
||||
/tmp/*|/var/folders/*|"$HOME"/*)
|
||||
if [[ -n $path_rest ]]; then
|
||||
PATH="$path_head:$bin_dir:$path_rest"
|
||||
else
|
||||
PATH="$path_head:$bin_dir"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
PATH="$bin_dir:$PATH"
|
||||
;;
|
||||
esac
|
||||
unset -v path_head path_rest
|
||||
;;
|
||||
esac
|
||||
done
|
||||
export PATH
|
||||
fi
|
||||
|
||||
REQUIRED_BREW_PKGS="coreutils gnu-tar jq"
|
||||
|
||||
require_cmd() {
|
||||
if command -v "$1" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
if $IS_MAC; then
|
||||
error "'$1' is required; install with: brew install $REQUIRED_BREW_PKGS"
|
||||
else
|
||||
error "'$1' is required"
|
||||
fi
|
||||
}
|
||||
for c in curl tar sha256sum realpath jq; do require_cmd "$c"; done
|
||||
|
||||
COLOR_TEXT=$'\033[38;5;247m'
|
||||
@@ -147,6 +197,26 @@ trim() {
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
resolve_path_relaxed() {
|
||||
local candidate=$1
|
||||
local resolved
|
||||
if resolved=$(realpath -m "$candidate" 2>/dev/null); then
|
||||
printf '%s' "$resolved"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
resolve_path_strict() {
|
||||
local candidate=$1
|
||||
local resolved
|
||||
if resolved=$(resolve_path_relaxed "$candidate"); then
|
||||
printf '%s' "$resolved"
|
||||
return 0
|
||||
fi
|
||||
error "failed to resolve path '$candidate'; install GNU coreutils for realpath support"
|
||||
}
|
||||
|
||||
declare -A MANIFEST=()
|
||||
declare -a SLOPTRAP_IGNORE_ENTRIES=()
|
||||
declare -a IGNORE_MOUNT_ARGS=()
|
||||
@@ -181,11 +251,11 @@ cleanup_ignore_stub_dir() {
|
||||
[[ -n $helper_root && -n $stub_base ]] || return 0
|
||||
[[ -d $stub_base ]] || return 0
|
||||
local resolved_helper resolved_stub
|
||||
if ! resolved_helper=$(realpath -m "$helper_root") 2>/dev/null; then
|
||||
if ! resolved_helper=$(resolve_path_relaxed "$helper_root"); then
|
||||
warn "failed to resolve helper root '$helper_root' during cleanup"
|
||||
return 0
|
||||
fi
|
||||
if ! resolved_stub=$(realpath -m "$stub_base") 2>/dev/null; then
|
||||
if ! resolved_stub=$(resolve_path_relaxed "$stub_base"); then
|
||||
warn "failed to resolve helper stub '$stub_base' during cleanup"
|
||||
return 0
|
||||
fi
|
||||
@@ -269,6 +339,18 @@ validate_basename() {
|
||||
[[ $name =~ ^[A-Za-z0-9._+-]+$ ]] || error "invalid basename '$name'"
|
||||
}
|
||||
|
||||
sanitize_engine_name() {
|
||||
local name=$1
|
||||
local lowered=${name,,}
|
||||
if [[ $lowered != "$name" ]]; then
|
||||
warn "normalizing name '$name' to '$lowered' for container engine compatibility"
|
||||
fi
|
||||
if [[ ! $lowered =~ ^[a-z0-9_.-]+$ ]]; then
|
||||
error "engine name '$name' is invalid after normalization"
|
||||
fi
|
||||
printf '%s' "$lowered"
|
||||
}
|
||||
|
||||
prepare_build_context() {
|
||||
if [[ -n $SLOPTRAP_BUILD_CONTEXT && -d $SLOPTRAP_BUILD_CONTEXT ]]; then
|
||||
return 0
|
||||
@@ -282,6 +364,9 @@ prepare_build_context() {
|
||||
|
||||
select_codex_home() {
|
||||
local preferred="$HOME/.codex"
|
||||
if [[ -L $preferred ]]; then
|
||||
error "Codex home '$preferred' must not be a symlink"
|
||||
fi
|
||||
if [[ -e $preferred && ! -d $preferred ]]; then
|
||||
error "expected Codex home '$preferred' to be a directory"
|
||||
fi
|
||||
@@ -298,7 +383,7 @@ select_codex_home() {
|
||||
assert_path_within_code_dir() {
|
||||
local candidate=$1
|
||||
local resolved
|
||||
resolved=$(realpath -m "$candidate")
|
||||
resolved=$(resolve_path_strict "$candidate")
|
||||
if [[ $resolved != "$CODE_DIR" && $resolved != "$CODE_DIR/"* ]]; then
|
||||
error "path '$candidate' escapes project root '$CODE_DIR'"
|
||||
fi
|
||||
@@ -345,7 +430,7 @@ sanitize_ignore_rel() {
|
||||
error "$source: .sloptrapignore entry '$original' contains control characters"
|
||||
fi
|
||||
local resolved
|
||||
resolved=$(realpath -m "$CODE_DIR/$rel")
|
||||
resolved=$(resolve_path_strict "$CODE_DIR/$rel")
|
||||
if [[ $resolved != "$CODE_DIR" && $resolved != "$CODE_DIR/"* ]]; then
|
||||
error "$source: .sloptrapignore entry '$original' resolves outside the project root"
|
||||
fi
|
||||
@@ -529,11 +614,12 @@ ensure_safe_for_make() {
|
||||
validate_package_list() {
|
||||
local key=$1
|
||||
local raw=$2
|
||||
local source=${3:-$MANIFEST_PATH}
|
||||
[[ -z $raw ]] && return 0
|
||||
local token
|
||||
for token in $raw; do
|
||||
if [[ ! $token =~ ^[A-Za-z0-9+.-]+$ ]]; then
|
||||
error "$MANIFEST_PATH: invalid package name '$token' in '$key'"
|
||||
error "$source: invalid package name '$token' in '$key'"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -552,7 +638,11 @@ detect_container_engine() {
|
||||
printf 'podman'
|
||||
return 0
|
||||
fi
|
||||
error "podman is required but was not found in PATH; set SLOPTRAP_CONTAINER_ENGINE to override explicitly"
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
printf 'docker'
|
||||
return 0
|
||||
fi
|
||||
error "container engine not found in PATH; install podman (preferred) or docker, or set SLOPTRAP_CONTAINER_ENGINE explicitly"
|
||||
}
|
||||
|
||||
parse_manifest() {
|
||||
@@ -592,6 +682,8 @@ print_config() {
|
||||
info_line "container_name=%s\n" "$SLOPTRAP_CONTAINER_NAME"
|
||||
info_line "codex_home=%s\n" "$CODEX_HOME_HOST"
|
||||
info_line "codex_home_bootstrap=%s\n" "$CODEX_HOME_BOOTSTRAP"
|
||||
info_line "codex_archive=%s\n" "$SLOPTRAP_CODEX_ARCHIVE"
|
||||
info_line "codex_url=%s\n" "$SLOPTRAP_CODEX_URL"
|
||||
info_line "needs_login=%s\n" "$NEED_LOGIN"
|
||||
info_line "codex_args=%s\n" "$CODEX_ARGS_DISPLAY"
|
||||
info_line "ignore_stub_base=%s\n" "$IGNORE_STUB_BASE"
|
||||
@@ -626,6 +718,7 @@ SLOPTRAP_PACKAGES_BASE=""
|
||||
SLOPTRAP_PACKAGES_EXTRA_RESOLVED=""
|
||||
SLOPTRAP_CODEX_BIN_NAME=""
|
||||
SLOPTRAP_CODEX_URL=""
|
||||
SLOPTRAP_CODEX_ARCHIVE=""
|
||||
SLOPTRAP_CODEX_HOME_CONT=""
|
||||
SLOPTRAP_SECURITY_OPTS_EXTRA=""
|
||||
SLOPTRAP_VOLUME_LABEL=""
|
||||
@@ -650,6 +743,29 @@ get_env_default() {
|
||||
fi
|
||||
}
|
||||
|
||||
validate_codex_archive_name() {
|
||||
local name=$1
|
||||
[[ $name =~ ^codex-[A-Za-z0-9_.-]+$ ]] || error "invalid Codex archive name '$name'"
|
||||
}
|
||||
|
||||
detect_codex_archive_name() {
|
||||
local os arch codex_os codex_arch
|
||||
os=$(uname -s 2>/dev/null || true)
|
||||
arch=$(uname -m 2>/dev/null || true)
|
||||
[[ -n $os ]] || error "failed to detect host OS for Codex download"
|
||||
[[ -n $arch ]] || error "failed to detect host architecture for Codex download"
|
||||
case "$os" in
|
||||
Linux|Darwin) codex_os="unknown-linux-gnu" ;; # Codex runs inside a Debian-based image
|
||||
*) error "unsupported host OS '$os' for Codex download" ;;
|
||||
esac
|
||||
case "$arch" in
|
||||
x86_64|amd64) codex_arch="x86_64" ;;
|
||||
arm64|aarch64) codex_arch="aarch64" ;;
|
||||
*) error "unsupported host architecture '$arch' for Codex download" ;;
|
||||
esac
|
||||
printf 'codex-%s-%s' "$codex_arch" "$codex_os"
|
||||
}
|
||||
|
||||
resolve_container_workdir() {
|
||||
if [[ -z ${SLOPTRAP_WORKDIR:-} ]]; then
|
||||
SLOPTRAP_WORKDIR=$(get_env_default "SLOPTRAP_WORKDIR" "/workspace")
|
||||
@@ -690,6 +806,8 @@ ensure_codex_home_dir() {
|
||||
|
||||
fetch_latest_codex_digest() {
|
||||
local api_url="https://api.github.com/repos/openai/codex/releases/latest"
|
||||
local target_asset="${SLOPTRAP_CODEX_ARCHIVE}.tar.gz"
|
||||
[[ -n $SLOPTRAP_CODEX_ARCHIVE ]] || error "Codex archive name is not set"
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
error "jq is required to verify the Codex binary digest"
|
||||
fi
|
||||
@@ -698,7 +816,7 @@ fetch_latest_codex_digest() {
|
||||
error "failed to download Codex release metadata from GitHub"
|
||||
fi
|
||||
local digest_line
|
||||
digest_line=$(jq -r '.assets[] | select(.name == "codex-x86_64-unknown-linux-gnu.tar.gz") | .digest' <<<"$response" | head -n 1)
|
||||
digest_line=$(jq -r --arg name "$target_asset" '.assets[] | select(.name == $name) | .digest' <<<"$response" | head -n 1)
|
||||
if [[ -z $digest_line || $digest_line == "null" ]]; then
|
||||
error "failed to resolve Codex digest from GitHub response"
|
||||
fi
|
||||
@@ -711,14 +829,15 @@ ensure_codex_binary() {
|
||||
if [[ -x $CODEX_BIN_PATH ]]; then
|
||||
return 0
|
||||
fi
|
||||
local tar_transform="s/${SLOPTRAP_CODEX_ARCHIVE}/${SLOPTRAP_CODEX_BIN_NAME}/"
|
||||
local download_dir
|
||||
download_dir=$(create_temp_dir "codex")
|
||||
local tmp_archive="$download_dir/codex.tar.gz"
|
||||
if $DRY_RUN; then
|
||||
print_command curl -Lso "$tmp_archive" "$SLOPTRAP_CODEX_URL"
|
||||
print_command sha256sum -c -
|
||||
print_command tar -xzf "$tmp_archive" --transform="s/codex-x86_64-unknown-linux-gnu/$SLOPTRAP_CODEX_BIN_NAME/" -C "$SLOPTRAP_BUILD_CONTEXT"
|
||||
print_command chmod +x "$CODEX_BIN_PATH"
|
||||
print_command tar -xzf "$tmp_archive" --transform="$tar_transform" -C "$SLOPTRAP_BUILD_CONTEXT"
|
||||
print_command chmod 0755 "$CODEX_BIN_PATH"
|
||||
return 0
|
||||
fi
|
||||
if ! curl -Lso "$tmp_archive" "$SLOPTRAP_CODEX_URL"; then
|
||||
@@ -731,12 +850,12 @@ ensure_codex_binary() {
|
||||
rm -rf "$download_dir" "$CODEX_BIN_PATH"
|
||||
error "checksum verification failed for $SLOPTRAP_CODEX_BIN_NAME"
|
||||
fi
|
||||
if ! tar -xzf "$tmp_archive" --transform="s/codex-x86_64-unknown-linux-gnu/$SLOPTRAP_CODEX_BIN_NAME/" -C "$SLOPTRAP_BUILD_CONTEXT"; then
|
||||
if ! tar -xzf "$tmp_archive" --transform="$tar_transform" -C "$SLOPTRAP_BUILD_CONTEXT"; then
|
||||
rm -rf "$download_dir"
|
||||
error "failed to extract Codex binary"
|
||||
fi
|
||||
rm -rf "$download_dir"
|
||||
chmod +x "$CODEX_BIN_PATH"
|
||||
chmod 0755 "$CODEX_BIN_PATH"
|
||||
}
|
||||
|
||||
ensure_safe_sandbox() {
|
||||
@@ -776,7 +895,7 @@ normalize_package_list() {
|
||||
prepare_container_runtime() {
|
||||
resolve_container_workdir
|
||||
SLOPTRAP_PACKAGES_EXTRA_RESOLVED=$PACKAGES_EXTRA
|
||||
SLOPTRAP_SHARED_DIR_ABS=$(get_env_default "SLOPTRAP_SHARED_DIR" "$CODE_DIR")
|
||||
SLOPTRAP_SHARED_DIR_ABS="$CODE_DIR"
|
||||
if [[ ! -d $SLOPTRAP_SHARED_DIR_ABS ]]; then
|
||||
error "shared directory '$SLOPTRAP_SHARED_DIR_ABS' does not exist"
|
||||
fi
|
||||
@@ -799,7 +918,28 @@ prepare_container_runtime() {
|
||||
fi
|
||||
|
||||
SLOPTRAP_PACKAGES_BASE=$(get_env_default "SLOPTRAP_PACKAGES" "curl bash ca-certificates libstdc++6 git ripgrep xxd file procps")
|
||||
SLOPTRAP_CODEX_URL=$(get_env_default "SLOPTRAP_CODEX_URL" "https://github.com/openai/codex/releases/latest/download/codex-x86_64-unknown-linux-gnu.tar.gz")
|
||||
validate_package_list "SLOPTRAP_PACKAGES" "$SLOPTRAP_PACKAGES_BASE" "SLOPTRAP_PACKAGES"
|
||||
local default_codex_archive
|
||||
default_codex_archive=$(detect_codex_archive_name)
|
||||
local env_codex_archive
|
||||
env_codex_archive=$(printenv "SLOPTRAP_CODEX_ARCHIVE" 2>/dev/null || true)
|
||||
if [[ -n $env_codex_archive ]]; then
|
||||
SLOPTRAP_CODEX_ARCHIVE=$env_codex_archive
|
||||
else
|
||||
SLOPTRAP_CODEX_ARCHIVE=$default_codex_archive
|
||||
fi
|
||||
validate_codex_archive_name "$SLOPTRAP_CODEX_ARCHIVE"
|
||||
local default_codex_url="https://github.com/openai/codex/releases/latest/download/${SLOPTRAP_CODEX_ARCHIVE}.tar.gz"
|
||||
SLOPTRAP_CODEX_URL=$(get_env_default "SLOPTRAP_CODEX_URL" "$default_codex_url")
|
||||
if [[ -z $env_codex_archive ]]; then
|
||||
local inferred_archive
|
||||
inferred_archive=$(basename "${SLOPTRAP_CODEX_URL%%\?*}")
|
||||
inferred_archive=${inferred_archive%.tar.gz}
|
||||
if [[ $inferred_archive == codex-* ]]; then
|
||||
validate_codex_archive_name "$inferred_archive"
|
||||
SLOPTRAP_CODEX_ARCHIVE=$inferred_archive
|
||||
fi
|
||||
fi
|
||||
SLOPTRAP_CODEX_BIN_NAME=$(get_env_default "SLOPTRAP_CODEX_BIN" "codex")
|
||||
SLOPTRAP_CODEX_HOME_CONT=$(get_env_default "SLOPTRAP_CODEX_HOME_CONT" "/codex")
|
||||
SLOPTRAP_CODEX_UID=$(get_env_default "SLOPTRAP_CODEX_UID" "1337")
|
||||
@@ -828,6 +968,8 @@ prepare_container_runtime() {
|
||||
SLOPTRAP_ROOTFS_READONLY=$(get_env_default "SLOPTRAP_ROOTFS_READONLY" "1")
|
||||
SLOPTRAP_IMAGE_NAME=$(get_env_default "SLOPTRAP_IMAGE_NAME" "${PROJECT_NAME}-sloptrap-image")
|
||||
SLOPTRAP_CONTAINER_NAME=$(get_env_default "SLOPTRAP_CONTAINER_NAME" "${PROJECT_NAME}-sloptrap-container")
|
||||
SLOPTRAP_IMAGE_NAME=$(sanitize_engine_name "$SLOPTRAP_IMAGE_NAME")
|
||||
SLOPTRAP_CONTAINER_NAME=$(sanitize_engine_name "$SLOPTRAP_CONTAINER_NAME")
|
||||
|
||||
local -a network_opts=(--network "$SLOPTRAP_NETWORK_NAME" --init)
|
||||
local -a security_opts=(--cap-drop=ALL --security-opt no-new-privileges)
|
||||
@@ -1167,6 +1309,9 @@ if [[ ! -d $CODE_DIR_INPUT ]]; then
|
||||
fi
|
||||
|
||||
CODE_DIR="$(cd "$CODE_DIR_INPUT" && pwd -P)"
|
||||
if [[ $CODE_DIR == "/" ]]; then
|
||||
error "project root may not be '/'"
|
||||
fi
|
||||
MANIFEST_PATH="$CODE_DIR/$MANIFEST_BASENAME"
|
||||
|
||||
if [[ -f $MANIFEST_PATH ]]; then
|
||||
|
||||
1
tests/abs_path_ignore/.sloptrapignore
Normal file
1
tests/abs_path_ignore/.sloptrapignore
Normal file
@@ -0,0 +1 @@
|
||||
/../outside.txt
|
||||
1
tests/dotdot_ignore/.sloptrapignore
Normal file
1
tests/dotdot_ignore/.sloptrapignore
Normal file
@@ -0,0 +1 @@
|
||||
../outside.txt
|
||||
2
tests/invalid_allow_host_network/.sloptrap
Normal file
2
tests/invalid_allow_host_network/.sloptrap
Normal file
@@ -0,0 +1,2 @@
|
||||
name=invalid-allow-host
|
||||
allow_host_network=maybe
|
||||
1
tests/invalid_manifest_name/.sloptrap
Normal file
1
tests/invalid_manifest_name/.sloptrap
Normal file
@@ -0,0 +1 @@
|
||||
name=bad/name
|
||||
2
tests/invalid_manifest_packages/.sloptrap
Normal file
2
tests/invalid_manifest_packages/.sloptrap
Normal file
@@ -0,0 +1,2 @@
|
||||
name=invalid-packages
|
||||
packages_extra=curl$bad
|
||||
2
tests/invalid_manifest_sandbox/.sloptrap
Normal file
2
tests/invalid_manifest_sandbox/.sloptrap
Normal file
@@ -0,0 +1,2 @@
|
||||
name=invalid-sandbox
|
||||
codex_args=--sandbox host
|
||||
1
tests/outside.txt
Normal file
1
tests/outside.txt
Normal file
@@ -0,0 +1 @@
|
||||
outside
|
||||
@@ -306,6 +306,115 @@ run_resume_target() {
|
||||
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
|
||||
@@ -314,6 +423,16 @@ 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'
|
||||
|
||||
Reference in New Issue
Block a user