diff --git a/tests/lib/test_bedrock.py b/tests/lib/test_bedrock.py index bc97af03f..a5e5290a1 100644 --- a/tests/lib/test_bedrock.py +++ b/tests/lib/test_bedrock.py @@ -4,9 +4,9 @@ import struct import typing as t import binascii -import tempfile import threading from typing import TypedDict, cast +from pathlib import Path from typing_extensions import Protocol import httpx2 @@ -61,13 +61,12 @@ def profiles() -> t.List[AwsConfigProfile]: def mock_aws_config( profiles: t.List[AwsConfigProfile], monkeypatch: t.Any, + tmp_path: Path, ) -> t.Iterable[None]: - with tempfile.NamedTemporaryFile(mode="w+", delete=True) as temp_file: - for profile in profiles: - temp_file.write(profile_to_ini(profile)) - temp_file.flush() - monkeypatch.setenv("AWS_CONFIG_FILE", str(temp_file.name)) - yield + config_file = tmp_path / "aws_config" + config_file.write_text("".join(profile_to_ini(profile) for profile in profiles)) + monkeypatch.setenv("AWS_CONFIG_FILE", str(config_file)) + yield @pytest.mark.respx() diff --git a/tests/lib/tools/memory_sync/test_delete_discipline.py b/tests/lib/tools/memory_sync/test_delete_discipline.py index 0483d0c23..d04c35c20 100644 --- a/tests/lib/tools/memory_sync/test_delete_discipline.py +++ b/tests/lib/tools/memory_sync/test_delete_discipline.py @@ -24,6 +24,8 @@ from .conftest import Clock, run_sync, listing_interrupted_by from ._fake_anthropic import MemoryServer, deleted, updated, fake_anthropic +pytestmark = pytest.mark.skipif(os.name != "posix", reason="FileStore refuses non-POSIX platforms") + LOGGER = "anthropic.lib.tools.agent_toolset" ELAPSED = memories_mod.DELETE_CORROBORATION_SECONDS + 1 @@ -165,7 +167,10 @@ async def test_a_folder_destroyed_mid_sync_sends_no_deletes(tmp_path: Path, cloc assert server.files == {"a.md": "v1", "keep.md": "v1"} -@pytest.mark.skipif(os.geteuid() == 0, reason="permission checks do not bind root") +@pytest.mark.skipif( + os.name != "posix" or getattr(os, "geteuid", lambda: -1)() == 0, + reason="permission checks only apply on POSIX non-root", +) @pytest.mark.asyncio() async def test_an_unreadable_subdirectory_fails_the_pass_instead_of_reading_as_deletions( tmp_path: Path, clock: Clock, caplog: pytest.LogCaptureFixture diff --git a/tests/lib/tools/memory_sync/test_memory_sync.py b/tests/lib/tools/memory_sync/test_memory_sync.py index df55bc235..89d5725ec 100644 --- a/tests/lib/tools/memory_sync/test_memory_sync.py +++ b/tests/lib/tools/memory_sync/test_memory_sync.py @@ -25,6 +25,8 @@ from .conftest import Clock, run_sync from ._fake_anthropic import MemoryServer, created, deleted, updated, _status_error, fake_anthropic +pytestmark = pytest.mark.skipif(os.name != "posix", reason="FileStore refuses non-POSIX platforms") + LOGGER = "anthropic.lib.tools.agent_toolset" @@ -370,6 +372,8 @@ async def test_an_unwritable_mount_path_fails_the_download(tmp_path: Path) -> No """A mount the host cannot provide is an environment failure: the download raises loudly (failing the work item) instead of degrading to a session with silently-empty memory.""" + if os.name != "posix": + pytest.skip("chmod semantics only apply on POSIX") if os.geteuid() == 0: pytest.skip("directory modes do not bind root") parent = tmp_path / "mnt" diff --git a/tests/lib/tools/test_agent_toolset.py b/tests/lib/tools/test_agent_toolset.py index d52c5e8f1..d7b793f86 100644 --- a/tests/lib/tools/test_agent_toolset.py +++ b/tests/lib/tools/test_agent_toolset.py @@ -784,6 +784,7 @@ async def test_bash_outer_cancel_closes_subprocess_no_stale_state(tmp_path: Path @needs_pydantic_v2 +@needs_symlinks async def test_read_through_symlink_escape_is_rejected(tmp_path: Path) -> None: """resolve_path realpaths, so a symlink that escapes the workdir is caught.""" outside = tmp_path / "outside" @@ -886,6 +887,7 @@ async def test_glob_rejects_dotdot_pattern(tmp_path: Path) -> None: @needs_pydantic_v2 +@needs_symlinks async def test_glob_post_filters_symlink_escape(tmp_path: Path) -> None: """A symlink traversed mid-pattern must not let a glob result escape the workdir.""" outside = tmp_path / "outside" @@ -911,6 +913,7 @@ async def test_glob_drops_matches_that_cannot_be_canonicalised(tmp_path: Path) - @needs_pydantic_v2 +@needs_symlinks async def test_grep_skips_symlinked_files(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: """The fallback walker must not read through a symlink that escapes the workdir.""" secret = tmp_path / "secret.txt" diff --git a/tests/lib/tools/test_file_store.py b/tests/lib/tools/test_file_store.py index 3b694a8b2..f65383ee6 100644 --- a/tests/lib/tools/test_file_store.py +++ b/tests/lib/tools/test_file_store.py @@ -132,7 +132,7 @@ async def test_filestore_get_does_not_follow_a_symlink_leaf(store: FileStore) -> async def test_filestore_get_refuses_a_non_regular_file(store: FileStore) -> None: """A present-but-non-regular leaf (fifo, symlink, ...) raises FileStoreError instead of hanging or being read.""" - os.mkfifo(store.root().path / "pipe.md") + os.mkfifo(store.root().path / "pipe.md") # pyright: ignore[reportAttributeAccessIssue,reportUnknownMemberType] os.symlink(store.root().path / "pipe.md", store.root().path / "link.md") with pytest.raises(FileStoreError, match="not a regular file"): @@ -204,7 +204,10 @@ async def test_filestore_hashtree_hashes_regular_files_and_skips_symlinks(tmp_pa assert await store.hashtree("sub/") == {"sub/b.md": _sha("bravo")} -@pytest.mark.skipif(os.geteuid() == 0, reason="permission checks do not bind root") +@pytest.mark.skipif( + os.name != "posix" or getattr(os, "geteuid", lambda: -1)() == 0, + reason="permission checks only apply on POSIX non-root", +) @pytest.mark.asyncio() async def test_filestore_listings_raise_on_an_unreadable_subdirectory(store: FileStore) -> None: """An unreadable subdirectory fails the listing rather than dropping out of it.""" @@ -314,7 +317,10 @@ async def test_filestore_remove_unlinks_a_dangling_symlink(store: FileStore) -> assert not (store.root().path / "dangling.md").is_symlink() -@pytest.mark.skipif(os.geteuid() == 0, reason="permission checks do not bind root") +@pytest.mark.skipif( + os.name != "posix" or getattr(os, "geteuid", lambda: -1)() == 0, + reason="permission checks only apply on POSIX non-root", +) @pytest.mark.asyncio() async def test_filestore_open_raises_on_an_unreadable_mount_path(tmp_path: Path) -> None: """A mount path the process cannot stat raises at open — it is never read