"""PR-Worker-Pool-Registry-1B — /internal/worker/* 권한 분리 (정정 #2 보조). worker user 외 모든 사용자 = 403. 1. voice-memo-bot JWT → 403 2. 일반 user JWT → 403 (401 = token 자체 invalid 시. 본 테스트는 토큰 자체는 유효 + 권한만 부족.) """ from __future__ import annotations import os import sys import pytest import pytest_asyncio sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "app")) from httpx import ASGITransport, AsyncClient from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from _worker_pool_helpers import ensure_user, get_database_url, mint_access_token @pytest_asyncio.fixture async def setup(monkeypatch): monkeypatch.setenv("LAPTOP_WORKER_BOT_USERNAME", "laptop-worker-bot") engine = create_async_engine(get_database_url()) sm = async_sessionmaker(engine, expire_on_commit=False) async with sm() as session: await ensure_user(session, "voice-memo-bot") await ensure_user(session, "test-regular-user-1b") await engine.dispose() @pytest_asyncio.fixture async def client(): from main import app async with AsyncClient( transport=ASGITransport(app=app), base_url="http://test", ) as ac: yield ac @pytest.mark.asyncio async def test_voice_memo_bot_jwt_rejected(client, setup): """voice-memo-bot JWT 로 /internal/worker/register 호출 → 403.""" token = mint_access_token("voice-memo-bot") r = await client.post( "/internal/worker/register", json={ "worker_id": "x", "device_label": "x", "worker_class": "x", "tier": "x", }, headers={"Authorization": f"Bearer {token}"}, ) assert r.status_code == 403, r.text assert "worker user" in r.json().get("detail", "").lower() @pytest.mark.asyncio async def test_regular_user_jwt_rejected(client, setup): """일반 user JWT 로 /internal/worker/heartbeat 호출 → 403.""" token = mint_access_token("test-regular-user-1b") r = await client.post( "/internal/worker/heartbeat", json={"worker_id": "x", "status": "available"}, headers={"Authorization": f"Bearer {token}"}, ) assert r.status_code == 403, r.text