fix(installer): fail closed on test enumeration errors
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/greenfield-install Pipeline failed

This commit is contained in:
2026-08-05 21:11:05 -05:00
parent 378bc1afe3
commit ff3f0d29f1
13 changed files with 227 additions and 14 deletions
+38 -5
View File
@@ -2,6 +2,8 @@
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/test-enumeration-assertions.sh
source "$ROOT/tools/test-enumeration-assertions.sh"
TMP="$(mktemp -d "${TMPDIR:-/tmp}/mosaic-next-install-test-XXXXXX")"
trap 'rm -rf "$TMP"' EXIT
export TMPDIR="$TMP/runtime-tmp"
@@ -15,6 +17,31 @@ STATE="$TMP/state"
LOG="$TMP/npm.log"
mkdir -p "$FAKE_BIN" "$HOME_DIR" "$STATE"
if [[ "${MOSAIC_TEST_ENUMERATION_FAILURE_CHILD:-0}" != "1" ]]; then
printf '[test] enumeration failure cannot mask a planted in-progress transaction\n'
set +e
if [[ "$(/usr/bin/id -u)" -eq 0 ]]; then
enumeration_control_output="$(
su -s /bin/bash nobody -c \
"TMPDIR=/tmp MOSAIC_TEST_ENUMERATION_FAILURE_CHILD=1 bash '$0'" 2>&1
)"
enumeration_control_status=$?
else
enumeration_control_output="$(MOSAIC_TEST_ENUMERATION_FAILURE_CHILD=1 bash "$0" 2>&1)"
enumeration_control_status=$?
fi
set -e
printf '%s\n' "$enumeration_control_output" > "$TMP/enumeration-failure-control.log"
if [[ "$enumeration_control_status" -eq 0 ]]; then
echo '[test] FAIL: planted in-progress transaction plus failed enumeration passed the full suite' >&2
exit 1
fi
grep -qF '[test] ERROR: P2 fault-state enumeration failed' "$TMP/enumeration-failure-control.log" || {
echo '[test] FAIL: failed fault-state enumeration was not named' >&2
exit 1
}
fi
# Model the supported non-root/glibc target explicitly even when this harness
# itself runs as root in Alpine/BusyBox CI.
cat > "$FAKE_BIN/id" <<'FAKE_ID'
@@ -518,9 +545,9 @@ fi
if [[ "$(cat "$TMP/canary-observed" 2>/dev/null || true)" != "$canary" ]]; then
echo 'credential canary positive control was not exercised' >&2; exit 1
fi
if find "$TMPDIR" -maxdepth 1 -type f \( -name 'mosaic-phase-redacted.*' -o -name 'mosaic-post-redacted.*' \) -print -quit | grep -q .; then
echo 'redacted diagnostic staging file survived normal completion' >&2; exit 1
fi
test_assert_find_empty 'redacted diagnostic staging files' \
"$TMPDIR" -maxdepth 1 -type f \
\( -name 'mosaic-phase-redacted.*' -o -name 'mosaic-post-redacted.*' \) || exit 1
printf '[test] framework nested capture redacts the same canary and URL variants\n'
framework_test_home="$TMP/framework-redact-home"
@@ -577,9 +604,15 @@ for phase in P2 P3 P4 P5 P6 P7 P8; do
[[ -s "$LOG" ]] || { echo "$phase fault never entered the real action path" >&2; exit 1; }
[[ "$(tree_fingerprint "$HOME_DIR")" == "$before" ]] || { echo "$phase real rollback mismatch" >&2; exit 1; }
grep -q "phase=$phase" "$TMP/fault-$phase.log"
if find "$TMP/fault-$phase" -type f -exec grep -l '"status"[[:space:]]*:[[:space:]]*"in-progress"' {} + 2>/dev/null | grep -q .; then
echo "$phase left an in-progress transaction" >&2; exit 1
if [[ "${MOSAIC_TEST_ENUMERATION_FAILURE_CHILD:-0}" == "1" && "$phase" == "P2" ]]; then
mkdir -p "$TMP/fault-$phase/blocked"
printf '{"status":"in-progress"}\n' > "$TMP/fault-$phase/blocked/planted-in-progress.json"
chmod 0666 "$TMP/fault-$phase/blocked/planted-in-progress.json"
chmod 0100 "$TMP/fault-$phase/blocked"
trap 'chmod 0700 "$TMP/fault-P2/blocked" 2>/dev/null || true; rm -rf "$TMP"' EXIT
fi
test_assert_no_file_content_match "$phase fault-state" \
'"status"[[:space:]]*:[[:space:]]*"in-progress"' "$TMP/fault-$phase" || exit 1
done
printf '[test] stale projection is preserved while the real fault path acquires a free OS lock\n'
+4 -1
View File
@@ -8,6 +8,8 @@
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/test-enumeration-assertions.sh
source "$ROOT/tools/test-enumeration-assertions.sh"
TMP="$(mktemp -d "${TMPDIR:-/tmp}/mosaic-install-state-test.XXXXXX")"
trap 'rm -rf "$TMP"' EXIT
failures=0
@@ -396,7 +398,8 @@ set -e
grep -q '^\[P0\] FAIL:.*unsafe context' "$TMP/symlink-target.log" \
&& pass_case 'symlinked rollback parent was rejected by P0' \
|| fail_case 'symlinked rollback parent lacked an attributable P0 failure'
[[ -z "$(find "$symlink_outside" -mindepth 1 -print -quit)" ]] || fail_case 'symlink target was mutated'
test_assert_find_empty 'symlink target mutation check' "$symlink_outside" -mindepth 1 \
|| fail_case 'symlink target was mutated or could not be enumerated'
printf '[test] case: journal initialization failure is fatal before mutation\n'
journal_home="$TMP/journal-failure/home"
+1 -1
View File
@@ -1 +1 @@
4cd391b0974d3cce6c2a98455420d45bc2a04cb624e3c4bf43a813b8e28693e6 install.sh
e59cb441a2f37ae9150f8eae470238e9d858a1816df93343d9784a6796676096 install.sh
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# Fail-closed filesystem-enumeration assertions for shell test harnesses.
# Usage: test_assert_find_empty <label> <find arguments...>
test_assert_find_empty() {
local label="$1"
shift
local inventory
inventory="$(mktemp "${TMPDIR:-/tmp}/mosaic-test-find.XXXXXX")" || {
printf '[test] ERROR: %s inventory allocation failed\n' "$label" >&2
return 2
}
if ! find "$@" -print0 > "$inventory"; then
rm -f "$inventory"
printf '[test] ERROR: %s enumeration failed\n' "$label" >&2
return 2
fi
if [[ -s "$inventory" ]]; then
rm -f "$inventory"
printf '[test] FAIL: %s was not empty\n' "$label" >&2
return 1
fi
rm -f "$inventory"
return 0
}
# Usage: test_assert_no_file_content_match <label> <extended-regex> <find roots/options...>
test_assert_no_file_content_match() {
local label="$1"
local pattern="$2"
shift 2
local inventory path grep_status result=0
inventory="$(mktemp "${TMPDIR:-/tmp}/mosaic-test-find.XXXXXX")" || {
printf '[test] ERROR: %s inventory allocation failed\n' "$label" >&2
return 2
}
if ! find "$@" -type f -print0 > "$inventory"; then
rm -f "$inventory"
printf '[test] ERROR: %s enumeration failed\n' "$label" >&2
return 2
fi
while IFS= read -r -d '' path; do
grep_status=0
grep -Eq -- "$pattern" "$path" || grep_status=$?
if [[ "$grep_status" -eq 0 ]]; then
result=1
break
fi
if [[ "$grep_status" -ne 1 ]]; then
result=2
break
fi
done < "$inventory"
rm -f "$inventory"
if [[ "$result" -eq 1 ]]; then
printf '[test] FAIL: %s contained a forbidden match\n' "$label" >&2
return 1
fi
if [[ "$result" -eq 2 ]]; then
printf '[test] ERROR: %s content inspection failed\n' "$label" >&2
return 2
fi
return 0
}
+3 -1
View File
@@ -1,6 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=tools/test-enumeration-assertions.sh
source "$ROOT/tools/test-enumeration-assertions.sh"
TMP="$(mktemp -d "${TMPDIR:-/tmp}/mosaic-fetch-contract.XXXXXX")"
trap 'rm -rf "$TMP"' EXIT
FAKE_BIN="$TMP/bin"; mkdir -p "$FAKE_BIN"
@@ -41,7 +43,7 @@ empty_sha="$(printf '' | sha256sum | awk '{print $1}')"
mkdir -p "$TMP/downloads"
output="$(TMPDIR="$TMP/downloads" PATH="$FAKE_BIN:$PATH" bash "$ROOT/tools/verified-installer-fetch.sh" fixture://ok "$ok_sha" -- marker)"
[[ "$output" == 'executed:marker' ]]
[[ -z "$(find "$TMP/downloads" -mindepth 1 -print -quit)" ]]
test_assert_find_empty 'verified-installer temporary downloads' "$TMP/downloads" -mindepth 1
printf '[test] PASS: digest-pinned fetched artifact executes and its temporary body is removed\n'
for row in 'fixture://empty empty-body' 'fixture://failed failed-fetch'; do