Try to inject the parent image in slopslopstrap

This commit is contained in:
Samuel Aubertin
2026-03-10 01:22:58 +01:00
parent 3731094f60
commit 438959ca03
3 changed files with 428 additions and 12 deletions

View File

@@ -35,5 +35,8 @@ Do not remove existing instructions unless they are outdated or wrong.
- Forcing `SLOPTRAP_CONTAINER_ENGINE=sloppodman` inside sloptrap also needs `TMPDIR` under `/workspace`; otherwise its build-context path guard rejects the staged Dockerfile under `/tmp` before you reach the real subuid/subgid problem. - Forcing `SLOPTRAP_CONTAINER_ENGINE=sloppodman` inside sloptrap also needs `TMPDIR` under `/workspace`; otherwise its build-context path guard rejects the staged Dockerfile under `/tmp` before you reach the real subuid/subgid problem.
- If a restarted session still inherits stale read-only `/etc/subuid` and `/etc/subgid` tmpfs mounts, an unprivileged agent cannot repair them in-place (`umount` says `must be superuser to unmount`); both podman and sloppodman stay blocked until the session starts without those mounts. - If a restarted session still inherits stale read-only `/etc/subuid` and `/etc/subgid` tmpfs mounts, an unprivileged agent cannot repair them in-place (`umount` says `must be superuser to unmount`); both podman and sloppodman stay blocked until the session starts without those mounts.
- Outer sloptrap launches no longer need `/etc/subuid` or `/etc/subgid` bind mounts: `nested-podman` now disables read-only rootfs and the container entrypoint synthesizes container-local subid files from `/proc/self/{uid,gid}_map` before dropping privileges. - Outer sloptrap launches no longer need `/etc/subuid` or `/etc/subgid` bind mounts: `nested-podman` now disables read-only rootfs and the container entrypoint synthesizes container-local subid files from `/proc/self/{uid,gid}_map` before dropping privileges.
- Even without stale `/etc/subuid` mounts, recursion still fails if the container-local subid files name `sloptrap` instead of the real dropped user (`sk4nz` here): `podman info --debug` warns `no subuid ranges found for user "sk4nz"` and the first inner build dies in `newuidmap ... write to uid_map failed: Operation not permitted`.
- In this Debian 13 / podman 5.4.2 environment, exporting `_CONTAINERS_USERNS_CONFIGURED=done` for nested podman moves the failure past `newuidmap`, but the next blockers are inside Buildah: with `BUILDAH_ISOLATION=chroot`, recursive builds fail `cannot set --network other than host with --isolation chroot`; without chroot, `podman build` can segfault in `network.defaultNetworkBackend`.
- Recursive preload now has a host-side path: the outer launcher saves `$SLOPTRAP_IMAGE_NAME` into capability state and mounts it into the container as `SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE=/codex/capabilities/podman/preload/<image>.tar`, and child `build-if-missing` tries `sloppodman load -i` before any inner build. A pre-existing session must be restarted to test that path because it cannot add the new preload mount/env to itself after startup.
- With stale subid mounts gone, recursive `./sloptrap /workspace` can still fail earlier during the inner image build: `crun` tries to open `/proc/sys/net/ipv4/ping_group_range` and gets `Read-only file system` while creating the build container. - With stale subid mounts gone, recursive `./sloptrap /workspace` can still fail earlier during the inner image build: `crun` tries to open `/proc/sys/net/ipv4/ping_group_range` and gets `Read-only file system` while creating the build container.
- In a fragile nested-podman session, `podman system migrate` can make things worse: a state that still answered `podman info` fell back to repeated `newuidmap ... write to uid_map failed: Operation not permitted` failures afterward. - In a fragile nested-podman session, `podman system migrate` can make things worse: a state that still answered `podman info` fell back to repeated `newuidmap ... write to uid_map failed: Operation not permitted` failures afterward.

288
sloptrap
View File

@@ -245,6 +245,7 @@ CAPABILITY_TRUST_ROOT_HOST=""
CAPABILITY_TRUST_FILE_HOST="" CAPABILITY_TRUST_FILE_HOST=""
CAPABILITY_BUILD_STAMP_HOST="" CAPABILITY_BUILD_STAMP_HOST=""
CAPABILITY_STATE_HOST="" CAPABILITY_STATE_HOST=""
CAPABILITY_PRELOAD_DIR_HOST=""
IGNORE_STUB_BASE="" IGNORE_STUB_BASE=""
IGNORE_HELPER_ROOT="" IGNORE_HELPER_ROOT=""
ALLOW_HOST_NETWORK=false ALLOW_HOST_NETWORK=false
@@ -355,6 +356,7 @@ write_embedded_helper() {
set -euo pipefail set -euo pipefail
helper_pid="" helper_pid=""
helperd_bin=${SLOPTRAP_HELPERD_BIN:-/usr/local/bin/sloptrap-helperd}
has_capability() { has_capability() {
local needle=$1 local needle=$1
@@ -440,12 +442,16 @@ lookup_account_name() {
ensure_subid_mappings() { ensure_subid_mappings() {
local account_id account_gid account_name="" local account_id account_gid account_name=""
local subuid_file subgid_file
local range_start="" range_count="" gid_start="" gid_count="" local range_start="" range_count="" gid_start="" gid_count=""
local detected_range="" local detected_range=""
account_id=${SLOPTRAP_HOST_UID:-$(id -u)} account_id=${SLOPTRAP_HOST_UID:-$(id -u)}
account_gid=${SLOPTRAP_HOST_GID:-$(id -g)} account_gid=${SLOPTRAP_HOST_GID:-$(id -g)}
if ! account_name=$(lookup_account_name "$account_id"); then account_name=${SLOPTRAP_HOST_USER:-}
subuid_file=${SLOPTRAP_PODMAN_SUBUID_FILE:-/etc/subuid}
subgid_file=${SLOPTRAP_PODMAN_SUBGID_FILE:-/etc/subgid}
if [[ -z $account_name ]] && ! account_name=$(lookup_account_name "$account_id"); then
account_name="" account_name=""
fi fi
@@ -463,10 +469,10 @@ ensure_subid_mappings() {
fi fi
if [[ -n $range_start && -n $range_count ]]; then if [[ -n $range_start && -n $range_count ]]; then
ensure_subid_mapping_file /etc/subuid "$account_name" "$account_id" "$range_start" "$range_count" ensure_subid_mapping_file "$subuid_file" "$account_name" "$account_id" "$range_start" "$range_count"
fi fi
if [[ -n $gid_start && -n $gid_count ]]; then if [[ -n $gid_start && -n $gid_count ]]; then
ensure_subid_mapping_file /etc/subgid "$account_name" "$account_id" "$gid_start" "$gid_count" ensure_subid_mapping_file "$subgid_file" "$account_name" "$account_id" "$gid_start" "$gid_count"
fi fi
} }
@@ -495,7 +501,7 @@ if [[ $(id -u) -eq 0 ]]; then
ensure_subid_mappings ensure_subid_mappings
fi fi
if [[ -n ${SLOPTRAP_ACTIVE_CAPABILITIES:-} ]]; then if [[ -n ${SLOPTRAP_ACTIVE_CAPABILITIES:-} ]]; then
/usr/local/bin/sloptrap-helperd & "$helperd_bin" &
helper_pid=$! helper_pid=$!
fi fi
if [[ -n $target_uid && -n $target_gid ]]; then if [[ -n $target_uid && -n $target_gid ]]; then
@@ -1129,7 +1135,7 @@ has_capability() {
} }
if [[ $# -eq 0 ]]; then if [[ $# -eq 0 ]]; then
printf 'usage: sloppodman <pull|build|tag|run|ps|logs|stop|rm|inspect> ...\n' >&2 printf 'usage: sloppodman <pull|build|tag|load|import|run|ps|logs|stop|rm|inspect> ...\n' >&2
exit 2 exit 2
fi fi
@@ -1139,7 +1145,7 @@ shift
subcommand_prefix=("$subcommand") subcommand_prefix=("$subcommand")
case "$subcommand" in case "$subcommand" in
pull|build|tag|run|ps|logs|stop|rm|inspect|rmi) pull|build|tag|load|import|run|ps|logs|stop|rm|inspect|rmi)
;; ;;
image) image)
[[ $# -gt 0 ]] || { [[ $# -gt 0 ]] || {
@@ -1204,6 +1210,7 @@ CONTAINERS_CONF_EOF
export CONTAINERS_STORAGE_CONF="$storage_conf" export CONTAINERS_STORAGE_CONF="$storage_conf"
export CONTAINERS_CONF="$containers_conf" export CONTAINERS_CONF="$containers_conf"
export BUILDAH_ISOLATION="${BUILDAH_ISOLATION:-chroot}" export BUILDAH_ISOLATION="${BUILDAH_ISOLATION:-chroot}"
export _CONTAINERS_USERNS_CONFIGURED="${_CONTAINERS_USERNS_CONFIGURED:-done}"
detect_subid_range_from_map() { detect_subid_range_from_map() {
local map_path=$1 local map_path=$1
@@ -1320,6 +1327,7 @@ exec_podman() {
CONTAINERS_STORAGE_CONF="$CONTAINERS_STORAGE_CONF" \ CONTAINERS_STORAGE_CONF="$CONTAINERS_STORAGE_CONF" \
CONTAINERS_CONF="$CONTAINERS_CONF" \ CONTAINERS_CONF="$CONTAINERS_CONF" \
BUILDAH_ISOLATION="$BUILDAH_ISOLATION" \ BUILDAH_ISOLATION="$BUILDAH_ISOLATION" \
_CONTAINERS_USERNS_CONFIGURED="$_CONTAINERS_USERNS_CONFIGURED" \
XDG_RUNTIME_DIR="$runtime_dir" \ XDG_RUNTIME_DIR="$runtime_dir" \
SLOPTRAP_PODMAN_ESCALATED=1 \ SLOPTRAP_PODMAN_ESCALATED=1 \
SLOPTRAP_PODMAN_CALLER_UID="${SLOPTRAP_PODMAN_CALLER_UID:-$(id -u)}" \ SLOPTRAP_PODMAN_CALLER_UID="${SLOPTRAP_PODMAN_CALLER_UID:-$(id -u)}" \
@@ -1352,6 +1360,19 @@ validate_workspace_path() {
esac esac
} }
validate_archive_path() {
local path=$1
local resolved allowed_archive=""
resolved=$(resolve_inner_path "$path")
if [[ -n ${SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE:-} ]]; then
allowed_archive=$(resolve_inner_path "$SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE")
if [[ $resolved == "$allowed_archive" ]]; then
return 0
fi
fi
validate_workspace_path "$path"
}
reject_flag() { reject_flag() {
local flag=$1 local flag=$1
printf 'sloppodman: %s is not permitted\n' "$flag" >&2 printf 'sloppodman: %s is not permitted\n' "$flag" >&2
@@ -1450,6 +1471,60 @@ if [[ $subcommand == "build" ]]; then
fi fi
fi fi
if [[ $subcommand == "import" ]]; then
args=("$@")
archive_path=""
idx=0
while (( idx < ${#args[@]} )); do
arg=${args[$idx]}
case "$arg" in
--change|--message)
((idx+=1))
(( idx < ${#args[@]} )) || { printf 'sloppodman: %s requires a value\n' "$arg" >&2; exit 2; }
;;
--change=*|--message=*|-q|--quiet)
;;
-*)
;;
*)
archive_path=$arg
break
;;
esac
((idx+=1))
done
[[ -n $archive_path ]] || { printf 'sloppodman: import requires an archive path\n' >&2; exit 2; }
validate_archive_path "$archive_path"
fi
if [[ $subcommand == "load" ]]; then
args=("$@")
archive_path=""
idx=0
while (( idx < ${#args[@]} )); do
arg=${args[$idx]}
case "$arg" in
-i|--input)
((idx+=1))
(( idx < ${#args[@]} )) || { printf 'sloppodman: %s requires a path\n' "$arg" >&2; exit 2; }
archive_path=${args[$idx]}
;;
--input=*|-i=*)
archive_path=${arg#*=}
;;
-*)
;;
*)
archive_path=$arg
break
;;
esac
((idx+=1))
done
[[ -n $archive_path ]] || { printf 'sloppodman: load requires an archive path\n' >&2; exit 2; }
validate_archive_path "$archive_path"
fi
if [[ $subcommand == "run" ]]; then if [[ $subcommand == "run" ]]; then
args=("$@") args=("$@")
idx=0 idx=0
@@ -1684,6 +1759,7 @@ select_capability_state_paths() {
CAPABILITY_TRUST_FILE_HOST="$CAPABILITY_TRUST_ROOT_HOST/$CODEX_STATE_KEY.trust" CAPABILITY_TRUST_FILE_HOST="$CAPABILITY_TRUST_ROOT_HOST/$CODEX_STATE_KEY.trust"
CAPABILITY_BUILD_STAMP_HOST="$capability_root/builds/$CODEX_STATE_KEY.stamp" CAPABILITY_BUILD_STAMP_HOST="$capability_root/builds/$CODEX_STATE_KEY.stamp"
CAPABILITY_STATE_HOST="$CODEX_STATE_HOME_HOST/capabilities" CAPABILITY_STATE_HOST="$CODEX_STATE_HOME_HOST/capabilities"
CAPABILITY_PRELOAD_DIR_HOST="$CAPABILITY_STATE_HOST/podman-preload"
} }
ensure_capability_state_paths() { ensure_capability_state_paths() {
@@ -1696,6 +1772,7 @@ ensure_capability_state_paths() {
ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-storage" "nested podman storage state" ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-storage" "nested podman storage state"
ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-run" "nested podman runroot state" ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-run" "nested podman runroot state"
ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-runtime" "nested podman runtime state" ensure_codex_directory "$CAPABILITY_STATE_HOST/podman-runtime" "nested podman runtime state"
ensure_codex_directory "$CAPABILITY_PRELOAD_DIR_HOST" "nested podman preload state"
fi fi
} }
@@ -1768,6 +1845,16 @@ capability_build_stamp_matches_current() {
[[ $stamp_digest == "$CAPABILITY_MANIFEST_DIGEST" && $stamp_caps == "$REQUESTED_CAPABILITIES" ]] [[ $stamp_digest == "$CAPABILITY_MANIFEST_DIGEST" && $stamp_caps == "$REQUESTED_CAPABILITIES" ]]
} }
run_with_nested_podman_root() {
if capability_list_contains "${SLOPTRAP_ACTIVE_CAPABILITIES:-}" "nested-podman" \
&& [[ $(id -u) -ne 0 ]] \
&& command -v setpriv >/dev/null 2>&1; then
setpriv --reuid 0 --regid 0 --clear-groups -- "$@"
return
fi
"$@"
}
assert_path_within_code_dir() { assert_path_within_code_dir() {
local candidate=$1 local candidate=$1
local resolved local resolved
@@ -2057,7 +2144,9 @@ detect_container_engine() {
local override=${SLOPTRAP_CONTAINER_ENGINE-} local override=${SLOPTRAP_CONTAINER_ENGINE-}
if [[ -n $override ]]; then if [[ -n $override ]]; then
local engine="${override,,}" local engine="${override,,}"
if ! command -v "$engine" >/dev/null 2>&1; then if [[ $engine == */* ]]; then
[[ -x $engine ]] || error "container engine '$engine' is not executable"
elif ! command -v "$engine" >/dev/null 2>&1; then
error "container engine '$engine' not found in PATH" error "container engine '$engine' not found in PATH"
fi fi
printf '%s' "$engine" printf '%s' "$engine"
@@ -2706,6 +2795,7 @@ prepare_container_runtime() {
-v "$CAPABILITY_STATE_HOST/podman-storage:$SLOPTRAP_CODEX_HOME_CONT/capabilities/podman/storage$SLOPTRAP_VOLUME_LABEL" -v "$CAPABILITY_STATE_HOST/podman-storage:$SLOPTRAP_CODEX_HOME_CONT/capabilities/podman/storage$SLOPTRAP_VOLUME_LABEL"
-v "$CAPABILITY_STATE_HOST/podman-run:$SLOPTRAP_CODEX_HOME_CONT/capabilities/podman/run$SLOPTRAP_VOLUME_LABEL" -v "$CAPABILITY_STATE_HOST/podman-run:$SLOPTRAP_CODEX_HOME_CONT/capabilities/podman/run$SLOPTRAP_VOLUME_LABEL"
-v "$CAPABILITY_STATE_HOST/podman-runtime:$SLOPTRAP_CODEX_HOME_CONT/capabilities/podman/runtime$SLOPTRAP_VOLUME_LABEL" -v "$CAPABILITY_STATE_HOST/podman-runtime:$SLOPTRAP_CODEX_HOME_CONT/capabilities/podman/runtime$SLOPTRAP_VOLUME_LABEL"
-v "$CAPABILITY_PRELOAD_DIR_HOST:$SLOPTRAP_CODEX_HOME_CONT/capabilities/podman/preload$SLOPTRAP_VOLUME_LABEL"
) )
fi fi
@@ -2728,14 +2818,24 @@ prepare_container_runtime() {
if capability_list_contains "$ENABLED_CAPABILITIES" "nested-podman" && [[ $SLOPTRAP_NETWORK_NAME == "host" ]]; then if capability_list_contains "$ENABLED_CAPABILITIES" "nested-podman" && [[ $SLOPTRAP_NETWORK_NAME == "host" ]]; then
env_args+=(-e "SLOPTRAP_INNER_PODMAN_HOST_NETWORK=1") env_args+=(-e "SLOPTRAP_INNER_PODMAN_HOST_NETWORK=1")
fi fi
if capability_list_contains "$ENABLED_CAPABILITIES" "nested-podman"; then
env_args+=(
-e "SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE=$(recursive_preload_archive_container_path)"
-e "SLOPTRAP_RECURSIVE_PARENT_IMAGE_NAME=$SLOPTRAP_IMAGE_NAME"
)
fi
local uid gid local uid gid user
uid=$(id -u) uid=$(id -u)
gid=$(id -g) gid=$(id -g)
user=$(id -un 2>/dev/null || true)
env_args+=( env_args+=(
-e "SLOPTRAP_HOST_UID=$uid" -e "SLOPTRAP_HOST_UID=$uid"
-e "SLOPTRAP_HOST_GID=$gid" -e "SLOPTRAP_HOST_GID=$gid"
) )
if [[ -n $user ]]; then
env_args+=(-e "SLOPTRAP_HOST_USER=$user")
fi
local -a user_opts=("--user" "$uid:$gid") local -a user_opts=("--user" "$uid:$gid")
if [[ $CONTAINER_ENGINE == "podman" ]]; then if [[ $CONTAINER_ENGINE == "podman" ]]; then
user_opts=(--userns="keep-id:uid=$uid,gid=$gid" "${user_opts[@]}") user_opts=(--userns="keep-id:uid=$uid,gid=$gid" "${user_opts[@]}")
@@ -2860,6 +2960,169 @@ rebuild_image() {
write_capability_build_stamp write_capability_build_stamp
} }
compute_recursive_preload_stamp() {
local launcher_source=${BASH_SOURCE[0]:-$0}
local launcher_digest
launcher_digest=$(sha256sum "$launcher_source")
printf '%s\n%s\n' "${launcher_digest%% *}" "$SLOPTRAP_IMAGE_NAME"
}
recursive_preload_archive_host_path() {
printf '%s/%s.tar\n' "$CAPABILITY_PRELOAD_DIR_HOST" "$SLOPTRAP_IMAGE_NAME"
}
recursive_preload_archive_container_path() {
printf '%s/capabilities/podman/preload/%s.tar\n' "$SLOPTRAP_CODEX_HOME_CONT" "$SLOPTRAP_IMAGE_NAME"
}
prepare_recursive_parent_image_preload() {
capability_list_contains "$ENABLED_CAPABILITIES" "nested-podman" || return 0
local engine_name=${CONTAINER_ENGINE##*/}
case "$engine_name" in
sloppodman|sloppodman*|.sloppodman*)
return 0
;;
esac
local archive_path stamp_path image_id recorded_id=""
archive_path=$(recursive_preload_archive_host_path)
stamp_path="${archive_path}.stamp"
if ! image_id=$("$CONTAINER_ENGINE" image inspect --format '{{.Id}}' "$SLOPTRAP_IMAGE_NAME" 2>/dev/null); then
return 1
fi
if [[ -f $archive_path && -f $stamp_path ]]; then
recorded_id=$(sed -n '1p' "$stamp_path" 2>/dev/null || true)
if [[ $recorded_id == "$image_id" ]]; then
return 0
fi
fi
local tmp_archive="${archive_path}.tmp"
if ! "$CONTAINER_ENGINE" save -o "$tmp_archive" "$SLOPTRAP_IMAGE_NAME"; then
rm -f "$tmp_archive"
return 1
fi
mv "$tmp_archive" "$archive_path"
printf '%s\n%s\n' "$image_id" "$SLOPTRAP_IMAGE_NAME" >"$stamp_path"
}
load_recursive_parent_image() {
local engine_name=${CONTAINER_ENGINE##*/}
local archive_path=${SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE:-}
local source_image_name=${SLOPTRAP_RECURSIVE_PARENT_IMAGE_NAME:-$SLOPTRAP_IMAGE_NAME}
case "$engine_name" in
sloppodman|sloppodman*|.sloppodman*)
;;
*)
return 1
;;
esac
capability_list_contains "${SLOPTRAP_ACTIVE_CAPABILITIES:-}" "nested-podman" || return 1
[[ -n $archive_path && -r $archive_path ]] || return 1
if ! "$CONTAINER_ENGINE" load -i "$archive_path"; then
return 1
fi
if ! "$CONTAINER_ENGINE" image inspect "$SLOPTRAP_IMAGE_NAME" >/dev/null 2>&1; then
[[ -n $source_image_name ]] || return 1
"$CONTAINER_ENGINE" tag "$source_image_name" "$SLOPTRAP_IMAGE_NAME" || return 1
fi
"$CONTAINER_ENGINE" image inspect "$SLOPTRAP_IMAGE_NAME" >/dev/null 2>&1 || return 1
write_capability_build_stamp
return 0
}
prepare_recursive_parent_image_archive() {
local archive_dir="$CODE_DIR/.sloptrap-preload"
local archive_path="$archive_dir/${SLOPTRAP_IMAGE_NAME}.tar"
local stamp_path="$archive_path.stamp"
local desired_stamp current_stamp=""
desired_stamp=$(compute_recursive_preload_stamp)
if [[ -f $archive_path && -f $stamp_path ]]; then
current_stamp=$(cat "$stamp_path" 2>/dev/null || true)
if [[ $current_stamp == "$desired_stamp" ]]; then
printf '%s\n' "$archive_path"
return 0
fi
fi
assert_path_within_code_dir "$archive_dir"
mkdir -p "$archive_dir"
local overlay_dir
overlay_dir=$(create_temp_dir "recursive-preload")
local helper
for helper in sloptrap-entrypoint sloptrap-helperd slop-apt slopcap sloppodman; do
populate_embedded_helper "$helper" "$overlay_dir/usr/local/bin/$helper"
done
chmod 0755 \
"$overlay_dir/usr/local/bin/sloptrap-entrypoint" \
"$overlay_dir/usr/local/bin/sloptrap-helperd" \
"$overlay_dir/usr/local/bin/slop-apt" \
"$overlay_dir/usr/local/bin/slopcap" \
"$overlay_dir/usr/local/bin/sloppodman"
local tmp_archive="$archive_path.tmp"
rm -f "$tmp_archive"
if ! run_with_nested_podman_root tar --numeric-owner --one-file-system \
--exclude=./proc \
--exclude=./sys \
--exclude=./dev \
--exclude=./run \
--exclude=./tmp \
--exclude=./workspace \
--exclude=./codex \
--exclude=./usr/local/bin/sloptrap-entrypoint \
--exclude=./usr/local/bin/sloptrap-helperd \
--exclude=./usr/local/bin/slop-apt \
--exclude=./usr/local/bin/slopcap \
--exclude=./usr/local/bin/sloppodman \
-cf "$tmp_archive" -C / .; then
rm -f "$tmp_archive"
return 1
fi
if ! tar --numeric-owner -rf "$tmp_archive" -C "$overlay_dir" .; then
rm -f "$tmp_archive"
return 1
fi
mv "$tmp_archive" "$archive_path"
printf '%s\n' "$desired_stamp" >"$stamp_path"
printf '%s\n' "$archive_path"
}
import_recursive_parent_image() {
local engine_name=${CONTAINER_ENGINE##*/}
local archive_path=${SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE:-}
case "$engine_name" in
sloppodman|sloppodman*|.sloppodman*)
;;
*)
return 1
;;
esac
capability_list_contains "${SLOPTRAP_ACTIVE_CAPABILITIES:-}" "nested-podman" || return 1
if [[ -n $archive_path ]]; then
[[ -r $archive_path ]] || return 1
else
if ! archive_path=$(prepare_recursive_parent_image_archive); then
return 1
fi
fi
if ! "$CONTAINER_ENGINE" import \
--change 'ENTRYPOINT ["/usr/local/bin/sloptrap-entrypoint"]' \
--change 'WORKDIR /workspace' \
--change 'ENV SHELL=/bin/bash' \
--change 'ENV HOME=/home/sloptrap' \
--change "LABEL $SLOPTRAP_IMAGE_LABEL" \
"$archive_path" \
"$SLOPTRAP_IMAGE_NAME"; then
return 1
fi
write_capability_build_stamp
return 0
}
build_if_missing() { build_if_missing() {
ensure_capability_trust ensure_capability_trust
if $DRY_RUN; then if $DRY_RUN; then
@@ -2888,6 +3151,12 @@ build_if_missing() {
fi fi
return 0 return 0
fi fi
if load_recursive_parent_image; then
return 0
fi
if import_recursive_parent_image; then
return 0
fi
build_image build_image
} }
@@ -2934,6 +3203,7 @@ prune_sloptrap_images() {
run_codex_command() { run_codex_command() {
local -a extra_args=("$@") local -a extra_args=("$@")
ensure_codex_storage_paths ensure_codex_storage_paths
prepare_recursive_parent_image_preload || true
local -a cmd=("${BASE_CONTAINER_CMD[@]}" "$SLOPTRAP_IMAGE_NAME" "codex") local -a cmd=("${BASE_CONTAINER_CMD[@]}" "$SLOPTRAP_IMAGE_NAME" "codex")
if [[ ${#CODEX_ARGS_ARRAY[@]} -gt 0 ]]; then if [[ ${#CODEX_ARGS_ARRAY[@]} -gt 0 ]]; then
cmd+=("${CODEX_ARGS_ARRAY[@]}") cmd+=("${CODEX_ARGS_ARRAY[@]}")
@@ -2955,6 +3225,7 @@ run_codex() {
run_login_target() { run_login_target() {
ensure_codex_storage_paths ensure_codex_storage_paths
prepare_recursive_parent_image_preload || true
if ! $DRY_RUN; then if ! $DRY_RUN; then
status_line "Login %s\n" "$SLOPTRAP_IMAGE_NAME" status_line "Login %s\n" "$SLOPTRAP_IMAGE_NAME"
fi fi
@@ -2964,6 +3235,7 @@ run_login_target() {
run_shell_target() { run_shell_target() {
ensure_codex_storage_paths ensure_codex_storage_paths
prepare_recursive_parent_image_preload || true
if ! $DRY_RUN; then if ! $DRY_RUN; then
status_line "Shell %s\n" "$SLOPTRAP_IMAGE_NAME" status_line "Shell %s\n" "$SLOPTRAP_IMAGE_NAME"
fi fi

View File

@@ -98,6 +98,10 @@ verify_secret_mounts() {
} }
if [[ ${1-} == "image" && ${2-} == "inspect" && ${FAKE_PODMAN_INSPECT_FAIL:-0} == 1 ]]; then 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" echo "FAKE PODMAN (fail): $*" >>"$FAKE_PODMAN_LOG"
exit 1 exit 1
fi fi
@@ -510,9 +514,15 @@ EOF
if ! grep -q -- "-v ${codex_root}/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then if ! grep -q -- "-v ${codex_root}/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then
record_failure "recursive_slopsloptrap: missing recursive auth bind mount" record_failure "recursive_slopsloptrap: missing recursive auth bind mount"
fi fi
if ! grep -q -- "/capabilities/podman-preload:/codex/capabilities/podman/preload:Z" "$STUB_LOG"; then
record_failure "recursive_slopsloptrap: missing recursive preload bind mount"
fi
if ! grep -q -- "-v ${codex_root}/sloptrap/state/" "$STUB_LOG"; then if ! grep -q -- "-v ${codex_root}/sloptrap/state/" "$STUB_LOG"; then
record_failure "recursive_slopsloptrap: missing recursive state bind mount" record_failure "recursive_slopsloptrap: missing recursive state bind mount"
fi fi
if ! grep -q -- "SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE=/codex/capabilities/podman/preload/slopsloptrap-sloptrap-image.tar" "$STUB_LOG"; then
record_failure "recursive_slopsloptrap: missing recursive preload archive environment"
fi
if grep -q -- "-v ${codex_root}/.codex/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then if grep -q -- "-v ${codex_root}/.codex/auth.json:/codex/auth.json:Z" "$STUB_LOG"; then
record_failure "recursive_slopsloptrap: should not fall back to CODEX_HOME/.codex in recursive mode" record_failure "recursive_slopsloptrap: should not fall back to CODEX_HOME/.codex in recursive mode"
fi fi
@@ -527,6 +537,9 @@ EOF
if [[ -z $first_run || $first_run == *" login" ]]; then if [[ -z $first_run || $first_run == *" login" ]]; then
record_failure "recursive_slopsloptrap: recursive auth should avoid login target" record_failure "recursive_slopsloptrap: recursive auth should avoid login target"
fi fi
if ! grep -q -- "FAKE PODMAN: save -o " "$STUB_LOG"; then
record_failure "recursive_slopsloptrap: should export the parent image for recursive preload"
fi
if [[ $first_run != *"/bin/bash"* ]]; then if [[ $first_run != *"/bin/bash"* ]]; then
record_failure "recursive_slopsloptrap: shell target did not reach child container run" record_failure "recursive_slopsloptrap: shell target did not reach child container run"
fi fi
@@ -540,6 +553,102 @@ EOF
rm -rf "$temp_root" rm -rf "$temp_root"
} }
run_recursive_parent_image_fallback() {
printf '==> recursive_parent_image_fallback\n'
local temp_root helper_bin scenario_dir archive_path tool_log
local inner_podman_root inner_podman_runroot inner_runtime_dir
temp_root=$(mktemp -d)
helper_bin="$temp_root/bin"
scenario_dir="$temp_root/fallback-repo"
archive_path="$scenario_dir/parent-runtime.tar"
tool_log="$temp_root/tool.log"
inner_podman_root="$temp_root/podman-storage"
inner_podman_runroot="$temp_root/podman-run"
inner_runtime_dir="$temp_root/podman-runtime"
mkdir -p "$helper_bin" "$scenario_dir" "$inner_podman_root" "$inner_podman_runroot" "$inner_runtime_dir"
: >"$tool_log"
cat >"$scenario_dir/.sloptrap" <<'EOF'
name=fallback-repo
capabilities=nested-podman
EOF
printf 'archive\n' >"$archive_path"
if ! extract_embedded_helper "sloppodman" "$helper_bin/sloppodman"; then
record_failure "recursive_parent_image_fallback: failed to extract sloppodman helper"
rm -rf "$temp_root"
return
fi
cat >"$helper_bin/podman" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
printf 'podman %s\n' "$*" >>"$TEST_TOOL_LOG"
args=("$@")
idx=0
loaded_flag="${TEST_TOOL_LOG}.loaded"
while (( idx < ${#args[@]} )); do
if [[ ${args[$idx]} == "image" ]] && (( idx + 1 < ${#args[@]} )) && [[ ${args[$((idx + 1))]} == "inspect" ]]; then
if [[ -f $loaded_flag ]]; then
exit 0
fi
exit 1
fi
if [[ ${args[$idx]} == "load" ]]; then
: >"$loaded_flag"
exit 0
fi
((idx+=1))
done
exit 0
EOF
cat >"$helper_bin/setpriv" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
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/sloppodman" "$helper_bin/podman" "$helper_bin/setpriv"
if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" HOME="$temp_root/home" CODEX_HOME="$temp_root/home" \
SLOPTRAP_CONTAINER_ENGINE="sloppodman" \
SLOPTRAP_ACTIVE_CAPABILITIES="nested-podman" \
SLOPTRAP_WORKDIR="$scenario_dir" \
SLOPTRAP_RECURSIVE_PARENT_IMAGE_ARCHIVE="$archive_path" \
SLOPTRAP_INNER_PODMAN_ROOT="$inner_podman_root" \
SLOPTRAP_INNER_PODMAN_RUNROOT="$inner_podman_runroot" \
XDG_RUNTIME_DIR="$inner_runtime_dir" \
"$SLOPTRAP_BIN" --trust-capabilities "$scenario_dir" build-if-missing >/dev/null 2>&1; then
record_failure "recursive_parent_image_fallback: build-if-missing exited non-zero"
rm -rf "$temp_root"
return
fi
if grep -q -- 'podman --root .* build ' "$tool_log"; then
record_failure "recursive_parent_image_fallback: fallback should avoid podman build"
fi
if ! grep -q -- "podman --root $inner_podman_root --runroot $inner_podman_runroot --storage-driver vfs --cgroup-manager cgroupfs --events-backend file load -i $archive_path" "$tool_log"; then
record_failure "recursive_parent_image_fallback: fallback did not load the parent archive into the nested store"
fi
rm -rf "$temp_root"
}
run_project_state_isolation() { run_project_state_isolation() {
local scenario_a scenario_b local scenario_a scenario_b
scenario_a=$(cd "$TEST_ROOT/resume_target" && pwd -P) scenario_a=$(cd "$TEST_ROOT/resume_target" && pwd -P)
@@ -885,6 +994,9 @@ run_capability_profiles() {
if ! grep -q -- "SLOPTRAP_HOST_GID=$(id -g)" "$STUB_LOG"; then if ! grep -q -- "SLOPTRAP_HOST_GID=$(id -g)" "$STUB_LOG"; then
record_failure "capability_profiles: host gid environment missing" record_failure "capability_profiles: host gid environment missing"
fi fi
if ! grep -q -- "SLOPTRAP_HOST_USER=$(id -un)" "$STUB_LOG"; then
record_failure "capability_profiles: host user environment missing"
fi
if ! grep -q -- "SLOPTRAP_INNER_PODMAN_HOST_NETWORK=1" "$STUB_LOG"; then if ! grep -q -- "SLOPTRAP_INNER_PODMAN_HOST_NETWORK=1" "$STUB_LOG"; then
record_failure "capability_profiles: inner podman host-network mirror flag missing" record_failure "capability_profiles: inner podman host-network mirror flag missing"
fi fi
@@ -938,11 +1050,11 @@ run_embedded_capability_helpers() {
return return
fi fi
cat >"$helper_bin/podman" <<'EOF' cat >"$helper_bin/podman" <<'EOF'
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
printf 'podman-env BUILDAH_ISOLATION=%s CONTAINERS_STORAGE_CONF=%s CONTAINERS_CONF=%s\n' \ printf 'podman-env BUILDAH_ISOLATION=%s _CONTAINERS_USERNS_CONFIGURED=%s CONTAINERS_STORAGE_CONF=%s CONTAINERS_CONF=%s\n' \
"${BUILDAH_ISOLATION:-}" "${CONTAINERS_STORAGE_CONF:-}" "${CONTAINERS_CONF:-}" >>"$TEST_TOOL_LOG" "${BUILDAH_ISOLATION:-}" "${_CONTAINERS_USERNS_CONFIGURED:-}" "${CONTAINERS_STORAGE_CONF:-}" "${CONTAINERS_CONF:-}" >>"$TEST_TOOL_LOG"
printf 'podman %s\n' "$*" >>"$TEST_TOOL_LOG" printf 'podman %s\n' "$*" >>"$TEST_TOOL_LOG"
exit 0 exit 0
EOF EOF
@@ -1086,6 +1198,9 @@ EOF
if ! grep -q -- 'podman-env BUILDAH_ISOLATION=chroot ' "$tool_log"; then if ! grep -q -- 'podman-env BUILDAH_ISOLATION=chroot ' "$tool_log"; then
record_failure "embedded_capability_helpers: sloppodman did not set BUILDAH_ISOLATION=chroot" record_failure "embedded_capability_helpers: sloppodman did not set BUILDAH_ISOLATION=chroot"
fi fi
if ! grep -q -- '_CONTAINERS_USERNS_CONFIGURED=done ' "$tool_log"; then
record_failure "embedded_capability_helpers: sloppodman did not mark nested podman as already userns-configured"
fi
if [[ ! -f $inner_runtime_dir/config/containers/storage.conf ]] \ if [[ ! -f $inner_runtime_dir/config/containers/storage.conf ]] \
|| [[ ! -f $inner_runtime_dir/config/containers/containers.conf ]]; then || [[ ! -f $inner_runtime_dir/config/containers/containers.conf ]]; then
record_failure "embedded_capability_helpers: sloppodman did not materialize its container config files" record_failure "embedded_capability_helpers: sloppodman did not materialize its container config files"
@@ -1115,7 +1230,32 @@ case "${1-}" in
;; ;;
esac esac
EOF EOF
chmod +x "$helper_bin/id" cat >"$temp_root/entrypoint-helperd" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
exit 0
EOF
chmod +x "$helper_bin/id" "$temp_root/entrypoint-helperd"
local entry_subuid entry_subgid
entry_subuid="$temp_root/entry-subuid"
entry_subgid="$temp_root/entry-subgid"
printf 'sloptrap:100000:65536\n' >"$entry_subuid"
printf 'sloptrap:100000:65536\n' >"$entry_subgid"
if ! TEST_TOOL_LOG="$tool_log" PATH="$helper_bin:$PATH" SLOPTRAP_ACTIVE_CAPABILITIES="nested-podman" \
SLOPTRAP_HOST_UID="1337" SLOPTRAP_HOST_GID="1337" SLOPTRAP_HOST_USER="$caller_user" \
SLOPTRAP_PODMAN_SUBUID_FILE="$entry_subuid" SLOPTRAP_PODMAN_SUBGID_FILE="$entry_subgid" \
SLOPTRAP_PODMAN_SUBID_START="200000" SLOPTRAP_PODMAN_SUBID_COUNT="65536" \
SLOPTRAP_PODMAN_SUBGID_START="200000" SLOPTRAP_PODMAN_SUBGID_COUNT="65536" \
SLOPTRAP_HELPERD_BIN="$temp_root/entrypoint-helperd" \
"$helper_bin/sloptrap-entrypoint" true >/dev/null 2>&1; then
record_failure "embedded_capability_helpers: entrypoint did not synthesize subid files for the host user"
fi
if [[ -z $(awk -F: -v account="$caller_user" '$1 == account { print $2 ":" $3 }' "$entry_subuid" 2>/dev/null || true) ]]; then
record_failure "embedded_capability_helpers: entrypoint did not prefer SLOPTRAP_HOST_USER for subuid synthesis"
fi
if [[ -z $(awk -F: -v account="$caller_user" '$1 == account { print $2 ":" $3 }' "$entry_subgid" 2>/dev/null || true) ]]; then
record_failure "embedded_capability_helpers: entrypoint did not prefer SLOPTRAP_HOST_USER for subgid synthesis"
fi
local caller_subuid root_subuid caller_subgid root_subgid local caller_subuid root_subuid caller_subgid root_subgid
local helper_subuid_file helper_subgid_file local helper_subuid_file helper_subgid_file
helper_subuid_file="$temp_root/helper-subuid" helper_subuid_file="$temp_root/helper-subuid"
@@ -1270,6 +1410,7 @@ run_resume_omits_runtime_context
run_auth_file_mount run_auth_file_mount
run_codex_home_override run_codex_home_override
run_recursive_slopsloptrap run_recursive_slopsloptrap
run_recursive_parent_image_fallback
run_project_state_isolation run_project_state_isolation
run_auto_login_empty_auth run_auto_login_empty_auth
run_codex_symlink_home run_codex_symlink_home