Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
"""Symlink-refusal and permission tests for tools.spill_safety.
|
||||
|
||||
The bug class: spill/cache writers used ``open(path, "w")`` /
|
||||
``Path.write_text`` in predictable directories, which follows a pre-planted
|
||||
symlink and redirects the write onto an arbitrary user-owned file. Every
|
||||
helper must refuse the link (never write through it) while keeping normal
|
||||
writes byte-identical.
|
||||
"""
|
||||
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from tools.spill_safety import (
|
||||
ensure_spill_dir,
|
||||
open_exclusive,
|
||||
write_text_exclusive,
|
||||
)
|
||||
|
||||
posix_only = pytest.mark.skipif(sys.platform == "win32", reason="POSIX perms/symlinks")
|
||||
|
||||
|
||||
def test_write_creates_file_with_content(tmp_path):
|
||||
target = tmp_path / "spill.txt"
|
||||
write_text_exclusive(target, "hello\n")
|
||||
assert target.read_text(encoding="utf-8") == "hello\n"
|
||||
|
||||
|
||||
@posix_only
|
||||
def test_private_file_is_0600(tmp_path):
|
||||
target = tmp_path / "spill.txt"
|
||||
write_text_exclusive(target, "secret", private=True)
|
||||
assert stat.S_IMODE(os.lstat(target).st_mode) == 0o600
|
||||
|
||||
|
||||
@posix_only
|
||||
def test_private_dir_is_0700_and_tightened(tmp_path):
|
||||
d = tmp_path / "spills"
|
||||
d.mkdir(mode=0o755)
|
||||
ensure_spill_dir(d, private=True)
|
||||
assert stat.S_IMODE(os.lstat(d).st_mode) == 0o700
|
||||
|
||||
|
||||
def test_ensure_spill_dir_refuses_symlinked_leaf(tmp_path):
|
||||
victim = tmp_path / "victim-dir"
|
||||
victim.mkdir()
|
||||
link = tmp_path / "spills"
|
||||
link.symlink_to(victim)
|
||||
with pytest.raises(OSError):
|
||||
ensure_spill_dir(link)
|
||||
|
||||
|
||||
def test_refuses_planted_symlink(tmp_path):
|
||||
"""The core attack: symlink at the spill path must fail, not redirect."""
|
||||
victim = tmp_path / "victim.txt"
|
||||
victim.write_text("original")
|
||||
target = tmp_path / "spill.txt"
|
||||
target.symlink_to(victim)
|
||||
with pytest.raises(OSError):
|
||||
write_text_exclusive(target, "attacker-controlled")
|
||||
assert victim.read_text() == "original"
|
||||
|
||||
|
||||
def test_refuses_dangling_symlink(tmp_path):
|
||||
target = tmp_path / "spill.txt"
|
||||
target.symlink_to(tmp_path / "does-not-exist.txt")
|
||||
with pytest.raises(OSError):
|
||||
write_text_exclusive(target, "x")
|
||||
assert not (tmp_path / "does-not-exist.txt").exists()
|
||||
|
||||
|
||||
def test_overwrite_removes_symlink_not_its_target(tmp_path):
|
||||
victim = tmp_path / "victim.txt"
|
||||
victim.write_text("original")
|
||||
target = tmp_path / "spill.txt"
|
||||
target.symlink_to(victim)
|
||||
write_text_exclusive(target, "redacted copy", overwrite=True)
|
||||
# Link replaced by a real file; the link's target untouched.
|
||||
assert not target.is_symlink()
|
||||
assert target.read_text(encoding="utf-8") == "redacted copy"
|
||||
assert victim.read_text() == "original"
|
||||
|
||||
|
||||
def test_overwrite_replaces_regular_file(tmp_path):
|
||||
target = tmp_path / "spill.txt"
|
||||
target.write_text("raw")
|
||||
write_text_exclusive(target, "redacted", overwrite=True)
|
||||
assert target.read_text(encoding="utf-8") == "redacted"
|
||||
|
||||
|
||||
def test_overwrite_refuses_directory(tmp_path):
|
||||
target = tmp_path / "spill.txt"
|
||||
target.mkdir()
|
||||
with pytest.raises(OSError):
|
||||
write_text_exclusive(target, "x", overwrite=True)
|
||||
assert target.is_dir()
|
||||
|
||||
|
||||
def test_exclusive_create_fails_on_existing_without_overwrite(tmp_path):
|
||||
target = tmp_path / "spill.txt"
|
||||
target.write_text("first")
|
||||
with pytest.raises(OSError):
|
||||
write_text_exclusive(target, "second")
|
||||
assert target.read_text() == "first"
|
||||
|
||||
|
||||
def test_open_exclusive_streaming_write(tmp_path):
|
||||
target = tmp_path / "spill.log"
|
||||
with open_exclusive(target, errors="replace") as fh:
|
||||
fh.write("chunk1")
|
||||
fh.write("chunk2")
|
||||
assert target.read_text(encoding="utf-8") == "chunk1chunk2"
|
||||
Reference in New Issue
Block a user