feat(bat-019): REQ-044 GET /v1/assets require_read + REQ-045 GET /v1/daemons caller-scope

REQ-044: list_catalog_assets 의존성을 require_admin → require_read로 완화.
asset 쓰기(POST/PATCH/DELETE)는 require_admin 유지.

REQ-045: GET /v1/daemons 신규 엔드포인트 — caller 소유 데몬만 반환(require_read).
user_id=None(env 토큰)은 빈 목록 200. DaemonResponse/DaemonListResponse 스키마 추가.

기존 테스트(test_v1.py, test_asset_catalog.py, test_daemon_assignment.py, test_tags_master.py)
REQ-044 권한 완화에 맞게 업데이트. test_v1_daemons.py 신규 추가(13 케이스).

pytest 472 passed, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
This commit is contained in:
2026-06-27 10:36:04 +09:00
co-authored by Claude Sonnet 4.6
parent d43ff430c2
commit c5288a8c42
13 changed files with 769 additions and 39 deletions
+20 -5
View File
@@ -1023,25 +1023,40 @@ def test_get_v1_assets_market_filter() -> None:
assert items[0]["symbol"] == "005930"
# REQ-010 AC-12: non-admin → HTTP 403
def test_get_v1_assets_user_token_returns_403() -> None:
# REQ-044: GET /v1/assets is now require_read — user/service tokens return 200
def test_get_v1_assets_user_token_returns_200() -> None:
"""REQ-044: read user token accepted by GET /v1/assets."""
client, _, patches = _make_catalog_get_client(_USER_KW, [], {})
try:
resp = client.get("/v1/assets", headers={"Authorization": "Bearer user"})
finally:
for p in patches:
p.stop()
assert resp.status_code == 403
assert resp.status_code == 200
assert resp.json()["total"] == 0
def test_get_v1_assets_service_token_returns_403() -> None:
def test_get_v1_assets_service_token_returns_200() -> None:
"""REQ-044: trade-write service token accepted by GET /v1/assets (trade-write >= read)."""
client, _, patches = _make_catalog_get_client(_SERVICE_KW, [], {})
try:
resp = client.get("/v1/assets", headers={"Authorization": "Bearer svc"})
finally:
for p in patches:
p.stop()
assert resp.status_code == 403
assert resp.status_code == 200
assert resp.json()["total"] == 0
def test_get_v1_assets_no_token_returns_401() -> None:
"""GET /v1/assets without token returns 401 (require_read still gates auth)."""
client, _, patches = _make_catalog_get_client(_ADMIN_KW, [], {})
try:
resp = client.get("/v1/assets") # no Authorization header
finally:
for p in patches:
p.stop()
assert resp.status_code == 401
# ---------------------------------------------------------------------------