Disable physical control through legacy HTTP/M30 producers, typed admission, queue dispatch and upgraded Windows executors. Restrict diagnostic transports to exact read-only operations, with ordinal PowerShell validation before sockets. Retire unsupported pending/claimed work with atomic, idempotent security audits. Preserve prior delivery evidence and report unknown outcomes after a prior claim, including explicitly repaired pending rows. Include containment, cancellation, concurrency and malformed-payload regressions and the old-Agent cutover runbook. Validation: independent final application-security revalidation PASS. Two unchanged baseline source-assertion failures are documented as exceptions. Production release still requires native Windows validation and verified fencing/stop/drain/upgrade; server cancellation alone cannot revoke a cached command held by an old Agent.
47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
"""HTTP boundary for authenticated Agent command transport."""
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
|
|
from app.agent_commands.dependencies import get_agent_command_service, require_agent_identity
|
|
from app.agent_commands.exceptions import (
|
|
AgentCommandConflict,
|
|
AgentCommandNotFound,
|
|
AgentResultValidationError,
|
|
)
|
|
from app.agent_commands.models import (
|
|
AgentCommandListResponse,
|
|
AgentCommandResultRequest,
|
|
AgentCommandResultResponse,
|
|
)
|
|
from app.agent_commands.service import AgentCommandService
|
|
|
|
router = APIRouter(prefix="/api/agent/commands", tags=["agent-commands"])
|
|
AgentIdentity = Annotated[str, Depends(require_agent_identity)]
|
|
AgentService = Annotated[AgentCommandService, Depends(get_agent_command_service)]
|
|
|
|
|
|
@router.get("/pending", response_model=AgentCommandListResponse)
|
|
def claim_pending_commands(
|
|
request: Request, agent_id: AgentIdentity, service: AgentService
|
|
) -> AgentCommandListResponse:
|
|
del request
|
|
return AgentCommandListResponse(commands=service.claim(agent_id))
|
|
|
|
|
|
@router.post("/result", response_model=AgentCommandResultResponse)
|
|
def submit_command_result(
|
|
request: AgentCommandResultRequest,
|
|
agent_id: AgentIdentity,
|
|
service: AgentService,
|
|
) -> AgentCommandResultResponse:
|
|
try:
|
|
service.submit_result(agent_id, request)
|
|
except AgentCommandNotFound as exc:
|
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
|
except AgentCommandConflict as exc:
|
|
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
except AgentResultValidationError as exc:
|
|
raise HTTPException(status_code=422, detail=str(exc)) from exc
|
|
return AgentCommandResultResponse(command_id=request.command_id, status=request.status)
|