from pathlib import Path import pytest from app.main import spa_fallback @pytest.fixture def static_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path: static = tmp_path / 'static' static.mkdir() (static / 'index.html').write_text('index', encoding='utf-8') (static / 'app.js').write_text("console.log('app')", encoding='utf-8') secret = tmp_path / 'secret.txt' secret.write_text('TOP SECRET', encoding='utf-8') monkeypatch.setattr('app.main.static_dir', static) return static def static_index(static_dir: Path) -> Path: return static_dir / 'index.html' def test_returns_existing_file(static_dir: Path) -> None: response = spa_fallback('app.js') assert response.path == static_dir / 'app.js' def test_unknown_path_falls_back_to_index(static_dir: Path) -> None: response = spa_fallback('does/not/exist.js') assert response.path == static_index(static_dir) def test_traversal_does_not_leak_outside_static(static_dir: Path) -> None: response = spa_fallback('../secret.txt') assert response.path == static_index(static_dir) response = spa_fallback('%2e%2e/secret.txt') assert response.path == static_index(static_dir) def test_symlink_outside_static_is_blocked(static_dir: Path, tmp_path: Path) -> None: target = tmp_path / 'outside.txt' target.write_text('secret', encoding='utf-8') link = static_dir / 'leak.txt' link.symlink_to(target) response = spa_fallback('leak.txt') assert response.path == static_index(static_dir)