porchlight/tests/conftest.py
Johan Lundberg c7550cbf09
fix(security): lock down signing-key file permissions
Private JWK files were written under the default umask (observed 0664 — group
and world readable). Create the key directory 0700, chmod private key files
(private_jwks.json, token_jwks.json) to 0600 after they are written, and
refuse to start if a pre-existing private key is group/world accessible.

Tests now use an isolated per-test key directory.

Refs: porchlight-91i

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 15:21:27 +02:00

46 lines
1.3 KiB
Python

import re
from collections.abc import AsyncIterator
from pathlib import Path
import pytest
from httpx import ASGITransport, AsyncClient
from porchlight.app import create_app
from porchlight.config import Settings
from porchlight.rate_limit import limiter
@pytest.fixture
def settings(tmp_path: Path) -> Settings:
return Settings(
issuer="http://localhost:8000",
sqlite_path=":memory:",
session_https_only=False,
signing_key_path=str(tmp_path / "keys"),
)
@pytest.fixture
async def client(settings: Settings) -> AsyncIterator[AsyncClient]:
app = create_app(settings)
transport = ASGITransport(app=app)
async with app.router.lifespan_context(app), AsyncClient(transport=transport, base_url=settings.issuer) as ac:
yield ac
@pytest.fixture(autouse=True)
def _reset_rate_limiter() -> None:
"""Reset the rate limiter storage before each test."""
limiter.reset()
async def get_csrf_token(client: AsyncClient) -> str:
"""Get a CSRF token by visiting the login page.
Returns the token string. The session cookie is automatically stored
in the client's cookie jar (httpx.AsyncClient persists cookies).
"""
resp = await client.get("/login")
match = re.search(r'name="csrf-token" content="([^"]+)"', resp.text)
assert match, "CSRF meta tag not found in page"
return match.group(1)