cybersec / server /app.py
Lonelyguyse1's picture
Upload folder using huggingface_hub
d550d57 verified
"""FastAPI application for the Cybersec OpenEnv environment.
The OpenEnv ``openenv.yaml`` declares ``app: server.app:app`` so this module
must expose a module-level ``app`` and a ``main`` callable for uvicorn.
Endpoints (provided by ``openenv.core.env_server.create_app``):
* POST /reset - one-shot reset of a fresh environment instance
* POST /step - one-shot step of a fresh environment instance
* GET /state - current environment state
* GET /schema - action / observation schemas
* WS /ws - persistent WebSocket session (use this for episodes)
Configuration knobs (read at process start, not per-request):
``CYBERSEC_SCENARIO_ID`` - default scenario; if unset, scenario follows
reset ``seed`` (see ``CybersecEnvironment.reset``;
omitted seed uses a random seed per reset).
``CYBERSEC_ATTACKER_PERSONALITY`` - default personality; if unset, sampled by RNG.
``CYBERSEC_MAX_CONCURRENT_ENVS`` - max concurrent WebSocket sessions (default 8).
"""
from __future__ import annotations
import os
from typing import Optional
from openenv.core.env_server.http_server import create_app
try:
from ..models import AttackerPersonality, CybersecAction, CybersecObservation
from .cybersec_environment import CybersecEnvironment
except ImportError: # pragma: no cover - hit only when CWD == cybersec/ and we're run as `server.app`
from models import AttackerPersonality, CybersecAction, CybersecObservation # type: ignore[no-redef]
from server.cybersec_environment import CybersecEnvironment # type: ignore[no-redef]
def _env_factory() -> CybersecEnvironment:
scenario_id: Optional[str] = os.getenv("CYBERSEC_SCENARIO_ID") or None
personality_raw: Optional[str] = os.getenv("CYBERSEC_ATTACKER_PERSONALITY") or None
personality = AttackerPersonality(personality_raw) if personality_raw else None
return CybersecEnvironment(
default_scenario_id=scenario_id,
default_personality=personality,
)
_max_concurrent = int(os.getenv("CYBERSEC_MAX_CONCURRENT_ENVS", "8"))
app = create_app(
env=_env_factory,
action_cls=CybersecAction,
observation_cls=CybersecObservation,
env_name="cybersec",
max_concurrent_envs=_max_concurrent,
)
def main() -> None:
"""Console-script entry point.
Used by:
* the ``server`` console script declared in ``pyproject.toml``
(``openenv validate`` requires this exact name).
* ``python -m cybersec.server.app`` and ``python server/app.py``.
CLI flags are honored for local development; ``CYBERSEC_HOST`` /
``CYBERSEC_PORT`` env vars take precedence so the Docker image and
Hugging Face Spaces deploy can override the bind address without code
changes.
"""
import argparse
import uvicorn
parser = argparse.ArgumentParser(description="Run the Cybersec OpenEnv server.")
parser.add_argument("--host", default="0.0.0.0")
parser.add_argument("--port", type=int, default=8000)
args = parser.parse_args()
host = os.getenv("CYBERSEC_HOST", args.host)
port = int(os.getenv("CYBERSEC_PORT", str(args.port)))
uvicorn.run(app, host=host, port=port, reload=False)
if __name__ == "__main__":
main()
__all__ = ["app", "main"]