From 1ca00565feaf3698d8b220643a1c2ad46bde3f70 Mon Sep 17 00:00:00 2001 From: Nathael Bonnal Date: Wed, 2 Sep 2026 23:32:32 +0200 Subject: [PATCH] fix(realm): correct client-role create/delete against a live server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified role get/create/list/delete (realm and client-scoped) against a running FerrisKey server: - create_client_role's response isn't enveloped in {"data": ...} like create_role's is — decode it as a bare CreatedRole instead. - There is no client-scoped delete endpoint; role ids are unique across realm and client scopes, so plain delete_role handles both. Dropped delete_client_role and simplified realm::delete_role accordingly. --- libs/ferriskey-cli-client/src/lib.rs | 27 +++------------------------ libs/ferriskey-cli-core/src/realm.rs | 18 ++++-------------- 2 files changed, 7 insertions(+), 38 deletions(-) diff --git a/libs/ferriskey-cli-client/src/lib.rs b/libs/ferriskey-cli-client/src/lib.rs index 867f5d4..f3f002d 100644 --- a/libs/ferriskey-cli-client/src/lib.rs +++ b/libs/ferriskey-cli-client/src/lib.rs @@ -523,29 +523,6 @@ impl FerriskeyClient { self.get_list(&self.endpoint(&format!("realms/{realm}/clients/{client_uuid}/roles"))) } - pub fn delete_client_role( - &self, - realm: &str, - client_uuid: &str, - role_id: &str, - ) -> Result<(), FerriskeyClientError> { - let response = self - .http - .delete(self.endpoint(&format!( - "realms/{realm}/clients/{client_uuid}/roles/{role_id}" - ))) - .bearer_auth(&self.token) - .send()?; - - if !response.status().is_success() { - let status = response.status(); - let body = response.text().unwrap_or_default(); - return Err(FerriskeyClientError::Api { status, body }); - } - - Ok(()) - } - pub fn create_client_role( &self, realm: &str, @@ -565,7 +542,9 @@ impl FerriskeyClient { return Err(FerriskeyClientError::Api { status, body }); } - self.extract_envelope(response) + // Unlike `create_role`, this endpoint returns the created role as a + // bare object, not wrapped in a `{"data": ...}` envelope. + Ok(response.json::()?) } pub fn add_client_redirect( diff --git a/libs/ferriskey-cli-core/src/realm.rs b/libs/ferriskey-cli-core/src/realm.rs index fb186bf..78ba99c 100644 --- a/libs/ferriskey-cli-core/src/realm.rs +++ b/libs/ferriskey-cli-core/src/realm.rs @@ -323,23 +323,13 @@ fn delete_role( let context = resolve_context(context_override, inline_context)?; let realm = resolve_realm(&context, args.realm)?; let client = auth_client(&context)?; - let client_uuid = args - .client - .as_deref() - .map(|client_id| resolve_client_uuid(&client, &realm, client_id)) - .transpose()?; - let roles = match &client_uuid { - Some(uuid) => client.list_client_roles(&realm, uuid)?, - None => client.list_realm_roles(&realm)?, - }; - let role = roles + let role = list_roles_in_scope(&client, &realm, args.client.as_deref())? .into_iter() .find(|r| r.name == args.name) .ok_or_else(|| RealmCommandError::RoleNotFound(args.name.clone()))?; - match &client_uuid { - Some(uuid) => client.delete_client_role(&realm, uuid, &role.id)?, - None => client.delete_role(&realm, &role.id)?, - } + // A role id is unique across both realm and client scopes, so deletion + // doesn't need to be scoped the way create/list do. + client.delete_role(&realm, &role.id)?; render_message(output_format, &format!("role '{}' deleted", args.name)) }