mirror of
https://github.com/unslothai/unsloth.git
synced 2026-08-22 07:13:52 +00:00
Report a denied UNSLOTH_LOCAL_LLAMA_CPP_DIR instead of aborting on errexit (#8143)
Some checks are pending
Local Agent Guides CI / connection (openclaw) (push) Waiting to run
Local Agent Guides CI / connection (pi) (push) Waiting to run
Core / Core (HF=default + TRL=default) (push) Waiting to run
Core / Core (HF=4.57.6 + TRL<1) (push) Waiting to run
Core / Core (HF=latest + TRL=latest) (push) Waiting to run
Core / llama.cpp build + smoke (push) Waiting to run
Cross-platform parity / parity (ubuntu-latest) (push) Waiting to run
Cross-platform parity / parity (windows-latest) (push) Waiting to run
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Waiting to run
Local Agent Guides CI / connection (claude) (push) Waiting to run
Local Agent Guides CI / connection (codex) (push) Waiting to run
Local Agent Guides CI / connection (hermes) (push) Waiting to run
Local Agent Guides CI / connection (opencode) (push) Waiting to run
Local Agent Guides CI / file-edit (claude) (push) Waiting to run
Local Agent Guides CI / file-edit (codex) (push) Waiting to run
Local Agent Guides CI / file-edit (hermes) (push) Waiting to run
Local Agent Guides CI / file-edit (openclaw) (push) Waiting to run
Local Agent Guides CI / file-edit (opencode) (push) Waiting to run
Local Agent Guides CI / file-edit (pi) (push) Waiting to run
Local Agent Guides CI / resume (claude) (push) Waiting to run
Local Agent Guides CI / resume (codex) (push) Waiting to run
Local Agent Guides CI / resume (opencode) (push) Waiting to run
Local Agent Guides CI / resume (pi) (push) Waiting to run
Local Agent Guides CI / prompt-cache (gemma-3-270m) (push) Waiting to run
MLX CI on Mac M1 / dispatch (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Windows Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
Wheel CI / Wheel build + content sanity + import smoke (push) Waiting to run
Security audit / advisory audit (pip + npm + cargo) (push) Waiting to run
Security audit / pip scan-packages :: extras (push) Waiting to run
Security audit / pip scan-packages :: studio (push) Waiting to run
Security audit / pip scan-packages :: hf-stack (push) Waiting to run
Security audit / npm scan-packages (Unsloth frontend tarballs) (push) Waiting to run
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Waiting to run
Security audit / pytest tests/security (push) Waiting to run
Security audit / npm provenance + new install-script diff (push) Waiting to run
Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Backend CI / (Python 3.10) (push) Waiting to run
Backend CI / (Python 3.11) (push) Waiting to run
Backend CI / (Python 3.12) (push) Waiting to run
Backend CI / (Python 3.13) (push) Waiting to run
Backend CI / Repo tests (CPU) (push) Waiting to run
Unsloth export capability / capability (ubuntu-latest) (push) Waiting to run
Unsloth export capability / capability (windows-latest) (push) Waiting to run
Frontend CI / Frontend build + bundle sanity (push) Waiting to run
Unsloth GGUF CI / OpenAI, Anthropic API tests (push) Waiting to run
Unsloth GGUF CI / Tool calling Tests (push) Waiting to run
Unsloth GGUF CI / JSON, images (push) Waiting to run
Unsloth load-orchestrator CI / test (push) Waiting to run
Mac Studio GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Waiting to run
Mac Studio UI + API + Update CI / Chat UI, API and Update Tests (push) Waiting to run
Unsloth Tauri CI / Tauri Linux debug build (no codesign) (push) Waiting to run
Unsloth Tauri CI / Rust unit tests (windows) (push) Waiting to run
Unsloth UI CI / Chat UI Tests (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
Windows Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Windows Unsloth GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Windows Unsloth GGUF CI / Unsloth install + inference without Visual Studio (push) Waiting to run
Windows Unsloth GGUF CI / GPU prebuilt resolves without Visual Studio (push) Waiting to run
Windows Unsloth GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection (VS 2022) (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection (VS 2026) (push) Waiting to run
Windows Unsloth GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Waiting to run
Windows Unsloth GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Waiting to run
Windows Unsloth UI CI / Chat UI Tests (push) Waiting to run
Some checks are pending
Local Agent Guides CI / connection (openclaw) (push) Waiting to run
Local Agent Guides CI / connection (pi) (push) Waiting to run
Core / Core (HF=default + TRL=default) (push) Waiting to run
Core / Core (HF=4.57.6 + TRL<1) (push) Waiting to run
Core / Core (HF=latest + TRL=latest) (push) Waiting to run
Core / llama.cpp build + smoke (push) Waiting to run
Cross-platform parity / parity (ubuntu-latest) (push) Waiting to run
Cross-platform parity / parity (windows-latest) (push) Waiting to run
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Waiting to run
Local Agent Guides CI / connection (claude) (push) Waiting to run
Local Agent Guides CI / connection (codex) (push) Waiting to run
Local Agent Guides CI / connection (hermes) (push) Waiting to run
Local Agent Guides CI / connection (opencode) (push) Waiting to run
Local Agent Guides CI / file-edit (claude) (push) Waiting to run
Local Agent Guides CI / file-edit (codex) (push) Waiting to run
Local Agent Guides CI / file-edit (hermes) (push) Waiting to run
Local Agent Guides CI / file-edit (openclaw) (push) Waiting to run
Local Agent Guides CI / file-edit (opencode) (push) Waiting to run
Local Agent Guides CI / file-edit (pi) (push) Waiting to run
Local Agent Guides CI / resume (claude) (push) Waiting to run
Local Agent Guides CI / resume (codex) (push) Waiting to run
Local Agent Guides CI / resume (opencode) (push) Waiting to run
Local Agent Guides CI / resume (pi) (push) Waiting to run
Local Agent Guides CI / prompt-cache (gemma-3-270m) (push) Waiting to run
MLX CI on Mac M1 / dispatch (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Windows Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
Wheel CI / Wheel build + content sanity + import smoke (push) Waiting to run
Security audit / advisory audit (pip + npm + cargo) (push) Waiting to run
Security audit / pip scan-packages :: extras (push) Waiting to run
Security audit / pip scan-packages :: studio (push) Waiting to run
Security audit / pip scan-packages :: hf-stack (push) Waiting to run
Security audit / npm scan-packages (Unsloth frontend tarballs) (push) Waiting to run
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Waiting to run
Security audit / pytest tests/security (push) Waiting to run
Security audit / npm provenance + new install-script diff (push) Waiting to run
Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Backend CI / (Python 3.10) (push) Waiting to run
Backend CI / (Python 3.11) (push) Waiting to run
Backend CI / (Python 3.12) (push) Waiting to run
Backend CI / (Python 3.13) (push) Waiting to run
Backend CI / Repo tests (CPU) (push) Waiting to run
Unsloth export capability / capability (ubuntu-latest) (push) Waiting to run
Unsloth export capability / capability (windows-latest) (push) Waiting to run
Frontend CI / Frontend build + bundle sanity (push) Waiting to run
Unsloth GGUF CI / OpenAI, Anthropic API tests (push) Waiting to run
Unsloth GGUF CI / Tool calling Tests (push) Waiting to run
Unsloth GGUF CI / JSON, images (push) Waiting to run
Unsloth load-orchestrator CI / test (push) Waiting to run
Mac Studio GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Waiting to run
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Waiting to run
Mac Studio UI + API + Update CI / Chat UI, API and Update Tests (push) Waiting to run
Unsloth Tauri CI / Tauri Linux debug build (no codesign) (push) Waiting to run
Unsloth Tauri CI / Rust unit tests (windows) (push) Waiting to run
Unsloth UI CI / Chat UI Tests (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
Windows Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Windows Unsloth GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Windows Unsloth GGUF CI / Unsloth install + inference without Visual Studio (push) Waiting to run
Windows Unsloth GGUF CI / GPU prebuilt resolves without Visual Studio (push) Waiting to run
Windows Unsloth GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection (VS 2022) (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection (VS 2026) (push) Waiting to run
Windows Unsloth GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Waiting to run
Windows Unsloth GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Waiting to run
Windows Unsloth UI CI / Chat UI Tests (push) Waiting to run
* Report a denied UNSLOTH_LOCAL_LLAMA_CPP_DIR instead of aborting on errexit * Report a denied ancestor and stop on a denied install parent Two gaps in the first pass, both reproduced. A build under an unsearchable ancestor cannot be stat'd, so `[ ! -d ]` read it as missing and setup said "does not exist", sending the user to correct a path that was already right. `_report_denied_ancestor` walks up to the deepest ancestor it can stat and reports that one, so the message names the directory that actually needs the permission change. A genuinely absent path still reports as missing. Keeping the textual path when the install parent could not be canonicalized only moved the abort: `rm -rf` fails, `[ -e ]` is false because the parent cannot be stat'd, and the following `ln -sfn` then aborts under errexit with no [TAURI:ERROR]. Nothing can be written under a parent we cannot search, so report there instead of continuing. * Follow symlinks and terminate dirname options when locating a denied ancestor * Strip trailing slashes before probing for a symlinked denied ancestor * Tighten the denied-ancestor comments in setup.sh and its test --------- Co-authored-by: danielhanchen <moonshotaisubstack@gmail.com>
This commit is contained in:
parent
c84e3e2323
commit
9f37302e2e
2 changed files with 184 additions and 12 deletions
|
|
@ -978,20 +978,18 @@ _studio_owned_adoptable() {
|
|||
[ -f "$1/UNSLOTH_WHISPER_PREBUILT_INFO.json" ] && return 0
|
||||
return 1
|
||||
}
|
||||
# Search (+x), not read (+r), is what the marker probes need: inside a directory
|
||||
# we cannot search every probe reports absent, so our own install reads as someone else's.
|
||||
# Marker probes need search (+x), not read (+r): in an unsearchable dir every probe reports absent, so our install looks foreign.
|
||||
_studio_dir_unsearchable() {
|
||||
[ -d "$1" ] || return 1
|
||||
( cd "$1" ) 2>/dev/null && return 1
|
||||
( cd -- "$1" ) 2>/dev/null && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Also needs +r, for callers that list or replace the tree: mode 111 is searchable
|
||||
# but still fails install_llama_prebuilt.py.
|
||||
# Also needs +r for callers that list or replace the tree: mode 111 is searchable but still fails install_llama_prebuilt.py.
|
||||
_studio_dir_unreadable() {
|
||||
[ -d "$1" ] || return 1
|
||||
_studio_dir_unsearchable "$1" && return 0
|
||||
ls -A "$1" >/dev/null 2>&1 && return 1
|
||||
ls -A -- "$1" >/dev/null 2>&1 && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -1018,6 +1016,41 @@ _path_access_denied() {
|
|||
setup_fail 1 "Permission denied reading the existing $_pad_label at $_pad_dir. Delete or rename that folder (Unsloth reinstalls it) or restore access, then re-run setup. Reinstalling the app does not reset it."
|
||||
}
|
||||
|
||||
# POSIX follows a final symlink when the path ends in /, so "link/" is never -L. Strip it, but never past the root.
|
||||
_studio_rstrip_slash() {
|
||||
_srs_path="$1"
|
||||
while [ "$_srs_path" != "/" ] && [ "${_srs_path%/}" != "$_srs_path" ]; do
|
||||
_srs_path="${_srs_path%/}"
|
||||
done
|
||||
printf '%s' "$_srs_path"
|
||||
}
|
||||
|
||||
# An unsearchable ancestor makes a real path read as missing. Walk up to the deepest
|
||||
# ancestor we can stat and report it as the blocker; stay quiet if the path is just absent.
|
||||
_report_denied_ancestor() {
|
||||
_rda_probe="$(_studio_rstrip_slash "$1")"
|
||||
_rda_hops=0
|
||||
while [ ! -e "$_rda_probe" ] && [ "$_rda_probe" != "/" ] && [ "$_rda_probe" != "." ]; do
|
||||
# An unfollowable symlink is the deepest name we have, so walk its target:
|
||||
# the denied ancestor lives there. The hop cap breaks symlink cycles.
|
||||
if [ -L "$_rda_probe" ] && [ "$_rda_hops" -lt 40 ]; then
|
||||
_rda_hops=$((_rda_hops + 1))
|
||||
_rda_target="$(readlink -- "$_rda_probe")" || break
|
||||
case "$_rda_target" in
|
||||
/*) _rda_probe="$_rda_target" ;;
|
||||
*) _rda_probe="$(dirname -- "$_rda_probe")/$_rda_target" ;;
|
||||
esac
|
||||
_rda_probe="$(_studio_rstrip_slash "$_rda_probe")"
|
||||
continue
|
||||
fi
|
||||
# -- keeps a leading-dash path an operand, not a dirname option.
|
||||
_rda_probe="$(dirname -- "$_rda_probe")"
|
||||
done
|
||||
if _studio_dir_unsearchable "$_rda_probe"; then
|
||||
_path_access_denied "$_rda_probe" "$2" owner-unverified
|
||||
fi
|
||||
}
|
||||
|
||||
_assert_studio_owned_or_absent() {
|
||||
_aso_dir="$1"
|
||||
_aso_label="$2"
|
||||
|
|
@ -1948,10 +1981,17 @@ _has_local_llama_server() {
|
|||
_LOCAL_LLAMA_CPP_LINKED=false
|
||||
if [ -n "${UNSLOTH_LOCAL_LLAMA_CPP_DIR:-}" ]; then
|
||||
if [ ! -d "$UNSLOTH_LOCAL_LLAMA_CPP_DIR" ]; then
|
||||
# A build under an unsearchable ancestor cannot be stat'd, so report permissions
|
||||
# rather than sending the user to fix a path that is already correct.
|
||||
_report_denied_ancestor "$UNSLOTH_LOCAL_LLAMA_CPP_DIR" "UNSLOTH_LOCAL_LLAMA_CPP_DIR"
|
||||
step "llama.cpp" "UNSLOTH_LOCAL_LLAMA_CPP_DIR does not exist: $UNSLOTH_LOCAL_LLAMA_CPP_DIR" "$C_ERR"
|
||||
setup_fail 1 "UNSLOTH_LOCAL_LLAMA_CPP_DIR does not exist: $UNSLOTH_LOCAL_LLAMA_CPP_DIR"
|
||||
fi
|
||||
_RESOLVED_LOCAL="$(CDPATH= cd -P -- "$UNSLOTH_LOCAL_LLAMA_CPP_DIR" && pwd -P)"
|
||||
# In an if condition so a denied dir reports instead of tripping errexit.
|
||||
if ! _RESOLVED_LOCAL="$(CDPATH= cd -P -- "$UNSLOTH_LOCAL_LLAMA_CPP_DIR" 2>/dev/null && pwd -P)"; then
|
||||
# owner-unverified: this is the user's own tree, never advise deleting it.
|
||||
_path_access_denied "$UNSLOTH_LOCAL_LLAMA_CPP_DIR" "UNSLOTH_LOCAL_LLAMA_CPP_DIR" owner-unverified
|
||||
fi
|
||||
# Canonicalize the install path the same way before comparing: _RESOLVED_LOCAL
|
||||
# is fully resolved, but LLAMA_CPP_DIR is textual ($UNSLOTH_HOME/llama.cpp). If
|
||||
# $HOME (or UNSLOTH_HOME) contains a symlink, the two never match even when the
|
||||
|
|
@ -1961,7 +2001,13 @@ if [ -n "${UNSLOTH_LOCAL_LLAMA_CPP_DIR:-}" ]; then
|
|||
_CANON_LLAMA_CPP_DIR="$LLAMA_CPP_DIR"
|
||||
_LLAMA_CPP_PARENT="$(dirname "$LLAMA_CPP_DIR")"
|
||||
if [ -d "$_LLAMA_CPP_PARENT" ]; then
|
||||
_CANON_LLAMA_CPP_DIR="$(CDPATH= cd -P -- "$_LLAMA_CPP_PARENT" && pwd -P)/$(basename "$LLAMA_CPP_DIR")"
|
||||
# Nothing can be written under a parent we cannot search, so report here
|
||||
# rather than let the link below abort raw a few lines later.
|
||||
if _canon_parent="$(CDPATH= cd -P -- "$_LLAMA_CPP_PARENT" 2>/dev/null && pwd -P)"; then
|
||||
_CANON_LLAMA_CPP_DIR="$_canon_parent/$(basename "$LLAMA_CPP_DIR")"
|
||||
else
|
||||
_path_access_denied "$_LLAMA_CPP_PARENT" "Unsloth install directory" owner-unverified
|
||||
fi
|
||||
fi
|
||||
if [ "$_RESOLVED_LOCAL" = "$_CANON_LLAMA_CPP_DIR" ]; then
|
||||
# Points at the canonical install location itself: never delete-then-link
|
||||
|
|
|
|||
|
|
@ -26,10 +26,9 @@ echo "=== setup.sh: the guards exist and probe the right permission ==="
|
|||
|
||||
assert_contains "defines the unsearchable-directory probe" \
|
||||
"$SETUP_SH" "_studio_dir_unsearchable() {"
|
||||
# cd needs +x, exactly what the marker probes need; ls needs +r, which is neither
|
||||
# sufficient nor necessary. Pin the cd form.
|
||||
# cd needs +x, what the marker probes need; ls needs +r, neither sufficient nor necessary. Pin the cd form.
|
||||
assert_contains "the probe tests search (cd), not read (ls)" \
|
||||
"$SETUP_SH" '( cd "$1" ) 2>/dev/null && return 1'
|
||||
"$SETUP_SH" '( cd -- "$1" ) 2>/dev/null && return 1'
|
||||
assert_contains "defines the denial reporter" \
|
||||
"$SETUP_SH" "_path_access_denied() {"
|
||||
assert_contains "the ownership guard checks readability before blaming ownership" \
|
||||
|
|
@ -111,6 +110,25 @@ else
|
|||
ok "no unguarded rm -rf of the install dir remains"
|
||||
fi
|
||||
|
||||
# A bare $(cd ...) assignment aborts under errexit before setup_fail can report, leaving
|
||||
# an exit code with no [TAURI:ERROR]. Both must sit in an if condition, which errexit exempts.
|
||||
if grep -qE '^\s*_RESOLVED_LOCAL="\$\(CDPATH= cd' "$SETUP_SH"; then
|
||||
bad "a denied UNSLOTH_LOCAL_LLAMA_CPP_DIR reports instead of tripping errexit"
|
||||
else
|
||||
ok "a denied UNSLOTH_LOCAL_LLAMA_CPP_DIR reports instead of tripping errexit"
|
||||
fi
|
||||
if grep -qE '^\s*_CANON_LLAMA_CPP_DIR="\$\(CDPATH= cd' "$SETUP_SH"; then
|
||||
bad "an unsearchable install parent is reported instead of aborting"
|
||||
else
|
||||
ok "an unsearchable install parent is reported instead of aborting"
|
||||
fi
|
||||
# Carrying on past a denied parent only moves the abort to the ln a few lines down.
|
||||
assert_contains "a denied install parent stops rather than continuing" \
|
||||
"$SETUP_SH" '_path_access_denied "$_LLAMA_CPP_PARENT" "Unsloth install directory" owner-unverified'
|
||||
# An unsearchable ancestor makes a real path unstattable, so [ ! -d ] would call it missing.
|
||||
assert_contains "a denied ancestor is reported before the missing-path guard" \
|
||||
"$SETUP_SH" '_report_denied_ancestor "$UNSLOTH_LOCAL_LLAMA_CPP_DIR" "UNSLOTH_LOCAL_LLAMA_CPP_DIR"'
|
||||
|
||||
echo ""
|
||||
echo "=== behaviour against a genuinely unsearchable tree ==="
|
||||
|
||||
|
|
@ -123,7 +141,8 @@ import sys, pathlib
|
|||
src = pathlib.Path(sys.argv[1]).read_text()
|
||||
out = []
|
||||
for name in ("_studio_owned_adoptable", "_studio_dir_unsearchable",
|
||||
"_studio_dir_unreadable",
|
||||
"_studio_dir_unreadable", "_studio_rstrip_slash",
|
||||
"_report_denied_ancestor",
|
||||
"_path_access_denied", "_assert_studio_owned_or_absent"):
|
||||
i = src.index(name + "() {")
|
||||
out.append(src[i:src.index("\n}\n", i) + 3])
|
||||
|
|
@ -225,6 +244,113 @@ else
|
|||
fi
|
||||
chmod 755 "$NOLIST"
|
||||
|
||||
# A real build under an unsearchable ancestor must report permissions, not "missing".
|
||||
ANC="$WORK/anc"; mkdir -p "$ANC/denied/llama.cpp"
|
||||
chmod 000 "$ANC/denied"
|
||||
if [ -d "$ANC/denied/llama.cpp" ]; then
|
||||
echo " SKIP: this host cannot make an ancestor unsearchable (running as root?)"
|
||||
else
|
||||
ok "the ancestor is really unsearchable (negative control)"
|
||||
out=$(bash -c '. "$1"
|
||||
C_ERR= C_WARN= C_DIM= C_OK= C_RST=
|
||||
step() { printf "STEP|%s|%s\n" "$1" "$2"; }; substep() { :; }
|
||||
setup_fail() { printf "FAIL|%s\n" "$2"; exit "$1"; }
|
||||
_report_denied_ancestor "$2" "UNSLOTH_LOCAL_LLAMA_CPP_DIR"
|
||||
echo "NOT_REPORTED"' _ "$WORK/helpers.sh" "$ANC/denied/llama.cpp" 2>&1)
|
||||
case "$out" in
|
||||
*"cannot be read: permission denied"*) ok "a build under a denied ancestor reports permissions" ;;
|
||||
*) bad "a build under a denied ancestor reports permissions (got: $out)" ;;
|
||||
esac
|
||||
case "$out" in
|
||||
*"$ANC/denied"*) ok "the message names the denied ancestor, not the leaf" ;;
|
||||
*) bad "the message names the denied ancestor, not the leaf (got: $out)" ;;
|
||||
esac
|
||||
fi
|
||||
chmod 755 "$ANC/denied"
|
||||
# A genuinely missing path must still be reported as missing, not as denied.
|
||||
out=$(bash -c '. "$1"
|
||||
C_ERR= C_WARN= C_DIM= C_OK= C_RST=
|
||||
step() { :; }; substep() { :; }
|
||||
setup_fail() { printf "FAIL|%s\n" "$2"; exit "$1"; }
|
||||
_report_denied_ancestor "$2" "UNSLOTH_LOCAL_LLAMA_CPP_DIR"
|
||||
echo "NOT_REPORTED"' _ "$WORK/helpers.sh" "$WORK/definitely-absent" 2>&1)
|
||||
case "$out" in
|
||||
*NOT_REPORTED*) ok "a genuinely missing path is not reported as denied" ;;
|
||||
*) bad "a genuinely missing path is not reported as denied (got: $out)" ;;
|
||||
esac
|
||||
|
||||
# Run the reporter over $2 from directory $1, with errexit on like the real script.
|
||||
rda() {
|
||||
( cd "$1" && bash -c 'set -e
|
||||
. "$1"
|
||||
C_ERR= C_WARN= C_DIM= C_OK= C_RST=
|
||||
step() { printf "STEP|%s|%s\n" "$1" "$2"; }; substep() { :; }
|
||||
setup_fail() { printf "FAIL|%s\n" "$2"; exit "$1"; }
|
||||
_report_denied_ancestor "$2" "UNSLOTH_LOCAL_LLAMA_CPP_DIR"
|
||||
echo "NOT_REPORTED"' _ "$WORK/helpers.sh" "$2" 2>&1 )
|
||||
}
|
||||
|
||||
# A symlink under a denied ancestor is unstattable all the way down, so a lexical walk alone would call the build missing.
|
||||
SYM="$WORK/sym"; mkdir -p "$SYM/shared/denied/build/llama.cpp" "$SYM/tmp"
|
||||
ln -s "$SYM/shared/denied/build" "$SYM/tmp/local"
|
||||
chmod 000 "$SYM/shared/denied"
|
||||
if [ -d "$SYM/tmp/local/llama.cpp" ]; then
|
||||
echo " SKIP: this host cannot make an ancestor unsearchable (running as root?)"
|
||||
else
|
||||
ok "the symlink target is really unreachable (negative control)"
|
||||
out=$(rda "$WORK" "$SYM/tmp/local/llama.cpp")
|
||||
case "$out" in
|
||||
*"$SYM/shared/denied"*) ok "a symlinked build names the denied target ancestor" ;;
|
||||
*) bad "a symlinked build names the denied target ancestor (got: $out)" ;;
|
||||
esac
|
||||
fi
|
||||
chmod 755 "$SYM/shared/denied"
|
||||
|
||||
# A trailing slash follows the link, so "link/" is not -L: it must still report.
|
||||
chmod 000 "$SYM/shared/denied"
|
||||
if [ -d "$SYM/tmp/local/llama.cpp" ]; then
|
||||
echo " SKIP: this host cannot make an ancestor unsearchable (running as root?)"
|
||||
else
|
||||
case "$(rda "$WORK" "$SYM/tmp/local/")" in
|
||||
*"$SYM/shared/denied"*) ok "a trailing slash still finds the denied target" ;;
|
||||
*) bad "a trailing slash still finds the denied target" ;;
|
||||
esac
|
||||
fi
|
||||
chmod 755 "$SYM/shared/denied"
|
||||
|
||||
# Stripping must stop at the root instead of emptying the path.
|
||||
case "$(bash -c '. "$1"; _studio_rstrip_slash "/"; printf "|"; _studio_rstrip_slash "//"' _ "$WORK/helpers.sh")" in
|
||||
"/|/") ok "stripping trailing slashes never consumes the root" ;;
|
||||
*) bad "stripping trailing slashes never consumes the root" ;;
|
||||
esac
|
||||
|
||||
# A dangling symlink is genuinely missing, so it must not be reported as denied.
|
||||
ln -s "$SYM/gone" "$SYM/tmp/dangle"
|
||||
case "$(rda "$WORK" "$SYM/tmp/dangle/llama.cpp")" in
|
||||
*NOT_REPORTED*) ok "a dangling symlink is not reported as denied" ;;
|
||||
*) bad "a dangling symlink is not reported as denied" ;;
|
||||
esac
|
||||
|
||||
# A symlink cycle must terminate on the hop cap instead of looping forever.
|
||||
ln -s "$SYM/tmp/a" "$SYM/tmp/b"; ln -s "$SYM/tmp/b" "$SYM/tmp/a"
|
||||
case "$(rda "$WORK" "$SYM/tmp/a/llama.cpp")" in
|
||||
*NOT_REPORTED*) ok "a symlink cycle terminates without reporting" ;;
|
||||
*) bad "a symlink cycle terminates without reporting" ;;
|
||||
esac
|
||||
|
||||
# A leading-dash path must reach the reporter, not be eaten as a dirname option and abort on errexit.
|
||||
DASH="$WORK/dash"; mkdir -p "$DASH"
|
||||
( cd "$DASH" && mkdir -p -- "-denied/llama.cpp" && chmod 000 -- "-denied" )
|
||||
if [ -d "$DASH/-denied/llama.cpp" ]; then
|
||||
echo " SKIP: this host cannot make an ancestor unsearchable (running as root?)"
|
||||
else
|
||||
case "$(rda "$DASH" "-denied/llama.cpp")" in
|
||||
*"cannot be read: permission denied"*) ok "a leading-dash path reports instead of aborting" ;;
|
||||
*) bad "a leading-dash path reports instead of aborting" ;;
|
||||
esac
|
||||
fi
|
||||
chmod 755 -- "$DASH/-denied"
|
||||
|
||||
echo ""
|
||||
echo "=== Results ==="
|
||||
echo " PASS: $PASS"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue