Spaces:
Sleeping
Sleeping
| """ | |
| server/app.py — OpenEnv-compatible FastAPI application. | |
| This is the canonical app entry point expected by `openenv validate`. | |
| The root server.py re-exports this for backwards compatibility. | |
| """ | |
| from fastapi import FastAPI, Request | |
| from environment import VulnPatchEnv | |
| app = FastAPI( | |
| title="vuln-patch-env", | |
| description="OpenEnv environment for code vulnerability detection and patching.", | |
| version="1.0.0", | |
| ) | |
| # One shared environment instance per server process (stateless reset on each call) | |
| _env = VulnPatchEnv() | |
| async def health_check(): | |
| return {"status": "running", "message": "vuln-patch-env OpenEnv Server is live"} | |
| async def health(): | |
| """Required by openenv validate — must return {"status": "healthy"}.""" | |
| return {"status": "healthy"} | |
| async def metadata(): | |
| """Required by openenv validate — must return name and description.""" | |
| return { | |
| "name": "vuln-patch-env", | |
| "description": ( | |
| "A real-world code security environment where AI agents detect " | |
| "and patch vulnerabilities (hardcoded secrets, SQL injection, " | |
| "command injection) in Python code." | |
| ), | |
| "version": "1.0.0", | |
| "tasks": ["easy", "medium", "hard"], | |
| } | |
| async def schema(): | |
| """Required by openenv validate — must return action, observation and state schemas.""" | |
| from environment import Action, Observation | |
| return { | |
| "action": Action.model_json_schema(), | |
| "observation": Observation.model_json_schema(), | |
| "state": Observation.model_json_schema(), # state has same shape as observation | |
| } | |
| async def mcp_endpoint(request: Request): | |
| """ | |
| Minimal Model Context Protocol (MCP) endpoint. | |
| Required by openenv validate — must return a JSON-RPC 2.0 envelope. | |
| """ | |
| try: | |
| body = await request.json() | |
| except Exception: | |
| body = {} | |
| return { | |
| "jsonrpc": "2.0", | |
| "id": body.get("id", 1), | |
| "result": { | |
| "name": "vuln-patch-env", | |
| "description": "OpenEnv environment for code vulnerability patching.", | |
| "tools": ["reset", "step", "state"], | |
| }, | |
| } | |
| async def reset_endpoint(request: Request): | |
| """Reset the environment and return the initial observation.""" | |
| try: | |
| body = await request.json() | |
| task = body.get("task", "easy") | |
| except Exception: | |
| task = "easy" | |
| _env.task = task | |
| obs = _env.reset() | |
| return {"status": "ok", "observation": obs.model_dump()} | |
| async def step_endpoint(request: Request): | |
| """Take one step in the environment.""" | |
| from environment import Action | |
| try: | |
| body = await request.json() | |
| action = Action(**body) | |
| except Exception as e: | |
| return {"error": str(e)}, 400 | |
| obs, reward, done, info = _env.step(action) | |
| return { | |
| "observation": obs.model_dump(), | |
| "reward": reward.value, | |
| "done": done, | |
| "info": info.model_dump(), | |
| } | |
| async def state_endpoint(): | |
| """Return the current environment state.""" | |
| return {"observation": _env.state().model_dump()} | |
| def main(): | |
| """Entry point for the server script (used by pyproject.toml [project.scripts]).""" | |
| import uvicorn | |
| uvicorn.run("server.app:app", host="0.0.0.0", port=7860, reload=False) | |
| if __name__ == "__main__": | |
| main() | |