feat: add connect devices reclaim subcommand#141
Open
lee-reinhardt wants to merge 1 commit intomainfrom
Open
Conversation
3edcf0b to
80fbab2
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new avocado connect devices reclaim command group to let operators run the admin-approved device reclaim workflow from the CLI, integrating with the existing Connect client and error-mapping behavior.
Changes:
- Introduces
connect devices reclaim {list,approve,deny,delete}command surface and wires it into the CLI entrypoint. - Implements reclaim request listing + approve/deny/delete workflows, including interactive confirmations and formatted table output.
- Extends
ConnectClientwith reclaim request API calls and adds reclaim-specific error mapping + unit tests.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/main.rs | Adds the connect devices reclaim subcommands and dispatches to the new command implementations. |
| src/commands/connect/mod.rs | Exposes the new device_reclaim module under commands::connect. |
| src/commands/connect/device_reclaim.rs | Implements reclaim list/approve/deny/delete command logic and unit tests. |
| src/commands/connect/client.rs | Adds reclaim request API models, client methods, and reclaim error parsing/mapping tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Operators can now run the admin-approved device reclaim workflow from the terminal, alongside the existing SPA surface: avocado connect devices reclaim list [--status pending|approved|completed|denied|expired|all] avocado connect devices reclaim approve <id> [-y] avocado connect devices reclaim deny <id> [--reason "..."] [-y] avocado connect devices reclaim delete <id> [-y] Workflow-shaped (verbs operators perform), not API-shaped — no `show` subcommand because `list` with filters covers inspection cleanly. Approve and deny are the two outcomes of a single decision so they ship together; delete is the recovery path for a typo'd deny. List prints full uuids in the ID column so operators can copy-paste without needing a separate show command. Reuses the existing `ConnectClient` Bearer profile and `resolve_org()` helpers; no new auth surface. Hits the existing reclaim endpoints under /api/orgs/:org_id/reclaim-requests. Errors from 422 (not_pending / not_denied / claim_token_unavailable / expired_token / invalid_token), 401 (auth needed), 403 (org-scope mismatch), and 404 (not found) are mapped to readable messages with actionable guidance. Unrecognized statuses fall back to the raw HTTP + body for triage. Tests: 17 new unit tests covering status validation, device label rendering, and HTTP error mapping (each known error code, plus fall-through behavior for unknowns).
80fbab2 to
71d39e7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a
connect devices reclaim {list,approve,deny,delete}subcommand so operators can run the admin-approved device reclaim workflow from the terminal alongside the existing SPA surface.This is opening as a draft because the workflow depends on the corresponding server-side reclaim flow, which has been implemented but is not yet rolled out. The CLI itself is complete and validated end-to-end against a local cluster — flagging draft so this doesn't get merged ahead of the runtime it depends on.
Command surface
Common flags inherited from the existing
connect devicespattern:--org,-C/--config <avocado.yaml>,--profile <name>.Design choices
Workflow-shaped, not API-shaped. Verbs operators perform day-to-day, not generic CRUD primitives:
showsubcommand.listwith--statusfiltering is the inspection surface;listdefaults to--status pending(the "what needs my attention" view) and prints full uuids in the ID column so operators can copy-paste directly into approve/deny calls without a dedicated show command.approveanddenyship together. They're the two outcomes of a single operator decision ("is this reset legit?"); shipping onlyapprovewould forcedenyback to the SPA mid-workflow, which is worse than the all-SPA status quo.deleteis the recovery path for a typo'd deny. A workflow that can deny but can't undo is incomplete; the API gatesDELETEto denied-only rows so this is non-destructive for active records.Error mapping
422 not_pending422 not_denied422 claim_token_unavailable422 expired_token422 invalid_token401403404HTTP {status}: {body}for triageTests
17 new unit tests:
validate_statusaccepts all 6 valid values and rejects unknowns with a useful errordevice_labelrenders correctly across all 3 cases (name + identifier, identifier-only, device_id fallback)format_reclaim_errormaps all 5 known 422 codes plus 401, 403, 404Test count: 917 (was 900).
Validation
cargo buildcleancargo clippy --all-targets -- -D warningscleancargo test --lib— all 917 tests passdevice_id(preserved across reclaim, only credentials rotate)403 reclaim_deniedand idles cleanly without crash-looping