Split /codex mount per project
This commit is contained in:
18
README.md
18
README.md
@@ -36,13 +36,13 @@ brew install coreutils gnu-tar jq
|
||||
3. Run `./sloptrap path/to/project`. On the first invocation sloptrap:
|
||||
- builds `path/to/project-sloptrap-image` if missing,
|
||||
- verifies the Codex binary hash,
|
||||
- creates `${HOME}/.codex` and runs `login` if credentials are absent.
|
||||
- creates `${HOME}/.codex`, prepares a per-project state directory, and runs `login` if `${HOME}/.codex/auth.json` is missing or empty.
|
||||
|
||||
> Use `./sloptrap path/to/project shell` to enter a troubleshooting shell inside the container or `./sloptrap path/to/project clean` to remove cached images and state.
|
||||
|
||||
## How It Works
|
||||
|
||||
- The project directory mounts at `/workspace`, and `${HOME}/.codex` mounts at `/codex`.
|
||||
- The project directory mounts at `/workspace`; project-scoped Codex state mounts at `/codex` from `${HOME}/.codex/sloptrap/state/<project-hash>`, and shared auth mounts from `${HOME}/.codex/auth.json` to `/codex/auth.json`.
|
||||
- `.sloptrapignore` entries (if present in your project) are overlaid by tmpfs (for directories) or empty bind mounts (for files) so Codex cannot read the masked content.
|
||||
- sloptrap launches containers on an isolated network (`bridge` on Docker, `slirp4netns` on Podman) with `--cap-drop=ALL`, `--security-opt no-new-privileges`, a read-only root filesystem, and tmpfs-backed `/tmp`, `/run`, and `/run/lock`. Projects that explicitly set `allow_host_network=true` in their manifest opt into `--network host`.
|
||||
- The helper Dockerfile is embedded inside `sloptrap`; set `SLOPTRAP_DOCKERFILE_PATH=/path/to/custom/Dockerfile` if you need to supply your own recipe. The default image installs `curl`, `bash`, `ca-certificates`, `libstdc++6`, `git`, `ripgrep`, `xxd`, and `file`, so most debugging helpers are already available without adding `packages_extra`.
|
||||
@@ -93,7 +93,7 @@ Behaviour:
|
||||
|
||||
- Missing manifests are treated as default configuration; when a build is requested, sloptrap runs the interactive wizard if a TTY is available, otherwise it warns and continues with defaults.
|
||||
- `SLOPTRAP_CONTAINER_ENGINE` overrides engine auto-detection.
|
||||
- If `${HOME}/.codex/auth.json` is absent, sloptrap prepends a login run before executing your targets.
|
||||
- If `${HOME}/.codex/auth.json` is absent or empty, sloptrap prepends a login run before executing your targets.
|
||||
- Exit status mirrors the last target executed; errors in parsing or setup abort early with a message.
|
||||
|
||||
`--print-config` fields include `manifest_present=true|false`, resolved paths, and the sanitised ignore mount roots so you can confirm what will be hidden inside the container.
|
||||
@@ -114,7 +114,7 @@ Targets are supplied after the code directory. When omitted, sloptrap defaults t
|
||||
| `rebuild` | Rebuild the image from scratch (`--no-cache`). |
|
||||
| `run` | Default goal. Runs the container with Codex as entrypoint and passes `codex_args`. |
|
||||
| `resume <session-id>` | Continues a Codex session by running `codex resume <session-id>` inside the container (builds if needed). |
|
||||
| `login` | Starts Codex in login mode to bootstrap `${HOME}/.codex`. |
|
||||
| `login` | Starts Codex in login mode to bootstrap shared `${HOME}/.codex/auth.json` credentials. |
|
||||
| `shell` | Launches `/bin/bash` inside the container for debugging. |
|
||||
| `wizzard` | Creates or updates `.sloptrap` interactively (no build); rerun `build` or `rebuild` afterward. |
|
||||
| `stop` | Best-effort stop of the running container (if any). |
|
||||
@@ -125,21 +125,21 @@ The launcher executes targets sequentially, so `./sloptrap repo build run` perfo
|
||||
## Execution Environment
|
||||
|
||||
- Container engine: Podman or podman with identical command lines. Podman uses `--userns=keep-id`; Docker receives the equivalent `--user UID:GID`.
|
||||
- Filesystem view: the project directory mounts at `/workspace`; `${HOME}/.codex` mounts at `/codex`.
|
||||
- Filesystem view: the project directory mounts at `/workspace`; `${HOME}/.codex/sloptrap/state/<project-hash>` mounts at `/codex`; `${HOME}/.codex/auth.json` mounts at `/codex/auth.json`.
|
||||
- Ignore filter: `.sloptrapignore` entries are overlaid with tmpfs directories or empty bind mounts so data remains unavailable to Codex.
|
||||
- Network: the container always runs with `--network host`. sloptrap does not filter or proxy outbound traffic.
|
||||
- Process context: capabilities are dropped, `no-new-privileges` is set, the root filesystem is read-only, and scratch paths (`/tmp`, `/run`, `/run/lock`) are tmpfs mounts. Resource limits follow the launcher defaults.
|
||||
- Codex configuration: runtime flags come from `codex_args`. Persistent Codex state is stored under `${HOME}/.codex`.
|
||||
- Codex configuration: runtime flags come from `codex_args`. Persistent Codex state is project-scoped under `${HOME}/.codex/sloptrap/state/`, while credentials are shared via `${HOME}/.codex/auth.json`.
|
||||
|
||||
## Threat Model and Limits
|
||||
|
||||
- **Outbound disclosure**: prompts and referenced data travel from the container to the configured LLM endpoint. Any file content within `/workspace` or environment data exposed to the process can appear in that traffic.
|
||||
- **Shared storage**: `/workspace` and `/codex` are the only host mounts. Files written to these locations become visible on the host and to the LLM provider through prompts.
|
||||
- **Shared storage**: `/workspace`, project-scoped `/codex`, and `/codex/auth.json` are host mounts. Files written to these locations become visible on the host and to the LLM provider through prompts.
|
||||
- **Environment surface**: the container receives a minimal fixed environment (HOME/XDG paths, `CODEX_HOME`). The manifest no longer allows injecting additional environment variables.
|
||||
- **Process isolation**: the container runs without additional Linux capabilities and with a read-only root filesystem. The container and host still share the same kernel; a kernel-level escape would affect host confidentiality.
|
||||
- **Networking stance**: traffic is unrestricted once it leaves the container. sloptrap does not enforce an allowlist or DNS policy, and `--network host` is always used because the bundled Codex CLI must reach an upstream LLM provider. If you require an offline or firewalled workflow, sloptrap is not an appropriate launcher.
|
||||
- **Persistence**: Codex history and logs accumulate under `${HOME}/.codex`. Sensitive prompts recorded on disk remain on the host after the session. Because `.git/` is ignored inside the container, any historical secrets in Git objects stay outside the LLM context unless explicitly surfaced in the working tree.
|
||||
- **Codex cache hygiene**: the `${HOME}/.codex` mount remains writable by the container and will hold tokens, cached prompts, and other state. Rotate credentials regularly and avoid co-locating unrelated secrets inside that directory.
|
||||
- **Persistence**: Codex history and logs accumulate per project under `${HOME}/.codex/sloptrap/state/`. Sensitive prompts recorded on disk remain on the host after the session. Because `.git/` is ignored inside the container, any historical secrets in Git objects stay outside the LLM context unless explicitly surfaced in the working tree.
|
||||
- **Codex cache hygiene**: per-project state mounts remain writable by the container and hold prompts/history/state, while `${HOME}/.codex/auth.json` holds shared credentials. Rotate credentials regularly and protect both locations.
|
||||
- **Secret scanning**: sloptrap does not perform secret discovery or redaction; any credentials present in the project remain available to Codex and the upstream provider.
|
||||
- **Local model exception**: pointing Codex at a local or self-hosted model keeps data within the host network boundary, but the filesystem and environment exposure described above is unchanged.
|
||||
|
||||
|
||||
80
sloptrap
80
sloptrap
@@ -225,7 +225,10 @@ MANIFEST_PRESENT=false
|
||||
|
||||
CURRENT_IGNORE_FILE=""
|
||||
CONTAINER_ENGINE=""
|
||||
CODEX_HOME_HOST=""
|
||||
CODEX_ROOT_HOST=""
|
||||
CODEX_STATE_HOME_HOST=""
|
||||
CODEX_AUTH_FILE_HOST=""
|
||||
CODEX_STATE_KEY=""
|
||||
CODEX_HOME_BOOTSTRAP=false
|
||||
NEED_LOGIN=false
|
||||
IGNORE_STUB_BASE=""
|
||||
@@ -372,13 +375,23 @@ select_codex_home() {
|
||||
error "expected Codex home '$preferred' to be a directory"
|
||||
fi
|
||||
|
||||
CODEX_HOME_HOST="$preferred"
|
||||
if [[ -d $CODEX_HOME_HOST ]]; then
|
||||
CODEX_HOME_HOST="$(cd "$CODEX_HOME_HOST" && pwd -P)"
|
||||
CODEX_ROOT_HOST="$preferred"
|
||||
if [[ -d $CODEX_ROOT_HOST ]]; then
|
||||
CODEX_ROOT_HOST="$(cd "$CODEX_ROOT_HOST" && pwd -P)"
|
||||
CODEX_HOME_BOOTSTRAP=false
|
||||
else
|
||||
CODEX_HOME_BOOTSTRAP=true
|
||||
fi
|
||||
CODEX_STATE_KEY=$(printf '%s' "$CODE_DIR" | sha256sum)
|
||||
CODEX_STATE_KEY=${CODEX_STATE_KEY%% *}
|
||||
CODEX_STATE_HOME_HOST="$CODEX_ROOT_HOST/sloptrap/state/$CODEX_STATE_KEY"
|
||||
CODEX_AUTH_FILE_HOST="$CODEX_ROOT_HOST/auth.json"
|
||||
if [[ -L $CODEX_AUTH_FILE_HOST ]]; then
|
||||
error "Codex auth file '$CODEX_AUTH_FILE_HOST' must not be a symlink"
|
||||
fi
|
||||
if [[ -e $CODEX_AUTH_FILE_HOST && ! -f $CODEX_AUTH_FILE_HOST ]]; then
|
||||
error "expected Codex auth file '$CODEX_AUTH_FILE_HOST' to be a regular file"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_path_within_code_dir() {
|
||||
@@ -820,7 +833,11 @@ print_config() {
|
||||
info_line "container_engine=%s\n" "$CONTAINER_ENGINE"
|
||||
info_line "image_name=%s\n" "$SLOPTRAP_IMAGE_NAME"
|
||||
info_line "container_name=%s\n" "$SLOPTRAP_CONTAINER_NAME"
|
||||
info_line "codex_home=%s\n" "$CODEX_HOME_HOST"
|
||||
info_line "codex_home=%s\n" "$CODEX_STATE_HOME_HOST"
|
||||
info_line "codex_root=%s\n" "$CODEX_ROOT_HOST"
|
||||
info_line "codex_state_home=%s\n" "$CODEX_STATE_HOME_HOST"
|
||||
info_line "codex_auth_file=%s\n" "$CODEX_AUTH_FILE_HOST"
|
||||
info_line "codex_state_key=%s\n" "$CODEX_STATE_KEY"
|
||||
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"
|
||||
@@ -942,15 +959,46 @@ run_or_print() {
|
||||
"$@"
|
||||
}
|
||||
|
||||
ensure_codex_home_dir() {
|
||||
if [[ -d $CODEX_HOME_HOST ]]; then
|
||||
ensure_codex_directory() {
|
||||
local path=$1
|
||||
local label=$2
|
||||
if [[ -L $path ]]; then
|
||||
error "$label '$path' must not be a symlink"
|
||||
fi
|
||||
if [[ -e $path && ! -d $path ]]; then
|
||||
error "expected $label '$path' to be a directory"
|
||||
fi
|
||||
if [[ -d $path ]]; then
|
||||
return 0
|
||||
fi
|
||||
if $DRY_RUN; then
|
||||
print_command mkdir -p "$CODEX_HOME_HOST"
|
||||
print_command mkdir -p "$path"
|
||||
return 0
|
||||
fi
|
||||
mkdir -p "$CODEX_HOME_HOST"
|
||||
mkdir -p "$path"
|
||||
}
|
||||
|
||||
ensure_codex_storage_paths() {
|
||||
local state_root="$CODEX_ROOT_HOST/sloptrap"
|
||||
local state_bucket="$state_root/state"
|
||||
ensure_codex_directory "$CODEX_ROOT_HOST" "Codex home"
|
||||
ensure_codex_directory "$state_root" "sloptrap Codex namespace"
|
||||
ensure_codex_directory "$state_bucket" "sloptrap Codex state root"
|
||||
ensure_codex_directory "$CODEX_STATE_HOME_HOST" "project Codex state"
|
||||
if [[ -L $CODEX_AUTH_FILE_HOST ]]; then
|
||||
error "Codex auth file '$CODEX_AUTH_FILE_HOST' must not be a symlink"
|
||||
fi
|
||||
if [[ -e $CODEX_AUTH_FILE_HOST && ! -f $CODEX_AUTH_FILE_HOST ]]; then
|
||||
error "expected Codex auth file '$CODEX_AUTH_FILE_HOST' to be a regular file"
|
||||
fi
|
||||
if [[ -f $CODEX_AUTH_FILE_HOST ]]; then
|
||||
return 0
|
||||
fi
|
||||
if $DRY_RUN; then
|
||||
print_command touch "$CODEX_AUTH_FILE_HOST"
|
||||
return 0
|
||||
fi
|
||||
: > "$CODEX_AUTH_FILE_HOST"
|
||||
}
|
||||
|
||||
fetch_latest_codex_digest() {
|
||||
@@ -1175,7 +1223,8 @@ prepare_container_runtime() {
|
||||
|
||||
local -a volume_opts=(
|
||||
-v "$SLOPTRAP_SHARED_DIR_ABS:$SLOPTRAP_WORKDIR$SLOPTRAP_VOLUME_LABEL"
|
||||
-v "$CODEX_HOME_HOST:$SLOPTRAP_CODEX_HOME_CONT$SLOPTRAP_VOLUME_LABEL"
|
||||
-v "$CODEX_STATE_HOME_HOST:$SLOPTRAP_CODEX_HOME_CONT$SLOPTRAP_VOLUME_LABEL"
|
||||
-v "$CODEX_AUTH_FILE_HOST:$SLOPTRAP_CODEX_HOME_CONT/auth.json$SLOPTRAP_VOLUME_LABEL"
|
||||
)
|
||||
|
||||
local -a env_args=(
|
||||
@@ -1361,6 +1410,7 @@ prune_sloptrap_images() {
|
||||
|
||||
run_codex_command() {
|
||||
local -a extra_args=("$@")
|
||||
ensure_codex_storage_paths
|
||||
local -a cmd=("${BASE_CONTAINER_CMD[@]}" "$SLOPTRAP_IMAGE_NAME")
|
||||
if [[ ${#CODEX_ARGS_ARRAY[@]} -gt 0 ]]; then
|
||||
cmd+=("${CODEX_ARGS_ARRAY[@]}")
|
||||
@@ -1379,6 +1429,7 @@ run_codex() {
|
||||
}
|
||||
|
||||
run_login_target() {
|
||||
ensure_codex_storage_paths
|
||||
if ! $DRY_RUN; then
|
||||
status_line "Login %s\n" "$SLOPTRAP_IMAGE_NAME"
|
||||
fi
|
||||
@@ -1387,6 +1438,7 @@ run_login_target() {
|
||||
}
|
||||
|
||||
run_shell_target() {
|
||||
ensure_codex_storage_paths
|
||||
if ! $DRY_RUN; then
|
||||
status_line "Shell %s\n" "$SLOPTRAP_IMAGE_NAME"
|
||||
fi
|
||||
@@ -1429,7 +1481,6 @@ dispatch_target() {
|
||||
;;
|
||||
login)
|
||||
build_if_missing
|
||||
ensure_codex_home_dir
|
||||
run_login_target
|
||||
;;
|
||||
shell)
|
||||
@@ -1553,9 +1604,7 @@ IGNORE_STUB_BASE="$IGNORE_HELPER_ROOT/session-${BASHPID:-$$}"
|
||||
resolve_sloptrap_ignore "$CODE_DIR"
|
||||
resolve_container_workdir
|
||||
NEED_LOGIN=false
|
||||
if [[ $CODEX_HOME_BOOTSTRAP == true ]]; then
|
||||
NEED_LOGIN=true
|
||||
elif [[ ! -f "$CODEX_HOME_HOST/auth.json" ]]; then
|
||||
if [[ ! -s "$CODEX_AUTH_FILE_HOST" ]]; then
|
||||
NEED_LOGIN=true
|
||||
fi
|
||||
|
||||
@@ -1653,9 +1702,8 @@ fi
|
||||
|
||||
if $AUTO_LOGIN; then
|
||||
if ! $DRY_RUN; then
|
||||
status_line "Codex login required (%s)\n" "$CODEX_HOME_HOST"
|
||||
status_line "Codex login required (%s)\n" "$CODEX_AUTH_FILE_HOST"
|
||||
fi
|
||||
ensure_codex_home_dir
|
||||
dispatch_target login
|
||||
fi
|
||||
|
||||
|
||||
@@ -11,3 +11,6 @@ Current scenarios:
|
||||
- `helper_symlink/` — ensures `.sloptrap-ignores` cannot be a symlink to directories outside the project.
|
||||
- `secret_mask/` — verifies masked files remain hidden even when sloptrap remaps the workspace mount.
|
||||
- `resume_target/` — verifies the resume target passes the requested session identifier to Codex.
|
||||
- `auth_file_mount` — verifies `~/.codex/auth.json` is mounted directly into `/codex/auth.json`.
|
||||
- `project_state_isolation` — verifies different projects map `/codex` to different host state directories.
|
||||
- `auto_login_empty_auth` — verifies an empty `auth.json` still triggers automatic login before the main target.
|
||||
|
||||
@@ -15,6 +15,16 @@ 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
|
||||
@@ -154,6 +164,9 @@ if [[ ${1-} == "-c" ]]; then
|
||||
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
|
||||
@@ -306,6 +319,94 @@ run_resume_target() {
|
||||
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 >/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_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 >/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 >/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 >/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)
|
||||
@@ -418,8 +519,8 @@ run_invalid_allow_host_network() {
|
||||
run_wizzard_create_manifest() {
|
||||
local scenario_dir="$TEST_ROOT/wizzard_empty"
|
||||
printf '==> wizzard_create_manifest\n'
|
||||
if ! command -v script >/dev/null 2>&1; then
|
||||
printf 'skipping wizzard_create_manifest: script binary not found in PATH\n'
|
||||
if ! can_run_script_pty; then
|
||||
printf 'skipping wizzard_create_manifest: script PTY support not available\n'
|
||||
return
|
||||
fi
|
||||
rm -f "$scenario_dir/.sloptrap"
|
||||
@@ -449,8 +550,8 @@ run_wizzard_create_manifest() {
|
||||
run_wizzard_existing_defaults() {
|
||||
local scenario_dir="$TEST_ROOT/wizzard_existing"
|
||||
printf '==> wizzard_existing_defaults\n'
|
||||
if ! command -v script >/dev/null 2>&1; then
|
||||
printf 'skipping wizzard_existing_defaults: script binary not found in PATH\n'
|
||||
if ! can_run_script_pty; then
|
||||
printf 'skipping wizzard_existing_defaults: script PTY support not available\n'
|
||||
return
|
||||
fi
|
||||
local input=$'\n\n\n\n\n'
|
||||
@@ -475,8 +576,8 @@ run_wizzard_existing_defaults() {
|
||||
run_wizzard_build_trigger() {
|
||||
local scenario_dir="$TEST_ROOT/wizzard_build"
|
||||
printf '==> wizzard_build_trigger\n'
|
||||
if ! command -v script >/dev/null 2>&1; then
|
||||
printf 'skipping wizzard_build_trigger: script binary not found in PATH\n'
|
||||
if ! can_run_script_pty; then
|
||||
printf 'skipping wizzard_build_trigger: script PTY support not available\n'
|
||||
return
|
||||
fi
|
||||
setup_stub_env
|
||||
@@ -504,6 +605,9 @@ run_manifest_injection
|
||||
run_helper_symlink
|
||||
run_secret_mask
|
||||
run_resume_target
|
||||
run_auth_file_mount
|
||||
run_project_state_isolation
|
||||
run_auto_login_empty_auth
|
||||
run_codex_symlink_home
|
||||
run_root_directory_project
|
||||
run_shared_dir_override
|
||||
|
||||
Reference in New Issue
Block a user