""" Tests for GET/PUT /files/* — allowed set enforcement, read/write, IDENTITY.md. """ import pytest @pytest.mark.anyio async def test_files_list(client): r = await client.get("/files") assert r.status_code == 200 files = r.json()["files"] names = [f["name"] for f in files] assert "SOUL.md" in names assert "IDENTITY.md" in names assert "USER.md" in names @pytest.mark.anyio async def test_files_get_allowed(client): r = await client.get("/files/IDENTITY.md") assert r.status_code == 200 assert "content" in r.json() @pytest.mark.anyio async def test_files_get_not_in_allowed(client): """Files outside the ALLOWED set should return 404, not the file content.""" # Note: paths with '..' are normalized at the ASGI layer (e.g. /files/../config.py # becomes /config.py which hits the /{username} UI catch-all, not the files router). # Only test paths that stay within the files router's scope. for name in ("TASKS.json", "CRONS.json", "SCRATCH.md", ".env"): r = await client.get(f"/files/{name}") assert r.status_code == 404, f"Expected 404 for {name}, got {r.status_code}" @pytest.mark.anyio async def test_files_put_and_get(client): """Write a new value and read it back.""" content = "# Updated PROTOCOLS\nTest content." r = await client.put("/files/PROTOCOLS.md", json={"content": content}) assert r.status_code == 200 assert r.json()["ok"] is True r2 = await client.get("/files/PROTOCOLS.md") assert r2.status_code == 200 assert r2.json()["content"] == content @pytest.mark.anyio async def test_files_put_not_allowed(client): # '../../etc/passwd' normalizes to '/etc/passwd' at the ASGI layer — # no route handles PUT there, so 404 or 405 are both acceptable safe responses. r = await client.put("/files/../../etc/passwd", json={"content": "pwned"}) assert r.status_code in (404, 405) @pytest.mark.anyio async def test_files_get_missing_but_allowed(client, home_root): """An allowed file that doesn't exist yet returns 404.""" # Temporarily remove MEMORY_MID.md f = home_root / "scott" / "persona" / "inara" / "MEMORY_MID.md" existed = f.exists() if existed: backup = f.read_text() f.unlink() try: r = await client.get("/files/MEMORY_MID.md") assert r.status_code == 404 finally: if existed: f.write_text(backup)