- EvalRun.triggered_by 全链路(manual/ai_assistant/cli)+ 迁移 b7d4e6f81c22 - 标准 agenteval-run SKILL.md 纳入版本管理,deploy 脚本同步 + API Key 注入 - 简单登录:AGENTEVAL_ADMIN_PASSWORD + HMAC 会话 token,require_auth 双凭据 - 对比报告限同场景(400)+ 空 results 误判修复 - /api/stats/dashboard 扩展聚合;/api/runs 返回场景/对象名 - 测试 218 → 232
90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
"""Integration tests for the login gate: /api/auth/* and require_auth."""
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlmodel import Session, SQLModel, create_engine
|
|
|
|
from agenteval.config.settings import Settings
|
|
from agenteval.web.app import app
|
|
from agenteval.web.deps import get_db
|
|
|
|
|
|
@pytest.fixture()
|
|
def client_with_db(tmp_path):
|
|
from agenteval.storage.db import ( # noqa: F401
|
|
EvalResultDB, EvalRunDB, EvalTargetDB, ScenarioDB, TurnDB,
|
|
)
|
|
engine = create_engine(
|
|
f"sqlite:///{tmp_path / 'auth_api.db'}",
|
|
connect_args={"check_same_thread": False},
|
|
)
|
|
SQLModel.metadata.create_all(engine)
|
|
session = Session(engine)
|
|
|
|
def override_get_db():
|
|
try:
|
|
yield session
|
|
finally:
|
|
pass
|
|
|
|
app.dependency_overrides[get_db] = override_get_db
|
|
client = TestClient(app)
|
|
yield client
|
|
app.dependency_overrides.clear()
|
|
session.close()
|
|
|
|
|
|
def _patch_settings(monkeypatch, **kwargs):
|
|
settings = Settings(_env_file=None, **kwargs)
|
|
from agenteval.web import deps as deps_module
|
|
from agenteval.web.routers import auth as auth_module
|
|
|
|
monkeypatch.setattr(deps_module, "get_settings", lambda: settings)
|
|
monkeypatch.setattr(auth_module, "get_settings", lambda: settings)
|
|
return settings
|
|
|
|
|
|
def test_no_credentials_configured_is_open(client_with_db, monkeypatch):
|
|
_patch_settings(monkeypatch)
|
|
assert client_with_db.get("/api/targets").status_code == 200
|
|
status = client_with_db.get("/api/auth/status").json()
|
|
assert status == {"auth_required": False, "authenticated": True}
|
|
|
|
|
|
def test_login_disabled_returns_400(client_with_db, monkeypatch):
|
|
_patch_settings(monkeypatch)
|
|
resp = client_with_db.post("/api/auth/login", json={"password": "whatever"})
|
|
assert resp.status_code == 400
|
|
|
|
|
|
def test_admin_password_gates_api(client_with_db, monkeypatch):
|
|
_patch_settings(monkeypatch, admin_password="s3cret")
|
|
|
|
# No credentials → 401.
|
|
assert client_with_db.get("/api/targets").status_code == 401
|
|
|
|
# Wrong password → 401.
|
|
assert client_with_db.post("/api/auth/login", json={"password": "nope"}).status_code == 401
|
|
|
|
# Correct password → token that unlocks the API.
|
|
token = client_with_db.post("/api/auth/login", json={"password": "s3cret"}).json()["token"]
|
|
resp = client_with_db.get("/api/targets", headers={"X-Auth-Token": token})
|
|
assert resp.status_code == 200
|
|
|
|
status = client_with_db.get("/api/auth/status", headers={"X-Auth-Token": token}).json()
|
|
assert status == {"auth_required": True, "authenticated": True}
|
|
assert client_with_db.get("/api/auth/status").json()["authenticated"] is False
|
|
|
|
|
|
def test_api_key_still_works_alongside_login(client_with_db, monkeypatch):
|
|
_patch_settings(monkeypatch, admin_password="s3cret", api_key="machine-key")
|
|
|
|
assert client_with_db.get("/api/targets").status_code == 401
|
|
assert client_with_db.get("/api/targets", headers={"X-API-Key": "machine-key"}).status_code == 200
|
|
assert client_with_db.get("/api/targets", headers={"X-API-Key": "wrong"}).status_code == 401
|
|
|
|
|
|
def test_health_stays_open(client_with_db, monkeypatch):
|
|
_patch_settings(monkeypatch, admin_password="s3cret")
|
|
assert client_with_db.get("/api/health").status_code == 200
|