diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 375ec46dd0..159115b31f 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -201,11 +201,12 @@ jobs: mise x -- e2e/run.sh \ --vm ubuntu-26-04 \ --with podman-rootless \ - --host-cli-bin "$OPENSHELL_BIN" \ + --tests-in-vm \ + --cli-bin "$OPENSHELL_BIN" \ --gateway-bin "$OPENSHELL_GATEWAY_BIN" \ --sandbox-bin "$OPENSHELL_SANDBOX_BIN" \ --gateway-config e2e/configs/gateway/podman.toml \ - --suite smoke + --features e2e_podman e2e-vm: name: E2E (rust-vm-${{ matrix.suite }}) diff --git a/e2e/run.sh b/e2e/run.sh index f3fd5e131f..068623c42f 100755 --- a/e2e/run.sh +++ b/e2e/run.sh @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 # Build the current checkout, run its gateway on the host or in a disposable -# Nix test guest, and execute host-side E2E tests against that gateway. +# Nix test guest, and execute E2E tests against that gateway. set -Eeuo pipefail @@ -25,7 +25,9 @@ Usage: Options: --vm DISTRO Run the gateway in a Nix test guest --with CONFIG Apply a Nix test-guest configuration; repeatable - --host-cli-bin PATH Use a prebuilt host openshell CLI instead of building it + --tests-in-vm Prebuild Linux Rust E2E test binaries on the host, + copy them into the Nix test guest, and run them there + --cli-bin PATH Use a prebuilt openshell CLI instead of building it --gateway-bin PATH Use a prebuilt openshell-gateway instead of building it --sandbox-bin PATH Use a prebuilt openshell-sandbox instead of building it --gateway-config PATH @@ -36,7 +38,9 @@ Options: Omit --vm and --with to run the gateway on the host. Supplying --with without --vm selects Fedora for the Podman driver and Ubuntu otherwise. Set -OPENSHELL_E2E_KEEP=1 to retain state. +OPENSHELL_CLI_BIN for a default --cli-bin; otherwise --tests-in-vm +cross-builds the guest CLI with cargo-zigbuild. Set OPENSHELL_E2E_KEEP=1 to +retain state. EOF } @@ -97,10 +101,11 @@ catalog_has_entry() { vm= gateway_config= gateway_bin= -host_cli_bin= +cli_bin= sandbox_bin= e2e_features=e2e suite_name= +tests_in_vm=0 with_configurations=() while [ "$#" -gt 0 ]; do @@ -115,9 +120,13 @@ while [ "$#" -gt 0 ]; do with_configurations+=("$2") shift 2 ;; - --host-cli-bin) + --tests-in-vm) + tests_in_vm=1 + shift + ;; + --cli-bin) require_value "$1" "$#" "${2:-}" - host_cli_bin="$(resolve_file "$2")" || die "--host-cli-bin does not name a file: $2" + cli_bin="$(resolve_file "$2")" || die "--cli-bin does not name a file: $2" shift 2 ;; --gateway-bin) @@ -161,11 +170,14 @@ fi if ! command -v python3 >/dev/null 2>&1; then die "python3 is required" fi +if ! command -v mise >/dev/null 2>&1; then + die "mise is required to build OpenShell" +fi gateway_config_source=${gateway_config} if ! gateway_config="$(resolve_file "${gateway_config_source}")"; then die "gateway config does not exist: ${gateway_config_source}" fi -gateway_driver="$(python3 -c ' +gateway_driver="$(mise x -- python3 -c ' import sys, tomllib print(tomllib.load(open(sys.argv[1], "rb"))["openshell"]["gateway"]["compute_drivers"][0]) ' "${gateway_config}")" @@ -221,15 +233,17 @@ if [ "${mode}" = vm ]; then die "unknown VM configuration in the Nix test-guest catalog: ${configuration}" fi done +elif [ "${tests_in_vm}" -eq 1 ]; then + die "--tests-in-vm requires --vm" +fi +if [ -z "${cli_bin}" ] && [ -n "${OPENSHELL_CLI_BIN:-}" ]; then + cli_bin="$(resolve_file "${OPENSHELL_CLI_BIN}")" || + die "OPENSHELL_CLI_BIN does not name a file: ${OPENSHELL_CLI_BIN}" fi - gateway_ready_timeout=${OPENSHELL_E2E_GATEWAY_READY_TIMEOUT:-600} if [[ ! ${gateway_ready_timeout} =~ ^[1-9][0-9]*$ ]]; then die "OPENSHELL_E2E_GATEWAY_READY_TIMEOUT must be a positive integer" fi -if ! command -v mise >/dev/null 2>&1; then - die "mise is required to build OpenShell" -fi if ! command -v openssl >/dev/null 2>&1; then die "OpenSSL is required to generate sandbox JWT keys" fi @@ -260,12 +274,28 @@ target_dir="$(e2e_cargo_target_dir "${ROOT}" mise x -- cargo)" ensure_build_nofile_limit -if [ -n "${host_cli_bin}" ]; then - echo "==> Using host openshell CLI: ${host_cli_bin}" +if [ "${tests_in_vm}" -eq 1 ]; then + if [ -n "${cli_bin}" ]; then + echo "==> Using Linux guest openshell CLI: ${cli_bin}" + else + echo "==> Building Linux guest openshell CLI (${linux_musl_target})" + mise x -- rustup target add "${linux_musl_target}" >/dev/null + ( + export CXXSTDLIB=c++ + mise x -- cargo zigbuild "${cargo_jobs[@]+"${cargo_jobs[@]}"}" \ + --release \ + --target "${linux_musl_target}" \ + -p openshell-cli \ + --bin openshell + ) + cli_bin="${target_dir}/${linux_musl_target}/release/openshell" + fi +elif [ -n "${cli_bin}" ]; then + echo "==> Using host openshell CLI: ${cli_bin}" else echo "==> Building native host openshell CLI" mise x -- cargo build "${cargo_jobs[@]+"${cargo_jobs[@]}"}" -p openshell-cli --bin openshell - host_cli_bin="${target_dir}/debug/openshell" + cli_bin="${target_dir}/debug/openshell" fi if [ -n "${sandbox_bin}" ]; then @@ -324,11 +354,13 @@ else fi fi -expected_binaries=("${host_cli_bin}" "${linux_sandbox_bin}") -if [ "${mode}" = host ]; then - expected_binaries+=("${host_gateway_bin}") +expected_binaries=("${linux_sandbox_bin}") +if [ "${tests_in_vm}" -eq 1 ]; then + expected_binaries+=("${cli_bin}" "${guest_gateway_bin}") +elif [ "${mode}" = host ]; then + expected_binaries+=("${cli_bin}" "${host_gateway_bin}") else - expected_binaries+=("${guest_gateway_bin}") + expected_binaries+=("${cli_bin}" "${guest_gateway_bin}") fi for binary in "${expected_binaries[@]}"; do if [ ! -x "${binary}" ]; then @@ -349,6 +381,8 @@ supervisor_archive="${run_dir}/supervisor.tar" mkdir -p "${supervisor_rootfs}" install -m 0555 "${linux_sandbox_bin}" "${supervisor_rootfs}/openshell-sandbox" tar -C "${supervisor_rootfs}" -cf "${supervisor_archive}" openshell-sandbox +chmod 0644 "${supervisor_archive}" +test_artifacts=() child_pid= runtime_log= keep=0 @@ -370,6 +404,65 @@ start_child() { child_pid=$! } +build_e2e_test_artifacts() { + local build_log="${run_dir}/e2e-test-build.jsonl" + local artifacts_file="${run_dir}/e2e-test-artifacts.txt" + local build_args=( + mise x -- cargo zigbuild + --manifest-path e2e/rust/Cargo.toml + --features "${e2e_features}" + --target "${linux_gateway_zig_target}" + --message-format=json + ) + if [ -n "${suite_name}" ]; then + build_args+=(--test "${suite_name}") + else + build_args+=(--tests) + fi + + echo "==> Prebuilding E2E test artifacts for guest execution (${linux_gateway_rust_target})" + if ! ( + eval "$( + "${ROOT}/tasks/scripts/setup-zig-cc-wrapper.sh" \ + "${linux_gateway_zig_target}" \ + "${linux_gateway_zig_target}" \ + "${target_dir}/zig-gnu-wrapper/e2e-tests" + )" + "${build_args[@]}" + ) >"${build_log}"; then + echo "=== E2E test artifact build output ===" >&2 + cat "${build_log}" >&2 + echo "=== end E2E test artifact build output ===" >&2 + return 1 + fi + python3 - "${build_log}" >"${artifacts_file}" <<'PY' +import json +import sys + +for line in open(sys.argv[1], encoding="utf-8"): + try: + message = json.loads(line) + except json.JSONDecodeError: + continue + if message.get("reason") != "compiler-artifact": + continue + target = message.get("target") or {} + if "test" not in (target.get("kind") or []): + continue + executable = message.get("executable") + if executable: + print(executable) +PY + while IFS= read -r artifact; do + if [ -n "${artifact}" ]; then + test_artifacts+=("${artifact}") + fi + done <"${artifacts_file}" + if [ "${#test_artifacts[@]}" -eq 0 ]; then + die "cargo did not report any E2E test executables" + fi +} + # Invoked by the EXIT trap through cleanup. # shellcheck disable=SC2329 stop_child() { @@ -416,6 +509,10 @@ trap cleanup EXIT trap 'exit 130' INT trap 'exit 143' TERM +if [ "${tests_in_vm}" -eq 1 ]; then + build_e2e_test_artifacts +fi + jwt_source_dir="${run_dir}/gateway-jwt" host_runtime_dir= if [ "${mode}" = host ]; then @@ -439,7 +536,7 @@ gateway_name="openshell-e2e-${mode}-${host_port}" gateway_endpoint="http://127.0.0.1:${host_port}" export OPENSHELL_GATEWAY_ENDPOINT="${gateway_endpoint}" export OPENSHELL_GATEWAY="${gateway_name}" -export OPENSHELL_BIN="${host_cli_bin}" +export OPENSHELL_BIN="${cli_bin}" if [ "${mode}" = host ]; then case "${gateway_driver}" in @@ -473,6 +570,23 @@ else guest_launcher="${run_dir}/launch-gateway.sh" guest_launcher_path=/home/openshell/.cache/openshell-e2e/bin/launch-gateway guest_supervisor_archive_path=/home/openshell/.cache/openshell-e2e/supervisor.tar + guest_test_artifact_dir=/home/openshell/.cache/openshell-e2e/tests + guest_test_manifest="${run_dir}/test-artifacts.txt" + guest_test_manifest_path=/home/openshell/.cache/openshell-e2e/test-artifacts.txt + if [ "${tests_in_vm}" -eq 1 ]; then + : >"${guest_test_manifest}" + for artifact in "${test_artifacts[@]}"; do + printf '%s/%s\n' "${guest_test_artifact_dir}" "${artifact##*/}" >>"${guest_test_manifest}" + done + chmod 0644 "${guest_test_manifest}" + fi + guest_e2e_network_name="$(mise x -- python3 - "${gateway_config}" <<'PY' +import sys, tomllib + +config = tomllib.load(open(sys.argv[1], "rb")) +print(config.get("openshell", {}).get("drivers", {}).get("podman", {}).get("network_name", "openshell-e2e")) +PY +)" config_payload="$(base64 <"${gateway_config}" | tr -d '\r\n')" jwt_signing_payload="$(base64 <"${jwt_source_dir}/signing.pem" | tr -d '\r\n')" jwt_public_payload="$(base64 <"${jwt_source_dir}/public.pem" | tr -d '\r\n')" @@ -524,13 +638,178 @@ podman) esac report_timing "${gateway_driver} supervisor import" "\${phase_started_at}" cd /home/openshell + +if [ '${tests_in_vm}' = 1 ]; then + gateway_log=\${state_root}/gateway.log + gateway_pid_file=\${state_root}/gateway.pid + gateway_args_file=\${state_root}/gateway.args + spiffe_root=\${state_root}/spiffe + mkdir -p "\${spiffe_root}" "${guest_test_artifact_dir}" + + toml_string() { + python3 - "\$1" <<'PY' +import json +import sys + +print(json.dumps(sys.argv[1])) +PY + } + + pick_free_port() { + python3 - <<'PY' +import socket + +sock = socket.socket() +sock.bind(("0.0.0.0", 0)) +print(sock.getsockname()[1]) +sock.close() +PY + } + + insert_podman_config_key() { + local key=\$1 + local value=\$2 + + python3 - "\${config_path}" "\${key}" "\${value}" <<'PY' +import pathlib +import sys + +path = pathlib.Path(sys.argv[1]) +key = sys.argv[2] +value = sys.argv[3] +section = "[openshell.drivers.podman]" +lines = path.read_text(encoding="utf-8").splitlines() +try: + start = next(index for index, line in enumerate(lines) if line.strip() == section) +except StopIteration: + raise SystemExit(f"{section} not found in {path}") +end = len(lines) +for index in range(start + 1, len(lines)): + if lines[index].lstrip().startswith("["): + end = index + break +for line in lines[start + 1:end]: + if line.split("=", 1)[0].strip() == key: + raise SystemExit(0) +lines.insert(end, f"{key} = {value}") +path.write_text("\\n".join(lines) + "\\n", encoding="utf-8") +PY + } + + write_gateway_args_file() { + : >"\${gateway_args_file}" + for arg in "\$@"; do + printf '%s\0' "\${arg}" >>"\${gateway_args_file}" + done + } + + stop_gateway() { + local gateway_pid= + if [ -f "\${gateway_pid_file}" ]; then + gateway_pid=\$(cat "\${gateway_pid_file}" 2>/dev/null || true) + fi + if [ -n "\${gateway_pid}" ] && kill -0 "\${gateway_pid}" 2>/dev/null; then + kill "\${gateway_pid}" 2>/dev/null || true + for _ in \$(seq 1 60); do + kill -0 "\${gateway_pid}" 2>/dev/null || break + sleep 0.5 + done + kill -KILL "\${gateway_pid}" 2>/dev/null || true + wait "\${gateway_pid}" 2>/dev/null || true + fi + rm -f "\${gateway_pid_file}" 2>/dev/null || true + } + + cleanup_guest_tests() { + local status=\$? + trap - EXIT INT TERM + stop_gateway + if [ "\${status}" -ne 0 ] && [ -f "\${gateway_log}" ]; then + echo "=== guest gateway log ===" >&2 + cat "\${gateway_log}" >&2 + echo "=== end guest gateway log ===" >&2 + fi + exit "\${status}" + } + trap cleanup_guest_tests EXIT + trap 'exit 130' INT + trap 'exit 143' TERM + + export OPENSHELL_BIN=/usr/local/bin/openshell + export OPENSHELL_GATEWAY_ENDPOINT=http://127.0.0.1:${guest_port} + export OPENSHELL_GATEWAY=openshell-e2e-vm-${guest_port} + export OPENSHELL_PROVISION_TIMEOUT=\${OPENSHELL_PROVISION_TIMEOUT:-300} + export OPENSHELL_E2E_TESTS_IN_VM=1 + if [ '${gateway_driver}' = podman ]; then + export CONTAINER_ENGINE=podman + export OPENSHELL_E2E_DRIVER=podman + export OPENSHELL_E2E_NETWORK_NAME='${guest_e2e_network_name}' + export OPENSHELL_E2E_SANDBOX_NAMESPACE='${guest_e2e_network_name}' + export XDG_RUNTIME_DIR="\${XDG_RUNTIME_DIR:-/run/user/\$(id -u)}" + export OPENSHELL_PODMAN_SOCKET="\${XDG_RUNTIME_DIR}/podman/podman.sock" + export CONTAINER_HOST="unix://\${OPENSHELL_PODMAN_SOCKET}" + export OPENSHELL_E2E_CONTAINER_ENGINE_UNSET_XDG_CONFIG_HOME=1 + insert_podman_config_key socket_path "\$(toml_string "\${OPENSHELL_PODMAN_SOCKET}")" + insert_podman_config_key enable_bind_mounts true + + provider_spiffe_port=\$(pick_free_port) + export OPENSHELL_E2E_GATEWAY_SPIFFE_SOCKET="\${spiffe_root}/gateway.sock" + export OPENSHELL_GATEWAY_SPIFFE_WORKLOAD_API_SOCKET="\${OPENSHELL_E2E_GATEWAY_SPIFFE_SOCKET}" + export OPENSHELL_E2E_PROVIDER_SPIFFE_LISTEN="0.0.0.0:\${provider_spiffe_port}" + export OPENSHELL_E2E_PROVIDER_SPIFFE_SOCKET="tcp:169.254.1.2:\${provider_spiffe_port}" + insert_podman_config_key provider_spiffe_workload_api_socket "\$(toml_string "\${OPENSHELL_E2E_PROVIDER_SPIFFE_SOCKET}")" + fi + + gateway_args=( + --config "\${config_path}" + --bind-address 127.0.0.1 + --port ${guest_port} + --disable-tls + ) + write_gateway_args_file "\${gateway_args[@]}" + export OPENSHELL_E2E_GATEWAY_BIN=/usr/local/bin/openshell-gateway + export OPENSHELL_E2E_GATEWAY_ARGS_FILE="\${gateway_args_file}" + export OPENSHELL_E2E_GATEWAY_LOG="\${gateway_log}" + export OPENSHELL_E2E_GATEWAY_PID_FILE="\${gateway_pid_file}" + + /usr/local/bin/openshell-gateway "\${gateway_args[@]}" >"\${gateway_log}" 2>&1 & + printf '%s\n' "\$!" >"\${gateway_pid_file}" + + echo "==> Waiting for guest gateway readiness" + gateway_ready=0 + for _ in \$(seq 1 "${gateway_ready_timeout}"); do + if ! kill -0 "\$(cat "\${gateway_pid_file}")" 2>/dev/null; then + echo "ERROR: guest gateway exited before becoming ready" >&2 + exit 1 + fi + if NO_COLOR=1 /usr/local/bin/openshell status >/tmp/openshell-e2e-status.log 2>&1 && + grep -q "Connected" /tmp/openshell-e2e-status.log; then + gateway_ready=1 + break + fi + sleep 1 + done + if [ "\${gateway_ready}" -ne 1 ]; then + echo "ERROR: guest gateway did not become ready" >&2 + cat /tmp/openshell-e2e-status.log >&2 || true + exit 1 + fi + + while IFS= read -r test_bin <&3; do + [ -n "\${test_bin}" ] || continue + echo "==> Running guest E2E artifact: \${test_bin##*/}" + "\${test_bin}" --nocapture Running prebuilt E2E test artifacts inside ${vm} test guest" + "${vm_args[@]}" + exit $? + fi + echo "==> Starting ${vm} test guest gateway at ${gateway_endpoint}" start_child "${ROOT}" "${runtime_log}" "${vm_args[@]}" fi diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 44881e1682..b0941eee08 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -32,6 +32,7 @@ e2e-kubernetes-credential-drivers = ["e2e-kubernetes"] e2e-kubernetes-workspace-managed = ["e2e-kubernetes"] e2e-kubernetes-workspace-operator = ["e2e-kubernetes"] e2e-podman = ["e2e", "e2e-host-gateway", "e2e-local-container-driver"] +e2e_podman = ["e2e-podman"] e2e-podman-gpu = ["e2e-podman", "e2e-gpu"] e2e-oidc-pkce = [] e2e-provider-refresh-keycloak = [] diff --git a/e2e/rust/tests/live_policy_update.rs b/e2e/rust/tests/live_policy_update.rs index 7a1e12923a..4cded2354b 100644 --- a/e2e/rust/tests/live_policy_update.rs +++ b/e2e/rust/tests/live_policy_update.rs @@ -56,6 +56,11 @@ ENV OPENSHELL_POLICY_POLL_INTERVAL_SECS=1 CMD ["sleep", "infinity"] "#; +const SPARSE_POLICY: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../examples/policy-advisor/sandbox-policy.yaml" +)); + // --------------------------------------------------------------------------- // Policy YAML builders // --------------------------------------------------------------------------- @@ -146,6 +151,15 @@ landlock: Ok(file) } +fn write_sparse_policy() -> Result { + let mut file = NamedTempFile::new().map_err(|e| format!("create temp policy file: {e}"))?; + file.write_all(SPARSE_POLICY.as_bytes()) + .map_err(|e| format!("write temp policy file: {e}"))?; + file.flush() + .map_err(|e| format!("flush temp policy file: {e}"))?; + Ok(file) +} + #[cfg(feature = "e2e-docker")] fn write_local_override_image() -> Result { let dir = tempfile::tempdir().map_err(|e| format!("create image context: {e}"))?; @@ -521,18 +535,18 @@ async fn live_policy_update_from_empty_network_policies() { /// no revision remaining `Pending` once the acknowledgement lands. #[tokio::test] async fn initial_sparse_policy_is_acknowledged_as_loaded() { - // Repo-relative path to the sparse network-only policy fixture. - let sparse_policy = concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../examples/policy-advisor/sandbox-policy.yaml" - ); + let sparse_policy = write_sparse_policy().expect("write sparse policy fixture"); + let sparse_policy_path = sparse_policy + .path() + .to_str() + .expect("sparse policy path is not UTF-8"); let mut guard = SandboxGuard::create_keep_with_args( &[ "--name", "e2e-sparse-enrich", "--policy", - sparse_policy, + sparse_policy_path, "--no-tty", ], &["sh", "-c", "echo Ready && sleep infinity"], diff --git a/e2e/rust/tests/transparent_tcp.rs b/e2e/rust/tests/transparent_tcp.rs index 1027654641..aef5a39d87 100644 --- a/e2e/rust/tests/transparent_tcp.rs +++ b/e2e/rust/tests/transparent_tcp.rs @@ -141,6 +141,13 @@ async fn rootless_podman_musl_getaddrinfo_uses_udp_policy_dns() { if !is_e2e_driver("podman") { return; } + if std::env::var_os("OPENSHELL_E2E_TESTS_IN_VM").is_some() { + eprintln!( + "skipping musl DNS probe test in guest prebuilt-artifact mode; \ + restore with a prebuilt probe artifact tracked in #3009" + ); + return; + } let probe = MuslDnsProbe::build().expect("build static musl DNS probe"); let fixture = SupportContainer::start_python( diff --git a/nix/test-guest/configuration/podman-rootless.yml b/nix/test-guest/configuration/podman-rootless.yml index defff095e8..dc99934f74 100644 --- a/nix/test-guest/configuration/podman-rootless.yml +++ b/nix/test-guest/configuration/podman-rootless.yml @@ -26,12 +26,30 @@ - name: Install Ubuntu rootless Podman ansible.builtin.apt: name: + - apparmor - fuse-overlayfs - passt - podman - uidmap state: present + - name: Allow pasta to receive Podman stop signals + ansible.builtin.lineinfile: + path: /etc/apparmor.d/usr.bin.pasta + insertafter: "^ include $" + line: " signal (receive) peer=podman," + state: present + register: pasta_apparmor_profile + + - name: Reload pasta AppArmor profile + ansible.builtin.command: + argv: + - apparmor_parser + - --replace + - /etc/apparmor.d/usr.bin.pasta + when: pasta_apparmor_profile.changed + changed_when: pasta_apparmor_profile.changed + - name: Enable the rootless Podman API socket ansible.builtin.systemd_service: name: podman.socket diff --git a/nix/test-guest/distros/ubuntu-26-04.nix b/nix/test-guest/distros/ubuntu-26-04.nix index 9a9023ce8e..7f37fec138 100644 --- a/nix/test-guest/distros/ubuntu-26-04.nix +++ b/nix/test-guest/distros/ubuntu-26-04.nix @@ -10,7 +10,7 @@ let if architecture == "aarch64" then "sha256-PhE/3UHznhNyk3UXO7KueT+H3G20KU5SUf8kdpcXiLo=" else - "sha256-ncfFNjwBRqCLoMmqg02CwsbfuxxHGtmi8KuhGJ4hvgU="; + "sha256-gZa+nXlYBZy1bGx1yA/fbO6KiIW8FJ6nkdfbHH75MDU="; in { osId = "ubuntu"; diff --git a/nix/test-guest/run.sh b/nix/test-guest/run.sh index 7fbe54062f..9e5d19baef 100644 --- a/nix/test-guest/run.sh +++ b/nix/test-guest/run.sh @@ -49,7 +49,7 @@ preserved_file_mode() { local source_mode if [ "$(uname -s)" = Darwin ]; then - if ! source_mode=$(stat -f '%Lp' "${source_path}"); then + if ! source_mode=$(/usr/bin/stat -f '%Lp' "${source_path}"); then echo "could not determine mode for --copy source: ${source_path}" >&2 return 1 fi diff --git a/tasks/test.toml b/tasks/test.toml index 4e7fa84b34..1bf3ae64fc 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -137,8 +137,12 @@ run = [ ] ["e2e:podman:rootless"] -description = "Run Podman e2e against a rootless Ubuntu 26.04 Nix test guest" -run = "e2e/run.sh --vm ubuntu-26-04 --with podman-rootless --gateway-config e2e/configs/gateway/podman.toml --suite smoke" +description = "Run Rust Podman e2e inside a rootless Ubuntu 26.04 Nix test guest" +run = "e2e/run.sh --vm ubuntu-26-04 --with podman-rootless --tests-in-vm --gateway-config e2e/configs/gateway/podman.toml --features e2e_podman" + +["e2e:podman:rootless:guest-tests"] +description = "Run prebuilt Rust Podman e2e test binaries inside a rootless Ubuntu 26.04 Nix test guest" +run = "e2e/run.sh --vm ubuntu-26-04 --with podman-rootless --tests-in-vm --gateway-config e2e/configs/gateway/podman.toml --features e2e_podman" ["e2e:podman:gpu"] description = "Run GPU e2e against a standalone gateway with the Podman compute driver"