Refuse sd.cpp install into unowned non-empty target dir
When the install target already exists, is non-empty and lacks the .unsloth-studio-owned marker (a user's own stable-diffusion.cpp checkout, or unrelated files beside a custom Studio root), install() previously still extracted the release into it. Skipping the ownership marker only stopped the uninstaller from deleting the directory; extraction still merged binaries into the user's working tree and could overwrite same-named files. Fail up front with a clear message pointing the user at a fresh/empty location before any download or extraction, leaving their directory untouched. Update the ownership test suite to assert the refusal.
This commit is contained in:
parent
5a17614b51
commit
da1770bb44
2 changed files with 21 additions and 8 deletions
|
|
@ -273,11 +273,12 @@ def test_install_into_empty_dir_claims_ownership(tmp_path, monkeypatch):
|
|||
assert (empty / ".unsloth-studio-owned").is_file()
|
||||
|
||||
|
||||
def test_install_into_nonempty_unowned_dir_does_not_claim_ownership(tmp_path, monkeypatch):
|
||||
def test_install_into_nonempty_unowned_dir_is_refused(tmp_path, monkeypatch):
|
||||
# A pre-existing, non-empty directory that Studio did not create (e.g. a user's own
|
||||
# stable-diffusion.cpp checkout) must NOT be marked owned: writing the marker would make the
|
||||
# uninstaller recursively delete the user's directory. The install still proceeds (extracts the
|
||||
# binary) but leaves the directory unowned so the uninstaller keeps it.
|
||||
# stable-diffusion.cpp checkout) must NOT be extracted into. Merging the release into it would
|
||||
# overwrite or mix our binaries into the user's working tree, and leaving it unowned only stops
|
||||
# the uninstaller from deleting it later. install() refuses up front and leaves the dir untouched
|
||||
# so the user can point us at a fresh/empty location.
|
||||
zb = _zip_with_sd_cli()
|
||||
_stub_release(monkeypatch, zip_bytes = zb, digest = "sha256:" + hashlib.sha256(zb).hexdigest())
|
||||
target = tmp_path / "stable-diffusion.cpp"
|
||||
|
|
@ -285,13 +286,13 @@ def test_install_into_nonempty_unowned_dir_does_not_claim_ownership(tmp_path, mo
|
|||
user_file = target / "USER_WORK"
|
||||
user_file.write_text("keep", encoding = "utf-8")
|
||||
|
||||
sd_cli = install(install_dir = target)
|
||||
with pytest.raises(RuntimeError, match = "not a Studio-managed directory"):
|
||||
install(install_dir = target)
|
||||
|
||||
# The user's file survives and no ownership marker was written.
|
||||
# The user's directory is left exactly as it was: file intact, no marker, nothing extracted.
|
||||
assert user_file.read_text(encoding = "utf-8") == "keep"
|
||||
assert not (target / ".unsloth-studio-owned").exists()
|
||||
# The binary was still installed (install is not refused).
|
||||
assert sd_cli.is_file() and sd_cli.name == "sd-cli"
|
||||
assert list(target.iterdir()) == [user_file]
|
||||
|
||||
|
||||
def test_reinstall_into_owned_dir_keeps_ownership(tmp_path, monkeypatch):
|
||||
|
|
|
|||
|
|
@ -418,6 +418,18 @@ def install(
|
|||
_pre_existing_entries = True
|
||||
# Empty dir, or one we already own, may be (re)claimed; a non-empty unowned dir may not.
|
||||
_may_own = (not _pre_existing_entries) or marker.is_file()
|
||||
# Refuse to extract into a pre-existing, non-empty directory we do not own (a user's own
|
||||
# stable-diffusion.cpp checkout, or unrelated files beside a custom Studio root). Not writing
|
||||
# the ownership marker only protects the uninstaller; extracting the release here would still
|
||||
# merge our binaries into the user's working tree and can overwrite same-named files. Fail with
|
||||
# a clear message so the user points us at a fresh/empty location instead of corrupting theirs.
|
||||
if not _may_own:
|
||||
raise RuntimeError(
|
||||
f"sd.cpp install target already exists and is not a Studio-managed directory: {target}. "
|
||||
f"Refusing to extract prebuilt binaries into it to avoid overwriting or mixing them "
|
||||
f"into your files. Remove or move that directory, or install into a different, empty "
|
||||
f"location (pass a different --install-dir / set the Studio sd.cpp install dir)."
|
||||
)
|
||||
used_repo, release, chosen = _resolve_with_fallback(accelerator, token)
|
||||
|
||||
if release is None or not chosen:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue