diff --git a/cli/connector/src/caches.rs b/cli/connector/src/caches.rs index f8f09647..d7804280 100644 --- a/cli/connector/src/caches.rs +++ b/cli/connector/src/caches.rs @@ -1,4 +1,4 @@ -use crate::{Client, ConnectorError, PaginatedListResponse, http}; +use crate::{Client, ConnectorError, ListResponse, PaginatedListResponse, http}; use reqwest::Method; use serde::{Deserialize, Serialize}; @@ -107,7 +107,7 @@ pub struct NarListQuery { pub struct CachesApi<'a>(pub(crate) &'a Client); impl CachesApi<'_> { - pub async fn list(&self) -> Result { + pub async fn list(&self) -> Result { let req = http::request( self.0.http(), self.0.base_url(), diff --git a/cli/connector/tests/caches_api.rs b/cli/connector/tests/caches_api.rs index a9903b8e..adb1754e 100644 --- a/cli/connector/tests/caches_api.rs +++ b/cli/connector/tests/caches_api.rs @@ -7,15 +7,25 @@ fn ok(m: T) -> serde_json::Value { } #[tokio::test] -async fn list_caches_returns_paginated() { +async fn list_caches_decodes_bare_array() { let server = MockServer::start().await; Mock::given(method("GET")) .and(path("/api/v1/caches")) .respond_with( - ResponseTemplate::new(200).set_body_json(ok(serde_json::json!({ - "items": [{"id": "c1", "name": "my-cache"}], - "total": 1, "page": 1, "per_page": 10 - }))), + ResponseTemplate::new(200).set_body_json(ok(serde_json::json!([{ + "id": "019e49bd-4474-79d0-8c16-c71631fb6e64", + "name": "krauterOS", + "display_name": "krauterOS", + "description": "", + "active": true, + "priority": 50, + "local_priority": 10, + "public_key": "4OAlLNfJx4uizm5zOrRrN4DwT6Af+Om7U0gvzRI8YDU=", + "public": false, + "created_by": "019e49bd-43c4-7ee2-afc8-40421c5ce6e9", + "created_at": "2026-05-21T08:53:21.140900", + "managed": true + }]))), ) .mount(&server) .await; @@ -26,7 +36,8 @@ async fn list_caches_returns_paginated() { .build() .unwrap(); let res = client.caches().list().await.unwrap(); - assert_eq!(res.items.len(), 1); + assert_eq!(res.len(), 1); + assert_eq!(res[0].name, "krauterOS"); } #[tokio::test] diff --git a/cli/src/commands/cache.rs b/cli/src/commands/cache.rs index 0bbdbe08..ca651c45 100644 --- a/cli/src/commands/cache.rs +++ b/cli/src/commands/cache.rs @@ -112,12 +112,12 @@ pub async fn handle(cmd: Commands, out: Output) { Commands::List => { let client = client_from_config(out); match client.caches().list().await { - Ok(res) => { - out.ok(&res); - if res.items.is_empty() { + Ok(caches) => { + out.ok(&caches); + if caches.is_empty() { out.human("You have no caches."); } else { - for cache in res.items { + for cache in caches { out.human(format!("{}: {}", cache.name, cache.id)); } } diff --git a/docs/src/tests.md b/docs/src/tests.md index 4e60540f..fe22e6cc 100644 --- a/docs/src/tests.md +++ b/docs/src/tests.md @@ -2497,6 +2497,13 @@ The `cli/connector` crate has wiremock-backed unit tests covering each sub-API Each file covers: happy path, server `{error: true}` envelope (→ `ConnectorError::Api`), 401 (→ `Unauthorized`), and transport failure. +`caches_api.rs::list_caches_decodes_bare_array` is a regression for #290: the +`GET /caches` endpoint returns `message` as a bare array (not the paginated +`{items,total,page,per_page}` envelope used by orgs/projects), so +`caches().list()` returns `ListResponse` (`Vec`). The test replays the +exact response from the bug report to prevent the connector from drifting back to +the paginated type, which made the CLI mis-report a 200 as `api error (200)`. + `cli/connector/tests/client.rs::builder_succeeds_without_system_certs` guards the rustls trust setup: `Client::builder().build()` must succeed regardless of whether the platform CA store is reachable. The CLI loads