diff --git a/ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue b/ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue
index fa1960a2d6bc9952fbe6fbef140d53c94bb08fff..e4f921147df068a8e784fa9c427e2213cf142227 100644
--- a/ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue
+++ b/ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue
@@ -4,6 +4,7 @@ import { GlButton } from '@gitlab/ui';
 import { mapState } from 'vuex';
 import { createAlert } from '~/alert';
 import { s__ } from '~/locale';
+import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin';
 import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import chatMutation from 'ee/ai/graphql/chat.mutation.graphql';
 import { convertToGraphQLId } from '~/graphql_shared/utils';
@@ -18,7 +19,7 @@ export default {
     GlButton,
     RootCauseAnalysis,
   },
-  mixins: [glFeatureFlagMixin()],
+  mixins: [glAbilitiesMixin(), glFeatureFlagMixin()],
   inject: ['aiRootCauseAnalysisAvailable', 'duoFeaturesEnabled', 'jobGid'],
   props: {
     size: {
@@ -84,7 +85,8 @@ export default {
         this.glFeatures.aiBuildFailureCause &&
         this.aiRootCauseAnalysisAvailable &&
         this.duoFeaturesEnabled &&
-        this.glFeatures.rootCauseAnalysisDuo
+        this.glFeatures.rootCauseAnalysisDuo &&
+        this.glAbilities.troubleshootJobWithAi
       );
     },
     jobFailed() {
diff --git a/ee/app/controllers/ee/projects/jobs_controller.rb b/ee/app/controllers/ee/projects/jobs_controller.rb
index 22fcd51e140f683a81e18c1ce2c4b94c400d286b..5f67f8191191e10538e11ce2c7859022d095048e 100644
--- a/ee/app/controllers/ee/projects/jobs_controller.rb
+++ b/ee/app/controllers/ee/projects/jobs_controller.rb
@@ -7,6 +7,7 @@ module JobsController
 
       prepended do
         before_action only: [:show] do
+          push_frontend_ability(ability: :troubleshoot_job_with_ai, resource: @build, user: @current_user)
           push_frontend_feature_flag(:root_cause_analysis_duo, @current_user)
         end
       end
diff --git a/ee/app/models/gitlab_subscriptions/features.rb b/ee/app/models/gitlab_subscriptions/features.rb
index a1a169c44c95e58b5b9e849aadb104c0839f28be..1eca8f1d6e3c9dcbde093efa066d6749a0e02a4a 100644
--- a/ee/app/models/gitlab_subscriptions/features.rb
+++ b/ee/app/models/gitlab_subscriptions/features.rb
@@ -261,6 +261,7 @@ class Features
       suggested_reviewers
       subepics
       observability
+      troubleshoot_job
       unique_project_download_limit
       vulnerability_finding_signatures
       container_scanning_for_registry
diff --git a/ee/app/policies/ee/ci/build_policy.rb b/ee/app/policies/ee/ci/build_policy.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3e79e822c0e94f89c58cbc6775caf20cf1a09379
--- /dev/null
+++ b/ee/app/policies/ee/ci/build_policy.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module EE
+  module Ci
+    module BuildPolicy
+      extend ActiveSupport::Concern
+
+      prepended do
+        # Authorize access to the troubleshoot job to Cloud Connector Service
+        condition(:troubleshoot_job_cloud_connector_authorized) do
+          next true if troubleshoot_job_connection.allowed_for?(@user)
+
+          next false unless troubleshoot_job_connection.free_access?
+
+          if ::Gitlab::Saas.feature_available?(:duo_chat_on_saas) # check if we are on SaaS
+            user.any_group_with_ai_available?
+          else
+            License.feature_available?(:ai_features)
+          end
+        end
+
+        # Authorize access to Troubleshoot Job
+        condition(:troubleshoot_job_with_ai_authorized, scope: :subject) do
+          ::Gitlab::Llm::Chain::Utils::ChatAuthorizer.resource(
+            resource: subject.project,
+            user: @user
+          ).allowed?
+        end
+
+        condition(:troubleshoot_job_licensed) do
+          next false unless ::Feature.enabled?(:root_cause_analysis_duo, @user)
+
+          ::License.feature_available?(:troubleshoot_job)
+        end
+
+        rule do
+          can?(:read_build_trace) &
+            troubleshoot_job_cloud_connector_authorized &
+            troubleshoot_job_with_ai_authorized &
+            troubleshoot_job_licensed
+        end.enable(:troubleshoot_job_with_ai)
+
+        def troubleshoot_job_connection
+          CloudConnector::AvailableServices.find_by_name(:troubleshoot_job)
+        end
+      end
+    end
+  end
+end
diff --git a/ee/config/cloud_connector/access_data.yml b/ee/config/cloud_connector/access_data.yml
index 49fa28766b61cf9597f3c46228c4ec0a322af55a..118292c6576529748e4aef10360d3d0bba3a5fae 100644
--- a/ee/config/cloud_connector/access_data.yml
+++ b/ee/config/cloud_connector/access_data.yml
@@ -77,6 +77,12 @@ services: # Cloud connector features (i.e. code_suggestions, duo_chat...)
       duo_enterprise:
         unit_primitives:
           - resolve_vulnerability
+  troubleshoot_job:
+    backend: 'gitlab-ai-gateway'
+    bundled_with:
+      duo_enterprise:
+        unit_primitives:
+          - troubleshoot_job
   self_hosted_models:
     backend: 'gitlab-ai-gateway'
     cut_off_date: 2024-10-17 00:00:00 UTC
diff --git a/ee/lib/gitlab/llm/chain/tools/troubleshoot_job/executor.rb b/ee/lib/gitlab/llm/chain/tools/troubleshoot_job/executor.rb
index 58e75ef5444ab8a26b959ca4db3e97def7b2da21..aeadfec7a5ba66c4f7bb334fdad1c707f56ae4fd 100644
--- a/ee/lib/gitlab/llm/chain/tools/troubleshoot_job/executor.rb
+++ b/ee/lib/gitlab/llm/chain/tools/troubleshoot_job/executor.rb
@@ -68,9 +68,6 @@ def self.slash_commands
             def perform
               error_message = if disabled?
                                 _('This feature is not enabled yet.')
-                              elsif !job.is_a?(::Ci::Build)
-                                _('This command is used for troubleshooting jobs and can only be invoked from ' \
-                                  'a job log page.')
                               elsif !job.failed?
                                 _('This command is used for troubleshooting jobs and can only be invoked from ' \
                                   'a failed job log page.')
@@ -83,6 +80,17 @@ def perform
 
             private
 
+            def unit_primitive
+              'troubleshoot_job'
+            end
+
+            def tracking_context
+              {
+                request_id: context.request_id,
+                action: unit_primitive
+              }
+            end
+
             def disabled?
               Feature.disabled?(:root_cause_analysis_duo, context.current_user)
             end
@@ -109,8 +117,7 @@ def job
             strong_memoize_attr :job
 
             def authorize
-              context.current_user.can?(:read_build_trace, job) &&
-                Utils::ChatAuthorizer.context(context: context).allowed?
+              context.current_user.can?(:troubleshoot_job_with_ai, job)
             end
 
             def resource_name
diff --git a/ee/spec/features/projects/jobs/root_cause_analysis_job_page_spec.rb b/ee/spec/features/projects/jobs/root_cause_analysis_job_page_spec.rb
index e15552744369571189e8a5c2df3c9294b5806499..bc2feca01a4d349e4d93622b32c8ac56b0554e30 100644
--- a/ee/spec/features/projects/jobs/root_cause_analysis_job_page_spec.rb
+++ b/ee/spec/features/projects/jobs/root_cause_analysis_job_page_spec.rb
@@ -71,17 +71,24 @@
       stub_feature_flags(root_cause_analysis_duo: true)
     end
 
-    context 'with failed jobs' do
+    context 'with duo enterprise license' do
       before do
-        allow(failed_job).to receive(:debug_mode?).and_return(false)
+        allow(Ability).to receive(:allowed?).and_call_original
+        allow(Ability).to receive(:allowed?).with(user, :troubleshoot_job_with_ai, failed_job).and_return(true)
+      end
 
-        visit(project_job_path(project, failed_job))
+      context 'with failed jobs' do
+        before do
+          allow(failed_job).to receive(:debug_mode?).and_return(false)
 
-        wait_for_requests
-      end
+          visit(project_job_path(project, failed_job))
+
+          wait_for_requests
+        end
 
-      it 'does display rca with duo button' do
-        expect(page).to have_selector("[data-testid='rca-duo-button']")
+        it 'does display rca with duo button' do
+          expect(page).to have_selector("[data-testid='rca-duo-button']")
+        end
       end
     end
   end
diff --git a/ee/spec/frontend/ci/job_details/components/sidebar/job_log_top_bar_spec.js b/ee/spec/frontend/ci/job_details/components/sidebar/job_log_top_bar_spec.js
index 7d0542cc83dc16579eb8ea0f9791ca0e9b68f58f..5e7d89637c50718a5301a1c2892c5fb315745497 100644
--- a/ee/spec/frontend/ci/job_details/components/sidebar/job_log_top_bar_spec.js
+++ b/ee/spec/frontend/ci/job_details/components/sidebar/job_log_top_bar_spec.js
@@ -28,6 +28,9 @@ describe('EE JobLogTopBar', () => {
         duoFeaturesEnabled: true,
         rootCauseAnalysisDuo: false,
         jobGid: 'gid://gitlab/Ci::Build/123',
+        glAbilities: {
+          troubleshootJobWithAi: false,
+        },
       },
     });
   };
diff --git a/ee/spec/lib/cloud_connector/self_signed/access_data_reader_spec.rb b/ee/spec/lib/cloud_connector/self_signed/access_data_reader_spec.rb
index d82a201f231b4b2abc25232150659e8ebb23ac8f..6a86268ce718dc3013d512118abb079da005a1ef 100644
--- a/ee/spec/lib/cloud_connector/self_signed/access_data_reader_spec.rb
+++ b/ee/spec/lib/cloud_connector/self_signed/access_data_reader_spec.rb
@@ -57,6 +57,14 @@
       }
     end
 
+    let_it_be(:troubleshoot_job_bundled_with) do
+      {
+        "duo_enterprise" => %i[
+          troubleshoot_job
+        ]
+      }
+    end
+
     let_it_be(:resolve_vulnerability_bundled_with) do
       {
         "duo_enterprise" => %i[
@@ -103,7 +111,8 @@
           glab_ask_git_command: [nil, glab_ask_git_command_bundled_with, backend],
           explain_vulnerability: [nil, explain_vulnerability_bundled_with,
             backend],
-          summarize_comments: [nil, summarize_comments_bundled_with, backend]
+          summarize_comments: [nil, summarize_comments_bundled_with, backend],
+          troubleshoot_job: [nil, troubleshoot_job_bundled_with, backend]
         }
       end
     end
diff --git a/ee/spec/lib/gitlab/llm/chain/tools/troubleshoot_job/executor_spec.rb b/ee/spec/lib/gitlab/llm/chain/tools/troubleshoot_job/executor_spec.rb
index 373a267fd16c6b912be31eb0dac2bb8c5afbf193..d6c22878a7047a017cc56c38f34ec74546d0447a 100644
--- a/ee/spec/lib/gitlab/llm/chain/tools/troubleshoot_job/executor_spec.rb
+++ b/ee/spec/lib/gitlab/llm/chain/tools/troubleshoot_job/executor_spec.rb
@@ -41,6 +41,11 @@
     end
   end
 
+  before do
+    allow(user).to receive(:can?).and_call_original
+    allow(user).to receive(:can?).with(:troubleshoot_job_with_ai, build).and_return(true)
+  end
+
   describe '#name' do
     it 'returns the correct tool name' do
       expect(described_class::NAME).to eq('TroubleshootJob')
@@ -68,10 +73,6 @@
       include_context 'with stubbed LLM authorizer', allowed: true
 
       before do
-        allow(user).to receive(:can?).and_call_original
-        allow(user).to receive(:can?).with(:read_build, build).and_return(true)
-        allow(user).to receive(:can?).with(:read_build_trace, build).and_return(true)
-        allow(Gitlab::Llm::Chain::Utils::ChatAuthorizer).to receive_message_chain(:context, :allowed?).and_return(true)
         allow(tool).to receive(:provider_prompt_class).and_return(prompt_class)
       end
 
@@ -80,6 +81,12 @@
         expect(tool.execute.content).to eq('Troubleshooting response')
       end
 
+      it 'sets the correct unit primitive' do
+        expect(ai_request_double).to receive(:request).with(tool.prompt, unit_primitive: 'troubleshoot_job')
+
+        tool.execute
+      end
+
       context 'with repository languages' do
         include_context 'with repo languages'
 
@@ -133,7 +140,7 @@
         end
 
         it 'returns an error message' do
-          expect(tool.execute.content).to include('This command is used for troubleshooting jobs')
+          expect(tool.execute.content).to include("I'm sorry, I can't generate a response.")
         end
       end
     end
@@ -145,7 +152,7 @@
         allow(tool).to receive(:provider_prompt_class).and_return(
           ::Gitlab::Llm::Chain::Tools::TroubleshootJob::Prompts::Anthropic
         )
-        allow(user).to receive(:can?).with(:read_build_trace, build).and_return(false)
+        allow(user).to receive(:can?).with(:troubleshoot_job_with_ai, build).and_return(false)
       end
 
       it 'returns an error message' do
diff --git a/ee/spec/policies/ci/build_policy_spec.rb b/ee/spec/policies/ci/build_policy_spec.rb
index ac992958620106111ee80282942e34ffd9c518e3..cc6436e86c69066d49f68168e2033c38adea4e38 100644
--- a/ee/spec/policies/ci/build_policy_spec.rb
+++ b/ee/spec/policies/ci/build_policy_spec.rb
@@ -4,4 +4,122 @@
 
 RSpec.describe Ci::BuildPolicy, feature_category: :continuous_integration do
   it_behaves_like 'a deployable job policy in EE', :ci_build
+
+  describe 'troubleshoot_job_with_ai' do
+    let(:authorized) { true }
+    let(:cloud_connector_free_access) { true }
+    let(:cloud_connector_user_access) { true }
+    let_it_be(:project) { create(:project, :private) }
+    let_it_be(:pipeline) { create(:ci_empty_pipeline, project: project) }
+    let_it_be(:build) { create(:ci_build, pipeline: pipeline) }
+    let_it_be(:user) { create(:user) }
+
+    subject { described_class.new(user, build) }
+
+    before_all do
+      project.add_maintainer(user)
+    end
+
+    before do
+      stub_licensed_features(ai_features: true, troubleshoot_job: true)
+      allow(::Gitlab::Llm::Chain::Utils::ChatAuthorizer).to receive_message_chain(
+        :resource, :allowed?).and_return(authorized)
+      allow(user).to receive(:can?).with(:admin_all_resources).and_call_original
+      allow(::Gitlab::Llm::StageCheck).to receive(:available?).and_return(true)
+      allow(user).to receive(:can?).with(:access_duo_chat).and_return(true)
+      allow(user).to receive(:can?).with(:access_duo_features, build.project).and_return(true)
+      allow(::CloudConnector::AvailableServices).to receive(:find_by_name).with(:troubleshoot_job).and_return(
+        instance_double(
+          CloudConnector::BaseAvailableServiceData,
+          free_access?: cloud_connector_free_access,
+          allowed_for?: cloud_connector_user_access
+        )
+      )
+    end
+
+    context 'when feature is chat authorized' do
+      subject { described_class.new(user, build) }
+
+      let(:authorized) { true }
+
+      it { is_expected.to be_allowed(:troubleshoot_job_with_ai) }
+
+      context 'when user cannot read_build' do
+        before_all do
+          project.add_guest(user)
+        end
+
+        before do
+          project.update_attribute(:public_builds, false)
+        end
+
+        it { is_expected.to be_disallowed(:troubleshoot_job_with_ai) }
+      end
+
+      context 'when the feature is not ai licensed' do
+        before do
+          stub_licensed_features(ai_features: false)
+        end
+
+        it { is_expected.to be_disallowed(:troubleshoot_job_with_ai) }
+      end
+
+      context 'when feature is not licensed' do
+        before do
+          stub_licensed_features(troubleshoot_job: false)
+        end
+
+        it { is_expected.to be_disallowed(:troubleshoot_job_with_ai) }
+      end
+    end
+
+    context 'when feature is not authorized' do
+      let(:authorized) { false }
+
+      it { is_expected.to be_disallowed(:troubleshoot_job_with_ai) }
+    end
+
+    # TODO: remove these tests when implementing https://gitlab.com/gitlab-org/gitlab/-/issues/473087
+    describe 'cloud connector' do
+      using RSpec::Parameterized::TableSyntax
+      where(:free_access, :user_access, :allowed) do
+        true  | true  | true
+        true  | false | true
+        false | true  | true
+        false | false | false
+      end
+
+      with_them do
+        let(:cloud_connector_free_access) { free_access }
+        let(:cloud_connector_user_access) { user_access }
+        let(:policy) { :troubleshoot_job_with_ai }
+
+        it { is_expected.to(allowed ? be_allowed(policy) : be_disallowed(policy)) }
+      end
+    end
+
+    context 'when on .org or .com', :saas do
+      using RSpec::Parameterized::TableSyntax
+      where(:group_with_ai_membership, :free_access, :user_access, :allowed) do
+        true  | true   | true  | true
+        true  | false  | true  | true
+        false | false  | true  | true
+        false | false  | false | false
+        true  | true   | false | true
+        false | true   | false | false
+      end
+
+      with_them do
+        before do
+          allow(user).to receive(:any_group_with_ai_available?).and_return(group_with_ai_membership)
+        end
+
+        let(:cloud_connector_free_access) { free_access }
+        let(:cloud_connector_user_access) { user_access }
+        let(:policy) { :troubleshoot_job_with_ai }
+
+        it { is_expected.to(allowed ? be_allowed(policy) : be_disallowed(policy)) }
+      end
+    end
+  end
 end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index bdcd35a7b0fdd076ad95a7781594a64c64cdbecd..ff2659a670fdcd0c812b71ef53decd4356867bf5 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -54190,9 +54190,6 @@ msgstr ""
 msgid "This command is used for troubleshooting jobs and can only be invoked from a failed job log page."
 msgstr ""
 
-msgid "This command is used for troubleshooting jobs and can only be invoked from a job log page."
-msgstr ""
-
 msgid "This comment changed after you started editing it. Review the %{startTag}updated comment%{endTag} to ensure information is not lost."
 msgstr ""