fix(mdm): idempotent DeviceInformation attestation enqueue (coordinator side of Secure Mode)#187
Conversation
…ing stale commands The coordinator side of Secure Mode never binding (isolated after #186 fixed the agent-side key mismatch): every request-attestation call APPENDED a new DeviceInformation command to NanoMDM's per-device FIFO queue, and NanoMDM has no clear-queue API. So repeated calls (agent auto-request every 6h + every wizard toggle + every restart) piled up stale commands with OLD-key nonces. The device drains them FIFO, each producing an attestation bound to an old key, which #178 correctly discards — so the real (current-key) command never gets a fresh attestation. Worse, hammering Apple's rate-limited DeviceAttestation (~1/device/7d) makes it return a CACHED old-key chain regardless of the new nonce. Live symptom: the coordinator logging "discarding captured attestation chain … freshness does not bind the currently-requested key" on a loop. Fix: make the enqueue idempotent. If we already requested attestation for THIS exact key within a 6h window, don't enqueue another command — just RE-PUSH so the device processes the one already queued. A KEY CHANGE still enqueues immediately. This stops the pile-up and the Apple-rate-limit hammering; combined with #186's now-stable key, the single current-key command drains and finally attests the right key. - `getExpectedAttestation(serial)` returns the requested key + timestamp so the enqueue can dedup on (pubkey, recency). - 4 new tests: first-request enqueues; same-key-recent re-pushes only (no duplicate enqueue); key-change enqueues; stale-same-key re-enqueues. Console-only; deploys on Railway. 29 coordinator tests pass, tsc + oxlint clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
DGaffney has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
🛠️ Provider build (macOS arm64) — menu-bar app + CLIBuilt from 🔌 Pre-wired to this PR's stack — the app defaults to ⬇️ cocore-mac-arm64-pr187-0069248.tar.gz (GitHub artifact — requires being signed in to this repo. The zip contains the tar -xzf cocore-mac-arm64*.tar.gz && cd cocore-mac-arm64
./install.sh # installs cocore.app to /Applications + the CLI, launches the tray
CLI only? It's wired to this PR's stack too: ./bin/cocore agent pair --console https://client-cocore-pr-187.up.railway.app
./bin/cocore agent serve --advisor wss://advisor-cocore-pr-187.up.railway.app/v1/agent |
There was a problem hiding this comment.
DGaffney has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
Context
With #186 the agent-side key mismatch is fixed and proven (serve =
agent pubkey= attestation, all1feH…). That isolated the last blocker for Secure Mode to the coordinator, which the live logs show precisely:The bug
requestDeviceInformationAttestationappended a new DeviceInformation command to NanoMDM's per-device FIFO queue on every call — and NanoMDM (standard-apibuild) has no clear-queue endpoint. Repeated calls (agent auto-request every 6h + every wizard toggle + every restart) piled up stale commands carrying old-key nonces. The device drains them FIFO, each yielding an attestation bound to an old key → #178 correctly discards it → the real, current-key command never lands a fresh attestation. And hammering Apple's rate-limited DeviceAttestation (~1/device/7d) makes it return a cached old-key chain regardless of the new nonce.Fix
Make the enqueue idempotent. If we already requested attestation for this exact key within a 6h window, don't enqueue another command — just re-push so the device processes the one already queued. A key change still enqueues immediately. This stops both the pile-up and the Apple-rate-limit hammering; combined with #186's now-stable key, the single current-key command drains and finally attests the right key.
getExpectedAttestation(serial)returns the requested key + timestamp for the (pubkey, recency) dedup.Notes
🤖 Generated with Claude Code