row 227 R3 (#1728): guard the test-case2.sh sandbox, sweep cwd links literally, refuse a long TMPDIR
P1: a failed mktemp, mkdir or output redirect now stops the script with exit 2 before it derives a path, sets a trap or starts anything. The sandbox root is checked to be absolute, a new empty directory this user owns and its own physical path, and its device:inode is recorded. sweep_sandbox and remove_sandbox in scripts/case2/sandbox.sh each refuse unless the root still matches, so an early, late or empty call gets a refusal instead of a sweep of the host. P2: the sweep reads every /proc/<pid>/cwd target with one find and compares it as a string, root or root plus "/", so *, ? and [ in the path are literal. A cwd in a deleted directory under the root matches. P3: a TMPDIR whose tools socket path would pass the 107-byte limit in packages/seat/src/session.mjs is refused at entry with one line naming the limit and both lengths. The length comes from the socket path built on the real sandbox root. scripts/case2/sandbox-check.sh checks the guard and the match against dummy symlinks; nothing in it sends a signal.
This commit is contained in:
1 parent
bd76d43453
commit
abc66a5988
3 files changed
+291
-25
No files matched your search
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env bash
|
||||
# C2-14 (#1728, row 227 R3): checks for scripts/case2/sandbox.sh, the sandbox guard and the literal
|
||||
# cwd match behind the kill sweep in scripts/test-case2.sh. The match runs against dummy symlinks in
|
||||
# a scratch directory. Nothing here sends a signal: kill is a stub that records its arguments, so
|
||||
# even a broken guard could not reach a process. One sweep call and the timing line read every
|
||||
# /proc/<pid>/cwd target, as the suite's sweep does, with a root that holds no process.
|
||||
# Run: bash scripts/case2/sandbox-check.sh (exit 0 when every check holds)
|
||||
set -uo pipefail
|
||||
cd "$(dirname "$0")/../.." || exit 2
|
||||
. scripts/case2/sandbox.sh || exit 2
|
||||
case "${TMPDIR:-/tmp}" in /*) ;; *) echo 'sandbox-check: TMPDIR must be absolute' >&2; exit 2 ;; esac
|
||||
made="$(mktemp -d)" || exit 2
|
||||
case "$made" in /?*) ;; *) exit 2 ;; esac
|
||||
W="$(cd -P -- "$made" && pwd -P)" && WID="$(sandbox_id "$W")" && sandbox_ok "$W" "$WID" || exit 2
|
||||
trap 'remove_sandbox "$W" "$WID"' EXIT
|
||||
kill() { printf '%s\n' "$*" >>"$W/kill-calls"; return 0; }
|
||||
PASS=0 FAIL=0
|
||||
expect() { # expect NAME WANT(0|1) COMMAND...: COMMAND exits 0 when WANT is 0, non-zero when 1
|
||||
local name=$1 want=$2 got
|
||||
shift 2
|
||||
"$@" 2>/dev/null; got=$?
|
||||
if { [ "$want" = 0 ] && [ "$got" = 0 ]; } || { [ "$want" = 1 ] && [ "$got" != 0 ]; }; then
|
||||
PASS=$((PASS+1)); echo "ok $name"
|
||||
else
|
||||
FAIL=$((FAIL+1)); echo "FAIL $name (exit $got)"
|
||||
fi
|
||||
}
|
||||
same() { # same NAME WANT GOT
|
||||
if [ "$2" = "$3" ]; then PASS=$((PASS+1)); echo "ok $1"
|
||||
else FAIL=$((FAIL+1)); printf 'FAIL %s\n want %q\n got %q\n' "$1" "$2" "$3"; fi
|
||||
}
|
||||
|
||||
# The guard. Roots with *, ? and [ are real directories here; the guard takes them as paths.
|
||||
for name in 'a[bc]' 's*t' 'q?x' 'ab' 'sXt' 'qZx' 'keep'; do mkdir -p -- "$W/$name/tmp.example/root"; done
|
||||
R="$W/a[bc]/tmp.example"
|
||||
RID=$(sandbox_id "$R")
|
||||
mkdir -- "$W/real" && ln -s -- "$W/real" "$W/alias"
|
||||
expect 'guard: the created root with its id' 0 sandbox_ok "$R" "$RID"
|
||||
expect 'guard: empty root' 1 sandbox_ok '' "$RID"
|
||||
expect 'guard: empty id' 1 sandbox_ok "$R" ''
|
||||
expect 'guard: relative root' 1 sandbox_ok 'scripts/case2' "$(sandbox_id scripts/case2)"
|
||||
expect 'guard: missing root' 1 sandbox_ok "$W/missing" "$RID"
|
||||
expect 'guard: / as root' 1 sandbox_ok / "$(sandbox_id /)"
|
||||
expect 'guard: trailing slash' 1 sandbox_ok "$R/" "$RID"
|
||||
expect 'guard: a . part' 1 sandbox_ok "$W/a[bc]/./tmp.example" "$RID"
|
||||
expect 'guard: a symlink as root' 1 sandbox_ok "$W/alias" "$(sandbox_id "$W/real")"
|
||||
expect 'guard: a path through a symlink' 1 sandbox_ok "$W/alias/../a[bc]/tmp.example" "$RID"
|
||||
expect 'guard: the right path, another id' 1 sandbox_ok "$R" "$(sandbox_id "$W/ab/tmp.example")"
|
||||
expect 'guard: a sibling with the root id' 1 sandbox_ok "$W/ab/tmp.example" "$RID"
|
||||
expect 'guard: root with *' 0 sandbox_ok "$W/s*t/tmp.example" "$(sandbox_id "$W/s*t/tmp.example")"
|
||||
expect 'guard: root with ?' 0 sandbox_ok "$W/q?x/tmp.example" "$(sandbox_id "$W/q?x/tmp.example")"
|
||||
expect 'guard: empty directory' 0 dir_empty "$W/real"
|
||||
touch -- "$W/real/.dot"
|
||||
expect 'guard: a dot entry is not empty' 1 dir_empty "$W/real"
|
||||
|
||||
# The sweep and the removal refuse on their own, before they read a link or remove anything.
|
||||
expect 'sweep: refuses an empty root' 1 sweep_sandbox '' ''
|
||||
expect 'sweep: refuses / as root' 1 sweep_sandbox / "$(sandbox_id /)"
|
||||
expect 'sweep: refuses a missing root' 1 sweep_sandbox "$W/missing" "$RID"
|
||||
expect 'remove: refuses an empty root' 1 remove_sandbox '' ''
|
||||
expect 'remove: refuses a root with the wrong id' 1 remove_sandbox "$W/keep" "$RID"
|
||||
expect 'remove: the refused root is still there' 0 test -d "$W/keep/tmp.example/root"
|
||||
expect 'sweep: a valid root with no process in it' 0 sweep_sandbox "$W/keep" "$(sandbox_id "$W/keep")"
|
||||
same 'sweep: no signal was asked for' '' "$(cat -- "$W/kill-calls" 2>/dev/null)"
|
||||
|
||||
# The match. Dummy links stand in for /proc/<pid>/cwd; a regular file stands in for a link this
|
||||
# user may not read (find prints an empty target for both).
|
||||
n=0
|
||||
link() { n=$((n+1)); mkdir -p -- "$W/links/$n"; ln -s -- "$1" "$W/links/$n/cwd"; LINKS+=("$W/links/$n/cwd"); }
|
||||
match() { # match ROOT: the indices of the dummy links cwd_links_in selects, space-separated
|
||||
local l out=''
|
||||
while IFS= read -r -d '' l; do l=${l#"$W/links/"}; out="$out ${l%/cwd}"; done \
|
||||
< <(cwd_links_in "$1" "${LINKS[@]}")
|
||||
printf '%s' "${out# }"
|
||||
}
|
||||
LINKS=()
|
||||
link "$R" # 1 the root itself
|
||||
link "$R/root" # 2 under the root
|
||||
link "$R/root/x (deleted)" # 3 a deleted directory under the root
|
||||
link "$R (deleted)" # 4 another directory: the root exists
|
||||
link "$W/ab/tmp.example" # 5 what [bc] would match as a pattern
|
||||
link "$W/ab/tmp.example/root" # 6 the same, deeper
|
||||
link "$W/a[bc]/tmp.example2" # 7 a sibling sharing a prefix
|
||||
link "$W/a[bc]/tmp.exampl" # 8 a shorter sibling
|
||||
link / # 9
|
||||
link /opt/unrelated/work # 10
|
||||
link "$R/line"$'\n'"break" # 11 a newline, under the root
|
||||
link "$R/a"$'\t'"b" # 12 a tab, under the root
|
||||
link "$R"$'\n' # 13 the root plus a newline: another directory
|
||||
n=$((n+1)); mkdir -p -- "$W/links/$n"; : >"$W/links/$n/cwd"; LINKS+=("$W/links/$n/cwd") # 14 no target
|
||||
link "$W/s*t/tmp.example/root" # 15
|
||||
link "$W/sXt/tmp.example/root" # 16 what * would match as a pattern
|
||||
link "$W/q?x/tmp.example/root" # 17
|
||||
link "$W/qZx/tmp.example/root" # 18 what ? would match as a pattern
|
||||
same 'match: root with [bc] selects only its own tree, deleted dirs inside included' '1 2 3 11 12' "$(match "$R")"
|
||||
same 'match: root with *' '15' "$(match "$W/s*t/tmp.example")"
|
||||
same 'match: root with ?' '17' "$(match "$W/q?x/tmp.example")"
|
||||
same 'match: the ab sibling selects only its own tree' '5 6' "$(match "$W/ab/tmp.example")"
|
||||
same 'match: an empty root selects nothing' '' "$(match '')"
|
||||
same 'match: / as root selects nothing' '' "$(match /)"
|
||||
same 'match: a relative root selects nothing' '' "$(match 'tmp.example')"
|
||||
same 'match: no links reads nothing' '' "$(cwd_links_in "$R" | tr '\0' ' ')"
|
||||
|
||||
# The pid of a link: only /proc/<digits>/cwd.
|
||||
same 'pid: /proc/123/cwd' '123' "$(link_pid /proc/123/cwd)"
|
||||
expect 'pid: /proc/self/cwd' 1 link_pid /proc/self/cwd
|
||||
expect 'pid: /proc//cwd' 1 link_pid /proc//cwd
|
||||
expect 'pid: /proc/12/task/13/cwd' 1 link_pid /proc/12/task/13/cwd
|
||||
expect 'pid: a dummy link' 1 link_pid "$W/links/1/cwd"
|
||||
|
||||
# The socket shape and byte length.
|
||||
same 'socket: shape' "$R/root/data/launches/acme/r000000000000/tools.sock" "$(socket_shape "$R")"
|
||||
same 'socket: bytes, not characters' 5 "$(LC_ALL=C.UTF-8 byte_length $'/a/\xc3\xa9')"
|
||||
|
||||
links=(/proc/[0-9]*/cwd)
|
||||
start=${EPOCHREALTIME/[.,]/}
|
||||
hits=$(cwd_links_in "$W/keep" "${links[@]}" | tr -cd '\0' | wc -c)
|
||||
end=${EPOCHREALTIME/[.,]/}
|
||||
same "speed: no process under an empty root among ${#links[@]} cwd links" 0 "$hits"
|
||||
echo "time: one read of ${#links[@]} cwd links took $(( (end - start) / 1000 )) ms"
|
||||
printf '\nsandbox-check: %s passed, %s failed\n' "$PASS" "$FAIL"
|
||||
[ "$FAIL" -eq 0 ]
|
||||
@@ -0,0 +1,113 @@
|
||||
# shellcheck shell=bash
|
||||
# C2-14 (#1728, row 227 R3): the sandbox root of scripts/test-case2.sh and the cleanup that hangs
|
||||
# off it. test-case2.sh sources this file before it allocates anything. The kill sweep and the
|
||||
# removal each check the root themselves, so a caller that runs them early, late or with an empty
|
||||
# value gets a refusal, never a sweep of the host. scripts/case2/sandbox-check.sh exercises the
|
||||
# guard and the match against dummy symlinks.
|
||||
|
||||
# The tools socket is the longest Unix socket path a run builds. packages/seat/src/session.mjs
|
||||
# newRun puts it at <data root>/launches/<business>/r<12 hex digits>/tools.sock and refuses a path
|
||||
# over SOCKET_LIMIT bytes. The driver's data root is <sandbox>/root/data (fixture() in
|
||||
# packages/cli/tests/helpers.mjs, given <sandbox>/root by test-case2.sh) and its business is acme
|
||||
# (scripts/case2/e2e.mjs). socket_shape builds that path on a real sandbox root with a run id of the
|
||||
# same length, so its byte length is the length the run will have.
|
||||
SOCKET_LIMIT=107
|
||||
socket_shape() { printf '%s/root/data/launches/acme/r%s/tools.sock' "$1" 000000000000; }
|
||||
|
||||
# The length of $1 in bytes, not characters, whatever the caller's locale.
|
||||
byte_length() {
|
||||
local LC_ALL=C
|
||||
printf '%s' "${#1}"
|
||||
}
|
||||
|
||||
# The device:inode of $1, the identity recorded when mktemp creates the sandbox.
|
||||
sandbox_id() { stat -c '%d:%i' -- "$1" 2>/dev/null; }
|
||||
|
||||
# sandbox_ok ROOT ID: ROOT is the sandbox this run created. It is non-empty, absolute and not /;
|
||||
# it is its own physical path (no symlink in it, no trailing slash, no . or .. part), which is the
|
||||
# form a /proc/<pid>/cwd link reads; it is a directory this user owns; and its device:inode is ID.
|
||||
sandbox_ok() {
|
||||
local root=${1-} id=${2-} physical
|
||||
[ -n "$root" ] && [ -n "$id" ] || return 1
|
||||
case "$root" in /?*) ;; *) return 1 ;; esac
|
||||
[ -d "$root" ] && [ ! -L "$root" ] && [ -O "$root" ] || return 1
|
||||
physical=$(cd -P -- "$root" 2>/dev/null && pwd -P) || return 1
|
||||
[ "$physical" = "$root" ] || return 1
|
||||
[ "$(sandbox_id "$root")" = "$id" ]
|
||||
}
|
||||
|
||||
# dir_empty DIR: DIR holds no entry, dot entries included.
|
||||
dir_empty() (
|
||||
shopt -s nullglob dotglob
|
||||
set -- "$1"/*
|
||||
[ "$#" -eq 0 ]
|
||||
)
|
||||
|
||||
# cwd_in ROOT TARGET: TARGET, a cwd link target, is ROOT or lies under ROOT/. The two are compared
|
||||
# as strings. Quoted text in a case pattern matches only itself, so *, ? and [ in ROOT are literal;
|
||||
# the only pattern character is the /* written here. A cwd in a deleted directory reads
|
||||
# "<path> (deleted)". One under ROOT/ still matches. "ROOT (deleted)" does not: the sweep runs only
|
||||
# after sandbox_ok has shown ROOT exists, so that target is another directory, one whose name ends
|
||||
# in " (deleted)".
|
||||
cwd_in() {
|
||||
case "${1-}" in /?*) ;; *) return 1 ;; esac
|
||||
case "${2-}" in "$1" | "$1"/*) return 0 ;; esac
|
||||
return 1
|
||||
}
|
||||
|
||||
# cwd_links_in ROOT LINK...: print, each followed by NUL, every LINK whose target cwd_in puts in
|
||||
# ROOT. One find reads every target (%l), so the cost is one process however many the host runs. A
|
||||
# link this user may not read, another user's process, gives an empty target, which never matches.
|
||||
# Each record is LINK, a tab, then TARGET; LINK has no tab and TARGET may hold anything but NUL.
|
||||
cwd_links_in() {
|
||||
local root=$1 record
|
||||
shift
|
||||
[ "$#" -gt 0 ] || return 0
|
||||
while IFS= read -r -d '' record; do
|
||||
if cwd_in "$root" "${record#*$'\t'}"; then printf '%s\0' "${record%%$'\t'*}"; fi
|
||||
done < <(command find "$@" -maxdepth 0 -printf '%p\t%l\0' 2>/dev/null)
|
||||
}
|
||||
|
||||
# link_pid LINK: the pid in a link of the form /proc/<digits>/cwd, or failure for anything else.
|
||||
link_pid() {
|
||||
local pid=${1#/proc/}
|
||||
[ "$pid" != "$1" ] || return 1
|
||||
pid=${pid%/cwd}
|
||||
case "$pid" in '' | *[!0-9]*) return 1 ;; esac
|
||||
printf '%s' "$pid"
|
||||
}
|
||||
|
||||
# sweep_sandbox ROOT ID: SIGKILL every process whose cwd is in ROOT. It refuses, before it reads any
|
||||
# link, unless sandbox_ok ROOT ID. Up to three passes, so a child forked during one pass is caught
|
||||
# by the next. Prints a note when it killed something; returns 1 when it refused.
|
||||
sweep_sandbox() {
|
||||
local root=${1-} id=${2-} link pid pass hit
|
||||
local -A killed=()
|
||||
if ! sandbox_ok "$root" "$id"; then
|
||||
printf 'test-case2: kill sweep refused: %q is not the sandbox this run created\n' "$root" >&2
|
||||
return 1
|
||||
fi
|
||||
for pass in 1 2 3; do
|
||||
hit=0
|
||||
while IFS= read -r -d '' link; do
|
||||
pid=$(link_pid "$link") || continue
|
||||
if kill -KILL "$pid" 2>/dev/null; then hit=1; killed[$pid]=1; fi
|
||||
done < <(cwd_links_in "$root" /proc/[0-9]*/cwd)
|
||||
[ "$hit" = 1 ] || break
|
||||
done
|
||||
if [ "${#killed[@]}" -gt 0 ]; then
|
||||
echo "note: ${#killed[@]} process(es) under the sandbox outlived the driver; sent SIGKILL"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# remove_sandbox ROOT ID: remove ROOT, refusing unless sandbox_ok ROOT ID. --one-file-system keeps
|
||||
# rm out of any mount left under it.
|
||||
remove_sandbox() {
|
||||
local root=${1-} id=${2-}
|
||||
if ! sandbox_ok "$root" "$id"; then
|
||||
printf 'test-case2: removal refused: %q is not the sandbox this run created\n' "$root" >&2
|
||||
return 1
|
||||
fi
|
||||
rm -rf --one-file-system -- "$root"
|
||||
}
|
||||
Executable → Regular
+56
-25
@@ -4,21 +4,30 @@
|
||||
# Stands alone: the landing gate runs it as `bash scripts/test-case2.sh` with nothing else set up.
|
||||
# The only human stand-in is bindHuman in-process; a development agent cannot prove human CLI ancestry.
|
||||
set -uo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
SANDBOX="$(mktemp -d)"
|
||||
fatal() { printf 'test-case2: %s\n' "$*" >&2; exit 2; }
|
||||
cd "$(dirname "$0")/.." || fatal 'cannot enter the repository root; nothing was started'
|
||||
. scripts/case2/sandbox.sh || fatal 'cannot load scripts/case2/sandbox.sh; nothing was started'
|
||||
# The sandbox root. Every later path, the kill sweep and the removal hang off it, so nothing is
|
||||
# derived from it, no trap is set and nothing starts until it is this run's own directory: mktemp
|
||||
# exited 0 under an absolute TMPDIR, and the result is absolute, not a symlink, an empty directory
|
||||
# this user owns. It is kept as its physical path, the form a /proc/<pid>/cwd link reads, and its
|
||||
# device:inode goes into SANDBOX_ID. sweep_sandbox and remove_sandbox check both again themselves.
|
||||
case "${TMPDIR:-/tmp}" in
|
||||
/*) ;;
|
||||
*) fatal "TMPDIR is not an absolute path: $TMPDIR; nothing was started" ;;
|
||||
esac
|
||||
made="$(mktemp -d)" || fatal "mktemp -d failed under TMPDIR=${TMPDIR:-/tmp}; nothing was started"
|
||||
case "$made" in
|
||||
/?*) ;;
|
||||
*) fatal "mktemp -d gave '$made', not an absolute path; nothing was started" ;;
|
||||
esac
|
||||
[ -d "$made" ] && [ ! -L "$made" ] && [ -O "$made" ] && dir_empty "$made" \
|
||||
|| fatal "mktemp -d gave $made, not a new empty directory of this user; nothing was started"
|
||||
SANDBOX="$(cd -P -- "$made" && pwd -P)" && SANDBOX_ID="$(sandbox_id "$SANDBOX")" \
|
||||
&& sandbox_ok "$SANDBOX" "$SANDBOX_ID" \
|
||||
|| fatal "cannot resolve the sandbox $made; nothing was started"
|
||||
readonly SANDBOX SANDBOX_ID
|
||||
DRIVER_PID=''
|
||||
CASE2_HOME="$SANDBOX/home"
|
||||
CASE2_TMP="$SANDBOX/t"
|
||||
CASE2_CONFIG="$SANDBOX/root/config/config.json"
|
||||
mkdir -p "$CASE2_HOME" "$CASE2_TMP"
|
||||
# The driver runs from an explicit environment: PATH and LANG, a sandbox HOME, XDG dirs and TMPDIR,
|
||||
# and the variables it needs. Nothing else from the caller, a credential variable included, reaches
|
||||
# the driver or the launcher it starts. TMPDIR in the sandbox takes the Chromium profile and the
|
||||
# plug-in tree with it when the sandbox goes.
|
||||
CLEAN_ENV=(env -i PATH="$PATH" LANG=C.UTF-8 HOME="$CASE2_HOME"
|
||||
XDG_CONFIG_HOME="$CASE2_HOME/.config" XDG_CACHE_HOME="$CASE2_HOME/.cache"
|
||||
XDG_DATA_HOME="$CASE2_HOME/.local/share" XDG_STATE_HOME="$CASE2_HOME/.local/state"
|
||||
TMPDIR="$CASE2_TMP" MOSAIC_CONFIG="$CASE2_CONFIG" GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1)
|
||||
alive() {
|
||||
local stat
|
||||
read -r stat 2>/dev/null <"/proc/$1/stat" || return 1
|
||||
@@ -28,11 +37,12 @@ alive() {
|
||||
# The driver leads its own process group (setsid below). On a signal it gets SIGTERM and 3 s by the
|
||||
# clock to close, inside the landing gate's 5 s grace, then its group gets SIGKILL. The launcher
|
||||
# starts each bwrap session in a group of its own, with its working directory in the sandbox; any
|
||||
# such process still alive then gets SIGKILL too, before the sandbox goes. One find reads every
|
||||
# cwd link, so the sweep stays in milliseconds however many processes the host runs.
|
||||
# such process still alive then gets SIGKILL too, before the sandbox goes. sweep_sandbox reads every
|
||||
# cwd link with one find and compares targets as strings, so the sweep stays in milliseconds however
|
||||
# many processes the host runs.
|
||||
now_us() { echo "${EPOCHREALTIME/[.,]/}"; }
|
||||
stop_driver() {
|
||||
local deadline p left=0
|
||||
local deadline
|
||||
if [ -n "$DRIVER_PID" ]; then
|
||||
kill -TERM "$DRIVER_PID" 2>/dev/null
|
||||
deadline=$(( $(now_us) + 3000000 ))
|
||||
@@ -41,22 +51,42 @@ stop_driver() {
|
||||
wait "$DRIVER_PID" 2>/dev/null
|
||||
DRIVER_PID=''
|
||||
fi
|
||||
for p in $(find /proc/[0-9]*/cwd -maxdepth 0 \( -lname "$SANDBOX" -o -lname "$SANDBOX/*" \) 2>/dev/null); do
|
||||
p="${p#/proc/}"
|
||||
kill -KILL "${p%/cwd}" 2>/dev/null && left=$((left+1))
|
||||
done
|
||||
if [ "$left" -gt 0 ]; then echo "note: $left process(es) under the sandbox outlived the driver; sent SIGKILL"; fi
|
||||
sweep_sandbox "$SANDBOX" "$SANDBOX_ID"
|
||||
}
|
||||
# A second INT or TERM during cleanup is ignored, so it cannot cut the sweep short; the gate's
|
||||
# SIGKILL after its grace still ends everything. A refused sweep or removal turns a pass red.
|
||||
cleanup() {
|
||||
local result=$?
|
||||
trap - EXIT INT TERM
|
||||
stop_driver
|
||||
rm -rf "$SANDBOX"
|
||||
trap '' INT TERM
|
||||
trap - EXIT
|
||||
stop_driver || result=$(( result ? result : 1 ))
|
||||
remove_sandbox "$SANDBOX" "$SANDBOX_ID" || result=$(( result ? result : 1 ))
|
||||
exit "$result"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
trap 'exit 130' INT
|
||||
trap 'exit 143' TERM
|
||||
# The tools socket is the longest socket path the run builds (scripts/case2/sandbox.sh). Refuse a
|
||||
# TMPDIR that would push it past the product's limit before anything starts.
|
||||
SOCKET_BYTES=$(byte_length "$(socket_shape "$SANDBOX")")
|
||||
if [ "$SOCKET_BYTES" -gt "$SOCKET_LIMIT" ]; then
|
||||
tmpdir_bytes=$(byte_length "${TMPDIR:-/tmp}")
|
||||
fatal "TMPDIR is too long: the run's tools socket path would be $SOCKET_BYTES bytes, over the" \
|
||||
"$SOCKET_LIMIT-byte limit in packages/seat/src/session.mjs; TMPDIR is $tmpdir_bytes bytes," \
|
||||
"at most $(( tmpdir_bytes - SOCKET_BYTES + SOCKET_LIMIT )) fit; nothing was started"
|
||||
fi
|
||||
CASE2_HOME="$SANDBOX/home"
|
||||
CASE2_TMP="$SANDBOX/t"
|
||||
CASE2_CONFIG="$SANDBOX/root/config/config.json"
|
||||
mkdir -p -- "$CASE2_HOME" "$CASE2_TMP" || fatal "cannot create $CASE2_HOME and $CASE2_TMP"
|
||||
# The driver runs from an explicit environment: PATH and LANG, a sandbox HOME, XDG dirs and TMPDIR,
|
||||
# and the variables it needs. Nothing else from the caller, a credential variable included, reaches
|
||||
# the driver or the launcher it starts. TMPDIR in the sandbox takes the Chromium profile and the
|
||||
# plug-in tree with it when the sandbox goes.
|
||||
CLEAN_ENV=(env -i PATH="$PATH" LANG=C.UTF-8 HOME="$CASE2_HOME"
|
||||
XDG_CONFIG_HOME="$CASE2_HOME/.config" XDG_CACHE_HOME="$CASE2_HOME/.cache"
|
||||
XDG_DATA_HOME="$CASE2_HOME/.local/share" XDG_STATE_HOME="$CASE2_HOME/.local/state"
|
||||
TMPDIR="$CASE2_TMP" MOSAIC_CONFIG="$CASE2_CONFIG" GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1)
|
||||
PASS=0 FAIL=0
|
||||
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
||||
C_OK=$'\033[0;32m'; C_FAIL=$'\033[0;31m'; C_RESET=$'\033[0m'
|
||||
@@ -72,6 +102,7 @@ STEPS='S1a S1b S2a S2b S2c S2d S3a S3b S3c S4 S5a S5b S6 S7 S8 S9 S10'
|
||||
"${CLEAN_ENV[@]}" node --check "$DRIVER" >/dev/null 2>&1
|
||||
check "syntax: $DRIVER" "$?"
|
||||
OUT="$SANDBOX/steps.txt" ERR="$SANDBOX/stderr.txt"
|
||||
: >"$OUT" && : >"$ERR" || fatal "cannot create the driver output files in $SANDBOX"
|
||||
"${CLEAN_ENV[@]}" setsid node "$DRIVER" "$SANDBOX/root" >"$OUT" 2>"$ERR" &
|
||||
DRIVER_PID=$!
|
||||
wait "$DRIVER_PID"
|
||||
|
||||
Reference in new issue
Block a user