"""Application service for secure one-time Agent enrollment.""" import secrets from uuid import UUID, uuid4 from app.agent_auth.service import hash_agent_secret from app.agent_enrollment.exceptions import ( AgentEnrollmentConflict, AgentEnrollmentCredentialCollision, ) from app.agent_enrollment.models import ( AgentEnrollmentCreateRequest, AgentEnrollRequest, ) MAX_GENERATION_ATTEMPTS = 3 def generate_enrollment_token() -> str: return secrets.token_urlsafe(32) def generate_agent_secret() -> str: return secrets.token_urlsafe(32) def generate_agent_id() -> str: return f"agent-{uuid4().hex}" class AgentEnrollmentService: def __init__(self, repository): self.repository = repository def create_enrollment( self, request: AgentEnrollmentCreateRequest, *, actor_user_id: UUID, ) -> dict: for _ in range(MAX_GENERATION_ATTEMPTS): token = generate_enrollment_token() try: enrollment = self.repository.create_enrollment( token_hash=hash_agent_secret(token), site_id=request.site_id, agent_zone_id=request.agent_zone_id, display_name=request.display_name, actor_user_id=actor_user_id, ) return { **enrollment, "enrollment_token": token, } except AgentEnrollmentCredentialCollision: continue raise AgentEnrollmentConflict( "Unable to generate a unique enrollment token" ) def list_enrollments( self, *, site_id: UUID | None = None, agent_zone_id: UUID | None = None, limit: int = 100, ) -> list[dict]: return self.repository.list_enrollments( site_id=site_id, agent_zone_id=agent_zone_id, limit=limit, ) def redeem(self, request: AgentEnrollRequest) -> dict: token_hash = hash_agent_secret(request.token) for _ in range(MAX_GENERATION_ATTEMPTS): agent_id = generate_agent_id() agent_secret = generate_agent_secret() try: result = self.repository.redeem_enrollment( token_hash=token_hash, agent_id=agent_id, agent_secret_hash=hash_agent_secret(agent_secret), ) return { **result, "agent_secret": agent_secret, } except AgentEnrollmentCredentialCollision: continue raise AgentEnrollmentConflict( "Unable to generate unique Agent credentials" )