From 98031909cabcb85cd58ae9d9e53e40f0becb3088 Mon Sep 17 00:00:00 2001 From: Marc Riegel Date: Thu, 5 Nov 2026 21:43:43 +0100 Subject: [PATCH] Show state and client id in the service accounts table The service account view showed the delete time, which is empty for every active account, and left out the state and the OAuth client id. The table now shows name, display name, state, member, client id and create time; the delete time moves to -o wide. --- crates/cli/src/sdk/generated/iam.rs | 18 ++++++++++++++-- crates/cli/tests/output.rs | 33 +++++++++++++++++++++++++++++ generator/commands.toml | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/crates/cli/src/sdk/generated/iam.rs b/crates/cli/src/sdk/generated/iam.rs index f240d50..33e5c25 100644 --- a/crates/cli/src/sdk/generated/iam.rs +++ b/crates/cli/src/sdk/generated/iam.rs @@ -827,7 +827,14 @@ async fn list_service_accounts( Listing { field: "serviceAccounts", item: Some("origincloud.iam.v1beta1.ServiceAccount"), - columns: &["name", "displayName", "member", "createTime", "deleteTime"], + columns: &[ + "name", + "displayName", + "state", + "member", + "clientId", + "createTime", + ], parents: listed, create: Some("origin iam create-service-account"), }, @@ -853,7 +860,14 @@ async fn list_service_accounts( Listing { field: "serviceAccounts", item: Some("origincloud.iam.v1beta1.ServiceAccount"), - columns: &["name", "displayName", "member", "createTime", "deleteTime"], + columns: &[ + "name", + "displayName", + "state", + "member", + "clientId", + "createTime", + ], parents: listed, create: Some("origin iam create-service-account"), }, diff --git a/crates/cli/tests/output.rs b/crates/cli/tests/output.rs index 2fe9d91..3eb8834 100644 --- a/crates/cli/tests/output.rs +++ b/crates/cli/tests/output.rs @@ -265,6 +265,39 @@ rb-2 serviceAccount:sa-1 viewer projects/p1 ); } +/// Service accounts are listed with the member a role binding names them +/// by, their state and the client id they log in with; a deleted one +/// (`--show-deleted`) says so in its state. +#[tokio::test(flavor = "multi_thread")] +async fn service_accounts_are_listed_by_member_state_and_client_id() { + const ACCOUNTS: &str = r#"{"serviceAccounts":[ + {"name":"organizations/o/serviceAccounts/sa-1","displayName":"CI deploy", + "member":"serviceAccount:sa-1","clientId":"c-7f3a","state":"ACTIVE", + "creator":"user:ada@example.com"}, + {"name":"organizations/o/serviceAccounts/sa-2","displayName":"Old backup", + "member":"serviceAccount:sa-2","clientId":"c-91be","state":"DELETED", + "creator":"user:ada@example.com","deleteTime":"2026-01-02T00:00:00Z"}]}"#; + let server = recording(|_| Response::json(ACCOUNTS)).await; + let args = ["list-service-accounts", "--organization", "o"]; + let table = server + .run("iam", &[&args[..], &["-o", "table"]].concat()) + .await; + assert_eq!( + text(&table.stdout), + "\ +NAME DISPLAY NAME STATE MEMBER CLIENT ID CREATE TIME +sa-1 CI deploy ACTIVE serviceAccount:sa-1 c-7f3a +sa-2 Old backup DELETED serviceAccount:sa-2 c-91be +" + ); + + let wide = server + .run("iam", &[&args[..], &["-o", "wide"]].concat()) + .await; + let header = text(&wide.stdout).lines().next().unwrap().to_owned(); + assert!(header.contains("DELETE TIME"), "{header}"); +} + #[tokio::test(flavor = "multi_thread")] async fn an_empty_list_says_where_it_looked_and_how_to_make_one() { let server = recording(|_| Response::json("{}")).await; diff --git a/generator/commands.toml b/generator/commands.toml index 8c45cdf..feff104 100644 --- a/generator/commands.toml +++ b/generator/commands.toml @@ -504,7 +504,7 @@ columns = ["name", "member", "role", "project", "create_time"] [[view]] service = "iam" message = "ServiceAccount" -columns = ["name", "display_name", "member", "create_time", "delete_time"] +columns = ["name", "display_name", "state", "member", "client_id", "create_time"] [[view]] service = "iam"