feat(fleet)!: per-worker fleet keys (full cutover, v1.0.0)#101
Conversation
US-001: workers.api_key_hash column (schema + idempotent ALTER migration), hash_worker_key (sha256), set/get_worker_key_hash. Foundation for the per-worker fleet-key cutover. Tests + full suite green; ruff clean.
US-002: /api/workers/heartbeat now enrolls each worker on first contact (shared key -> mint+store its own key, return once) and thereafter REQUIRES that per-worker key, rejecting the shared key for enrolled workers (impersonation protection). Shared CASHPILOT_API_KEY remains the enrollment bootstrap. Tests + full suite green (1086); ruff clean.
…tover) The UI must also authenticate OUTBOUND to each worker for a full cutover, so it needs the key itself, not a one-way hash. Store keys Fernet-encrypted at rest (api_key_enc) via set_worker_key/get_worker_key; heartbeat verify + enrollment now compare/issue the key directly. Prep for US-003 (UI->worker auth). Full suite green (1086); ruff clean.
US-003: _get_verified_worker_url (the single outbound auth point for all command/deploy/logs proxying) now sends the worker's own per-worker key when enrolled, falling back to the shared bootstrap key only for unenrolled workers. Tests + full suite green (1088); ruff clean.
US-004: the worker adopts the key the UI issues on enrollment (persisted to its private /data/.worker_key), uses it for outbound heartbeats, and requires it for inbound UI->worker calls — rejecting the shared key once enrolled (accepting it only before enrollment so the UI can reach it to enroll). Tests + full suite green (1096); ruff clean.
US-005: the auto-release now bumps MAJOR on a 'BREAKING CHANGE' footer or a 'type!:' subject in the commits since the last tag, MINOR on feat:, else PATCH — still fully automated, no manual tags. Lets the per-worker-keys cutover release as v1.0.0. Bump logic validated locally against sample messages.
US-006: rewrite the fleet Authentication section for the per-worker-key model, add docs/upgrade-v1.md (what changed, automatic enrollment, upgrade steps, recovery/rollback, v1.0.0 release notes) + nav entry, and update the CASHPILOT_API_KEY description in README + CLAUDE.md to 'enrollment/bootstrap key'.
Addresses the architect review of the per-worker-key cutover: - MEDIUM: at-most-once enrollment could permanently lock out a worker if the response was lost. Add a key_confirmed flag: until the worker proves receipt by authenticating with its own key, the shared key still works AND the same key is re-delivered — closing the lockout window without weakening the finalized cutover. - Reject empty client_id (400); rowcount guard + warning on set_worker_key. - Remove dead _verify_fleet_api_key; fix CLAUDE.md release-bump note; note the shared enrollment key stays sensitive. Full suite green (1099); ruff check + format clean.
|
Warning Review limit reached
Next review available in: 17 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (15)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…I UI env) The UI test environment has no docker package (only the worker image does), so importing app.worker_api errored at collection. Match the existing worker-test pattern: try/except ImportError -> pytest.skip(allow_module_level=True).
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #101 +/- ##
==========================================
+ Coverage 92.61% 92.63% +0.02%
==========================================
Files 31 31
Lines 3180 3243 +63
==========================================
+ Hits 2945 3004 +59
- Misses 235 239 +4
🚀 New features to boost your workflow:
|
Per-worker fleet keys — the full cutover (deferred item from the audit). Retires the single shared key as the day-to-day fleet credential: each worker gets its own key, and the shared
CASHPILOT_API_KEYbecomes an enrollment-only bootstrap. Breaking → v1.0.0 (the title'sfeat(fleet)!:drives the major bump via the updated release workflow). Do not merge without review — existing fleets must re-enroll.What & why
Before, one shared key authenticated everything, in both directions. A leaked key = the whole fleet, and any worker could present another worker's identity. Now:
/data/.worker_key.How it's built (by story)
workers.api_key_enc(encrypted) +key_confirmed;/api/workers/heartbeatenrolls → issues → confirms, and rejects the shared key for a confirmed worker._get_verified_worker_url(the one outbound auth point for all command/deploy/logs) sends each worker's own key.BREAKING CHANGE/type!:marker, minor onfeat:, else patch — still fully automated, no manual tags.Robustness (architect review)
A thorough architect pass PASSED all 5 security criteria (enrolled workers reject the shared key everywhere; no empty-string bypass; adequate entropy; all proxy paths authenticated). It flagged one MEDIUM availability defect — a lost enrollment response could permanently lock a worker out — which this PR fixes: until a worker confirms its key, the shared key still works and the same key is re-delivered on each heartbeat, closing the lockout window without weakening the finalized cutover. Also addressed its low-severity items (empty-
client_id→ 400,set_worker_keyrowcount guard, removed dead_verify_fleet_api_key, doc fixes).Verification
ruff check+ruff format --checkclean; fullpytest1099 passed (new tests cover the DB layer, enrollment/reissue/confirmed heartbeat states, outbound key selection, and the worker side). Release bump logic validated locally (feat(fleet)!:→ v1.0.0).BREAKING CHANGE: fleet authentication moves to per-worker keys. Existing fleets must upgrade both UI and worker images to v1.0.0; workers re-enroll automatically on their first heartbeat. See docs/upgrade-v1.md.