Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
dca8df0c90
commit
473b876fe3
|
|
@ -72,6 +72,7 @@ db:check-schema-single-db:
|
|||
db:check-migrations:
|
||||
extends:
|
||||
- .db-job-base
|
||||
- .use-pg13 # Should match the db same version used by GDK
|
||||
- .rails:rules:ee-and-foss-mr-with-migration
|
||||
script:
|
||||
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME:$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --depth 20
|
||||
|
|
|
|||
|
|
@ -336,13 +336,11 @@ RSpec/FactoryBot/AvoidCreate:
|
|||
- 'spec/helpers/wiki_helper_spec.rb'
|
||||
- 'spec/helpers/wiki_page_version_helper_spec.rb'
|
||||
- 'spec/lib/sidebars/admin/menus/abuse_reports_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/admin/menus/monitoring_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/ci_cd_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/group_information_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/issues_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/kubernetes_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/merge_requests_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/observability_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/menus/settings_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/groups/super_sidebar_panel_spec.rb'
|
||||
|
|
@ -358,17 +356,8 @@ RSpec/FactoryBot/AvoidCreate:
|
|||
- 'spec/lib/sidebars/projects/menus/project_information_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/projects/menus/repository_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/projects/menus/settings_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/projects/menus/shimo_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/projects/panel_spec.rb'
|
||||
- 'spec/lib/sidebars/projects/super_sidebar_panel_spec.rb'
|
||||
- 'spec/lib/sidebars/search/panel_spec.rb'
|
||||
- 'spec/lib/sidebars/user_profile/panel_spec.rb'
|
||||
- 'spec/lib/sidebars/user_settings/panel_spec.rb'
|
||||
- 'spec/lib/sidebars/your_work/menus/issues_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/your_work/menus/merge_requests_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/your_work/menus/todos_menu_spec.rb'
|
||||
- 'spec/lib/sidebars/your_work/panel_spec.rb'
|
||||
- 'spec/mailers/abuse_report_mailer_spec.rb'
|
||||
- 'spec/mailers/devise_mailer_spec.rb'
|
||||
- 'spec/mailers/emails/auto_devops_spec.rb'
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 16.0.4 (2023-06-08)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
||||
- [Fix LDAP tls_options not working](gitlab-org/gitlab@e6038d0d4e8bb190ccfeca5fe7204d6a6af266e5) ([merge request](gitlab-org/gitlab!122797))
|
||||
|
||||
## 16.0.3 (2023-06-06)
|
||||
|
||||
### Fixed (3 changes)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1934b9991139b48ed58d78dc89b35c262acd5150
|
||||
468ba7de9380a1eb6321dbdf9b7ddffd7eda90f7
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export default {
|
|||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08 gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8 gl-flex-shrink-0"
|
||||
class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-border-0 border-top border-bottom gl-border-gray-a-08! gl-box-shadow-none gl-display-flex gl-align-items-center gl-font-weight-bold gl-w-full gl-h-8 gl-flex-shrink-0"
|
||||
data-qa-selector="context_switcher"
|
||||
>
|
||||
<span
|
||||
|
|
|
|||
|
|
@ -15,6 +15,55 @@ module Admin
|
|||
def project_missing_pipeline_yaml?(project)
|
||||
project.repository&.gitlab_ci_yml.blank?
|
||||
end
|
||||
|
||||
def code_suggestions_token_explanation
|
||||
link_start = code_suggestions_link_start(code_suggestions_pat_docs_url)
|
||||
|
||||
# rubocop:disable Layout/LineLength
|
||||
# rubocop:disable Style/FormatString
|
||||
s_('CodeSuggestionsSM|Your personal access token from GitLab.com. See the %{link_start}documentation%{link_end} for information on creating a personal access token.')
|
||||
.html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
|
||||
# rubocop:enable Style/FormatString
|
||||
# rubocop:enable Layout/LineLength
|
||||
end
|
||||
|
||||
def code_suggestions_agreement
|
||||
terms_link_start = code_suggestions_link_start(code_suggestions_agreement_url)
|
||||
ai_docs_link_start = code_suggestions_link_start(code_suggestions_ai_docs_url)
|
||||
|
||||
# rubocop:disable Layout/LineLength
|
||||
# rubocop:disable Style/FormatString
|
||||
s_('CodeSuggestionsSM|• Agree to the %{terms_link_start}GitLab Testing Agreement%{link_end}.%{br} • Acknowledge that GitLab will send data from the instance, including personal data, to Google for cloud hosting.%{br} We may also send data to %{ai_docs_link_start}third-party AI providers%{link_end} to provide this feature.')
|
||||
.html_safe % { terms_link_start: terms_link_start, ai_docs_link_start: ai_docs_link_start, link_end: '</a>'.html_safe, br: '</br>'.html_safe }
|
||||
# rubocop:enable Style/FormatString
|
||||
# rubocop:enable Layout/LineLength
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# rubocop:disable Gitlab/DocUrl
|
||||
# We want to link SaaS docs for flexibility for every URL related to Code Suggestions on Self Managed.
|
||||
# We expect to update docs often during the Beta and we want to point user to the most up to date information.
|
||||
def code_suggestions_docs_url
|
||||
'https://docs.gitlab.com/ee/user/project/repository/code_suggestions.html'
|
||||
end
|
||||
|
||||
def code_suggestions_agreement_url
|
||||
'https://about.gitlab.com/handbook/legal/testing-agreement/'
|
||||
end
|
||||
|
||||
def code_suggestions_ai_docs_url
|
||||
'https://docs.gitlab.com/ee/user/ai_features.html'
|
||||
end
|
||||
|
||||
def code_suggestions_pat_docs_url
|
||||
'https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#create-a-personal-access-token'
|
||||
end
|
||||
# rubocop:enable Gitlab/DocUrl
|
||||
|
||||
def code_suggestions_link_start(url)
|
||||
"<a href=\"#{url}\" target=\"_blank\" rel=\"noopener noreferrer\">".html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ module ApplicationSettingsHelper
|
|||
:admin_mode,
|
||||
:after_sign_out_path,
|
||||
:after_sign_up_text,
|
||||
:ai_access_token,
|
||||
:akismet_api_key,
|
||||
:akismet_enabled,
|
||||
:allow_local_requests_from_hooks_and_services,
|
||||
|
|
@ -309,6 +310,7 @@ module ApplicationSettingsHelper
|
|||
:inactive_projects_delete_after_months,
|
||||
:inactive_projects_min_size_mb,
|
||||
:inactive_projects_send_warning_email_after_months,
|
||||
:instance_level_code_suggestions_enabled,
|
||||
:invisible_captcha_enabled,
|
||||
:jira_connect_application_key,
|
||||
:jira_connect_public_key_storage_enabled,
|
||||
|
|
|
|||
|
|
@ -720,6 +720,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
allow_nil: false,
|
||||
inclusion: { in: [true, false], message: N_('must be a boolean value') }
|
||||
|
||||
validates :ai_access_token,
|
||||
presence: { message: N_("is required to enable Code Suggestions") },
|
||||
if: :instance_level_code_suggestions_enabled
|
||||
|
||||
attr_encrypted :asset_proxy_secret_key,
|
||||
mode: :per_attribute_iv,
|
||||
key: Settings.attr_encrypted_db_key_base_truncated,
|
||||
|
|
@ -948,4 +952,5 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
ApplicationSetting.prepend(ApplicationSettingMaskedAttrs)
|
||||
ApplicationSetting.prepend_mod_with('ApplicationSetting')
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ module ApplicationSettingImplementation
|
|||
{
|
||||
admin_mode: false,
|
||||
after_sign_up_text: nil,
|
||||
ai_access_token: nil,
|
||||
akismet_enabled: false,
|
||||
akismet_api_key: nil,
|
||||
allow_local_requests_from_system_hooks: true,
|
||||
|
|
@ -104,6 +105,7 @@ module ApplicationSettingImplementation
|
|||
housekeeping_gc_period: 200,
|
||||
housekeeping_incremental_repack_period: 10,
|
||||
import_sources: Settings.gitlab['import_sources'],
|
||||
instance_level_code_suggestions_enabled: false,
|
||||
invisible_captcha_enabled: false,
|
||||
issues_create_limit: 300,
|
||||
jira_connect_application_key: nil,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Similar to MASK_PASSWORD mechanism we do for EE, see:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/463bb1f855d71fadef931bd50f1692ee04f211a8/ee/app/models/ee/application_setting.rb#L15
|
||||
# but for non-EE attributes.
|
||||
module ApplicationSettingMaskedAttrs
|
||||
MASK = '*****'
|
||||
|
||||
def ai_access_token=(value)
|
||||
return if value == MASK
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
|
|
@ -11,9 +11,14 @@ module AutoMerge
|
|||
end
|
||||
|
||||
def process(merge_request)
|
||||
logger.info("Processing Automerge")
|
||||
return unless merge_request.actual_head_pipeline_success?
|
||||
|
||||
logger.info("Pipeline Success")
|
||||
return unless merge_request.mergeable?
|
||||
|
||||
logger.info("Merge request mergeable")
|
||||
|
||||
merge_request.merge_async(merge_request.merge_user_id, merge_request.merge_params)
|
||||
end
|
||||
|
||||
|
|
@ -40,5 +45,9 @@ module AutoMerge
|
|||
def notify(merge_request)
|
||||
notification_service.async.merge_when_pipeline_succeeds(merge_request, current_user) if merge_request.saved_change_to_auto_merge_enabled?
|
||||
end
|
||||
|
||||
def logger
|
||||
@logger ||= Gitlab::AppLogger
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ module MergeRequests
|
|||
|
||||
result = yield
|
||||
|
||||
observe_result(mergeability_name, result)
|
||||
observe("mergeability.#{mergeability_name}.duration_s", current_monotonic_time - op_started_at)
|
||||
|
||||
observe_sql_counters(mergeability_name, op_start_db_counters, current_db_counter_payload)
|
||||
|
||||
result
|
||||
|
|
@ -31,7 +31,13 @@ module MergeRequests
|
|||
|
||||
private
|
||||
|
||||
attr_reader :destination, :merge_request
|
||||
attr_reader :destination, :merge_request, :stored_result
|
||||
|
||||
def observe_result(name, result)
|
||||
return unless result.respond_to?(:success?)
|
||||
|
||||
observe("mergeability.#{name}.successful", result.success?)
|
||||
end
|
||||
|
||||
def observe(name, value)
|
||||
observations[name.to_s].push(value)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
- return if Gitlab.org_or_com?
|
||||
|
||||
- expanded = integration_expanded?('ai_access')
|
||||
- token_is_present = @application_setting.ai_access_token.present?
|
||||
- token_label = token_is_present ? s_('CodeSuggestionsSM|Enter new personal access token') : s_('CodeSuggestionsSM|Personal access token')
|
||||
- token_value = token_is_present ? ApplicationSettingMaskedAttrs::MASK : ''
|
||||
|
||||
%section.settings.no-animate#js-ai-access-settings{ class: ('expanded' if expanded) }
|
||||
.settings-header
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
|
||||
= s_('CodeSuggestionsSM|Code Suggestions')
|
||||
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= s_('CodeSuggestionsSM|Enable Code Suggestion for users of this GitLab instance.')
|
||||
= link_to sprite_icon('question-o'), code_suggestions_docs_url, target: '_blank', class: 'has-tooltip', title: _('More information')
|
||||
|
||||
.settings-content
|
||||
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-ai-access-settings'), html: { class: 'fieldset-form', id: 'ai-access-settings' } do |f|
|
||||
= form_errors(@application_setting)
|
||||
|
||||
%fieldset
|
||||
.form-group
|
||||
= f.gitlab_ui_checkbox_component :instance_level_code_suggestions_enabled,
|
||||
s_('CodeSuggestionsSM|Turn on Code Suggestions for this instance. By turning on this feature, you:'),
|
||||
help_text: code_suggestions_agreement
|
||||
= f.label :ai_access_token, token_label, class: 'label-bold'
|
||||
= f.password_field :ai_access_token, value: token_value, autocomplete: 'on', class: 'form-control gl-form-input', aria: { describedby: 'code_suggestions_token_explanation' }
|
||||
%p.form-text.text-muted{ id: 'code_suggestions_token_explanation' }
|
||||
= code_suggestions_token_explanation
|
||||
|
||||
= f.submit _('Save changes'), pajamas_button: true
|
||||
|
|
@ -109,3 +109,4 @@
|
|||
= render 'admin/application_settings/floc'
|
||||
= render_if_exists 'admin/application_settings/add_license'
|
||||
= render 'admin/application_settings/jira_connect'
|
||||
= render_if_exists 'admin/application_settings/ai_access'
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ en:
|
|||
pwa_short_name: "PWA short name"
|
||||
pwa_description: "PWA description"
|
||||
pwa_icon: "Icon"
|
||||
application_setting:
|
||||
ai_access_token: "Personal access token"
|
||||
incident_management/timeline_event:
|
||||
note: 'Timeline text'
|
||||
issue_link:
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ metadata:
|
|||
description: Operations related to metadata of the GitLab instance
|
||||
- name: metrics_user_starred_dashboards
|
||||
description: Operations related to User-starred metrics dashboards
|
||||
- name: ml_model_registry
|
||||
description: Operations related to Model registry
|
||||
- name: npm_packages
|
||||
description: Operations related to NPM packages
|
||||
- name: nuget_packages
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class EnsureBackfillBigintIdIsCompleted < Gitlab::Database::Migration[2.1]
|
||||
include Gitlab::Database::MigrationHelpers::ConvertToBigint
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
disable_ddl_transaction!
|
||||
|
||||
TABLE_NAME = :ci_pipeline_variables
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
|
||||
table_name: TABLE_NAME,
|
||||
column_name: 'id',
|
||||
job_arguments: [['id'], ['id_convert_to_bigint']]
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddConcurrentIndexForCiPipelineVariablesBigintId < Gitlab::Database::Migration[2.1]
|
||||
include Gitlab::Database::MigrationHelpers::ConvertToBigint
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
TABLE_NAME = :ci_pipeline_variables
|
||||
INDEX_NAME = "index_#{TABLE_NAME}_on_id_convert_to_bigint"
|
||||
|
||||
def up
|
||||
add_concurrent_index TABLE_NAME, :id_convert_to_bigint, unique: true, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
4d84a87532b45436e64d0c919b361548b4b69b200ec3a91f454af718a51fd22a
|
||||
|
|
@ -0,0 +1 @@
|
|||
7428675eac2c572aa3521df7af7e79f7cf1b6e8f8472e99c842dddf2f3c7ce77
|
||||
|
|
@ -30525,6 +30525,8 @@ CREATE INDEX index_ci_pipeline_schedules_on_owner_id_and_id_and_active ON ci_pip
|
|||
|
||||
CREATE INDEX index_ci_pipeline_schedules_on_project_id ON ci_pipeline_schedules USING btree (project_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_ci_pipeline_variables_on_id_convert_to_bigint ON ci_pipeline_variables USING btree (id_convert_to_bigint);
|
||||
|
||||
CREATE UNIQUE INDEX index_ci_pipeline_variables_on_pipeline_id_and_key ON ci_pipeline_variables USING btree (pipeline_id, key);
|
||||
|
||||
CREATE INDEX index_ci_pipelines_config_on_pipeline_id ON ci_pipelines_config USING btree (pipeline_id);
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
|
|||
|
||||
1. On your GitLab server, open the configuration file:
|
||||
|
||||
For Omnibus GitLab installations:
|
||||
For Linux package installations:
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
For installations from source:
|
||||
For self-compiled installations:
|
||||
|
||||
```shell
|
||||
sudo -u git -H editor /home/git/gitlab/config/gitlab.yml
|
||||
|
|
@ -47,7 +47,7 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
|
|||
GitLab account.
|
||||
1. Add the provider configuration for Atlassian:
|
||||
|
||||
For Omnibus GitLab installations:
|
||||
For Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -61,7 +61,7 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
|
|||
]
|
||||
```
|
||||
|
||||
For installations from source:
|
||||
For self-compiled installations:
|
||||
|
||||
```yaml
|
||||
- { name: "atlassian_oauth2",
|
||||
|
|
@ -76,8 +76,8 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
|
|||
1. Save the configuration file.
|
||||
|
||||
1. For the changes to take effect:
|
||||
- If you installed via Omnibus, [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
- If you installed from source, [restart GitLab](../restart_gitlab.md#installations-from-source).
|
||||
- If you installed using the Linux package, [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
- If you self-compiled your installation, [restart GitLab](../restart_gitlab.md#installations-from-source).
|
||||
|
||||
On the sign-in page there should now be an Atlassian icon below the regular sign in form. Select the icon to begin the authentication process.
|
||||
|
||||
|
|
|
|||
|
|
@ -37,16 +37,14 @@ To enable AWS Cognito as an authentication provider, complete the following step
|
|||
|
||||
1. Save changes for the app client settings.
|
||||
1. Under **Domain name**, include the AWS domain name for your AWS Cognito application.
|
||||
1. Under **App Clients**, find your app client ID. Select **Show details* to display the app client secret. These values correspond to the OAuth 2.0 Client ID and Client Secret. Save these values.
|
||||
1. Under **App Clients**, find your app client ID. Select **Show details** to display the app client secret. These values correspond to the OAuth 2.0 Client ID and Client Secret. Save these values.
|
||||
|
||||
## Configure GitLab
|
||||
|
||||
1. Configure the [common settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `cognito` as a single sign-on provider. This enables Just-In-Time
|
||||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. On your GitLab server, open the configuration file.
|
||||
|
||||
**For Omnibus installations**
|
||||
1. On your GitLab server, open the configuration file. For Linux package installations:
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
|
|
|
|||
|
|
@ -26,19 +26,19 @@ this provider also allows Crowd authentication for Git-over-https requests.
|
|||
|
||||
1. On your GitLab server, open the configuration file.
|
||||
|
||||
**Omnibus:**
|
||||
- Linux package installations:
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
**Source:**
|
||||
- Self-compiled installations:
|
||||
|
||||
```shell
|
||||
cd /home/git/gitlab
|
||||
```shell
|
||||
cd /home/git/gitlab
|
||||
|
||||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. Configure the [common settings](../../integration/omniauth.md#configure-common-settings)
|
||||
to add `crowd` as a single sign-on provider. This enables Just-In-Time
|
||||
|
|
@ -46,39 +46,39 @@ this provider also allows Crowd authentication for Git-over-https requests.
|
|||
|
||||
1. Add the provider configuration:
|
||||
|
||||
**Omnibus:**
|
||||
- Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
{
|
||||
name: "crowd",
|
||||
# label: "Provider name", # optional label for login button, defaults to "Crowd"
|
||||
args: {
|
||||
crowd_server_url: "CROWD_SERVER_URL",
|
||||
application_name: "YOUR_APP_NAME",
|
||||
application_password: "YOUR_APP_PASSWORD"
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
{
|
||||
name: "crowd",
|
||||
# label: "Provider name", # optional label for login button, defaults to "Crowd"
|
||||
args: {
|
||||
crowd_server_url: "CROWD_SERVER_URL",
|
||||
application_name: "YOUR_APP_NAME",
|
||||
application_password: "YOUR_APP_PASSWORD"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
]
|
||||
```
|
||||
|
||||
**Source:**
|
||||
- Self-compiled installations:
|
||||
|
||||
```yaml
|
||||
- { name: 'crowd',
|
||||
# label: 'Provider name', # optional label for login button, defaults to "Crowd"
|
||||
args: {
|
||||
crowd_server_url: 'CROWD_SERVER_URL',
|
||||
application_name: 'YOUR_APP_NAME',
|
||||
application_password: 'YOUR_APP_PASSWORD' } }
|
||||
```
|
||||
```yaml
|
||||
- { name: 'crowd',
|
||||
# label: 'Provider name', # optional label for login button, defaults to "Crowd"
|
||||
args: {
|
||||
crowd_server_url: 'CROWD_SERVER_URL',
|
||||
application_name: 'YOUR_APP_NAME',
|
||||
application_password: 'YOUR_APP_PASSWORD' } }
|
||||
```
|
||||
|
||||
1. Change `CROWD_SERVER_URL` to the [base URL of your Crowd server](https://confluence.atlassian.com/crowdkb/how-to-change-the-crowd-base-url-245827278.html).
|
||||
1. Change `YOUR_APP_NAME` to the application name from Crowd applications page.
|
||||
1. Change `YOUR_APP_PASSWORD` to the application password you've set.
|
||||
1. Save the configuration file.
|
||||
1. [Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) (Omnibus GitLab) or [restart](../restart_gitlab.md#installations-from-source) (source installations) for
|
||||
the changes to take effect.
|
||||
1. [Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) (Linux package installations) or
|
||||
[restart](../restart_gitlab.md#installations-from-source) (self-compiled installations) for the changes to take effect.
|
||||
|
||||
On the sign in page there should now be a Crowd tab in the sign in form.
|
||||
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ JWT provides you with a secret key for you to use.
|
|||
|
||||
1. On your GitLab server, open the configuration file.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
For installations from source:
|
||||
For self-compiled installations:
|
||||
|
||||
```shell
|
||||
cd /home/git/gitlab
|
||||
|
|
@ -30,7 +30,7 @@ JWT provides you with a secret key for you to use.
|
|||
account provisioning for users who do not have an existing GitLab account.
|
||||
1. Add the provider configuration.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -49,7 +49,7 @@ JWT provides you with a secret key for you to use.
|
|||
]
|
||||
```
|
||||
|
||||
For installation from source:
|
||||
For self-compiled installations:
|
||||
|
||||
```yaml
|
||||
- { name: 'jwt',
|
||||
|
|
@ -75,9 +75,9 @@ JWT provides you with a secret key for you to use.
|
|||
|
||||
1. Change `YOUR_APP_SECRET` to the client secret and set `auth_url` to your redirect URL.
|
||||
1. Save the configuration file.
|
||||
1. For the changes to take effect:
|
||||
- If you installed via Omnibus, [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
- If you installed from source, [restart GitLab](../restart_gitlab.md#installations-from-source).
|
||||
1. For changes to take effect, if you:
|
||||
- Used the Linux package to install GitLab, [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
- Self-compiled your GitLab installation, [restart GitLab](../restart_gitlab.md#installations-from-source).
|
||||
|
||||
On the sign in page there should now be a JWT icon below the regular sign in form.
|
||||
Select the icon to begin the authentication process. JWT asks the user to
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ values obtained during the LDAP client configuration earlier:
|
|||
- `cert`: The `.crt` file text from the downloaded certificate bundle
|
||||
- `key`: The `.key` file text from the downloaded certificate bundle
|
||||
|
||||
**For Omnibus installations**
|
||||
For Linux package installations:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -142,9 +142,7 @@ values obtained during the LDAP client configuration earlier:
|
|||
|
||||
1. Save the file and [reconfigure](../../restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
**For installations from source**
|
||||
For self-compiled installations:
|
||||
|
||||
1. Edit `config/gitlab.yml`:
|
||||
|
||||
|
|
|
|||
|
|
@ -1037,8 +1037,8 @@ For more information on synchronizing users and groups between LDAP and GitLab,
|
|||
## Move from LDAP to SAML
|
||||
|
||||
1. [Configure SAML](../../../integration/saml.md). Add `auto_link_ldap_user` to:
|
||||
- [`gitlab.rb` for Omnibus](../../../integration/saml.html?tab=Linux+package+%28Omnibus%29).
|
||||
- [`values.yml` for Kubernetes](../../../integration/saml.html?tab=Helm+chart+%28Kubernetes%29).
|
||||
- [`gitlab.rb` for Linux package installations](../../../integration/saml.html?tab=Linux+package+%28Omnibus%29).
|
||||
- [`values.yml` for Helm chart installations](../../../integration/saml.html?tab=Helm+chart+%28Kubernetes%29).
|
||||
For more information, see the [initial settings for all providers](../../../integration/omniauth.md#configure-initial-settings).
|
||||
|
||||
1. Optional. [Disable the LDAP auth from the sign-in page](#disable-ldap-web-sign-in).
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ The OpenID Connect provides you with a client's details and secret for you to us
|
|||
|
||||
1. On your GitLab server, open the configuration file.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
|
|
@ -35,7 +35,7 @@ The OpenID Connect provides you with a client's details and secret for you to us
|
|||
|
||||
1. Add the provider configuration.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -63,7 +63,7 @@ The OpenID Connect provides you with a client's details and secret for you to us
|
|||
]
|
||||
```
|
||||
|
||||
For Omnibus GitLab with multiple identity providers:
|
||||
For Linux package installations with multiple identity providers:
|
||||
|
||||
```ruby
|
||||
{ 'name' => 'openid_connect',
|
||||
|
|
@ -108,7 +108,7 @@ The OpenID Connect provides you with a client's details and secret for you to us
|
|||
NOTE:
|
||||
For more information on using multiple identity providers with OIDC, see [issue 5992](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5992).
|
||||
|
||||
For installation from source:
|
||||
For self-compiled installations:
|
||||
|
||||
```yaml
|
||||
- { name: 'openid_connect', # do not change this parameter
|
||||
|
|
@ -184,10 +184,10 @@ The OpenID Connect provides you with a client's details and secret for you to us
|
|||
- `jwks_uri` is the URL to the endpoint where the Token signer publishes its keys.
|
||||
|
||||
1. Save the configuration file.
|
||||
1. For changes to take effect, if you installed GitLab:
|
||||
1. For changes to take effect, if you:
|
||||
|
||||
- With Omnibus, [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
- From source, [restart GitLab](../restart_gitlab.md#installations-from-source).
|
||||
- Used the Linux package to install GitLab, [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
|
||||
- Self-compiled your GitLab installation, [restart GitLab](../restart_gitlab.md#installations-from-source).
|
||||
|
||||
On the sign in page, you have an OpenID Connect option below the regular sign in form.
|
||||
Select this option to begin the authentication process. The OpenID Connect provider
|
||||
|
|
@ -197,7 +197,7 @@ by the client. You are redirected to GitLab and signed in.
|
|||
## Example configurations
|
||||
|
||||
The following configurations illustrate how to set up OpenID with
|
||||
different providers with Omnibus GitLab.
|
||||
different providers when using the GitLab Linux package installation.
|
||||
|
||||
### Configure Google
|
||||
|
||||
|
|
@ -240,7 +240,7 @@ you need the following information:
|
|||
[Microsoft Quickstart Register an Application](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) documentation
|
||||
to obtain the tenant ID, client ID, and client secret for your app.
|
||||
|
||||
Example Omnibus configuration block:
|
||||
Example configuration block for Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -372,7 +372,7 @@ but `LocalAccounts` authenticates against local Active Directory accounts. Befor
|
|||
```
|
||||
|
||||
1. Configure the issuer URL with the custom policy used for `signup_signin`. For example, this is
|
||||
the Omnibus configuration with a custom policy for `b2c_1a_signup_signin`:
|
||||
the configuration with a custom policy for `b2c_1a_signup_signin` for Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -432,7 +432,7 @@ HS256 or HS358) to sign tokens. Public key encryption algorithms are:
|
|||
1. Select **Realm Settings > Tokens > Default Signature Algorithm**.
|
||||
1. Configure the signature algorithm.
|
||||
|
||||
Example Omnibus configuration block:
|
||||
Example configuration block for Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -556,7 +556,7 @@ For your app, complete the following steps on Casdoor:
|
|||
|
||||
See the [Casdoor documentation](https://casdoor.org/docs/integration/ruby/gitlab) for more details.
|
||||
|
||||
Example Omnibus GitLab configuration (file path: `/etc/gitlab/gitlab.rb`):
|
||||
Example configuration for Linux package installations (file path: `/etc/gitlab/gitlab.rb`):
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -617,7 +617,7 @@ This is not compatible with [configuring users based on OIDC group membership](#
|
|||
|
||||
The following example configurations show how to offer different levels of authentication, one option with 2FA and one without 2FA.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
|
@ -668,7 +668,7 @@ gitlab_rails['omniauth_providers'] = [
|
|||
]
|
||||
```
|
||||
|
||||
For installation from source:
|
||||
For self-compiled installations:
|
||||
|
||||
```yaml
|
||||
- { name: 'openid_connect',
|
||||
|
|
@ -774,7 +774,7 @@ response to require users to be members of a certain group, configure GitLab to
|
|||
|
||||
If you do not set `required_groups` or leave the setting empty, any user authenticated by the IdP through OIDC can use GitLab.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -808,7 +808,7 @@ For Omnibus GitLab:
|
|||
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
for the changes to take effect.
|
||||
|
||||
For installation from source:
|
||||
For self-compiled installations:
|
||||
|
||||
1. Edit `/home/git/gitlab/config/gitlab.yml`:
|
||||
|
||||
|
|
@ -853,7 +853,7 @@ based on group membership, configure GitLab to identify:
|
|||
[external user](../../user/admin_area/external_users.md), using the
|
||||
`external_groups` setting.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -887,7 +887,7 @@ For Omnibus GitLab:
|
|||
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
for the changes to take effect.
|
||||
|
||||
For installation from source:
|
||||
For self-compiled installations:
|
||||
|
||||
1. Edit `/home/git/gitlab/config/gitlab.yml`:
|
||||
|
||||
|
|
@ -930,7 +930,7 @@ response to assign users as administrator based on group membership, configure G
|
|||
- Which group memberships grant the user administrator access, using the
|
||||
`admin_groups` setting.
|
||||
|
||||
For Omnibus GitLab:
|
||||
For Linux package installations:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -964,7 +964,7 @@ For Omnibus GitLab:
|
|||
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
for the changes to take effect.
|
||||
|
||||
For installation from source:
|
||||
For self-compiled installations:
|
||||
|
||||
1. Edit `/home/git/gitlab/config/gitlab.yml`:
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
|
||||
## Configure GitLab for smartcard authentication
|
||||
|
||||
**For Omnibus installations**
|
||||
For Linux package installations:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -140,9 +140,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
GitLab for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
**For installations from source**
|
||||
For self-compiled installations:
|
||||
|
||||
1. Configure NGINX to request a client side certificate
|
||||
|
||||
|
|
@ -237,7 +235,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
|
||||
### Additional steps when using SAN extensions
|
||||
|
||||
**For Omnibus installations**
|
||||
For Linux package installations:
|
||||
|
||||
1. Add to `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -248,7 +246,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
GitLab for the changes to take effect.
|
||||
|
||||
**For installations from source**
|
||||
For self-compiled installations:
|
||||
|
||||
1. Add the `san_extensions` line to `config/gitlab.yml` within the smartcard section:
|
||||
|
||||
|
|
@ -267,7 +265,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
|
||||
### Additional steps when authenticating against an LDAP server
|
||||
|
||||
**For Omnibus installations**
|
||||
For Linux package installations:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -284,7 +282,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
GitLab for the changes to take effect.
|
||||
|
||||
**For installations from source**
|
||||
For self-compiled installations:
|
||||
|
||||
1. Edit `config/gitlab.yml`:
|
||||
|
||||
|
|
@ -304,7 +302,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
|
||||
### Require browser session with smartcard sign-in for Git access
|
||||
|
||||
**For Omnibus installations**
|
||||
For Linux package installations:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
|
|
@ -315,7 +313,7 @@ more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/
|
|||
1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
GitLab for the changes to take effect.
|
||||
|
||||
**For installations from source**
|
||||
For self-compiled installations:
|
||||
|
||||
1. Edit `config/gitlab.yml`:
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ If you use self-managed GitLab, you must install an agent server or specify an e
|
|||
|
||||
As a GitLab administrator, you can install the agent server:
|
||||
|
||||
- For [Omnibus installations](#for-omnibus).
|
||||
- For [GitLab Helm Chart installations](#for-gitlab-helm-chart).
|
||||
- For [Linux package installations](#for-linux-package-installations).
|
||||
- For [GitLab Helm chart installations](#for-gitlab-helm-chart).
|
||||
|
||||
### For Omnibus
|
||||
### For Linux package installations
|
||||
|
||||
You can enable the agent server for [Omnibus](https://docs.gitlab.com/omnibus/) package installations on a single node, or on multiple nodes at once.
|
||||
You can enable the agent server for Linux package installations on a single node, or on multiple nodes at once.
|
||||
|
||||
#### Enable on a single node
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ service logs by running the following command:
|
|||
kubectl logs -f -l=app=kas -n <YOUR-GITLAB-NAMESPACE>
|
||||
```
|
||||
|
||||
In Omnibus GitLab, find the logs in `/var/log/gitlab/gitlab-kas/`.
|
||||
In Linux package installations, find the logs in `/var/log/gitlab/gitlab-kas/`.
|
||||
|
||||
You can also [troubleshoot issues with individual agents](../../user/clusters/agent/troubleshooting.md).
|
||||
|
||||
|
|
@ -212,7 +212,7 @@ When the agent server tries to connect to the GitLab API, the following error mi
|
|||
{"level":"error","time":"2021-08-16T14:56:47.289Z","msg":"GetAgentInfo()","correlation_id":"01FD7QE35RXXXX8R47WZFBAXTN","grpc_service":"gitlab.agent.reverse_tunnel.rpc.ReverseTunnel","grpc_method":"Connect","error":"Get \"https://gitlab.example.com/api/v4/internal/kubernetes/agent_info\": dial tcp 172.17.0.4:443: connect: connection refused"}
|
||||
```
|
||||
|
||||
To fix this issue for [Omnibus](https://docs.gitlab.com/omnibus/) package installations,
|
||||
To fix this issue for Linux package installations,
|
||||
set the following parameter in `/etc/gitlab/gitlab.rb`. Replace `gitlab.example.com` with your GitLab instance's hostname:
|
||||
|
||||
```ruby
|
||||
|
|
|
|||
|
|
@ -211,6 +211,71 @@ make Prometheus scrape them over HTTPS, and support for it is being discussed
|
|||
Hence, it is not technically possible to turn off this HTTP listener without
|
||||
losing Prometheus metrics.
|
||||
|
||||
### Using an encrypted SSL key
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7799) in GitLab 16.1.
|
||||
|
||||
Puma supports the use of an encrypted private SSL key, which can be
|
||||
decrypted at runtime. The following instructions illustrate how to
|
||||
configure this:
|
||||
|
||||
1. Encrypt the key with a password if it is not already:
|
||||
|
||||
```shell
|
||||
openssl rsa -aes256 -in /path/to/ssl-key.pem -out /path/to/encrypted-ssl-key.pem
|
||||
```
|
||||
|
||||
Enter in a password twice to write the encrypted file. In this
|
||||
example, we use `some-password-here`.
|
||||
|
||||
1. Create a script or executable that prints the password. For
|
||||
example, create a basic script in
|
||||
`/var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password` that echoes
|
||||
the password:
|
||||
|
||||
```shell
|
||||
#!/bin/sh
|
||||
echo some-password-here
|
||||
```
|
||||
|
||||
Note that in production, you should avoid storing the password on
|
||||
disk and use a secure mechanism for retrieving a password, such as
|
||||
Vault. For example, the script might look like:
|
||||
|
||||
```shell
|
||||
#!/bin/sh
|
||||
export VAULT_ADDR=http://vault-password-distribution-point:8200
|
||||
export VAULT_TOKEN=<some token>
|
||||
|
||||
echo "$(vault kv get -mount=secret puma-ssl-password)"
|
||||
```
|
||||
|
||||
1. Ensure the Puma process has sufficient permissions to execute the
|
||||
script and to read the encrypted key:
|
||||
|
||||
```shell
|
||||
chown git:git /var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password
|
||||
chmod 770 /var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password
|
||||
chmod 660 /path/to/encrypted-ssl-key.pem
|
||||
```
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`, and replace `puma['ssl_certificate_key']` with the encrypted key and specify
|
||||
`puma['ssl_key_password_command]`:
|
||||
|
||||
```ruby
|
||||
puma['ssl_certificate_key'] = '/path/to/encrypted-ssl-key.pem'
|
||||
puma['ssl_key_password_command'] = '/var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password'
|
||||
```
|
||||
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. If GitLab comes up successfully, you should be able to remove the
|
||||
unencrypted SSL key that was stored on the GitLab instance.
|
||||
|
||||
## Switch from Unicorn to Puma
|
||||
|
||||
NOTE:
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ Read more about update policies and warnings in the PostgreSQL
|
|||
|
||||
| GitLab version | PostgreSQL versions | Default version for fresh installs | Default version for upgrades | Notes |
|
||||
| -------------- | --------------------- | ---------------------------------- | ---------------------------- | ----- |
|
||||
| 16.0 | 13.11 | 13.11 | 13.11 | |
|
||||
| 15.6 | 12.12, 13.8 | 13.8 | 12.12 | For upgrades, users can manually upgrade to 13.8 following the [upgrade documentation](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-150-and-later). |
|
||||
| 15.0 | 12.10, 13.6 | 13.6 | 12.10 | For upgrades, users can manually upgrade to 13.6 following the [upgrade documentation](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-150-and-later). |
|
||||
| 14.1 | 12.7, 13.3 | 12.7 | 12.7 | PostgreSQL 13 available for fresh installations if not using [Geo](../geo/index.md#requirements-for-running-geo) or [Patroni](../postgresql/index.md#postgresql-replication-and-failover-with-omnibus-gitlab).
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ As a user, to delete your own account:
|
|||
NOTE:
|
||||
On GitLab.com, there is a seven day delay between a user deleting their own account and deletion of the user record. During this time, that user is [blocked](../../admin_area/moderate_users.md#block-a-user) and a new account with the same email address or username cannot be created.
|
||||
|
||||
Unblocking the account does not undo the deletion because the account will still be in the deletion queue, and there is no quick method to reverse this process.
|
||||
|
||||
## Delete users and user contributions **(FREE SELF)**
|
||||
|
||||
As an administrator, to delete a user account:
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ module API
|
|||
mount ::API::Metadata
|
||||
mount ::API::Metrics::Dashboard::Annotations
|
||||
mount ::API::Metrics::UserStarredDashboards
|
||||
mount ::API::MlModelPackages
|
||||
mount ::API::Namespaces
|
||||
mount ::API::NpmGroupPackages
|
||||
mount ::API::NpmInstancePackages
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
class MlModelPackages < ::API::Base
|
||||
include APIGuard
|
||||
include ::API::Helpers::Authentication
|
||||
|
||||
ML_MODEL_PACKAGES_REQUIREMENTS = {
|
||||
package_name: API::NO_SLASH_URL_PART_REGEX,
|
||||
file_name: API::NO_SLASH_URL_PART_REGEX
|
||||
}.freeze
|
||||
|
||||
ALLOWED_STATUSES = %w[default hidden].freeze
|
||||
|
||||
feature_category :mlops
|
||||
urgency :low
|
||||
|
||||
after_validation do
|
||||
require_packages_enabled!
|
||||
authenticate_non_get!
|
||||
|
||||
not_found! unless can?(current_user, :read_model_registry, user_project)
|
||||
end
|
||||
|
||||
authenticate_with do |accept|
|
||||
accept.token_types(:personal_access_token, :deploy_token, :job_token)
|
||||
.sent_through(:http_token)
|
||||
end
|
||||
|
||||
helpers do
|
||||
include ::API::Helpers::PackagesHelpers
|
||||
include ::API::Helpers::Packages::BasicAuthHelpers
|
||||
|
||||
def project
|
||||
authorized_user_project
|
||||
end
|
||||
|
||||
def max_file_size_exceeded?
|
||||
project.actual_limits.exceeded?(:ml_model_max_file_size, params[:file].size)
|
||||
end
|
||||
end
|
||||
|
||||
params do
|
||||
requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
|
||||
end
|
||||
|
||||
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||
namespace ':id/packages/ml_models' do
|
||||
params do
|
||||
requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.ml_model_name_regex,
|
||||
file_path: true
|
||||
requires :package_version, type: String, desc: 'Package version',
|
||||
regexp: Gitlab::Regex.ml_model_version_regex
|
||||
requires :file_name, type: String, desc: 'Package file name',
|
||||
regexp: Gitlab::Regex.ml_model_file_name_regex, file_path: true
|
||||
optional :status, type: String, values: ALLOWED_STATUSES, desc: 'Package status'
|
||||
end
|
||||
namespace ':package_name/*package_version/:file_name', requirements: ML_MODEL_PACKAGES_REQUIREMENTS do
|
||||
desc 'Workhorse authorize model package file' do
|
||||
detail 'Introduced in GitLab 16.1'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not Found' }
|
||||
]
|
||||
tags %w[ml_model_registry]
|
||||
end
|
||||
put 'authorize' do
|
||||
authorize_workhorse!(subject: project, maximum_size: project.actual_limits.ml_model_max_file_size)
|
||||
end
|
||||
|
||||
desc 'Workhorse upload model package file' do
|
||||
detail 'Introduced in GitLab 16.1'
|
||||
success code: 201
|
||||
failure [
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not Found' }
|
||||
]
|
||||
tags %w[ml_model_registry]
|
||||
end
|
||||
params do
|
||||
requires :file,
|
||||
type: ::API::Validations::Types::WorkhorseFile,
|
||||
desc: 'The package file to be published (generated by Multipart middleware)',
|
||||
documentation: { type: 'file' }
|
||||
end
|
||||
put do
|
||||
authorize_upload!(project)
|
||||
|
||||
bad_request!('File is too large') if max_file_size_exceeded?
|
||||
|
||||
create_package_file_params = declared(params).merge(build: current_authenticated_job)
|
||||
package_file = ::Packages::MlModel::CreatePackageFileService
|
||||
.new(project, current_user, create_package_file_params)
|
||||
.execute
|
||||
|
||||
bad_request!('Package creation failed') unless package_file
|
||||
|
||||
created!
|
||||
rescue ObjectStorage::RemoteStoreError => e
|
||||
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project.id })
|
||||
|
||||
forbidden!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -623,6 +623,18 @@ module Gitlab
|
|||
def x509_subject_key_identifier_regex
|
||||
@x509_subject_key_identifier_regex ||= /\A(?:\h{2}:)*\h{2}\z/.freeze
|
||||
end
|
||||
|
||||
def ml_model_version_regex
|
||||
maven_version_regex
|
||||
end
|
||||
|
||||
def ml_model_name_regex
|
||||
package_name_regex
|
||||
end
|
||||
|
||||
def ml_model_file_name_regex
|
||||
maven_file_name_regex
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -11070,6 +11070,27 @@ msgstr ""
|
|||
msgid "CodeSuggestionsAlert|Get started with Code Suggestions, available for free during the beta period."
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|• Agree to the %{terms_link_start}GitLab Testing Agreement%{link_end}.%{br} • Acknowledge that GitLab will send data from the instance, including personal data, to Google for cloud hosting.%{br} We may also send data to %{ai_docs_link_start}third-party AI providers%{link_end} to provide this feature."
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Code Suggestions"
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Enable Code Suggestion for users of this GitLab instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Enter new personal access token"
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Personal access token"
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Turn on Code Suggestions for this instance. By turning on this feature, you:"
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestionsSM|Your personal access token from GitLab.com. See the %{link_start}documentation%{link_end} for information on creating a personal access token."
|
||||
msgstr ""
|
||||
|
||||
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -54137,6 +54158,9 @@ msgstr ""
|
|||
msgid "is read-only"
|
||||
msgstr ""
|
||||
|
||||
msgid "is required to enable Code Suggestions"
|
||||
msgstr ""
|
||||
|
||||
msgid "is too long (%{current_value}). The maximum size is %{max_size}."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -133,8 +133,8 @@ function disable_sign_ups() {
|
|||
# We use this weird syntax because we need to pass a one-liner ruby command to a Kubernetes container via kubectl.
|
||||
read -r -d '' multiline_ruby_code <<RUBY
|
||||
user = User.find_by_username('root');
|
||||
puts 'Error: Could not find root user. Check that the database was properly seeded'; exit(1) unless user;
|
||||
token = user.personal_access_tokens.create(scopes: [:api], name: 'Token to disable sign-ups');
|
||||
(puts 'Error: Could not find root user. Check that the database was properly seeded'; exit(1)) unless user;
|
||||
token = user.personal_access_tokens.create(scopes: [:api], name: 'Token to disable sign-ups', expires_at: 30.days.from_now);
|
||||
token.set_token('${REVIEW_APPS_ROOT_TOKEN}');
|
||||
begin;
|
||||
token.save!;
|
||||
|
|
|
|||
|
|
@ -31,4 +31,18 @@ RSpec.describe Admin::ApplicationSettings::SettingsHelper do
|
|||
})
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Code Suggestions for Self-Managed instances', feature_category: :code_suggestions do
|
||||
describe '#code_suggestions_token_explanation' do
|
||||
subject { helper.code_suggestions_token_explanation }
|
||||
|
||||
it { is_expected.to include 'https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#create-a-personal-access-token' }
|
||||
end
|
||||
|
||||
describe '#code_suggestions_agreement' do
|
||||
subject { helper.code_suggestions_agreement }
|
||||
|
||||
it { is_expected.to include 'https://about.gitlab.com/handbook/legal/testing-agreement/' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ RSpec.describe Sidebars::Admin::Menus::AbuseReportsMenu, feature_category: :navi
|
|||
it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :abuse_reports }
|
||||
|
||||
describe '#pill_count' do
|
||||
let_it_be(:user) { create(:user, :admin) }
|
||||
let(:user) { build_stubbed(:user, :admin) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Admin::Menus::MonitoringMenu, feature_category: :navigation do
|
||||
let_it_be(:user) { create(:user, :admin) }
|
||||
let(:user) { build_stubbed(:user, :admin) }
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
|
||||
let(:menu) { described_class.new(context) }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'fast_spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Concerns::ContainerWithHtmlOptions do
|
||||
RSpec.describe Sidebars::Concerns::ContainerWithHtmlOptions, feature_category: :navigation do
|
||||
subject do
|
||||
Class.new do
|
||||
include Sidebars::Concerns::ContainerWithHtmlOptions
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'fast_spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Concerns::LinkWithHtmlOptions do
|
||||
RSpec.describe Sidebars::Concerns::LinkWithHtmlOptions, feature_category: :navigation do
|
||||
let(:options) { {} }
|
||||
|
||||
subject { Class.new { include Sidebars::Concerns::LinkWithHtmlOptions }.new }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::Menus::CiCdMenu do
|
||||
RSpec.describe Sidebars::Groups::Menus::CiCdMenu, feature_category: :navigation do
|
||||
let_it_be(:owner) { create(:user) }
|
||||
let_it_be(:root_group) do
|
||||
build(:group, :private).tap do |g|
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::Menus::ObservabilityMenu do
|
||||
let_it_be(:owner) { create(:user) }
|
||||
let_it_be(:root_group) do
|
||||
RSpec.describe Sidebars::Groups::Menus::ObservabilityMenu, feature_category: :navigation do
|
||||
let(:owner) { build_stubbed(:user) }
|
||||
let(:root_group) do
|
||||
build(:group, :private).tap do |g|
|
||||
g.add_owner(owner)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::Menus::SettingsMenu, :with_license do
|
||||
RSpec.describe Sidebars::Groups::Menus::SettingsMenu, :with_license, feature_category: :navigation do
|
||||
let_it_be(:owner) { create(:user) }
|
||||
|
||||
let_it_be_with_refind(:group) do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'fast_spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::MenuItem do
|
||||
RSpec.describe Sidebars::MenuItem, feature_category: :navigation do
|
||||
let(:title) { 'foo' }
|
||||
let(:html_options) { {} }
|
||||
let(:menu_item) { described_class.new(title: title, active_routes: {}, link: '', container_html_options: html_options) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Context do
|
||||
RSpec.describe Sidebars::Projects::Context, feature_category: :navigation do
|
||||
let(:project) { build(:project) }
|
||||
|
||||
subject { described_class.new(current_user: nil, container: project) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::AnalyticsMenu do
|
||||
RSpec.describe Sidebars::Projects::Menus::AnalyticsMenu, feature_category: :navigation do
|
||||
let_it_be_with_refind(:project) { create(:project, :repository) }
|
||||
let_it_be(:guest) do
|
||||
create(:user).tap { |u| project.add_guest(u) }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::CiCdMenu do
|
||||
RSpec.describe Sidebars::Projects::Menus::CiCdMenu, feature_category: :navigation do
|
||||
let(:project) { build(:project) }
|
||||
let(:user) { project.first_owner }
|
||||
let(:can_view_pipeline_editor) { true }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::ConfluenceMenu do
|
||||
RSpec.describe Sidebars::Projects::Menus::ConfluenceMenu, feature_category: :navigation do
|
||||
let_it_be_with_refind(:project) { create(:project, has_external_wiki: true) }
|
||||
|
||||
let(:user) { project.first_owner }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::ExternalIssueTrackerMenu do
|
||||
RSpec.describe Sidebars::Projects::Menus::ExternalIssueTrackerMenu, feature_category: :navigation do
|
||||
let(:project) { build(:project) }
|
||||
let(:user) { project.first_owner }
|
||||
let(:jira_issues_integration_active) { false }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::HiddenMenu do
|
||||
RSpec.describe Sidebars::Projects::Menus::HiddenMenu, feature_category: :navigation do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
let(:user) { project.first_owner }
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ RSpec.describe Sidebars::Projects::Menus::IssuesMenu, feature_category: :navigat
|
|||
context 'when there are open issues' do
|
||||
it 'returns the number of open issues' do
|
||||
create_list(:issue, 2, :opened, project: project)
|
||||
create(:issue, :closed, project: project)
|
||||
build_stubbed(:issue, :closed, project: project)
|
||||
|
||||
expect(subject.pill_count).to eq '2'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::MonitorMenu do
|
||||
RSpec.describe Sidebars::Projects::Menus::MonitorMenu, feature_category: :navigation do
|
||||
let_it_be_with_refind(:project) { create(:project) }
|
||||
|
||||
let(:user) { project.first_owner }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::SettingsMenu do
|
||||
let_it_be(:project) { create(:project) }
|
||||
RSpec.describe Sidebars::Projects::Menus::SettingsMenu, feature_category: :navigation do
|
||||
let(:project) { build_stubbed(:project) }
|
||||
|
||||
let(:user) { project.first_owner }
|
||||
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::Menus::ZentaoMenu do
|
||||
RSpec.describe Sidebars::Projects::Menus::ZentaoMenu, feature_category: :navigation do
|
||||
it_behaves_like 'ZenTao menu with CE version'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Projects::SuperSidebarPanel, feature_category: :navigation do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:project) { build_stubbed(:project, :repository) }
|
||||
|
||||
let(:user) { project.first_owner }
|
||||
let(:context) do
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Search::Panel, feature_category: :navigation do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:current_user) { build_stubbed(:user) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
|
||||
let(:panel) { described_class.new(context) }
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Panel, feature_category: :navigation do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:current_user) { build_stubbed(:user) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserSettings::Panel, feature_category: :navigation do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::YourWork::Menus::IssuesMenu, feature_category: :navigation do
|
||||
let(:user) { create(:user) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
|
||||
|
||||
subject { described_class.new(context) }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::YourWork::Menus::MergeRequestsMenu, feature_category: :navigation do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::YourWork::Menus::TodosMenu, feature_category: :navigation do
|
||||
let(:user) { create(:user) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
|
||||
|
||||
subject { described_class.new(context) }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::YourWork::Panel, feature_category: :navigation do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
|
||||
|
||||
|
|
|
|||
|
|
@ -1650,4 +1650,29 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
|
|||
expect(setting.personal_access_tokens_disabled?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ai_access_token' do
|
||||
context 'when `instance_level_code_suggestions_enabled` is true' do
|
||||
before do
|
||||
setting.instance_level_code_suggestions_enabled = true
|
||||
end
|
||||
|
||||
it { is_expected.not_to allow_value(nil).for(:ai_access_token) }
|
||||
end
|
||||
|
||||
context 'when `instance_level_code_suggestions_enabled` is false' do
|
||||
before do
|
||||
setting.instance_level_code_suggestions_enabled = false
|
||||
end
|
||||
|
||||
it { is_expected.to allow_value(nil).for(:ai_access_token) }
|
||||
end
|
||||
|
||||
it 'does not modify the token if it is unchanged in the form' do
|
||||
setting.ai_access_token = 'foo'
|
||||
setting.ai_access_token = ApplicationSettingMaskedAttrs::MASK
|
||||
|
||||
expect(setting.ai_access_token).to eq('foo')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ::API::MlModelPackages, feature_category: :mlops do
|
||||
include HttpBasicAuthHelpers
|
||||
include PackagesManagerApiSpecHelpers
|
||||
include WorkhorseHelpers
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
include_context 'workhorse headers'
|
||||
|
||||
let_it_be(:project, reload: true) { create(:project) }
|
||||
let_it_be(:personal_access_token) { create(:personal_access_token) }
|
||||
let_it_be(:job) { create(:ci_build, :running, user: personal_access_token.user, project: project) }
|
||||
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
|
||||
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
|
||||
let_it_be(:another_project, reload: true) { create(:project) }
|
||||
|
||||
let_it_be(:tokens) do
|
||||
{
|
||||
personal_access_token: personal_access_token.token,
|
||||
deploy_token: deploy_token.token,
|
||||
job_token: job.token
|
||||
}
|
||||
end
|
||||
|
||||
let(:user) { personal_access_token.user }
|
||||
let(:user_role) { :developer }
|
||||
let(:member) { true }
|
||||
let(:ci_build) { create(:ci_build, :running, user: user, project: project) }
|
||||
let(:project_to_enable_ff) { project }
|
||||
let(:headers) { {} }
|
||||
|
||||
shared_context 'ml model authorize permissions table' do # rubocop:disable RSpec/ContextWording
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
# :visibility, :user_role, :member, :token_type, :valid_token, :expected_status
|
||||
def authorize_permissions_table
|
||||
:public | :developer | true | :personal_access_token | true | :success
|
||||
:public | :guest | true | :personal_access_token | true | :forbidden
|
||||
:public | :developer | true | :personal_access_token | false | :unauthorized
|
||||
:public | :guest | true | :personal_access_token | false | :unauthorized
|
||||
:public | :developer | false | :personal_access_token | true | :forbidden
|
||||
:public | :guest | false | :personal_access_token | true | :forbidden
|
||||
:public | :developer | false | :personal_access_token | false | :unauthorized
|
||||
:public | :guest | false | :personal_access_token | false | :unauthorized
|
||||
:public | :anonymous | false | :personal_access_token | true | :unauthorized
|
||||
:private | :developer | true | :personal_access_token | true | :success
|
||||
:private | :guest | true | :personal_access_token | true | :forbidden
|
||||
:private | :developer | true | :personal_access_token | false | :unauthorized
|
||||
:private | :guest | true | :personal_access_token | false | :unauthorized
|
||||
:private | :developer | false | :personal_access_token | true | :not_found
|
||||
:private | :guest | false | :personal_access_token | true | :not_found
|
||||
:private | :developer | false | :personal_access_token | false | :unauthorized
|
||||
:private | :guest | false | :personal_access_token | false | :unauthorized
|
||||
:private | :anonymous | false | :personal_access_token | true | :unauthorized
|
||||
:public | :developer | true | :job_token | true | :success
|
||||
:public | :guest | true | :job_token | true | :forbidden
|
||||
:public | :developer | true | :job_token | false | :unauthorized
|
||||
:public | :guest | true | :job_token | false | :unauthorized
|
||||
:public | :developer | false | :job_token | true | :forbidden
|
||||
:public | :guest | false | :job_token | true | :forbidden
|
||||
:public | :developer | false | :job_token | false | :unauthorized
|
||||
:public | :guest | false | :job_token | false | :unauthorized
|
||||
:private | :developer | true | :job_token | true | :success
|
||||
:private | :guest | true | :job_token | true | :forbidden
|
||||
:private | :developer | true | :job_token | false | :unauthorized
|
||||
:private | :guest | true | :job_token | false | :unauthorized
|
||||
:private | :developer | false | :job_token | true | :not_found
|
||||
:private | :guest | false | :job_token | true | :not_found
|
||||
:private | :developer | false | :job_token | false | :unauthorized
|
||||
:private | :guest | false | :job_token | false | :unauthorized
|
||||
:public | :developer | true | :deploy_token | true | :success
|
||||
:public | :developer | true | :deploy_token | false | :unauthorized
|
||||
:private | :developer | true | :deploy_token | true | :success
|
||||
:private | :developer | true | :deploy_token | false | :unauthorized
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
end
|
||||
|
||||
before do
|
||||
project.send("add_#{user_role}", user) if member && user_role != :anonymous
|
||||
end
|
||||
|
||||
subject(:api_response) do
|
||||
request
|
||||
response
|
||||
end
|
||||
|
||||
describe 'PUT /api/v4/projects/:id/packages/ml_models/:package_name/:package_version/:file_name/authorize' do
|
||||
include_context 'ml model authorize permissions table'
|
||||
|
||||
let(:token) { tokens[:personal_access_token] }
|
||||
let(:user_headers) { { 'HTTP_AUTHORIZATION' => token } }
|
||||
let(:headers) { user_headers.merge(workhorse_headers) }
|
||||
let(:request) { authorize_upload_file(headers) }
|
||||
|
||||
describe 'user access' do
|
||||
where(:visibility, :user_role, :member, :token_type, :valid_token, :expected_status) do
|
||||
authorize_permissions_table
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:token) { valid_token ? tokens[token_type] : 'invalid-token123' }
|
||||
let(:user_headers) { user_role == :anonymous ? {} : { 'HTTP_AUTHORIZATION' => token } }
|
||||
|
||||
before do
|
||||
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility.to_s))
|
||||
end
|
||||
|
||||
it { is_expected.to have_gitlab_http_status(expected_status) }
|
||||
end
|
||||
|
||||
it_behaves_like 'Endpoint not found if read_model_registry not available'
|
||||
end
|
||||
|
||||
describe 'application security' do
|
||||
where(:param_name, :param_value) do
|
||||
:package_name | 'my-package/../'
|
||||
:package_name | 'my-package%2f%2e%2e%2f'
|
||||
:file_name | '../.ssh%2fauthorized_keys'
|
||||
:file_name | '%2e%2e%2f.ssh%2fauthorized_keys'
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:request) { authorize_upload_file(headers, param_name => param_value) }
|
||||
|
||||
it 'rejects malicious request' do
|
||||
is_expected.to have_gitlab_http_status(:bad_request)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v4/projects/:id/packages/ml_models/:package_name/:package_version/:file_name' do
|
||||
include_context 'ml model authorize permissions table'
|
||||
|
||||
let_it_be(:file_name) { 'model.md5' }
|
||||
|
||||
let(:token) { tokens[:personal_access_token] }
|
||||
let(:user_headers) { { 'HTTP_AUTHORIZATION' => token } }
|
||||
let(:headers) { user_headers.merge(workhorse_headers) }
|
||||
let(:params) { { file: temp_file(file_name) } }
|
||||
let(:file_key) { :file }
|
||||
let(:send_rewritten_field) { true }
|
||||
|
||||
let(:request) do
|
||||
upload_file(headers)
|
||||
end
|
||||
|
||||
describe 'success' do
|
||||
it 'creates a new package' do
|
||||
expect { api_response }.to change { Packages::PackageFile.count }.by(1)
|
||||
expect(api_response).to have_gitlab_http_status(:created)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'user access' do
|
||||
where(:visibility, :user_role, :member, :token_type, :valid_token, :expected_status) do
|
||||
authorize_permissions_table
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:token) { valid_token ? tokens[token_type] : 'invalid-token123' }
|
||||
let(:user_headers) { user_role == :anonymous ? {} : { 'HTTP_AUTHORIZATION' => token } }
|
||||
|
||||
before do
|
||||
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility.to_s))
|
||||
end
|
||||
|
||||
if params[:expected_status] == :success
|
||||
it_behaves_like 'process ml model package upload'
|
||||
else
|
||||
it { is_expected.to have_gitlab_http_status(expected_status) }
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'Endpoint not found if read_model_registry not available'
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_upload_file(request_headers, package_name: 'mypackage', file_name: 'myfile.tar.gz')
|
||||
url = "/projects/#{project.id}/packages/ml_models/#{package_name}/0.0.1/#{file_name}/authorize"
|
||||
|
||||
put api(url), headers: request_headers
|
||||
end
|
||||
|
||||
def upload_file(request_headers, package_name: 'mypackage')
|
||||
url = "/projects/#{project.id}/packages/ml_models/#{package_name}/0.0.1/#{file_name}"
|
||||
|
||||
workhorse_finalize(
|
||||
api(url),
|
||||
method: :put,
|
||||
file_key: file_key,
|
||||
params: params,
|
||||
headers: request_headers,
|
||||
send_rewritten_field: send_rewritten_field
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -40,6 +40,37 @@ RSpec.describe MergeRequests::Mergeability::Logger, :request_store, feature_cate
|
|||
logger.commit
|
||||
end
|
||||
|
||||
context 'when block value responds to #success?' do
|
||||
let(:success?) { true }
|
||||
let(:check_result) { instance_double(Gitlab::MergeRequests::Mergeability::CheckResult, success?: success?) }
|
||||
|
||||
let(:extra_data) do
|
||||
{
|
||||
'mergeability.expensive_operation.successful.values' => [success?]
|
||||
}
|
||||
end
|
||||
|
||||
shared_examples_for 'success state logger' do
|
||||
it 'records operation success state' do
|
||||
expect_next_instance_of(Gitlab::AppJsonLogger) do |app_logger|
|
||||
expect(app_logger).to receive(:info).with(match(a_hash_including(loggable_data(**extra_data))))
|
||||
end
|
||||
|
||||
expect(logger.instrument(mergeability_name: :expensive_operation) { check_result }).to eq(check_result)
|
||||
|
||||
logger.commit
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'success state logger'
|
||||
|
||||
context 'when not successful' do
|
||||
let(:success?) { false }
|
||||
|
||||
it_behaves_like 'success state logger'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple observations' do
|
||||
let(:operation_count) { 2 }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'Endpoint not found if read_model_registry not available' do
|
||||
context 'when read_model_registry disabled for current project' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).and_call_original
|
||||
allow(Ability).to receive(:allowed?)
|
||||
.with(user, :read_model_registry, project)
|
||||
.and_return(false)
|
||||
end
|
||||
|
||||
it "is not found" do
|
||||
is_expected.to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'creates model experiments package files' do
|
||||
it 'creates package files', :aggregate_failures do
|
||||
expect { api_response }
|
||||
.to change { project.packages.count }.by(1)
|
||||
.and change { Packages::PackageFile.count }.by(1)
|
||||
expect(api_response).to have_gitlab_http_status(:created)
|
||||
|
||||
package_file = project.packages.last.package_files.reload.last
|
||||
expect(package_file.file_name).to eq(file_name)
|
||||
end
|
||||
|
||||
it 'returns bad request if package creation fails' do
|
||||
allow_next_instance_of(::Packages::MlModel::CreatePackageFileService) do |instance|
|
||||
expect(instance).to receive(:execute).and_return(nil)
|
||||
end
|
||||
|
||||
expect(api_response).to have_gitlab_http_status(:bad_request)
|
||||
end
|
||||
|
||||
context 'when file is too large' do
|
||||
it 'is bad request', :aggregate_failures do
|
||||
allow_next_instance_of(UploadedFile) do |uploaded_file|
|
||||
allow(uploaded_file).to receive(:size).and_return(project.actual_limits.ml_model_max_file_size + 1)
|
||||
end
|
||||
|
||||
expect(api_response).to have_gitlab_http_status(:bad_request)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'process ml model package upload' do
|
||||
context 'with object storage disabled' do
|
||||
before do
|
||||
stub_package_file_object_storage(enabled: false)
|
||||
end
|
||||
|
||||
context 'without a file from workhorse' do
|
||||
let(:send_rewritten_field) { false }
|
||||
|
||||
it_behaves_like 'returning response status', :bad_request
|
||||
end
|
||||
|
||||
context 'with correct params' do
|
||||
it_behaves_like 'package workhorse uploads'
|
||||
it_behaves_like 'creates model experiments package files'
|
||||
# To be reactivated with https://gitlab.com/gitlab-org/gitlab/-/issues/414270
|
||||
# it_behaves_like 'a package tracking event', '::API::MlModelPackages', 'push_package'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with object storage enabled' do
|
||||
let(:tmp_object) do
|
||||
fog_connection.directories.new(key: 'packages').files.create( # rubocop:disable Rails/SaveBang
|
||||
key: "tmp/uploads/#{file_name}",
|
||||
body: 'content'
|
||||
)
|
||||
end
|
||||
|
||||
let(:fog_file) { fog_to_uploaded_file(tmp_object) }
|
||||
let(:params) { { file: fog_file, 'file.remote_id' => file_name } }
|
||||
|
||||
context 'and direct upload enabled' do
|
||||
let(:fog_connection) do
|
||||
stub_package_file_object_storage(direct_upload: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'creates model experiments package files'
|
||||
|
||||
['123123', '../../123123'].each do |remote_id|
|
||||
context "with invalid remote_id: #{remote_id}" do
|
||||
let(:params) do
|
||||
{
|
||||
file: fog_file,
|
||||
'file.remote_id' => remote_id
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to have_gitlab_http_status(:forbidden) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'and direct upload disabled' do
|
||||
let(:fog_connection) do
|
||||
stub_package_file_object_storage(direct_upload: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'creates model experiments package files'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'admin/application_settings/_ai_access.html.haml', feature_category: :code_suggestions do
|
||||
let_it_be(:admin) { build_stubbed(:admin) }
|
||||
let(:page) { Capybara::Node::Simple.new(rendered) }
|
||||
|
||||
before do
|
||||
allow(::Gitlab).to receive(:org_or_com?).and_return(false) # Will not render partial for .com or .org
|
||||
assign(:application_setting, application_setting)
|
||||
allow(view).to receive(:current_user) { admin }
|
||||
allow(view).to receive(:expanded).and_return(true)
|
||||
end
|
||||
|
||||
context 'when ai_access_token is not set' do
|
||||
let(:application_setting) { build(:application_setting) }
|
||||
|
||||
it 'renders an empty password field' do
|
||||
render
|
||||
expect(rendered).to have_field('Personal access token', type: 'password')
|
||||
expect(page.find_field('Personal access token').value).to be_blank
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ai_access_token is set' do
|
||||
let(:application_setting) do
|
||||
build(:application_setting, ai_access_token: 'ai_access_token',
|
||||
instance_level_code_suggestions_enabled: true)
|
||||
end
|
||||
|
||||
it 'renders masked password field' do
|
||||
render
|
||||
expect(rendered).to have_field('Enter new personal access token', type: 'password')
|
||||
expect(page.find_field('Enter new personal access token').value).to eq(ApplicationSettingMaskedAttrs::MASK)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -110,4 +110,30 @@ RSpec.describe 'admin/application_settings/general.html.haml' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'instance-level code suggestions settings', feature_category: :code_suggestions do
|
||||
before do
|
||||
allow(::Gitlab).to receive(:org_or_com?).and_return(gitlab_org_or_com?)
|
||||
|
||||
render
|
||||
end
|
||||
|
||||
context 'when on .com or .org' do
|
||||
let(:gitlab_org_or_com?) { true }
|
||||
|
||||
it 'does not render the form' do
|
||||
expect(rendered).not_to have_field('application_setting_instance_level_code_suggestions_enabled')
|
||||
expect(rendered).not_to have_field('application_setting_ai_access_token')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not on .com and not on .org' do
|
||||
let(:gitlab_org_or_com?) { false }
|
||||
|
||||
it 'renders the form' do
|
||||
expect(rendered).to have_field('application_setting_instance_level_code_suggestions_enabled')
|
||||
expect(rendered).to have_field('application_setting_ai_access_token')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -279,6 +279,9 @@ func configureRoutes(u *upstream) {
|
|||
// Generic Packages Repository
|
||||
u.route("PUT", apiProjectPattern+`/packages/generic/`, requestBodyUploader),
|
||||
|
||||
// Ml Model Packages Repository
|
||||
u.route("PUT", apiProjectPattern+`/packages/ml_models/`, requestBodyUploader),
|
||||
|
||||
// NuGet Artifact Repository
|
||||
u.route("PUT", apiProjectPattern+`/packages/nuget/`, mimeMultipartUploader),
|
||||
|
||||
|
|
|
|||
|
|
@ -580,6 +580,7 @@ func TestPackageFilesUpload(t *testing.T) {
|
|||
{"PUT", "/api/v4/projects/group%2Fproject/packages/conan/v1/files"},
|
||||
{"PUT", "/api/v4/projects/group%2Fproject/packages/maven/v1/files"},
|
||||
{"PUT", "/api/v4/projects/group%2Fproject/packages/generic/mypackage/0.0.1/myfile.tar.gz"},
|
||||
{"PUT", "/api/v4/projects/group%2Fproject/packages/ml_models/mymodel/0.0.1/myfile.tar.gz"},
|
||||
{"PUT", "/api/v4/projects/group%2Fproject/packages/debian/libsample0_1.2.3~alpha2-1_amd64.deb"},
|
||||
{"POST", "/api/v4/projects/group%2Fproject/packages/rubygems/api/v1/gems/sample.gem"},
|
||||
{"POST", "/api/v4/projects/group%2Fproject/packages/rpm/sample-4.23.fc21.x86_64.rpm"},
|
||||
|
|
|
|||
Loading…
Reference in New Issue