Corrected 2026-07-28. The original body of this issue was substantially wrong. It claimed the CLI had no quarantine support at all. It does, and has since v1.2.0. The corrected scope is below; see the comment thread for what changed and why.
Summary
ak quarantine shipped in v1.2.0 with status, release, and reject. Two gaps remain:
- There is no
hold subcommand, despite the backend exposing an admin quarantine-now endpoint.
- The command shipped undocumented. It is absent from the README command list and never got a CHANGELOG entry.
What already exists
src/commands/quarantine.rs (404 lines), added in 32c0aa6 "feat: add quarantine CLI command coverage (#102)" on 2026-07-09. Wired into src/cli.rs and src/commands/mod.rs, with 17 passing tests covering clap parsing, wiremock-backed handler behaviour, and two insta snapshots.
Implemented today:
ak quarantine status <artifact-id>
ak quarantine release <artifact-id>
ak quarantine reject <artifact-id> [--reason "..."]
Gap 1: no hold subcommand
origin/main of the backend registers four quarantine routes:
.route("/:artifact_id", get(get_quarantine_status))
.route("/:artifact_id/quarantine", post(quarantine_artifact)) // admin: quarantine now
.route("/:artifact_id/release", post(release_artifact))
.route("/:artifact_id/reject", post(reject_artifact))
The CLI covers three of the four. POST /:artifact_id/quarantine has no CLI equivalent, so placing a manual admin hold is the one quarantine operation with no command.
Proposed:
ak quarantine hold <artifact-id> --reason "..."
Implementation notes:
- Verify the request body shape and whether the reason is required against
backend/src/api/handlers/quarantine.rs on origin/main.
- Match the conventions of the three existing subcommands, including their test style.
- Check whether the vendored SDK's
ClientQuarantineExt exposes the quarantine-now operation. If the vendored SDK is stale relative to the backend, use the same raw HTTP path the sibling commands use rather than blocking on an SDK regen.
Gap 2: undocumented
ak quarantine is missing from the README command list and has no CHANGELOG entry, so it shipped in v1.2.0 with no user-facing documentation. completion.rs needs no change; it derives from the clap tree via Cli::command().
Explicitly out of scope
ak quarantine list is not implementable. The backend has no endpoint listing quarantined artifacts; all four routes are keyed by a single artifact_id. This needs a backend counterpart first and should be filed separately if wanted.
Do not make --reason required on reject. RejectRequest.reason is Option<String> on the backend ("Optional reason for rejection"), and the shipped command correctly mirrors that. Changing it would be a breaking change to a released command.
Note on API path drift
The running 1.6.0-demo-fix build exposes the admin hold at POST /api/v1/quarantine/{artifact_id} (verified live, HTTP 200), while origin/main exposes it at POST /api/v1/quarantine/{artifact_id}/quarantine. The endpoint was renamed after that image was built. Implement against origin/main.
Summary
ak quarantineshipped in v1.2.0 withstatus,release, andreject. Two gaps remain:holdsubcommand, despite the backend exposing an admin quarantine-now endpoint.What already exists
src/commands/quarantine.rs(404 lines), added in 32c0aa6 "feat: add quarantine CLI command coverage (#102)" on 2026-07-09. Wired intosrc/cli.rsandsrc/commands/mod.rs, with 17 passing tests covering clap parsing, wiremock-backed handler behaviour, and two insta snapshots.Implemented today:
Gap 1: no
holdsubcommandorigin/mainof the backend registers four quarantine routes:The CLI covers three of the four.
POST /:artifact_id/quarantinehas no CLI equivalent, so placing a manual admin hold is the one quarantine operation with no command.Proposed:
Implementation notes:
backend/src/api/handlers/quarantine.rsonorigin/main.ClientQuarantineExtexposes the quarantine-now operation. If the vendored SDK is stale relative to the backend, use the same raw HTTP path the sibling commands use rather than blocking on an SDK regen.Gap 2: undocumented
ak quarantineis missing from the README command list and has no CHANGELOG entry, so it shipped in v1.2.0 with no user-facing documentation.completion.rsneeds no change; it derives from the clap tree viaCli::command().Explicitly out of scope
ak quarantine listis not implementable. The backend has no endpoint listing quarantined artifacts; all four routes are keyed by a singleartifact_id. This needs a backend counterpart first and should be filed separately if wanted.Do not make
--reasonrequired onreject.RejectRequest.reasonisOption<String>on the backend ("Optional reason for rejection"), and the shipped command correctly mirrors that. Changing it would be a breaking change to a released command.Note on API path drift
The running
1.6.0-demo-fixbuild exposes the admin hold atPOST /api/v1/quarantine/{artifact_id}(verified live, HTTP 200), whileorigin/mainexposes it atPOST /api/v1/quarantine/{artifact_id}/quarantine. The endpoint was renamed after that image was built. Implement againstorigin/main.