From 396b681cb5acbc441a09becdd728d7b4c0078337 Mon Sep 17 00:00:00 2001
From: Jens Kraemer <jk@jkraemer.net>
Date: Wed, 5 Aug 2026 15:56:07 +0800
Subject: [PATCH] Allow reading issue categories with the view_issues
 permission.

Reading a project's issue categories through the REST API requires
manage_categories, while the equivalent read on versions is granted by
view_issues. This asymmetry means an API client cannot list the
categories a user is able to filter issues by unless that user is also
allowed to create, rename and delete categories.

Category names are already exposed to everyone with view_issues, both
on the issues themselves and as the available values of the category_id
filter in the search form, so this change does not expose any data not
previously already visible to a user with :view_issues permission.

---
 lib/redmine/preparation.rb                    |  1 +
 .../api_test/issue_categories_test.rb         | 28 +++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/lib/redmine/preparation.rb b/lib/redmine/preparation.rb
index 946fbb153..fdd713303 100644
--- a/lib/redmine/preparation.rb
+++ b/lib/redmine/preparation.rb
@@ -59,6 +59,7 @@ module Redmine
                                         :auto_complete => [:issues],
                                         :context_menus => [:issues],
                                         :versions => [:index, :show, :status_by],
+                                        :issue_categories => [:index, :show],
                                         :journals => [:index, :diff],
                                         :queries => :index,
                                         :reports => [:issue_report, :issue_report_details]},
diff --git a/test/integration/api_test/issue_categories_test.rb b/test/integration/api_test/issue_categories_test.rb
index 7096e5ce0..e114fa35b 100644
--- a/test/integration/api_test/issue_categories_test.rb
+++ b/test/integration/api_test/issue_categories_test.rb
@@ -34,6 +34,34 @@ class Redmine::ApiTest::IssueCategoriesTest < Redmine::ApiTest::Base
     assert_select 'issue_category id', :text => '2'
   end
 
+  test "GET /projects/:project_id/issue_categories.xml should be allowed with view_issues permission" do
+    Role.find(1).remove_permission! :manage_categories
+
+    get '/projects/1/issue_categories.xml', :headers => credentials('jsmith')
+    assert_response :success
+    assert_select 'issue_categories issue_category id', :text => '2'
+  end
+
+  test "GET /issue_categories/:id.xml should be allowed with view_issues permission" do
+    Role.find(1).remove_permission! :manage_categories
+
+    get '/issue_categories/2.xml', :headers => credentials('jsmith')
+    assert_response :success
+    assert_select 'issue_category id', :text => '2'
+  end
+
+  test "POST /projects/:project_id/issue_categories.xml should be denied without manage_categories permission" do
+    Role.find(1).remove_permission! :manage_categories
+
+    assert_no_difference 'IssueCategory.count' do
+      post(
+        '/projects/1/issue_categories.xml',
+        :params => {:issue_category => {:name => 'API'}},
+        :headers => credentials('jsmith'))
+    end
+    assert_response :forbidden
+  end
+
   test "POST /projects/:project_id/issue_categories.xml should return create issue category" do
     assert_difference 'IssueCategory.count' do
       post(
-- 
2.55.0

