New enroll module: on a managed agent with no stored cak_ but with
enrollment_key + site_code, POST machine_uid + hostname + labels to
<https-base>/api/enroll and persist the minted cak_. Handles every Phase A
status code distinctly:
- 201 new / 200 reuse -> persist cak_ (DPAPI store) and connect
- 202 collision_pending -> log "pending operator confirmation", slow
re-check loop (no key issued; cannot connect until confirmed)
- 401 ENROLL_REJECTED / 409 ENROLL_SITE_CONFLICT -> distinct actionable
errors, long backoff (won't fix without operator action, but recovers
automatically once it does) — no tight loop
- 429 -> honor Retry-After, short backoff
- network / 5xx / decode -> short backoff
The enrollment_key and cak_ are never logged. Uses the existing reqwest
client and the update path's TLS posture (rustls; dev-insecure only in
debug + opt-in). Wire-contract unit tests pin the request shape against
the server's EnrollRequest/EnrollLabels and decode active + pending bodies.
main.rs run-mode wiring: before a managed agent connects, resolve the
operating credential by precedence — stored cak_ (steady state, no
network) -> first-run enrollment -> DEPRECATED legacy api_key (transition
only, logged at WARNING) -> error. The relay already accepts the cak_ as
the api_key query param, so the persistent transport authenticates with it
unchanged. Attended/support-code and viewer paths are untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>