feat: host session list/terminate and event session actions (0.20.28)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-22 10:13:42 +10:00
parent ca0255e13b
commit d848d94604
12 changed files with 773 additions and 5 deletions
+65
View File
@@ -20,6 +20,13 @@ from app.services.agent_commands import (
get_command_by_uuid,
)
from app.services.rdg_winrm_actions import execute_logoff_via_winrm, execute_qwinsta_via_winrm
from app.services.host_sessions import (
event_session_id,
event_supports_session_terminate,
terminate_session_for_event,
)
from app.services.linux_admin_settings import get_effective_linux_admin_config
from app.services.win_admin_settings import get_effective_win_admin_config
from app.services.ingest import ingest_event
from app.services.event_summary import event_to_summary
from app.services.event_type_visibility import get_hidden_event_types, visibility_type_filter
@@ -214,6 +221,64 @@ class LogoffActionBody(BaseModel):
session_id: int
class EventSessionTerminateBody(BaseModel):
session_id: str | None = None
class EventSessionTerminateResponse(BaseModel):
ok: bool
message: str
target: str | None = None
stdout: str | None = None
stderr: str | None = None
@router.post("/{event_db_id}/actions/terminate-session", response_model=EventSessionTerminateResponse)
def post_event_terminate_session(
event_db_id: int,
body: EventSessionTerminateBody | None = Body(default=None),
db: Session = Depends(get_db),
user: CurrentUser = Depends(get_current_user),
) -> EventSessionTerminateResponse:
event = db.scalar(
select(Event).options(joinedload(Event.host)).where(Event.id == event_db_id)
)
if event is None:
raise HTTPException(status_code=404, detail="Event not found")
if not event_supports_session_terminate(event):
raise HTTPException(status_code=400, detail="Event type does not support session terminate")
linux_cfg = get_effective_linux_admin_config(db)
win_cfg = get_effective_win_admin_config(db)
sid = (body.session_id if body else None) or event_session_id(event)
try:
result = terminate_session_for_event(
event,
linux_cfg=linux_cfg,
win_cfg=win_cfg,
session_id=sid,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
if hasattr(result, "exit_code"):
return EventSessionTerminateResponse(
ok=result.ok,
message=result.message,
target=getattr(result, "target", None),
stdout=getattr(result, "stdout", None) or None,
stderr=getattr(result, "stderr", None) or None,
)
return EventSessionTerminateResponse(
ok=result.ok,
message=result.message,
target=getattr(result, "target", None),
stdout=getattr(result, "stdout", None) or None,
stderr=getattr(result, "stderr", None) or None,
)
@router.post("/{event_db_id}/actions/qwinsta", response_model=AgentCommandResponse)
def post_event_qwinsta(
event_db_id: int,