mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
Review on #2199: cbm_test_runtime_init ran more than a hundred lines before the only EXIT trap, so under `set -e` a failure in the fixture mktemp or its cygpath conversion left the private root behind, and the fixture trap ran smoke_rmtree ahead of the runtime cleanup. Arm `trap 'cbm_test_runtime_cleanup "$BINARY"' EXIT` immediately after a successful init, as soak-test.sh and memlab.sh do. The fixture trap that replaces it now retires the private daemon first and removes the fixtures second, so no earlier cleanup step stands between the exit and the runtime cleanup; on Windows the retirement is also what unblocks the fixture rm. tests/test_smoke_runtime_isolation_contract.sh pins the early trap to the window between the init call and the first fixture; the pin fails against the previous head. Part of #1696. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Anton Standrik <astandrik@yandex-team.ru>
104 lines
4.3 KiB
Bash
Executable File
104 lines
4.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Runtime-isolation contract for the smoke harness (#1696, follow-up to #1691).
|
|
#
|
|
# scripts/smoke-test.sh is the process that actually starts the product during
|
|
# a smoke run, and it retires "the account daemon" seven times through
|
|
# `daemon stop`. Its wrappers sandbox HOME/XDG/TMPDIR and CBM_CACHE_DIR, but
|
|
# only CBM_RUNTIME_DIR moves the daemon rendezvous (docs/CONFIGURATION.md), so
|
|
# without a private runtime every one of those stops lands on the operator's
|
|
# live daemon. Drive the harness with an environment-probe fixture and require
|
|
# that no product process ever receives the caller's runtime or cache.
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
WORKDIR="$(mktemp -d)"
|
|
trap 'rm -rf "$WORKDIR"' EXIT
|
|
|
|
fail() {
|
|
echo "FAIL: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
normalize_path() {
|
|
local path=${1%$'\r'}
|
|
if command -v cygpath >/dev/null 2>&1; then
|
|
cygpath -u "$path" 2>/dev/null && return 0
|
|
fi
|
|
printf '%s\n' "${path//\\//}"
|
|
}
|
|
|
|
ENV_PROBE="$WORKDIR/environment-probe"
|
|
cat > "$ENV_PROBE" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
printf '%s\t%s\n' "${CBM_CACHE_DIR-}" "${CBM_RUNTIME_DIR-}" >> "$CBM_SMOKE_ENV_PROBE"
|
|
case "${1-}" in
|
|
--version) echo "v0.0.0-probe"; exit 0 ;;
|
|
daemon) [[ "${2-}" == status ]] && exit 1; exit 0 ;;
|
|
esac
|
|
echo '{}'
|
|
exit 0
|
|
EOF
|
|
chmod +x "$ENV_PROBE"
|
|
|
|
CALLER_CACHE="$WORKDIR/caller-cache"
|
|
CALLER_RUNTIME="$WORKDIR/caller-runtime"
|
|
ENV_LOG="$WORKDIR/environment.log"
|
|
mkdir -p "$CALLER_CACHE" "$CALLER_RUNTIME"
|
|
|
|
# The fixture answers nothing beyond --version, so the smoke fails early; only
|
|
# the environment it handed to the product is under test here.
|
|
CBM_CACHE_DIR="$CALLER_CACHE" \
|
|
CBM_RUNTIME_DIR="$CALLER_RUNTIME" \
|
|
CBM_SMOKE_ENV_PROBE="$ENV_LOG" \
|
|
"$ROOT/scripts/smoke-test.sh" "$ENV_PROBE" > "$WORKDIR/smoke.out" 2>&1 || true
|
|
|
|
[[ -s "$ENV_LOG" ]] || fail "smoke-test did not execute the environment-probe fixture"
|
|
|
|
CALLER_CACHE_NORMALIZED=$(normalize_path "$CALLER_CACHE")
|
|
CALLER_RUNTIME_NORMALIZED=$(normalize_path "$CALLER_RUNTIME")
|
|
private_root=""
|
|
while IFS=$'\t' read -r child_cache_raw child_runtime_raw; do
|
|
child_cache=$(normalize_path "$child_cache_raw")
|
|
child_runtime=$(normalize_path "$child_runtime_raw")
|
|
if [[ -z "$child_runtime" || "$child_runtime" == "$CALLER_RUNTIME_NORMALIZED" ]]; then
|
|
fail "smoke-test exposed the caller CBM_RUNTIME_DIR to a product process"
|
|
fi
|
|
if [[ -z "$child_cache" || "$child_cache" == "$CALLER_CACHE_NORMALIZED" ]]; then
|
|
fail "smoke-test exposed the caller CBM_CACHE_DIR to a product process"
|
|
fi
|
|
if [[ "${child_runtime%/*}" != "${child_cache%/*}" ||
|
|
"${child_runtime##*/}" != "runtime" || "${child_cache##*/}" != "cache" ]]; then
|
|
fail "smoke runtime/cache were not isolated beneath one private root"
|
|
fi
|
|
if [[ -n "$private_root" && "$private_root" != "${child_runtime%/*}" ]]; then
|
|
fail "smoke-test switched private roots mid-run"
|
|
fi
|
|
private_root="${child_runtime%/*}"
|
|
done < "$ENV_LOG"
|
|
|
|
[[ ! -e "$private_root" ]] || fail "smoke-test left its private root behind: $private_root"
|
|
|
|
# The run above exits through the fixture trap, so it cannot show what happens
|
|
# to the private root when the harness dies before that trap exists — the
|
|
# fixture mktemp and its cygpath conversion are in that window, and under
|
|
# `set -e` either can end the run. Reproducing that failure would mean scanning
|
|
# the shared /tmp parent for orphaned roots, which races every other harness
|
|
# test in the same suite, so pin the ordering instead: the cleanup trap is
|
|
# armed between the init call and the first fixture work.
|
|
smoke="$ROOT/scripts/smoke-test.sh"
|
|
smoke_line_of() {
|
|
# A missing pattern is the failure this check reports, not a reason to end
|
|
# the test silently under `set -e`.
|
|
grep -n "$1" "$smoke" | head -1 | cut -d: -f1 || true
|
|
}
|
|
init_line=$(smoke_line_of '^cbm_test_runtime_init$')
|
|
early_trap_line=$(smoke_line_of "^trap 'cbm_test_runtime_cleanup \"\$BINARY\"' EXIT\$")
|
|
fixture_line=$(smoke_line_of '^TMPDIR=\$(smoke_mktemp_dir)$')
|
|
if [[ -z "$init_line" || -z "$early_trap_line" || -z "$fixture_line" ]] ||
|
|
((early_trap_line < init_line || early_trap_line > fixture_line)); then
|
|
fail "smoke-test must arm the runtime cleanup trap between cbm_test_runtime_init and its first fixture"
|
|
fi
|
|
|
|
echo "PASS: smoke harness isolates its daemon runtime and cache from the caller"
|