Harden launcher overrides and fix opencode backend regressions

- remove codex auth mounts from opencode run/shell paths
  - reject opencode login and invalid backend values
  - harden opencode config writes against symlink clobbering
  - fix opencode build args and packages_extra handling
  - enforce cap-drop and read-only rootfs in runtime commands
  - reject dangerous runtime/build env overrides
  - update README and test docs to match actual behavior
  - extend regression coverage for backend safety and hardening
This commit is contained in:
Samuel Aubertin
2026-04-16 18:17:17 +02:00
parent 549862290f
commit e7112db3d7
7 changed files with 238 additions and 47 deletions

View File

@@ -477,6 +477,9 @@ run_shell_target_uses_entrypoint() {
if ! grep -q -- "--entrypoint /bin/bash" "$STUB_LOG"; then
record_failure "shell_target_uses_entrypoint: missing entrypoint override"
fi
if grep -q -- "/codex/auth.json" "$STUB_LOG"; then
record_failure "shell_target_uses_entrypoint: codex auth mount should not be present for opencode shell"
fi
teardown_stub_env
}
@@ -502,6 +505,28 @@ run_auth_file_mount() {
teardown_stub_env
}
run_runtime_hardening_flags() {
local scenario_dir
scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P)
printf '==> runtime_hardening_flags\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 "runtime_hardening_flags: sloptrap exited non-zero"
teardown_stub_env
return
fi
if ! grep -q -- "--cap-drop ALL" "$STUB_LOG"; then
record_failure "runtime_hardening_flags: cap-drop flag missing"
fi
if ! grep -q -- "--read-only" "$STUB_LOG"; then
record_failure "runtime_hardening_flags: read-only rootfs flag missing"
fi
teardown_stub_env
}
run_codex_home_override() {
local scenario_dir codex_root
scenario_dir=$(cd "$TEST_ROOT/resume_target" && pwd -P)
@@ -652,6 +677,59 @@ run_invalid_manifest_packages() {
fi
}
run_invalid_manifest_agent() {
printf '==> invalid_manifest_agent\n'
local scenario_dir
scenario_dir=$(mktemp -d)
cat >"$scenario_dir/.sloptrap" <<'EOF'
name=invalid-agent
agent=bogus
EOF
if "$SLOPTRAP_BIN" --dry-run "$scenario_dir" </dev/null >/dev/null 2>&1; then
record_failure "invalid_manifest_agent: expected rejection for invalid agent"
fi
rm -rf "$scenario_dir"
}
run_invalid_agent_env_override() {
local scenario_dir="$TEST_ROOT/opencode_print_config"
printf '==> invalid_agent_env_override\n'
if SLOPTRAP_AGENT=bogus "$SLOPTRAP_BIN" --dry-run "$scenario_dir" </dev/null >/dev/null 2>&1; then
record_failure "invalid_agent_env_override: expected rejection for invalid SLOPTRAP_AGENT"
fi
}
run_removed_runtime_override_envs() {
local scenario_dir="$TEST_ROOT/resume_target"
printf '==> removed_runtime_override_envs\n'
if SLOPTRAP_SECURITY_OPTS_EXTRA='--privileged' "$SLOPTRAP_BIN" --dry-run "$scenario_dir" </dev/null >/dev/null 2>&1; then
record_failure "removed_runtime_override_envs: expected rejection for SLOPTRAP_SECURITY_OPTS_EXTRA"
fi
if SLOPTRAP_ROOTFS_READONLY=0 "$SLOPTRAP_BIN" --dry-run "$scenario_dir" </dev/null >/dev/null 2>&1; then
record_failure "removed_runtime_override_envs: expected rejection for SLOPTRAP_ROOTFS_READONLY"
fi
if SLOPTRAP_NETWORK_NAME=host "$SLOPTRAP_BIN" --dry-run "$scenario_dir" </dev/null >/dev/null 2>&1; then
record_failure "removed_runtime_override_envs: expected rejection for SLOPTRAP_NETWORK_NAME"
fi
}
run_removed_build_override_envs() {
local scenario_dir="$TEST_ROOT/resume_target"
printf '==> removed_build_override_envs\n'
if SLOPTRAP_DOCKERFILE_PATH=/etc/passwd "$SLOPTRAP_BIN" --dry-run "$scenario_dir" build </dev/null >/dev/null 2>&1; then
record_failure "removed_build_override_envs: expected rejection for SLOPTRAP_DOCKERFILE_PATH"
fi
if SLOPTRAP_CODEX_URL=https://example.invalid/codex.tgz "$SLOPTRAP_BIN" --dry-run "$scenario_dir" build </dev/null >/dev/null 2>&1; then
record_failure "removed_build_override_envs: expected rejection for SLOPTRAP_CODEX_URL"
fi
if SLOPTRAP_CODEX_ARCHIVE=codex-custom "$SLOPTRAP_BIN" --dry-run "$scenario_dir" build </dev/null >/dev/null 2>&1; then
record_failure "removed_build_override_envs: expected rejection for SLOPTRAP_CODEX_ARCHIVE"
fi
if SLOPTRAP_CODEX_BIN=custom-codex "$SLOPTRAP_BIN" --dry-run "$scenario_dir" build </dev/null >/dev/null 2>&1; then
record_failure "removed_build_override_envs: expected rejection for SLOPTRAP_CODEX_BIN"
fi
}
run_wizard_create_manifest() {
local scenario_dir="$TEST_ROOT/wizard_empty"
printf '==> wizard_create_manifest\n'
@@ -695,7 +773,7 @@ run_wizard_existing_defaults() {
cat > "$scenario_dir/.sloptrap" <<EOF
name=custom-wizard
packages_extra=make git
capabilities=apt-install
agent=codex
allow_host_network=true
EOF
# Wizard now has: name, packages_extra, agent (codex), allow_host_network
@@ -759,7 +837,7 @@ run_opencode_build_downloads_release_cli() {
mkdir -p "$scenario_dir"
cat > "$scenario_dir/.sloptrap" <<'EOF'
name=opencode-build
packages_extra=
packages_extra=htop
agent=opencode
allow_host_network=false
EOF
@@ -772,6 +850,12 @@ EOF
if ! grep -q -- "FAKE PODMAN: build " "$STUB_LOG"; then
record_failure "opencode_build_downloads_release_cli: build not invoked"
fi
if ! grep -q -- "--build-arg OPENCODE_BIN=opencode" "$STUB_LOG"; then
record_failure "opencode_build_downloads_release_cli: default OPENCODE_BIN build arg missing"
fi
if ! grep -q -- "--build-arg EXTRA_PACKAGES=htop" "$STUB_LOG"; then
record_failure "opencode_build_downloads_release_cli: EXTRA_PACKAGES build arg missing"
fi
teardown_stub_env
}
@@ -814,6 +898,9 @@ EOF
if ! grep -q -- "OPENCODE_CONFIG=/codex/config/opencode/opencode.json" "$STUB_LOG"; then
record_failure "opencode_localhost_rewrite: opencode config path not exported"
fi
if grep -q -- "/codex/auth.json" "$STUB_LOG"; then
record_failure "opencode_localhost_rewrite: codex auth mount should not be present for opencode"
fi
if ! grep -q -- '"baseURL": "http://sloptrap.host:8080/v1"' "$config_path"; then
record_failure "opencode_localhost_rewrite: localhost server not rewritten in config"
fi
@@ -871,6 +958,76 @@ EOF
teardown_stub_env
}
run_opencode_env_overrides() {
local scenario_dir="$TEST_ROOT/opencode_print_config"
printf '==> opencode_env_overrides\n'
setup_stub_env
mkdir -p "$scenario_dir"
cat > "$scenario_dir/.sloptrap" <<'EOF'
name=opencode-print-config
packages_extra=
agent=opencode
opencode_server=http://manifest:8080
opencode_model=manifest-model
opencode_context=128K
allow_host_network=false
EOF
local output
local plain_output
if ! output=$(env PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \
SLOPTRAP_OPENCODE_SERVER=http://env:8080 SLOPTRAP_OPENCODE_MODEL=env-model SLOPTRAP_OPENCODE_CONTEXT=64K \
"$SLOPTRAP_BIN" --print-config "$scenario_dir" 2>/dev/null); then
record_failure "opencode_env_overrides: print-config failed"
teardown_stub_env
return
fi
plain_output=$(printf '%s' "$output" | sed -E $'s/\x1B\\[[0-9;]*m//g')
if ! grep -q 'opencode_server=http://env:8080' <<<"$plain_output"; then
record_failure "opencode_env_overrides: server env override missing"
fi
if ! grep -q 'opencode_model=env-model' <<<"$plain_output"; then
record_failure "opencode_env_overrides: model env override missing"
fi
if ! grep -q 'opencode_context=64K' <<<"$plain_output"; then
record_failure "opencode_env_overrides: context env override missing"
fi
teardown_stub_env
}
run_opencode_config_symlink_rejected() {
local scenario_dir="$TEST_ROOT/opencode_localhost"
printf '==> opencode_config_symlink_rejected\n'
setup_stub_env
mkdir -p "$scenario_dir"
cat > "$scenario_dir/.sloptrap" <<'EOF'
name=opencode-localhost
packages_extra=
agent=opencode
allow_host_network=false
EOF
local state_key
state_key=$(printf '%s' "$scenario_dir" | sha256sum | awk '{print $1}')
local config_dir="$STUB_HOME/.codex/sloptrap/state/$state_key/config/opencode"
mkdir -p "$config_dir"
ln -s "$STUB_HOME/target.json" "$config_dir/opencode.json"
if 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 "opencode_config_symlink_rejected: expected rejection for symlinked config"
fi
teardown_stub_env
}
run_opencode_login_rejected() {
local scenario_dir="$TEST_ROOT/opencode_localhost"
printf '==> opencode_login_rejected\n'
setup_stub_env
if env PATH="$STUB_BIN:$PATH" HOME="$STUB_HOME" FAKE_PODMAN_LOG="$STUB_LOG" FAKE_PODMAN_INSPECT_FAIL=1 \
"$SLOPTRAP_BIN" "$scenario_dir" login </dev/null >/dev/null 2>&1; then
record_failure "opencode_login_rejected: expected login rejection for opencode"
fi
teardown_stub_env
}
run_symlink_escape
run_manifest_injection
run_helper_symlink
@@ -881,6 +1038,7 @@ run_sh_reexec
run_resume_omits_runtime_context
run_shell_target_uses_entrypoint
run_auth_file_mount
run_runtime_hardening_flags
run_codex_home_override
run_project_state_isolation
run_auto_login_empty_auth
@@ -889,9 +1047,16 @@ run_root_directory_project
run_wizard_create_manifest
run_wizard_existing_defaults
run_wizard_build_trigger
run_invalid_manifest_agent
run_invalid_agent_env_override
run_removed_runtime_override_envs
run_removed_build_override_envs
run_opencode_build_downloads_release_cli
run_opencode_localhost_rewrite
run_opencode_print_config_runtime_flags
run_opencode_env_overrides
run_opencode_config_symlink_rejected
run_opencode_login_rejected
if [[ ${#failures[@]} -gt 0 ]]; then
printf '\nTest failures:\n'