mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-06-30 07:15:30 +02:00
a5badefc29
Engine:
- Fix: inject IS_SANDBOX=1 so Claude Code's --dangerously-skip-permissions
works under root (real backend runs were exiting rc=1 immediately)
- models: expand to 40 models / 13 providers, tagged CLI vs API
(NVIDIA NIM, DeepSeek, Mistral, Qwen/DashScope, Groq, Together, OpenRouter,
Ollama, Gemini) — Qwen/DeepSeek/Llama usable via API
- backends: on_start callback surfaces the exact argv ("what runs behind it")
- orchestrator: require a Playwright screenshot per confirmed finding; collect
results/activity.json; auto-generate reports after a run
- report.py: HTML always + PDF via Typst engine (.typ source emitted too)
Web dashboard (webgui/, stdlib only — no npm/build):
- Sidebar dashboard (PentAGI-style): Run / Agents / Insights / Reports / Settings
- Multi-target runs; live execution console + per-task activity; finding cards
with screenshots; backend+provider+model pickers (CLI & API)
- Agents tab: browse 213 + add new .md agents from the UI
- Insights: interactive RL-weight + severity charts
- Reports: download/preview PDF + HTML
- Settings/API: execution mode, per-provider API keys, orchestrator, verbosity
- Endpoints: /api/agents (GET/POST), /api/rl, /api/config, /api/reports,
/reports/* + /shots/* static serving
Cleanup: retire replaced web stack (frontend React, FastAPI backend, core
orchestration, old test) to legacy/. Active engine + GUI are fully standalone.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
141 lines
4.4 KiB
Python
Executable File
141 lines
4.4 KiB
Python
Executable File
"""
|
|
NeuroSploit v3 - Scheduler API Router
|
|
|
|
CRUD endpoints for managing scheduled scan jobs.
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from fastapi import APIRouter, HTTPException, Request
|
|
from pydantic import BaseModel
|
|
from typing import Optional, List, Dict
|
|
|
|
router = APIRouter()
|
|
|
|
CONFIG_PATH = Path(__file__).parent.parent.parent.parent / "config" / "config.json"
|
|
|
|
|
|
class ScheduleJobRequest(BaseModel):
|
|
"""Request model for creating a scheduled job."""
|
|
job_id: str
|
|
target: str
|
|
scan_type: str = "quick"
|
|
cron_expression: Optional[str] = None
|
|
interval_minutes: Optional[int] = None
|
|
agent_role: Optional[str] = None
|
|
llm_profile: Optional[str] = None
|
|
|
|
|
|
class ScheduleJobResponse(BaseModel):
|
|
"""Response model for a scheduled job."""
|
|
id: str
|
|
target: str
|
|
scan_type: str
|
|
schedule: str
|
|
status: str
|
|
next_run: Optional[str] = None
|
|
last_run: Optional[str] = None
|
|
run_count: int = 0
|
|
|
|
|
|
@router.get("/", response_model=List[Dict])
|
|
async def list_scheduled_jobs(request: Request):
|
|
"""List all scheduled scan jobs."""
|
|
scheduler = getattr(request.app.state, 'scheduler', None)
|
|
if not scheduler:
|
|
return []
|
|
return scheduler.list_jobs()
|
|
|
|
|
|
@router.post("/", response_model=Dict)
|
|
async def create_scheduled_job(job: ScheduleJobRequest, request: Request):
|
|
"""Create a new scheduled scan job."""
|
|
scheduler = getattr(request.app.state, 'scheduler', None)
|
|
if not scheduler:
|
|
raise HTTPException(status_code=503, detail="Scheduler not available")
|
|
|
|
if not job.cron_expression and not job.interval_minutes:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Either cron_expression or interval_minutes must be provided"
|
|
)
|
|
|
|
result = scheduler.add_job(
|
|
job_id=job.job_id,
|
|
target=job.target,
|
|
scan_type=job.scan_type,
|
|
cron_expression=job.cron_expression,
|
|
interval_minutes=job.interval_minutes,
|
|
agent_role=job.agent_role,
|
|
llm_profile=job.llm_profile
|
|
)
|
|
|
|
if "error" in result:
|
|
raise HTTPException(status_code=400, detail=result["error"])
|
|
|
|
return result
|
|
|
|
|
|
@router.delete("/{job_id}")
|
|
async def delete_scheduled_job(job_id: str, request: Request):
|
|
"""Delete a scheduled scan job."""
|
|
scheduler = getattr(request.app.state, 'scheduler', None)
|
|
if not scheduler:
|
|
raise HTTPException(status_code=503, detail="Scheduler not available")
|
|
|
|
success = scheduler.remove_job(job_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail=f"Job '{job_id}' not found")
|
|
|
|
return {"message": f"Job '{job_id}' deleted", "id": job_id}
|
|
|
|
|
|
@router.post("/{job_id}/pause")
|
|
async def pause_scheduled_job(job_id: str, request: Request):
|
|
"""Pause a scheduled scan job."""
|
|
scheduler = getattr(request.app.state, 'scheduler', None)
|
|
if not scheduler:
|
|
raise HTTPException(status_code=503, detail="Scheduler not available")
|
|
|
|
success = scheduler.pause_job(job_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail=f"Job '{job_id}' not found")
|
|
|
|
return {"message": f"Job '{job_id}' paused", "id": job_id, "status": "paused"}
|
|
|
|
|
|
@router.post("/{job_id}/resume")
|
|
async def resume_scheduled_job(job_id: str, request: Request):
|
|
"""Resume a paused scheduled scan job."""
|
|
scheduler = getattr(request.app.state, 'scheduler', None)
|
|
if not scheduler:
|
|
raise HTTPException(status_code=503, detail="Scheduler not available")
|
|
|
|
success = scheduler.resume_job(job_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail=f"Job '{job_id}' not found")
|
|
|
|
return {"message": f"Job '{job_id}' resumed", "id": job_id, "status": "active"}
|
|
|
|
|
|
@router.get("/agent-roles", response_model=List[Dict])
|
|
async def get_agent_roles():
|
|
"""Return available agent roles from config.json for scheduler dropdown."""
|
|
try:
|
|
if not CONFIG_PATH.exists():
|
|
return []
|
|
config = json.loads(CONFIG_PATH.read_text())
|
|
roles = config.get("agent_roles", {})
|
|
result = []
|
|
for role_id, role_data in roles.items():
|
|
if role_data.get("enabled", True):
|
|
result.append({
|
|
"id": role_id,
|
|
"name": role_id.replace("_", " ").title(),
|
|
"description": role_data.get("description", ""),
|
|
"tools": role_data.get("tools_allowed", []),
|
|
})
|
|
return result
|
|
except Exception:
|
|
return []
|