From b13951a79b5787c225dbc42383ef5199274454c8 Mon Sep 17 00:00:00 2001
From: Firstyear <william@blackhats.net.au>
Date: Tue, 18 Mar 2025 21:54:20 +1000
Subject: [PATCH] Add set-description to group tooling (#3511)

---
 libs/client/src/group.rs       | 16 ++++++++++++++++
 tools/cli/src/cli/group/mod.rs | 24 +++++++++++++++++++++++-
 tools/cli/src/opt/kanidm.rs    |  8 ++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/libs/client/src/group.rs b/libs/client/src/group.rs
index a33b98554..29ac8ae1d 100644
--- a/libs/client/src/group.rs
+++ b/libs/client/src/group.rs
@@ -195,4 +195,20 @@ impl KanidmClient {
         self.perform_get_request(&format!("/v1/group/{}/_attr/mail", id))
             .await
     }
+
+    pub async fn idm_group_purge_description(&self, id: &str) -> Result<(), ClientError> {
+        self.idm_group_purge_attr(id, "description").await
+    }
+
+    pub async fn idm_group_set_description(
+        &self,
+        id: &str,
+        description: &str,
+    ) -> Result<(), ClientError> {
+        self.perform_put_request(
+            &format!("/v1/group/{}/_attr/description", id),
+            &[description],
+        )
+        .await
+    }
 }
diff --git a/tools/cli/src/cli/group/mod.rs b/tools/cli/src/cli/group/mod.rs
index 258327443..dccbeb397 100644
--- a/tools/cli/src/cli/group/mod.rs
+++ b/tools/cli/src/cli/group/mod.rs
@@ -16,7 +16,9 @@ impl GroupOpt {
             GroupOpt::RemoveMembers(gcopt) => gcopt.copt.debug,
             GroupOpt::SetMembers(gcopt) => gcopt.copt.debug,
             GroupOpt::PurgeMembers(gcopt) => gcopt.copt.debug,
-            GroupOpt::Rename { copt, .. } | GroupOpt::SetMail { copt, .. } => copt.debug,
+            GroupOpt::SetDescription { copt, .. }
+            | GroupOpt::Rename { copt, .. }
+            | GroupOpt::SetMail { copt, .. } => copt.debug,
             GroupOpt::Posix { commands } => match commands {
                 GroupPosix::Show(gcopt) => gcopt.copt.debug,
                 GroupPosix::Set(gcopt) => gcopt.copt.debug,
@@ -178,6 +180,26 @@ impl GroupOpt {
                     Ok(_) => println!("Successfully set mail for group {}", name.as_str()),
                 }
             }
+            GroupOpt::SetDescription {
+                copt,
+                name,
+                description,
+            } => {
+                let client = copt.to_client(OpType::Write).await;
+
+                let result = if let Some(description) = description {
+                    client
+                        .idm_group_set_description(name.as_str(), description.as_str())
+                        .await
+                } else {
+                    client.idm_group_purge_description(name.as_str()).await
+                };
+
+                match result {
+                    Err(e) => handle_client_error(e, copt.output_mode),
+                    Ok(_) => println!("Successfully set description for group {}", name.as_str()),
+                }
+            }
             GroupOpt::Rename {
                 copt,
                 name,
diff --git a/tools/cli/src/opt/kanidm.rs b/tools/cli/src/opt/kanidm.rs
index 608cd9c53..5e02a10ba 100644
--- a/tools/cli/src/opt/kanidm.rs
+++ b/tools/cli/src/opt/kanidm.rs
@@ -348,6 +348,14 @@ pub enum GroupOpt {
         name: String,
         mail: Vec<String>,
     },
+    /// Set the description of this group. If no description is provided, the value is cleared
+    #[clap(name = "set-description")]
+    SetDescription {
+        #[clap(flatten)]
+        copt: CommonOpt,
+        name: String,
+        description: Option<String>,
+    },
     /// Set a new entry-managed-by for this group.
     #[clap(name = "set-entry-manager")]
     SetEntryManagedBy {