diff --git a/packages/mosaic/framework/fleet/bin/mosaic b/packages/mosaic/framework/fleet/bin/mosaic index f1beace0..ce8362ee 100755 --- a/packages/mosaic/framework/fleet/bin/mosaic +++ b/packages/mosaic/framework/fleet/bin/mosaic @@ -86,7 +86,7 @@ fallback_candidate_usable() { return 1 ;; esac - if printf '%s' "$candidate" | grep -qE '(^|/)\\.\\.(/|$)'; then + if printf '%s' "$candidate" | grep -qE '(^|/)\.\.(/|$)'; then echo "mosaic: refusing \$HOME candidate $candidate: parent-escape component" >&2 return 1 fi diff --git a/packages/mosaic/framework/fleet/bin/test-mosaic-launcher.sh b/packages/mosaic/framework/fleet/bin/test-mosaic-launcher.sh index 8cf221f7..77832143 100755 --- a/packages/mosaic/framework/fleet/bin/test-mosaic-launcher.sh +++ b/packages/mosaic/framework/fleet/bin/test-mosaic-launcher.sh @@ -159,4 +159,35 @@ set -e [ "$rmrc" = "0" ] || fail "A7b mutant did not execute the relative plant (rc $rmrc, out '$rmout') - A7 proves nothing" [ -e "$WORK/relative-sentinel" ] || fail "A7b mutant ran but relative sentinel absent - arm wrong, A7 proves nothing" +# A8 — parent-escape hostile arm (rev-code-02 delta, B2 remains): an absolute +# HOME containing a literal '..' component must be refused by the +# parent-escape check — the traversal would otherwise land on a planted tree +# OUTSIDE the seat home with no symlink involved. +ESC_BASE="$WORK/escape-base" +ESC_TARGET="$WORK/escape-target" +mkdir -p "$ESC_BASE" "$ESC_TARGET/.npm-global/bin" +cat >"$ESC_TARGET/.npm-global/bin/mosaic" <&1)" +erc=$? +set -e +[ "$erc" = "127" ] || fail "A8 parent-escape HOME was followed (rc $erc, out '$eout')" +case "$eout" in *"parent-escape component"*) ;; *) fail "A8 parent-escape diagnostic missing: '$eout'" ;; esac +[ ! -e "$WORK/escape-sentinel" ] || fail "A8 escape plant EXECUTED" + +# A8b — mutation control: the guard-bypassed copy MUST execute the parent- +# escape plant under the identical arm (sentinel present, rc 0), proving the +# parent-escape check is what stands. +set +e +emout="$(printf '' | env GETENT_STUB=fail HOME="$ESC_BASE/../escape-target" PATH="$STUB_BIN:/usr/bin:/bin" "$MUTANT" --version 2>&1)" +emrc=$? +set -e +[ "$emrc" = "0" ] || fail "A8b mutant did not execute the escape plant (rc $emrc, out '$emout') - A8 proves nothing" +[ -e "$WORK/escape-sentinel" ] || fail "A8b mutant ran but escape sentinel absent - arm wrong, A8 proves nothing" + echo "mosaic launcher suite: all arms passed"