diff --git a/doc/development/ai_features/_index.md b/doc/development/ai_features/_index.md index 095e2d23692bc3d710cb2317b494e10def7c2362..5ab94d820ab4a1c975a86fc610b48a34b4a8ed9c 100644 --- a/doc/development/ai_features/_index.md +++ b/doc/development/ai_features/_index.md @@ -45,20 +45,15 @@ For Duo Pro, [you can provision a license yourself](ai_development_license.md#se {{< /alert >}} **Why**: This ensures that your instance or group has the correct licenses, settings, and feature flags to test Duo features locally. -AI gateway is what routes request between GitLab Rails and the LLM. The script should take care of most of the setup required. Once it has been run, make sure -to check in your GDK database that the ai gateway URL is correct. Run: +AI gateway is what routes request between GitLab Rails and the LLM. The setup script automatically configures the AI Gateway URL in the database, so you should not need to manually configure it. Once the script has been run, you can verify that the AI gateway URL is correct by running: ```ruby Ai::Setting.first.ai_gateway_url ``` -This should return a URL that points to your local and uses the right port: `http://0.0.0.0:5052`. +This should return a URL that points to your local AI gateway: `http://0.0.0.0:5052`. -If the value points to a non-local URL, you can manually execute an update to your GDK database: - -```ruby -Ai::Setting.first.update!(ai_gateway_url: "http://0.0.0.0:5052") -``` +The setup script now automatically configures this URL in the database, replacing the deprecated `AI_GATEWAY_URL` environment variable approach. Now in your `gdk` directory, you can `cd` into the `gitlab-ai-gateway` directory and run `poetry sync`. This should install all project dependency. If this resolves without error, try now to run the test of the project with `make test`. If there are errors, check the results as it can help debug potential issues with your configuration. diff --git a/doc/development/ai_features/amazon_q_integration.md b/doc/development/ai_features/amazon_q_integration.md index 95f470ba0771c8184067e4b79d6142202bfdd55c..06a4e2f4f4084a7e0e66bd45be6a5c12398a7b06 100644 --- a/doc/development/ai_features/amazon_q_integration.md +++ b/doc/development/ai_features/amazon_q_integration.md @@ -40,11 +40,12 @@ This guide describes how to set up Amazon Q in a GitLab Linux package running in ```ruby gitlab_rails['env'] = { "GITLAB_LICENSE_MODE" => "test", - "CUSTOMER_PORTAL_URL" => "https://customers.staging.gitlab.com", - "AI_GATEWAY_URL" => "https://cloud.staging.gitlab.com/ai" + "CUSTOMER_PORTAL_URL" => "https://customers.staging.gitlab.com" } ``` + Note: The AI Gateway URL should be configured through the database using `Ai::Setting.instance.update!(ai_gateway_url: 'https://cloud.staging.gitlab.com/ai')` instead of the deprecated `AI_GATEWAY_URL` environment variable. + 1. Apply the config changes by `sudo gitlab-ctl reconfigure` 1. Obtain and activate a self-managed ultimate license 1. Go to [staging customers portal](https://customers.staging.gitlab.com/), select "Signin with GitLab.com account". diff --git a/ee/app/models/ai/setting.rb b/ee/app/models/ai/setting.rb index a0a99eae190c89a35b083adb199e9c4a60e85f6e..77efdb575f5125bf1a77007020692549141d979c 100644 --- a/ee/app/models/ai/setting.rb +++ b/ee/app/models/ai/setting.rb @@ -28,7 +28,7 @@ class Setting < ApplicationRecord def self.defaults { - ai_gateway_url: ENV['AI_GATEWAY_URL'], + ai_gateway_url: ::Gitlab::AiGateway.cloud_connector_url, enabled_instance_verbose_ai_logs: Feature.enabled?(:expanded_ai_logging) # rubocop:disable Gitlab/FeatureFlagWithoutActor -- this is an instance level FF } end diff --git a/ee/lib/gitlab/ai_gateway.rb b/ee/lib/gitlab/ai_gateway.rb index e369018c8cca6a2f7bc600d1ad262f86b4863956..f11b88ba2f0a9adefe0653a0de8142854b37bfd8 100644 --- a/ee/lib/gitlab/ai_gateway.rb +++ b/ee/lib/gitlab/ai_gateway.rb @@ -33,11 +33,11 @@ def self.access_token_url(code_completions_feature_setting) end def self.self_hosted_url - ::Ai::Setting.instance&.ai_gateway_url || ENV["AI_GATEWAY_URL"] + ::Ai::Setting.instance&.ai_gateway_url end def self.has_self_hosted_ai_gateway? - !::Ai::Setting.instance&.ai_gateway_url.blank? + ::Ai::Setting.self_hosted? end def self.enabled_instance_verbose_ai_logs diff --git a/ee/lib/gitlab/duo/developments/setup.rb b/ee/lib/gitlab/duo/developments/setup.rb index 0a276e6735cadaf47dc2426e8fb0216f2fc470a9..69c6e9412ba7516a70a45bd8fd8cfe6181adfc61 100644 --- a/ee/lib/gitlab/duo/developments/setup.rb +++ b/ee/lib/gitlab/duo/developments/setup.rb @@ -35,6 +35,12 @@ def initialize(namespace, args) private + def configure_ai_gateway_url! + puts "Configuring AI Gateway URL...." + + ::Ai::Setting.instance.update!(ai_gateway_url: 'http://0.0.0.0:5052') + end + def create_add_on_purchases!(group: nil) ::GitlabSubscriptions::AddOnPurchase.by_namespace(group).delete_all @@ -106,6 +112,7 @@ def execute TXT require_self_managed! + configure_ai_gateway_url! Developments.seed_data(@namespace) create_add_on_purchases! @@ -138,6 +145,7 @@ def execute TXT ensure_application_settings! + configure_ai_gateway_url! Developments.seed_data(@namespace) diff --git a/ee/spec/lib/gitlab/ai_gateway_spec.rb b/ee/spec/lib/gitlab/ai_gateway_spec.rb index 86bf68714f757b95e50d08bc5614e6ea35dd5edf..51bd74a8c704fd6692fb9b8bea03e0b0a6a5b1be 100644 --- a/ee/spec/lib/gitlab/ai_gateway_spec.rb +++ b/ee/spec/lib/gitlab/ai_gateway_spec.rb @@ -25,15 +25,13 @@ ai_setting.update!(ai_gateway_url: nil) end - context 'when AI_GATEWAY_URL environment variable is set' do - it 'returns the env var' do - stub_env('AI_GATEWAY_URL', url) - - expect(described_class.url).to eq(url) + context 'when AI gateway is configured via setting only' do + it 'falls back to cloud connector url' do + expect(described_class.url).to eq(described_class.cloud_connector_url) end end - context 'when AI_GATEWAY_URL is not set' do + context 'when self hosted URL is not set' do it 'returns the cloud connector url' do allow(::CloudConnector::Config).to receive(:base_url).and_return(url) @@ -44,7 +42,7 @@ end describe '.cloud_connector_url' do - context 'when AI_GATEWAY_URL environment variable is not set' do + context 'when no self-hosted URL is configured' do let(:url) { 'http:://example.com' } it 'returns the cloud connector url' do @@ -59,18 +57,16 @@ context 'when the ai_gateway_url setting is set' do it 'returns the the setting value' do ai_setting.update!(ai_gateway_url: url) - stub_env('AI_GATEWAY_URL', nil) expect(described_class.self_hosted_url).to eq(url) end end context 'when the ai_gateway_url setting is not set' do - it 'returns the AI_GATEWAY_URL env var value' do + it 'returns nil' do ai_setting.update!(ai_gateway_url: nil) - stub_env('AI_GATEWAY_URL', url) - expect(described_class.self_hosted_url).to eq(url) + expect(described_class.self_hosted_url).to be_nil end end end @@ -78,32 +74,22 @@ describe '.has_self_hosted_ai_gateway?' do subject(:has_self_hosted_ai_gateway) { described_class.has_self_hosted_ai_gateway? } - context 'when AI Gateway url is set' do + context 'when there are any self-hosted models configured' do before do - ai_setting.update!(ai_gateway_url: url) + create(:ai_self_hosted_model) end it { is_expected.to be(true) } end - context 'when AI Gateway url is not set' do - before do - ai_setting.update!(ai_gateway_url: nil) - end - - it { is_expected.to be(false) } - end - - context 'when AI Gateway url is nil' do - let(:ai_setting) { nil } - + context 'when there are no self-hosted models configured' do it { is_expected.to be(false) } end end describe '.access_token_url' do before do - stub_env('AI_GATEWAY_URL', 'http://local-aigw:5052') + ai_setting.update!(ai_gateway_url: 'http://local-aigw:5052') allow(::CloudConnector::Config).to receive(:base_url).and_return(url) end @@ -135,7 +121,6 @@ describe '.cloud_connector_auth_url' do before do - stub_env('AI_GATEWAY_URL', 'http://local-aigw:5052') allow(::CloudConnector::Config).to receive(:base_url).and_return(url) end diff --git a/ee/spec/lib/gitlab/duo/developments/setup_spec.rb b/ee/spec/lib/gitlab/duo/developments/setup_spec.rb index a33f089595c5e7ca429f25c75325c9f898398360..74ff9a33f010a4130b27f850488c36ce17fc51c4 100644 --- a/ee/spec/lib/gitlab/duo/developments/setup_spec.rb +++ b/ee/spec/lib/gitlab/duo/developments/setup_spec.rb @@ -72,19 +72,36 @@ end end + shared_examples 'configures AI Gateway URL' do + it 'configures AI Gateway URL in database' do + expect { setup }.to change { ::Ai::Setting.instance.ai_gateway_url } + .to('http://0.0.0.0:5052') + end + end + context 'when simulating GitLabCom', :saas do let(:args) { {} } before do stub_env('GITLAB_SIMULATE_SAAS', '1') + # Speed up: avoid heavy seed_fu; stub the rake task with minimal behavior + seed_task = instance_double(Rake::Task, invoke: true) + allow(Rake::Task).to receive(:[]).with('db:seed_fu').and_return(seed_task) + allow(seed_task).to receive(:invoke) do + grp = Group.find_by_full_path('gitlab-duo') || create(:group, path: 'gitlab-duo') + # Ensure test user is a maintainer of the group + grp.add_maintainer(user) unless grp.members.exists?(user_id: user.id) + end + allow(seed_task).to receive(:reenable) + original_paths = SeedFu.fixture_paths - allow(SeedFu).to receive(:fixture_paths).and_return( - original_paths + ['ee/db/fixtures/development'] + allow(SeedFu).to receive_messages( + fixture_paths: original_paths + ['ee/db/fixtures/development'], + seed: true ) stub_env('SEED_GITLAB_DUO', '1') - allow(SeedFu).to receive(:seed).and_call_original end context 'when group does not exist' do @@ -119,6 +136,7 @@ it_behaves_like 'enables all necessary feature flags' it_behaves_like 'errors when there is no license' it_behaves_like 'creates add-on purchases' + it_behaves_like 'configures AI Gateway URL' it 'creates add on purchases for the right group, and not for the entire instance' do setup @@ -173,6 +191,7 @@ it_behaves_like 'enables all necessary feature flags' it_behaves_like 'errors when there is no license' it_behaves_like 'creates add-on purchases' + it_behaves_like 'configures AI Gateway URL' it 'sets up add on purchases for the entire instance, and not for a specific group' do setup diff --git a/ee/spec/models/ai/setting_spec.rb b/ee/spec/models/ai/setting_spec.rb index a2583b4d8385ddcfb85a398ef3cc3bf088b8b22c..7fd6cf2aacb2be3f79148f33ecb7eb7b6ec05afb 100644 --- a/ee/spec/models/ai/setting_spec.rb +++ b/ee/spec/models/ai/setting_spec.rb @@ -32,14 +32,14 @@ it 'rejects private IP addresses' do setting.write_attribute(attribute_name, 'http://169.254.169.254') - expect { setting.valid? }.to change { setting.errors[attribute_name] }.from([]) - expect(setting.errors[attribute_name].first).to match(/allow list|denied/i) + setting.valid? + expect(setting.errors[attribute_name]).to include(a_string_matching(/allow list|denied/i)) end it 'rejects AWS internal hostnames' do setting.write_attribute(attribute_name, 'http://ip-172-31-1-1.ec2.internal') - expect { setting.valid? }.to change { setting.errors[attribute_name] }.from([]) - expect(setting.errors[attribute_name].first).to match(/allow list|denied/i) + setting.valid? + expect(setting.errors[attribute_name]).to include(a_string_matching(/allow list|denied/i)) end it 'shows the actual error message from UrlBlocker' do @@ -141,13 +141,11 @@ end it 'does not override existing record attributes' do - original_url = 'http://example.com' new_url = 'http://new.example.com' - stub_env('AI_GATEWAY_URL', original_url) - # on create, uses default value from AI_GATEWAY_URL + # on create, defaults to production cloud connector URL via defaults described_class.instance - expect(described_class.first.ai_gateway_url).to eq original_url + expect(described_class.first.ai_gateway_url).to eq('https://cloud.gitlab.com/ai') # update to non-default value described_class.first.update!(ai_gateway_url: new_url)