Files
archy/scripts/test-terminal-backend-isolated.sh
T

86 lines
4.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Inspected control plane only. No compilation/fallback and no host test execution.
set -euo pipefail
CONTROL=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
[[ $# == 0 && ${ARCHY_TEST_ISOLATOR:-} == podman && ${ARCHY_TEST_TERMINAL_FIXTURE:-} == 1 ]] || exit 2
[[ ${ARCHY_TEST_CLOUD_COMPILE_ONLY:-0} == 0 && -z ${ARCHY_TEST_ARTIFACT_EXPORT:-} && -z ${ARCHY_TEST_CLOUD_FIXTURE_CONTAINER:-} ]] || exit 2
[[ ${ARCHY_TEST_PACKAGE:-archipelago} == archipelago ]] || exit 2
REPO=$(realpath -e "${ARCHY_TEST_REPO:?Exact source export required}")
[[ -d "$REPO/core" && ! -e "$REPO/.git" && ! -L "$REPO/.git" ]] || exit 2
image=${ARCHY_TEST_IMAGE:?Immutable compiler identity required}
runtime_image=${ARCHY_TEST_TERMINAL_RUNTIME_IMAGE:?Immutable tmux/browser runtime required}
[[ "$image" =~ ^(sha256:)?[a-f0-9]{64}$ && "$runtime_image" =~ ^(sha256:)?[a-f0-9]{64}$ ]] || exit 2
reuse=$(realpath -e "${ARCHY_TEST_REUSE_ARTIFACT:?Precompiled exact artifact required; no Cargo fallback}")
out=$(realpath -e "${ARCHY_TEST_EVIDENCE_DIR:?Existing empty receipt directory required}")
[[ -d "$out" && -z $(find "$out" -mindepth 1 -maxdepth 1 -print -quit) ]] || exit 2
podman image exists "$runtime_image"
# Inherited image volumes must not introduce undeclared writable storage.
volumes=$(podman image inspect "$runtime_image" --format '{{json .Config.Volumes}}')
[[ "$volumes" == null || "$volumes" == '{}' ]] || exit 2
mkdir "$out/screenshots"
artifacts=$(mktemp -d /tmp/archy-terminal-test.XXXXXXXX)
cleanup() {
local status=$? cid exists
trap - EXIT INT TERM
set +e
if [[ -s "$artifacts/runtime.cid" ]]; then
cid=$(<"$artifacts/runtime.cid")
if [[ "$cid" =~ ^[a-f0-9]{64}$ ]]; then
printf '%s\n' "$cid" > "$out/owned.id"
timeout --kill-after=2s 10s podman rm -f "$cid" > "$out/cleanup.log" 2>&1 || status=1
podman container exists "$cid"; exists=$?
[[ "$exists" == 1 ]] || status=1
else status=1; fi
fi
podman ps -aq --no-trunc | sort > "$out/containers.after" || status=1
cmp "$out/containers.before" "$out/containers.after" || status=1
rm -rf -- "$artifacts" || status=1
printf '%s\n' "$status" > "$out/outer.exit"
exit "$status"
}
trap cleanup EXIT
trap 'exit 143' TERM
trap 'exit 130' INT
podman ps -aq --no-trunc | sort > "$out/containers.before"
: > "$artifacts/test-binary"
: > "$artifacts/empty-resolv.conf"
: > "$artifacts/host-only-canary"
python3 "$CONTROL/scripts/cloud-test-artifact.py" reuse "$REPO" "$image" "$runtime_image" "$artifacts/test-binary" "$reuse" v1
chmod 0500 "$artifacts/test-binary"
sha256sum "$artifacts/test-binary" | cut -d' ' -f1 > "$out/binary.sha256"
host_netns=$(readlink /proc/self/ns/net)
host_pidns=$(readlink /proc/self/ns/pid)
host_ipcns=$(readlink /proc/self/ns/ipc)
podman create --cidfile "$artifacts/runtime.cid" --name "archy-terminal-execute-${artifacts##*.}" --pull=never \
--network=none --pid=private --ipc=private --no-hosts --http-proxy=false \
--log-driver=none --timeout=120 --cpus=2 --memory=3g --memory-swap=3g --pids-limit=256 \
--ulimit fsize=1073741824:1073741824 --cap-drop=all --security-opt=no-new-privileges --read-only \
--tmpfs /tmp:rw,notmpcopyup,size=128m --tmpfs /root:rw,notmpcopyup,size=16m --tmpfs /run:rw,notmpcopyup,size=16m \
--tmpfs /var/lib/archipelago:rw,notmpcopyup,size=64m --tmpfs /var/lib/containers:rw,notmpcopyup,size=16m \
--volume "$REPO:/workspace:ro" --volume "$artifacts/test-binary:/test-binary:ro" \
--volume "$artifacts/empty-resolv.conf:/etc/resolv.conf:ro" --volume "$out/screenshots:/out:rw" \
--env HOME=/root --env ARCHY_TEST_ISOLATED=1 --env "ARCHY_TEST_HOST_CANARY=$artifacts/host-only-canary" \
--workdir /workspace/core --entrypoint /bin/sh "$runtime_image" -ec '
[ "$(readlink /proc/self/ns/net)" != "$1" ] || { echo "Host network namespace leaked"; exit 2; }
[ "$(readlink /proc/self/ns/pid)" != "$2" ] || { echo "Host PID namespace leaked"; exit 2; }
[ "$(readlink /proc/self/ns/ipc)" != "$3" ] || { echo "Host IPC namespace leaked"; exit 2; }
target=api::handler::terminal_transport_tests::actual_handler_private_tmux_history_and_reconnect
/test-binary --list --ignored --exact "$target" > /tmp/test-list
grep -Fx "$target: test" /tmp/test-list
[ "$(grep -c ": test$" /tmp/test-list)" = 1 ]
exec /test-binary --test-threads=1 --ignored --exact "$target" --nocapture
' terminal-netns "$host_netns" "$host_pidns" "$host_ipcns" > "$out/create.log" 2>&1
cid=$(<"$artifacts/runtime.cid")
[[ "$cid" =~ ^[a-f0-9]{64}$ ]] || exit 2
podman inspect "$cid" > "$out/container.inspect.json"
date -u +%FT%TZ > "$out/start"
set +e
timeout --signal=TERM --kill-after=10s 140s podman start --attach "$cid" 2>&1 |
python3 "$CONTROL/scripts/limit-test-output.py" | tee "$out/runtime.log"
result=$?
set -e
printf '%s\n' "$result" > "$out/test.exit"
date -u +%FT%TZ > "$out/end"
[[ "$result" == 0 ]] || exit "$result"
grep -F 'test result: ok. 1 passed; 0 failed; 0 ignored;' "$out/runtime.log" >/dev/null