95 lines
2.6 KiB
Python
95 lines
2.6 KiB
Python
|
|
"""File management endpoints for creating FILE_INSPECT tasks."""
|
||
|
|
|
||
|
|
import uuid
|
||
|
|
|
||
|
|
from fastapi import APIRouter, HTTPException, status
|
||
|
|
from sqlalchemy import select
|
||
|
|
|
||
|
|
from app.db import AsyncSessionDep
|
||
|
|
from app.models.agent import Agent
|
||
|
|
from app.models.task import Task, TaskStatus
|
||
|
|
from app.models.tenant import Tenant
|
||
|
|
from app.schemas.file import FileInspectRequest
|
||
|
|
from app.schemas.task import TaskResponse
|
||
|
|
|
||
|
|
router = APIRouter(prefix="/agents/{agent_id}/files", tags=["File Management"])
|
||
|
|
|
||
|
|
|
||
|
|
# --- Helper functions ---
|
||
|
|
|
||
|
|
|
||
|
|
async def get_tenant_by_id(db: AsyncSessionDep, tenant_id: uuid.UUID) -> Tenant | None:
|
||
|
|
"""Retrieve a tenant by ID."""
|
||
|
|
result = await db.execute(select(Tenant).where(Tenant.id == tenant_id))
|
||
|
|
return result.scalar_one_or_none()
|
||
|
|
|
||
|
|
|
||
|
|
async def get_agent_by_id(db: AsyncSessionDep, agent_id: uuid.UUID) -> Agent | None:
|
||
|
|
"""Retrieve an agent by ID."""
|
||
|
|
result = await db.execute(select(Agent).where(Agent.id == agent_id))
|
||
|
|
return result.scalar_one_or_none()
|
||
|
|
|
||
|
|
|
||
|
|
# --- Route handlers ---
|
||
|
|
|
||
|
|
|
||
|
|
@router.post(
|
||
|
|
"/inspect",
|
||
|
|
response_model=TaskResponse,
|
||
|
|
status_code=status.HTTP_201_CREATED,
|
||
|
|
)
|
||
|
|
async def inspect_file(
|
||
|
|
agent_id: uuid.UUID,
|
||
|
|
request: FileInspectRequest,
|
||
|
|
db: AsyncSessionDep,
|
||
|
|
) -> Task:
|
||
|
|
"""
|
||
|
|
Create a FILE_INSPECT task to read file contents.
|
||
|
|
|
||
|
|
The SysAdmin Agent will execute this task and return the file
|
||
|
|
contents (up to max_bytes) in the task result.
|
||
|
|
|
||
|
|
## Request Body
|
||
|
|
- **tenant_id**: UUID of the tenant
|
||
|
|
- **path**: Absolute path to the file to inspect
|
||
|
|
- **max_bytes**: Optional max bytes to read (default 4096, max 1MB)
|
||
|
|
|
||
|
|
## Response
|
||
|
|
Returns the created Task with type="FILE_INSPECT" and status="pending".
|
||
|
|
"""
|
||
|
|
# Validate tenant exists
|
||
|
|
tenant = await get_tenant_by_id(db, request.tenant_id)
|
||
|
|
if tenant is None:
|
||
|
|
raise HTTPException(
|
||
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
||
|
|
detail=f"Tenant {request.tenant_id} not found",
|
||
|
|
)
|
||
|
|
|
||
|
|
# Validate agent exists
|
||
|
|
agent = await get_agent_by_id(db, agent_id)
|
||
|
|
if agent is None:
|
||
|
|
raise HTTPException(
|
||
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
||
|
|
detail=f"Agent {agent_id} not found",
|
||
|
|
)
|
||
|
|
|
||
|
|
# Build payload
|
||
|
|
payload: dict = {"path": request.path}
|
||
|
|
if request.max_bytes is not None:
|
||
|
|
payload["max_bytes"] = request.max_bytes
|
||
|
|
|
||
|
|
# Create the task
|
||
|
|
task = Task(
|
||
|
|
tenant_id=request.tenant_id,
|
||
|
|
agent_id=agent_id,
|
||
|
|
type="FILE_INSPECT",
|
||
|
|
payload=payload,
|
||
|
|
status=TaskStatus.PENDING.value,
|
||
|
|
)
|
||
|
|
|
||
|
|
db.add(task)
|
||
|
|
await db.commit()
|
||
|
|
await db.refresh(task)
|
||
|
|
|
||
|
|
return task
|