fix(security): enforce premium flags on SLA automation, Captain runtime, and v2-only scenarios

This commit is contained in:
Tanmay Deep Sharma
2026-07-22 17:59:05 +05:30
parent 3b6e07c737
commit 5bf6c0ddc3
6 changed files with 22 additions and 2 deletions
@@ -1,4 +1,5 @@
class Api::V1::Accounts::Captain::ScenariosController < Api::V1::Accounts::Captain::BaseController
before_action :ensure_captain_v2_enabled
before_action -> { check_authorization(Captain::Scenario) }
before_action :set_assistant
before_action :set_scenario, only: [:show, :update, :destroy]
@@ -24,6 +25,13 @@ class Api::V1::Accounts::Captain::ScenariosController < Api::V1::Accounts::Capta
private
# Scenarios are a Captain v2-only feature; the shared base guard allows either flag, so require v2 here.
def ensure_captain_v2_enabled
return if current_account.feature_enabled?('captain_integration_v2')
render json: { error: 'Captain is not enabled for this account' }, status: :forbidden
end
def set_assistant
@assistant = account_assistants.find(params[:assistant_id])
end
@@ -1,6 +1,8 @@
module Enterprise::ActionService
def add_sla(sla_policy_id)
return if sla_policy_id.blank?
# SLA is a premium feature; automation rules must not keep applying SLAs once it is disabled.
return unless @account.feature_enabled?('sla')
sla_policy = @account.sla_policies.find_by(id: sla_policy_id.first)
return if sla_policy.nil?
@@ -50,7 +50,14 @@ module Enterprise::MessageTemplates::HookExecutionService
end
def should_process_captain_response?
conversation.pending? && message.incoming? && inbox.captain_assistant.present?
conversation.pending? && message.incoming? && inbox.captain_assistant.present? && captain_feature_enabled?
end
# Captain is a premium feature; stop the runtime responder when it has been revoked, even if an
# assistant is still linked to the inbox.
def captain_feature_enabled?
account = conversation.account
account.feature_enabled?('captain_integration') || account.feature_enabled?('captain_integration_v2')
end
def perform_handoff
@@ -6,7 +6,7 @@ RSpec.describe 'Api::V1::Accounts::Captain::Scenarios', type: :request do
let(:agent) { create(:user, account: account, role: :agent) }
let(:assistant) { create(:captain_assistant, account: account) }
before { account.enable_features!('captain_integration') }
before { account.enable_features!('captain_integration_v2') }
def json_response
JSON.parse(response.body, symbolize_names: true)
@@ -8,6 +8,8 @@ describe ActionService do
let(:conversation) { create(:conversation, account: account) }
let(:action_service) { described_class.new(conversation) }
before { account.enable_features!('sla') }
context 'when sla_policy_id is present' do
it 'adds the sla policy to the conversation and create applied_sla entry' do
action_service.add_sla([sla_policy.id])
@@ -8,6 +8,7 @@ RSpec.describe MessageTemplates::HookExecutionService do
let(:assistant) { create(:captain_assistant, account: account) }
before do
account.enable_features!('captain_integration')
create(:captain_inbox, captain_assistant: assistant, inbox: inbox)
end