Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-12-20 18:11:16 +00:00
parent 78f02b73cf
commit 054c9f71bc
87 changed files with 640 additions and 374 deletions

View File

@ -1040,6 +1040,7 @@ RSpec/ContextWording:
- 'spec/features/admin/admin_mode_spec.rb'
- 'spec/features/admin/admin_settings_spec.rb'
- 'spec/features/admin/dashboard_spec.rb'
- 'spec/features/admin/users/user_impersonation_spec.rb'
- 'spec/features/admin/users/user_spec.rb'
- 'spec/features/admin/users/users_spec.rb'
- 'spec/features/atom/dashboard_issues_spec.rb'

View File

@ -1414,6 +1414,7 @@ RSpec/NamedSubject:
- 'spec/controllers/users/callouts_controller_spec.rb'
- 'spec/experiments/application_experiment_spec.rb'
- 'spec/experiments/in_product_guidance_environments_webide_experiment_spec.rb'
- 'spec/features/admin/users/user_impersonation_spec.rb'
- 'spec/features/admin/users/user_spec.rb'
- 'spec/features/groups/clusters/user_spec.rb'
- 'spec/features/merge_request/user_sees_merge_widget_spec.rb'

View File

@ -14,6 +14,9 @@ export default function initProjectPermissionsSettings() {
const mountPoint = document.querySelector('.js-project-permissions-form');
const componentPropsEl = document.querySelector('.js-project-permissions-form-data');
if (!mountPoint) return null;
const componentProps = JSON.parse(componentPropsEl.innerHTML);
const {

View File

@ -5,6 +5,8 @@ import store from '~/badges/store';
export default (kind) => {
const badgeSettingsElement = document.getElementById('badge-settings');
if (!badgeSettingsElement) return null;
store.dispatch('loadBadges', {
kind,
apiEndpointUrl: badgeSettingsElement.dataset.apiEndpointUrl,

View File

@ -29,7 +29,7 @@ class ProjectsController < Projects::ApplicationController
before_action :authorize_read_code!, only: [:refs]
# Authorize
before_action :authorize_admin_project_or_custom_permissions!, only: :edit
before_action :authorize_view_edit_page!, only: :edit
before_action :authorize_admin_project!, only: [:update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export]
before_action :authorize_archive_project!, only: [:archive, :unarchive]
before_action :event_filter, only: [:show, :activity]
@ -612,11 +612,6 @@ class ProjectsController < Projects::ApplicationController
def render_edit
render 'edit'
end
# Overridden in EE
def authorize_admin_project_or_custom_permissions!
authorize_admin_project!
end
end
ProjectsController.prepend_mod_with('ProjectsController')

View File

@ -7,6 +7,7 @@ class NamespaceSetting < ApplicationRecord
cascading_attr :delayed_project_removal
cascading_attr :toggle_security_policy_custom_ci
cascading_attr :toggle_security_policies_policy_scope
belongs_to :namespace, inverse_of: :namespace_settings

View File

@ -914,6 +914,7 @@ class ProjectPolicy < BasePolicy
rule { can?(:admin_project) }.policy do
enable :read_usage_quotas
enable :view_edit_page
end
rule { can?(:project_bot_access) }.policy do

View File

@ -49,6 +49,7 @@
= render_if_exists 'groups/personal_access_token_expiration_policy', f: f, group: @group
= render 'groups/settings/membership', f: f, group: @group
= render_if_exists 'groups/settings/security_policies_custom_ci', f: f, group: @group
= render_if_exists 'groups/settings/security_policies_policy_scope', f: f, group: @group
%h5= _('Customer relations')
.form-group.gl-mb-3

View File

@ -118,8 +118,11 @@
= render 'remove_fork', project: @project
= render 'remove', project: @project
- elsif can?(current_user, :archive_project, @project)
= render_if_exists 'projects/settings/archive'
- else
- if can?(current_user, :archive_project, @project)
= render_if_exists 'projects/settings/archive'
- if can?(current_user, :remove_project, @project)
= render 'remove', project: @project
.save-project-loader.hide
.center

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
class AddRemoveProjectToMemberRoles < Gitlab::Database::Migration[2.2]
milestone '16.8'
enable_lock_retries!
def change
add_column :member_roles, :remove_project, :boolean, default: false, null: false
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddCascadingToggleSecurityPoliciesPolicyScopeSetting < Gitlab::Database::Migration[2.2]
milestone '16.7'
include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
enable_lock_retries!
def up
add_cascading_namespace_setting :toggle_security_policies_policy_scope, :boolean, default: false, null: false
end
def down
remove_cascading_namespace_setting :toggle_security_policies_policy_scope
end
end

View File

@ -0,0 +1 @@
f73fde4e3e54fa88d8dba9ec3a98b7dfb8332aaf7a76de73baf899292ed751b1

View File

@ -0,0 +1 @@
7bdc5d7aa9f9228aac355e51b1461b7d07083e8e5481ccf3e59c5ec48c9230ab

View File

@ -12284,6 +12284,8 @@ CREATE TABLE application_settings (
encrypted_arkose_labs_data_exchange_key_iv bytea,
toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
lock_toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
toggle_security_policies_policy_scope boolean DEFAULT false NOT NULL,
lock_toggle_security_policies_policy_scope boolean DEFAULT false NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
@ -18640,6 +18642,7 @@ CREATE TABLE member_roles (
admin_group_member boolean DEFAULT false NOT NULL,
manage_project_access_tokens boolean DEFAULT false NOT NULL,
archive_project boolean DEFAULT false NOT NULL,
remove_project boolean DEFAULT false NOT NULL,
CONSTRAINT check_4364846f58 CHECK ((char_length(description) <= 255)),
CONSTRAINT check_9907916995 CHECK ((char_length(name) <= 255))
);
@ -19592,6 +19595,8 @@ CREATE TABLE namespace_settings (
enforce_ssh_certificates boolean DEFAULT false NOT NULL,
toggle_security_policy_custom_ci boolean,
lock_toggle_security_policy_custom_ci boolean DEFAULT false NOT NULL,
toggle_security_policies_policy_scope boolean,
lock_toggle_security_policies_policy_scope boolean DEFAULT false NOT NULL,
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)),
CONSTRAINT namespace_settings_unique_project_download_limit_alertlist_size CHECK ((cardinality(unique_project_download_limit_alertlist) <= 100)),
CONSTRAINT namespace_settings_unique_project_download_limit_allowlist_size CHECK ((cardinality(unique_project_download_limit_allowlist) <= 100))

View File

@ -5362,6 +5362,7 @@ Input type: `MemberRoleCreateInput`
| <a id="mutationmemberrolecreatereadcode"></a>`readCode` | [`Boolean`](#boolean) | Permission to read code. |
| <a id="mutationmemberrolecreatereaddependency"></a>`readDependency` | [`Boolean`](#boolean) | Permission to read dependency. |
| <a id="mutationmemberrolecreatereadvulnerability"></a>`readVulnerability` | [`Boolean`](#boolean) | Permission to read vulnerability. |
| <a id="mutationmemberrolecreateremoveproject"></a>`removeProject` | [`Boolean`](#boolean) | Permission to delete projects. |
#### Fields
@ -21408,6 +21409,7 @@ Represents a member role.
| <a id="memberrolereadcode"></a>`readCode` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in 16.5. This feature is an Experiment. It can be changed or removed at any time. Permission to read code. |
| <a id="memberrolereaddependency"></a>`readDependency` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in 16.5. This feature is an Experiment. It can be changed or removed at any time. Permission to read dependency. |
| <a id="memberrolereadvulnerability"></a>`readVulnerability` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in 16.5. This feature is an Experiment. It can be changed or removed at any time. Permission to read vulnerability. |
| <a id="memberroleremoveproject"></a>`removeProject` **{warning-solid}** | [`Boolean`](#boolean) | **Introduced** in 16.8. This feature is an Experiment. It can be changed or removed at any time. Permission to delete projects. |
### `MergeAccessLevel`
@ -30753,6 +30755,7 @@ Member role permission.
| <a id="memberrolepermissionread_code"></a>`READ_CODE` | Allows read-only access to the source code. |
| <a id="memberrolepermissionread_dependency"></a>`READ_DEPENDENCY` | Allows read-only access to the dependencies. |
| <a id="memberrolepermissionread_vulnerability"></a>`READ_VULNERABILITY` | Allows read-only access to the vulnerability reports. |
| <a id="memberrolepermissionremove_project"></a>`REMOVE_PROJECT` | Allows deletion of projects. |
### `MemberSort`

View File

@ -17,6 +17,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Admin group members introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131914) in GitLab 16.5 [with a flag](../administration/feature_flags.md) named `admin_group_member`. Disabled by default. The feature flag has been removed in GitLab 16.6.
> - [Manage project access tokens introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132342) in GitLab 16.5 in [with a flag](../administration/feature_flags.md) named `manage_project_access_tokens`. Disabled by default.
> - [Archive project introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134998) in GitLab 16.7.
> - [Delete project introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139696) in GitLab 16.8.
FLAG:
On self-managed GitLab, by default these features are not available. To make them available, an administrator can [enable the feature flags](../administration/feature_flags.md) named `admin_group_member` and `manage_project_access_tokens`.
@ -51,6 +52,7 @@ If successful, returns [`200`](rest/index.md#status-codes) and the following res
| `[].admin_group_member` | boolean | Permission to admin members of a group. |
| `[].manage_project_access_tokens` | boolean | Permission to manage project access tokens. |
| `[].archive_project` | boolean | Permission to archive projects. |
| `[].remove_project` | boolean | Permission to delete projects. |
Example request:
@ -74,7 +76,8 @@ Example response:
"read_dependency": false,
"read_vulnerability": false,
"manage_project_access_tokens": false,
"archive_project": false
"archive_project": false,
"remove_project": false
},
{
"id": 3,
@ -88,7 +91,8 @@ Example response:
"read_dependency": true,
"read_vulnerability": true,
"manage_project_access_tokens": false,
"archive_project": false
"archive_project": false,
"remove_project": false
}
]
```

View File

@ -492,6 +492,7 @@ command line.
To configure markdownlint in your editor, install one of the following as appropriate:
- Visual Studio Code [`DavidAnson.vscode-markdownlint` extension](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint).
- Sublime Text [`SublimeLinter-contrib-markdownlint` package](https://packagecontrol.io/packages/SublimeLinter-contrib-markdownlint).
This package uses `markdownlint-cli` by default, but can be configured to use `markdownlint-cli2` with this
SublimeLinter configuration:
@ -502,11 +503,20 @@ To configure markdownlint in your editor, install one of the following as approp
}
```
- Visual Studio Code [`DavidAnson.vscode-markdownlint` extension](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint).
- Vim [ALE plugin](https://github.com/dense-analysis/ale).
- Emacs [Flycheck extension](https://github.com/flycheck/flycheck). `Flycheck` supports
`markdownlint-cli` out of the box, but you must add a `.dir-locals.el` file to
point it to the `.markdownlint.yml` at the base of the project directory:
```lisp
;; Place this code in a file called `.dir-locals.el` at the root of the gitlab project.
((markdown-mode . ((flycheck-markdown-markdownlint-cli-config . ".markdownlint.yml"))))
```
To configure Vale in your editor, install one of the following as appropriate:
- Visual Studio Code [`ChrisChinchilla.vale-vscode` extension](https://marketplace.visualstudio.com/items?itemName=ChrisChinchilla.vale-vscode).
You can configure the plugin to [display only a subset of alerts](#show-subset-of-vale-alerts).
- Sublime Text [`SublimeLinter-vale` package](https://packagecontrol.io/packages/SublimeLinter-vale). To have Vale
suggestions appears as blue instead of red (which is how errors appear), add `vale` configuration to your
[SublimeLinter](http://sublimelinter.readthedocs.org) configuration:
@ -522,26 +532,12 @@ To configure Vale in your editor, install one of the following as appropriate:
```
- [LSP for Sublime Text](https://lsp.sublimetext.io) package [`LSP-vale-ls`](https://packagecontrol.io/packages/LSP-vale-ls).
- Visual Studio Code [`ChrisChinchilla.vale-vscode` extension](https://marketplace.visualstudio.com/items?itemName=ChrisChinchilla.vale-vscode).
You can configure the plugin to [display only a subset of alerts](#show-subset-of-vale-alerts).
- Vim [ALE plugin](https://github.com/dense-analysis/ale).
- JetBrains IDEs - No plugin exists, but
[this issue comment](https://github.com/errata-ai/vale-server/issues/39#issuecomment-751714451)
contains tips for configuring an external tool.
- Emacs [Flycheck extension](https://github.com/flycheck/flycheck).
This requires some configuration:
- `Flycheck` supports `markdownlint-cli` out of the box, but you must point it
to the `.markdownlint.yml` at the base of the project directory. A `.dir-locals.el`
file can accomplish this:
```lisp
;; Place this code in a file called `.dir-locals.el` at the root of the gitlab project.
((markdown-mode . ((flycheck-markdown-markdownlint-cli-config . ".markdownlint.yml"))))
```
- A minimal configuration for Flycheck to work with Vale could look like this:
- Emacs [Flycheck extension](https://github.com/flycheck/flycheck). A minimal configuration
for Flycheck to work with Vale could look like:
```lisp
(flycheck-define-checker vale

View File

@ -272,10 +272,10 @@ Changing the linked namespace is not supported for all subscription types.
You cannot transfer:
- A subscription with compute minutes.
- An expired or trial subscription.
- A subscription to a namespace which already has a Premium or Ultimate plan.
- A subscription from a namespace with multiple subscriptions.
- A subscription with compute minutes which is already linked to a namespace.
- A subscription with a Premium or Ultimate plan to a namespace which already has a Premium or Ultimate plan.
- A subscription with code suggestions to a namespace which already has a subscriptions with code suggestions.
## Upgrade your GitLab SaaS subscription tier

View File

@ -17,6 +17,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Ability to manage project access tokens [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/421778) in GitLab 16.5 [with a flag](../administration/feature_flags.md) named `manage_project_access_tokens`.
> - Ability to archive projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/425957) in GitLab 16.7.
> - Ability to use the UI to add a user to your group with a custom role, change a user's custom role, or remove a custom role from a group member [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393239) in GitLab 16.7.
> - Ability to delete projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/425959) in GitLab 16.8.
Custom roles allow group Owners or instance administrators to create roles
specific to the needs of their organization.
@ -114,7 +115,8 @@ These requirements are documented in the `Required permission` column in the fol
| `admin_merge_request` | GitLab 16.4 and later | Not applicable | View and approve [merge requests](project/merge_requests/index.md), revoke merge request approval, and view the associated merge request code. <br> Does not allow users to view or change merge request approval rules. |
| `manage_project_access_tokens` | GitLab 16.5 and later | Not applicable | Create, delete, and list [project access tokens](project/settings/project_access_tokens.md). |
| `admin_group_member` | GitLab 16.5 and later | Not applicable | Add or remove [group members](group/manage.md). |
| `archive_project` | GitLab 16.6 and later | Not applicable | Archive and unarchive [projects](project/settings/migrate_projects.md#archive-a-project). |
| `archive_project` | GitLab 16.7 and later | Not applicable | [Archive and unarchive projects](project/settings/migrate_projects.md#archive-a-project). |
| `remove_project` | GitLab 16.8 and later | Not applicable | [Delete projects](project/working_with_projects.md#delete-a-project). |
## Billing and seat usage

View File

@ -6,6 +6,7 @@ module Gitlab
include ForeignKeyHelpers
include TableManagementHelpers
include IndexHelpers
include UniquenessHelpers
end
end
end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
module Gitlab
module Database
module PartitioningMigrationHelpers
module UniquenessHelpers
include Gitlab::Database::MigrationHelpers
include Gitlab::Database::SchemaHelpers
def ensure_unique_id(table_name)
function_name = "assign_#{table_name}_id_value"
trigger_name = "assign_#{table_name}_id_trigger"
return if trigger_exists?(table_name, trigger_name)
change_column_default(table_name, :id, nil)
create_trigger_function(function_name) do
<<~SQL
IF NEW."id" IS NOT NULL THEN
RAISE WARNING 'Manually assigning ids is not allowed, the value will be ignored';
END IF;
NEW."id" := nextval('#{existing_sequence(table_name)}'::regclass);
RETURN NEW;
SQL
end
create_trigger(table_name, trigger_name, function_name, fires: 'BEFORE INSERT')
end
private
def existing_sequence(table_name)
Gitlab::Database::PostgresSequence.by_table_name(table_name).first
end
end
end
end
end

View File

@ -23543,6 +23543,9 @@ msgstr ""
msgid "GroupSettings|Security policy custom CI Experiment"
msgstr ""
msgid "GroupSettings|Security policy scope Experiment"
msgstr ""
msgid "GroupSettings|Select a subgroup to use as a source of custom templates for new projects in this group. %{link_start}Learn more%{link_end}."
msgstr ""
@ -41613,6 +41616,9 @@ msgstr ""
msgid "Runners|Existing runners are not affected. To permit runner registration for all projects, enable this setting in the Admin Area in Settings &gt; CI/CD."
msgstr ""
msgid "Runners|Export as CSV"
msgstr ""
msgid "Runners|Failed adding runner to project"
msgstr ""
@ -41887,6 +41893,9 @@ msgstr ""
msgid "Runners|Runner Registration token"
msgstr ""
msgid "Runners|Runner Usage"
msgstr ""
msgid "Runners|Runner assigned to project."
msgstr ""
@ -42245,9 +42254,24 @@ msgstr ""
msgid "Runners|shared"
msgstr ""
msgid "Runner|Export runner usage"
msgstr ""
msgid "Runner|Export runner usage for previous month"
msgstr ""
msgid "Runner|Runner actions"
msgstr ""
msgid "Runner|Something went wrong while generating the CSV export. Please try again."
msgstr ""
msgid "Runner|The CSV export contains a list of projects, the number of minutes used by instance runners, and the number of jobs that ran in the previous month. When the export is completed, it is sent as an attachment to your email."
msgstr ""
msgid "Runner|Your CSV export has started. It will be sent to your email inbox when its ready."
msgstr ""
msgid "Running"
msgstr ""
@ -45352,9 +45376,15 @@ msgstr ""
msgid "Settings|Enable this feature allows you to add customized CI YAML file to run as part of the policies action. This features is your acceptance of the %{link_start}GitLab Testing Agreement%{link_end}."
msgstr ""
msgid "Settings|Enabling this feature allows you to scope scan result policies and scan execution policies, which determines which projects specifically will be enforced by a given policy. This features is your acceptance of the %{link_start}GitLab Testing Agreement%{link_end}."
msgstr ""
msgid "Settings|Run customized CI YAML file as security policy actions"
msgstr ""
msgid "Settings|Security Policy Scopes"
msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""

View File

@ -59,7 +59,7 @@
"@gitlab/cluster-client": "^2.1.0",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.3.0",
"@gitlab/svgs": "3.72.0",
"@gitlab/svgs": "3.74.0",
"@gitlab/ui": "^72.0.0",
"@gitlab/visual-review-tools": "1.7.3",
"@gitlab/web-ide": "^0.0.1-dev-20231211152737",

View File

@ -9,7 +9,7 @@ module QA
Flow::Login.sign_in
end
it 'can be reverted', :can_use_large_setup, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347709' do
it 'can be reverted', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347709' do
revertible_merge_request.visit!
Page::MergeRequest::Show.perform do |merge_request|

View File

@ -6,7 +6,7 @@ module QA
it 'pushes to a project using a canary specific Gitaly repository storage', :smoke, :requires_admin, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/351116' do
Flow::Login.sign_in_as_admin
project = create(:project, name: 'canary-specific-repository-storage', repository_storage: 'nfs-file-cny01') # TODO: move to ENV var
project = create(:project, name: 'canary-specific-repository-storage', repository_storage: 'gitaly-cny-01-stor-gstg.c.gitlab-staging-1.internal') # TODO: move to ENV var
Resource::Repository::Push.fabricate! do |push|
push.repository_http_uri = project.repository_http_location.uri

View File

@ -308,7 +308,7 @@ if $PROGRAM_NAME == __FILE__
puts
timed('Review Apps cleanup') do
automated_cleanup.perform_gitlab_environment_cleanup!(days_for_delete: 3)
automated_cleanup.perform_gitlab_environment_cleanup!(days_for_delete: 7)
end
puts

View File

@ -17,7 +17,7 @@ RSpec.describe "Admin::AbuseReports", :js, feature_category: :insider_threat do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_abuse_reports_path
end

View File

@ -12,7 +12,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'create new appearance' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
fill_in 'appearance_title', with: 'MyCompany'
@ -39,7 +39,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'preview sign-in page appearance' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
click_link "Sign-in page"
@ -53,7 +53,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'preview new project page appearance', :js do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
click_link "New project page"
@ -64,7 +64,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
context 'Custom system header and footer' do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
context 'when system header and footer messages are empty' do
@ -102,7 +102,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'custom new project page', :js do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit new_project_path
click_link 'Create blank project'
@ -112,7 +112,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
context 'Profile page with custom profile image guidelines' do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
fill_in 'appearance_profile_image_guidelines', with: 'Custom profile image guidelines, please :smile:!'
click_button 'Update appearance settings'
@ -128,7 +128,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'appearance logo' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
attach_file(:appearance_logo, logo_fixture)
@ -141,7 +141,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'appearance pwa icon' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
attach_file(:appearance_pwa_icon, logo_fixture)
@ -154,7 +154,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'header logos' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
attach_file(:appearance_header_logo, logo_fixture)
@ -167,7 +167,7 @@ RSpec.describe 'Admin Appearance', feature_category: :shared do
it 'Favicon' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_application_settings_appearances_path
attach_file(:appearance_favicon, logo_fixture)

View File

@ -8,7 +8,7 @@ RSpec.describe 'Admin browse spam logs', feature_category: :shared do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
it 'browse spam logs' do

View File

@ -12,7 +12,7 @@ RSpec.describe 'admin deploy keys', :js, feature_category: :system_access do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
it 'show all public deploy keys' do

View File

@ -6,7 +6,7 @@ RSpec.describe 'DevOps Report page', :js, feature_category: :devops_reports do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
context 'without licensed feature devops adoption' do

View File

@ -12,7 +12,7 @@ RSpec.describe 'Admin disables Git access protocol', :js, feature_category: :sou
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
context 'with HTTP disabled' do

View File

@ -8,7 +8,7 @@ RSpec.describe 'Admin disables 2FA for a user', feature_category: :system_access
it 'successfully', :js do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
user = create(:user, :two_factor)
edit_user(user)
@ -27,7 +27,7 @@ RSpec.describe 'Admin disables 2FA for a user', feature_category: :system_access
it 'for a user without 2FA enabled' do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
user = create(:user)
edit_user(user)

View File

@ -15,7 +15,7 @@ RSpec.describe 'Admin Groups', feature_category: :groups_and_projects do
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user)
enable_admin_mode!(current_user)
stub_application_setting(default_group_visibility: internal)
end

View File

@ -10,7 +10,7 @@ RSpec.describe "Admin Health Check", :js, feature_category: :error_budgets do
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
describe '#show' do

View File

@ -9,7 +9,7 @@ RSpec.describe 'Admin::HookLogs', feature_category: :webhooks do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
it 'show list of hook logs' do

View File

@ -9,7 +9,7 @@ RSpec.describe 'Admin::Hooks', feature_category: :webhooks do
before do
sign_in(user)
gitlab_enable_admin_mode_sign_in(user)
enable_admin_mode!(user)
end
describe 'GET /admin/hooks' do

View File

@ -8,7 +8,7 @@ RSpec.describe 'Admin Jobs', :js, feature_category: :continuous_integration do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
describe 'GET /admin/jobs' do

View File

@ -11,7 +11,7 @@ RSpec.describe 'admin issues labels', feature_category: :team_planning do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
describe 'list' do

View File

@ -10,7 +10,7 @@ RSpec.describe 'admin manage applications', feature_category: :system_access do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
include_examples 'manage applications'

View File

@ -24,7 +24,7 @@ RSpec.describe 'Admin Mode Login', feature_category: :system_access do
repeated_otp = user.current_otp
enter_code(repeated_otp)
gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: false)
enable_admin_mode!(user, use_ui: true)
expect(page).to have_content(_('Enter verification code'))
@ -41,7 +41,7 @@ RSpec.describe 'Admin Mode Login', feature_category: :system_access do
expect(page).to have_content('Enter verification code')
enter_code(user.current_otp)
gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: false)
enable_admin_mode!(user, use_ui: true)
expect(page).to have_content(_('Enter verification code'))
end

View File

@ -12,7 +12,7 @@ RSpec.describe 'Admin Mode Logout', :js, feature_category: :system_access do
# TODO: This used to use gitlab_sign_in, instead of sign_in, but that is buggy. See
# this issue to look into why: https://gitlab.com/gitlab-org/gitlab/-/issues/331851
sign_in(user)
gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: false)
enable_admin_mode!(user, use_ui: true)
visit admin_root_path
end

View File

@ -34,7 +34,7 @@ RSpec.describe 'Admin mode for workers', :request_store, feature_category: :syst
context 'when admin mode enabled', :delete do
before do
gitlab_enable_admin_mode_sign_in(user)
enable_admin_mode!(user)
end
it 'can delete user', :js do
@ -67,6 +67,6 @@ RSpec.describe 'Admin mode for workers', :request_store, feature_category: :syst
Sidekiq::Worker.drain_all
sign_in(user)
gitlab_enable_admin_mode_sign_in(user)
enable_admin_mode!(user)
end
end

View File

@ -69,7 +69,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :shared do
context 'when in admin_mode' do
before do
gitlab_enable_admin_mode_sign_in(admin, use_mock_admin_mode: false)
enable_admin_mode!(admin, use_ui: true)
end
it 'contains link to leave admin mode' do

View File

@ -14,7 +14,7 @@ RSpec.describe "Admin::Projects", feature_category: :groups_and_projects do
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user)
enable_admin_mode!(current_user)
end
describe 'when membership is set to expire', :js do

View File

@ -11,7 +11,7 @@ RSpec.describe "Admin Runners", feature_category: :fleet_visibility do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
describe "Admin Runners page", :js do

View File

@ -8,7 +8,7 @@ RSpec.describe 'Admin searches application settings', :js, feature_category: :gl
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
context 'in appearances page' do

View File

@ -18,7 +18,7 @@ RSpec.describe "Admin > Admin sees background migrations", feature_category: :da
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
it 'can navigate to background migrations', :js do

View File

@ -7,7 +7,7 @@ RSpec.describe "Admin > Admin sees project statistics", feature_category: :group
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user)
enable_admin_mode!(current_user)
visit admin_project_path(project)
end

View File

@ -10,7 +10,7 @@ RSpec.describe "Admin > Admin sees projects statistics", feature_category: :grou
create(:project, :repository) { |project| project.statistics.destroy! }
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user)
enable_admin_mode!(current_user)
visit admin_projects_path
end

View File

@ -13,7 +13,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin, use_mock_admin_mode: false)
enable_admin_mode!(admin, use_ui: true)
end
context 'General page' do

View File

@ -6,7 +6,7 @@ RSpec.describe 'Admin System Info', feature_category: :shared do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
describe 'GET /admin/system_info' do

View File

@ -11,7 +11,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js, feature_category: :s
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
describe "token creation" do

View File

@ -7,7 +7,7 @@ RSpec.describe "Admin::Users", feature_category: :user_management do
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user)
enable_admin_mode!(current_user)
end
describe 'Tabs' do

View File

@ -25,7 +25,7 @@ RSpec.describe 'Admin uses repository checks', :request_store, feature_category:
context 'when admin mode is enabled' do
before do
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
it 'to trigger a single check', :js do

View File

@ -7,7 +7,7 @@ RSpec.describe 'Admin Broadcast Messages', :js, feature_category: :onboarding do
it 'previews, creates and edits a broadcast message' do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
# create
visit admin_broadcast_messages_path

View File

@ -8,7 +8,7 @@ RSpec.describe 'admin visits dashboard' do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
context 'counting forks', :js, feature_category: :source_code_management do

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Admin::Users::UserIdentities', feature_category: :user_management do
let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
let_it_be(:current_user) { create(:admin) }
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user, use_mock_admin_mode: false)
end
describe 'GET /admin/users/:id' do
describe 'show user identities' do
it 'shows user identities', :aggregate_failures do
visit admin_user_identities_path(user)
expect(page).to have_content(user.name)
expect(page).to have_content('twitter')
end
end
describe 'update user identities' do
before do
allow(Gitlab::Auth::OAuth::Provider).to receive(:providers).and_return([:twitter, :twitter_updated])
end
it 'modifies twitter identity', :aggregate_failures do
visit admin_user_identities_path(user)
find('.table').find(:link, 'Edit').click
fill_in 'identity_extern_uid', with: '654321'
select 'twitter_updated', from: 'identity_provider'
click_button 'Save changes'
expect(page).to have_content(user.name)
expect(page).to have_content('twitter_updated')
expect(page).to have_content('654321')
end
end
describe 'remove user with identities' do
it 'removes user with twitter identity', :aggregate_failures do
visit admin_user_identities_path(user)
click_link 'Delete'
expect(page).to have_content(user.name)
expect(page).not_to have_content('twitter')
end
end
end
end

View File

@ -0,0 +1,209 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Admin::Users::UserImpersonation', feature_category: :user_management do
let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
let_it_be(:current_user) { create(:admin) }
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user, use_mock_admin_mode: false)
end
describe 'GET /admin/users/:id' do
describe 'Impersonation' do
let_it_be(:another_user) { create(:user) }
context 'before impersonating' do
subject { visit admin_user_path(user_to_visit) }
let_it_be(:user_to_visit) { another_user }
shared_examples "user that cannot be impersonated" do
it 'disables impersonate button' do
subject
impersonate_btn = find_by_testid('impersonate-user-link')
expect(impersonate_btn).not_to be_nil
expect(impersonate_btn['disabled']).not_to be_nil
end
it "shows tooltip with correct error message" do
subject
expect(find("span[title='#{impersonation_error_msg}']")).not_to be_nil
end
end
context 'for other users' do
it 'shows impersonate button for other users' do
subject
expect(page).to have_content('Impersonate')
impersonate_btn = find_by_testid('impersonate-user-link')
expect(impersonate_btn['disabled']).to be_nil
end
end
context 'for admin itself' do
let(:user_to_visit) { current_user }
it 'does not show impersonate button for admin itself' do
subject
expect(page).not_to have_content('Impersonate')
end
end
context 'for blocked user' do
let_it_be(:blocked_user) { create(:user, :blocked) }
let(:user_to_visit) { blocked_user }
let(:impersonation_error_msg) { _('You cannot impersonate a blocked user') }
it_behaves_like "user that cannot be impersonated"
end
context 'for user with expired password' do
let(:user_to_visit) do
another_user.update!(password_expires_at: Time.zone.now - 5.minutes)
another_user
end
let(:impersonation_error_msg) { _("You cannot impersonate a user with an expired password") }
it_behaves_like "user that cannot be impersonated"
end
context 'for internal user' do
let_it_be(:internal_user) { create(:user, :bot) }
let(:user_to_visit) { internal_user }
let(:impersonation_error_msg) { _("You cannot impersonate an internal user") }
it_behaves_like "user that cannot be impersonated"
end
context 'for locked user' do
let_it_be(:locked_user) { create(:user, :locked) }
let(:user_to_visit) { locked_user }
let(:impersonation_error_msg) { _("You cannot impersonate a user who cannot log in") }
it_behaves_like "user that cannot be impersonated"
end
context 'when already impersonating another user' do
let_it_be(:admin_user) { create(:user, :admin) }
let(:impersonation_error_msg) { _("You are already impersonating another user") }
subject do
visit admin_user_path(admin_user)
click_link 'Impersonate'
visit admin_user_path(another_user)
end
it_behaves_like "user that cannot be impersonated"
end
context 'when impersonation is disabled' do
before do
stub_config_setting(impersonation_enabled: false)
end
it 'does not show impersonate button' do
subject
expect(page).not_to have_content('Impersonate')
end
end
end
context 'when impersonating' do
subject { click_link 'Impersonate' }
before do
visit admin_user_path(another_user)
end
it 'logs in as the user when impersonate is clicked', :js do
subject
expect(page).to have_button("#{another_user.name} users menu")
end
it 'sees impersonation log out icon', :js do
subject
icon = first('[data-testid="incognito-icon"]')
expect(icon).not_to be nil
end
context 'when viewing the confirm email warning', :js do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
let_it_be(:another_user) { create(:user, :unconfirmed) }
let(:warning_alert) { page.find(:css, '[data-testid="alert-warning"]') }
let(:expected_styling) { { 'pointer-events' => 'none', 'cursor' => 'default' } }
context 'with an email that does not contain HTML' do
before do
subject
end
it 'displays the warning alert including the email' do
expect(warning_alert.text).to include("Please check your email (#{another_user.email}) to verify")
end
end
context 'with an email that contains HTML' do
let(:malicious_email) { "malicious@test.com<form><input/title='<script>alert(document.domain)</script>'>" }
let(:another_user) { create(:user, confirmed_at: nil, unconfirmed_email: malicious_email) }
before do
subject
end
it 'displays the impersonation alert, excludes email, and disables links' do
expect(warning_alert.text).to include("check your email (#{another_user.unconfirmed_email}) to verify")
end
end
end
end
context 'ending impersonation', :js do
subject { click_on 'Stop impersonating' }
before do
visit admin_user_path(another_user)
click_link 'Impersonate'
end
it 'logs out of impersonated user back to original user' do
subject
expect(page).to have_button("#{current_user.name} users menu")
end
it 'is redirected back to the impersonated users page in the admin after stopping' do
subject
expect(page).to have_current_path("/admin/users/#{another_user.username}", ignore_query: true)
end
context 'a user with an expired password' do
before do
another_user.update!(password_expires_at: Time.zone.now - 5.minutes)
end
it 'is redirected back to the impersonated users page in the admin after stopping' do
subject
expect(page).to have_current_path("/admin/users/#{another_user.username}", ignore_query: true)
end
end
end
end
end
end

View File

@ -11,7 +11,7 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user, use_mock_admin_mode: false)
enable_admin_mode!(current_user, use_ui: true)
end
describe 'GET /admin/users/:id' do
@ -144,200 +144,6 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
end
end
describe 'Impersonation' do
let_it_be(:another_user) { create(:user) }
context 'before impersonating' do
subject { visit admin_user_path(user_to_visit) }
let_it_be(:user_to_visit) { another_user }
shared_examples "user that cannot be impersonated" do
it 'disables impersonate button' do
subject
impersonate_btn = find_by_testid('impersonate-user-link')
expect(impersonate_btn).not_to be_nil
expect(impersonate_btn['disabled']).not_to be_nil
end
it "shows tooltip with correct error message" do
subject
expect(find("span[title='#{impersonation_error_msg}']")).not_to be_nil
end
end
context 'for other users' do
it 'shows impersonate button for other users' do
subject
expect(page).to have_content('Impersonate')
impersonate_btn = find_by_testid('impersonate-user-link')
expect(impersonate_btn['disabled']).to be_nil
end
end
context 'for admin itself' do
let(:user_to_visit) { current_user }
it 'does not show impersonate button for admin itself' do
subject
expect(page).not_to have_content('Impersonate')
end
end
context 'for blocked user' do
let_it_be(:blocked_user) { create(:user, :blocked) }
let(:user_to_visit) { blocked_user }
let(:impersonation_error_msg) { _('You cannot impersonate a blocked user') }
it_behaves_like "user that cannot be impersonated"
end
context 'for user with expired password' do
let(:user_to_visit) do
another_user.update!(password_expires_at: Time.zone.now - 5.minutes)
another_user
end
let(:impersonation_error_msg) { _("You cannot impersonate a user with an expired password") }
it_behaves_like "user that cannot be impersonated"
end
context 'for internal user' do
let_it_be(:internal_user) { create(:user, :bot) }
let(:user_to_visit) { internal_user }
let(:impersonation_error_msg) { _("You cannot impersonate an internal user") }
it_behaves_like "user that cannot be impersonated"
end
context 'for locked user' do
let_it_be(:locked_user) { create(:user, :locked) }
let(:user_to_visit) { locked_user }
let(:impersonation_error_msg) { _("You cannot impersonate a user who cannot log in") }
it_behaves_like "user that cannot be impersonated"
end
context 'when already impersonating another user' do
let_it_be(:admin_user) { create(:user, :admin) }
let(:impersonation_error_msg) { _("You are already impersonating another user") }
subject do
visit admin_user_path(admin_user)
click_link 'Impersonate'
visit admin_user_path(another_user)
end
it_behaves_like "user that cannot be impersonated"
end
context 'when impersonation is disabled' do
before do
stub_config_setting(impersonation_enabled: false)
end
it 'does not show impersonate button' do
subject
expect(page).not_to have_content('Impersonate')
end
end
end
context 'when impersonating' do
subject { click_link 'Impersonate' }
before do
visit admin_user_path(another_user)
end
it 'logs in as the user when impersonate is clicked', :js do
subject
expect(page).to have_button("#{another_user.name} users menu")
end
it 'sees impersonation log out icon', :js do
subject
icon = first('[data-testid="incognito-icon"]')
expect(icon).not_to be nil
end
context 'when viewing the confirm email warning', :js do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
end
let_it_be(:another_user) { create(:user, :unconfirmed) }
let(:warning_alert) { page.find(:css, '[data-testid="alert-warning"]') }
let(:expected_styling) { { 'pointer-events' => 'none', 'cursor' => 'default' } }
context 'with an email that does not contain HTML' do
before do
subject
end
it 'displays the warning alert including the email' do
expect(warning_alert.text).to include("Please check your email (#{another_user.email}) to verify")
end
end
context 'with an email that contains HTML' do
let(:malicious_email) { "malicious@test.com<form><input/title='<script>alert(document.domain)</script>'>" }
let(:another_user) { create(:user, confirmed_at: nil, unconfirmed_email: malicious_email) }
before do
subject
end
it 'displays the impersonation alert, excludes email, and disables links' do
expect(warning_alert.text).to include("check your email (#{another_user.unconfirmed_email}) to verify")
end
end
end
end
context 'ending impersonation', :js do
subject { click_on 'Stop impersonating' }
before do
visit admin_user_path(another_user)
click_link 'Impersonate'
end
it 'logs out of impersonated user back to original user' do
subject
expect(page).to have_button("#{current_user.name} users menu")
end
it 'is redirected back to the impersonated users page in the admin after stopping' do
subject
expect(page).to have_current_path("/admin/users/#{another_user.username}", ignore_query: true)
end
context 'a user with an expired password' do
before do
another_user.update!(password_expires_at: Time.zone.now - 5.minutes)
end
it 'is redirected back to the impersonated users page in the admin after stopping' do
subject
expect(page).to have_current_path("/admin/users/#{another_user.username}", ignore_query: true)
end
end
end
end
describe 'Two-factor Authentication status' do
it 'shows when enabled' do
user.update!(otp_required_for_login: true)
@ -479,26 +285,6 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
end
end
describe 'GET /admin/users', :js do
context 'user pending approval' do
it 'shows user info', :aggregate_failures do
user = create(:user, :blocked_pending_approval)
visit admin_users_path
click_link 'Pending approval'
click_link user.name
expect(page).to have_content(user.name)
expect(page).to have_content('Pending approval')
click_user_dropdown_toggle(user.id)
expect(page).to have_button('Approve')
expect(page).to have_button('Reject')
end
end
end
context 'when user has an unconfirmed email', :js do
# Email address contains HTML to ensure email address is displayed in an HTML safe way.
let_it_be(:unconfirmed_email) { "#{generate(:email)}<h2>testing<img/src=http://localhost:8000/test.png>" }

View File

@ -12,7 +12,7 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do
before do
sign_in(current_user)
gitlab_enable_admin_mode_sign_in(current_user)
enable_admin_mode!(current_user)
end
describe 'GET /admin/users', :js do
@ -381,6 +381,24 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do
expect(find_by_testid("user-group-count-#{current_user.id}").text).to eq("2")
end
end
context 'user pending approval' do
it 'shows user info', :aggregate_failures do
user = create(:user, :blocked_pending_approval)
visit admin_users_path
click_link 'Pending approval'
click_link user.name
expect(page).to have_content(user.name)
expect(page).to have_content('Pending approval')
click_user_dropdown_toggle(user.id)
expect(page).to have_button('Approve')
expect(page).to have_button('Reject')
end
end
end
describe 'GET /admin/users/new' do

View File

@ -11,7 +11,7 @@ RSpec.describe 'Instance variables', :js, feature_category: :secrets_management
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit page_path
wait_for_requests

View File

@ -11,7 +11,7 @@ RSpec.describe 'Issue Boards shortcut', :js, feature_category: :team_planning do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit project_path(project)
end
@ -30,7 +30,7 @@ RSpec.describe 'Issue Boards shortcut', :js, feature_category: :team_planning do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit project_path(project)
end

View File

@ -121,7 +121,7 @@ RSpec.describe 'Broadcast Messages', feature_category: :onboarding do
stub_const('Gitlab::Cache::JsonCaches::JsonKeyed::STRATEGY_KEY_COMPONENTS', original_strategy_value)
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_broadcast_messages_path

View File

@ -145,7 +145,7 @@ RSpec.describe 'Clusterable > Show page', feature_category: :deployment_manageme
let(:cluster) { create(:cluster, :provided_by_gcp, :instance) }
before do
gitlab_enable_admin_mode_sign_in(current_user)
enable_admin_mode!(current_user)
end
it_behaves_like 'show page' do

View File

@ -12,7 +12,7 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_
allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.kilobytes)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
wait_for_requests

View File

@ -12,7 +12,7 @@ RSpec.describe "Gitlab::Experiment", :js, feature_category: :activation do
before do
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
stub_experiments(null_hypothesis: :candidate)
end

View File

@ -130,7 +130,7 @@ RSpec.describe 'User Cluster', :js, feature_category: :environment_management do
gitlab_sign_out
gitlab_sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit group_clusters_path(group)
end

View File

@ -66,7 +66,7 @@ RSpec.describe 'Groups > Members > List members', :js, feature_category: :groups
it 'shows 2FA badge to admins' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit group_group_members_path(group)

View File

@ -27,7 +27,7 @@ RSpec.describe "Help Dropdown", :js, feature_category: :shared do
context "when severity is #{severity}" do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
allow_next_instance_of(VersionCheck) do |instance|
allow(instance).to receive(:response).and_return({ "severity" => severity })

View File

@ -11,7 +11,7 @@ RSpec.describe 'Admin views hidden merge requests', feature_category: :insider_t
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit(project_merge_requests_path(project))
end

View File

@ -110,7 +110,7 @@ RSpec.describe 'Gcp Cluster', :js, feature_category: :deployment_management do
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
gitlab_enable_admin_mode_sign_in(user)
enable_admin_mode!(user)
visit general_admin_application_settings_path
end

View File

@ -120,7 +120,7 @@ RSpec.describe 'User Cluster', :js, feature_category: :deployment_management do
gitlab_sign_out
gitlab_sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit project_clusters_path(project)
end

View File

@ -153,7 +153,7 @@ RSpec.describe 'Edit Project Settings', feature_category: :groups_and_projects d
before do
non_member.update_attribute(:admin, true)
sign_in(non_member)
gitlab_enable_admin_mode_sign_in(non_member)
enable_admin_mode!(non_member)
end
it 'renders 404 if feature is disabled' do

View File

@ -265,7 +265,7 @@ RSpec.describe 'Projects > Members > Manage members', :js, feature_category: :on
it 'shows 2FA badge to admins' do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit_members_page

View File

@ -43,7 +43,7 @@ RSpec.describe 'User views an empty project', feature_category: :groups_and_proj
context 'when admin mode is enabled' do
before do
sign_in(user)
gitlab_enable_admin_mode_sign_in(user)
enable_admin_mode!(user)
end
it_behaves_like 'allowing push to default branch'

View File

@ -82,7 +82,7 @@ RSpec.describe 'Protected Branches', :js, feature_category: :source_code_managem
context 'logged in as admin' do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
describe "explicit protected branches" do

View File

@ -19,7 +19,7 @@ RSpec.describe 'Usage stats consent', feature_category: :service_ping do
end
gitlab_sign_in(user)
gitlab_enable_admin_mode_sign_in(user)
enable_admin_mode!(user)
end
shared_examples 'dismissible banner' do |button_text|

View File

@ -47,7 +47,7 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state, fe
)
gitlab_sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
visit admin_user_path(user)

View File

@ -0,0 +1,71 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::UniquenessHelpers, feature_category: :database do
let(:migration) do
ActiveRecord::Migration.new.extend(described_class)
end
let(:connection) { ActiveRecord::Base.connection }
let(:table_not_partitioned) { '_test_not_partitioned_table' }
let(:table_partitioned) { '_test_partitioned_table' }
before do
connection.execute(<<~SQL)
CREATE TABLE _test_partitioned_table
(
id serial NOT NULL,
PARTITION bigint NULL DEFAULT 1,
PRIMARY KEY (id, partition)
) PARTITION BY list(partition);
CREATE TABLE _test_partitioned_table_1
PARTITION OF _test_partitioned_table FOR VALUES IN (1);
SQL
end
describe '#ensure_unique_id' do
subject(:ensure_unique_id) { migration.ensure_unique_id(table_name) }
context 'when table is partitioned' do
let(:table_name) { table_partitioned }
let(:trigger_name) { "assign_#{table_name}_id_trigger" }
let(:function_name) { "assign_#{table_name}_id_value" }
context 'when trigger already exists' do
before do
allow(migration).to receive(:trigger_exists?)
.with(table_name, trigger_name)
.and_return(true)
end
it 'does not modify existing trigger' do
expect(migration).not_to receive(:change_column_default)
expect(migration).not_to receive(:create_trigger_function)
expect(migration).not_to receive(:create_trigger)
expect do
ensure_unique_id
end.not_to raise_error
end
end
context 'when trigger is not defined' do
it 'creates trigger', :aggregate_failures do
expect(migration).to receive(:change_column_default).with(table_name, :id, nil).and_call_original
expect(migration).to receive(:create_trigger_function).with(function_name).and_call_original
expect(migration).to receive(:create_trigger)
.with(table_name, trigger_name, function_name, fires: 'BEFORE INSERT')
.and_call_original
expect do
ensure_unique_id
end.not_to raise_error
expect(migration.trigger_exists?(table_name, trigger_name)).to eq(true)
end
end
end
end
end

View File

@ -472,12 +472,12 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
end
end
context 'reading usage quotas' do
context 'reading usage quotas and viewing the edit page' do
%w[maintainer owner].each do |role|
context "with #{role}" do
let(:current_user) { send(role) }
it { is_expected.to be_allowed(:read_usage_quotas) }
it { is_expected.to be_allowed(:read_usage_quotas, :view_edit_page) }
end
end
@ -485,7 +485,7 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
context "with #{role}" do
let(:current_user) { send(role) }
it { is_expected.to be_disallowed(:read_usage_quotas) }
it { is_expected.to be_disallowed(:read_usage_quotas, :view_edit_page) }
end
end
@ -493,11 +493,11 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
let(:current_user) { admin }
context 'when admin mode is enabled', :enable_admin_mode do
it { expect_allowed(:read_usage_quotas) }
it { expect_allowed(:read_usage_quotas, :view_edit_page) }
end
context 'when admin mode is disabled' do
it { expect_disallowed(:read_usage_quotas) }
it { expect_disallowed(:read_usage_quotas, :view_edit_page) }
end
end
end

View File

@ -8,6 +8,11 @@ RSpec.describe Cli, feature_category: :service_ping do
let(:prompt) { TTY::Prompt::Test.new }
let(:files_to_cleanup) { [] }
let(:example_timeout) { 3 }
let(:example_error) { Class.new(Timeout::Error) }
let(:interaction_timeout) { 1 }
let(:interaction_error) { Class.new(Timeout::Error) }
let(:event1_filepath) { 'config/events/internal_events_cli_used.yml' }
let(:event1_content) { internal_event_fixture('events/event_with_identifiers.yml') }
let(:event2_filepath) { 'ee/config/events/internal_events_cli_opened.yml' }
@ -26,13 +31,29 @@ RSpec.describe Cli, feature_category: :service_ping do
delete_files(files_to_cleanup)
end
around do |example|
Timeout.timeout(example_timeout, example_error) { example.run }
rescue example_error => e
# Override error to include CLI output in error detail
raise e.class, timeout_error_message, e.backtrace
end
subject(:execute) do
Timeout.timeout(interaction_timeout, interaction_error) { described_class.new(prompt).run }
rescue interaction_error
# Rescue from timeout so we can make assertions on the CLI output
end
# Shared examples used for examples defined in new_events.yml & new_metrics.yml fixtures.
# Note: Expects CLI to be exited using the 'Exit' option or completing definition flow
shared_examples 'creates the right defintion files' do |description, test_case = {}|
# For expected keystroke mapping, see https://github.com/piotrmurach/tty-reader/blob/master/lib/tty/reader/keys.rb
let(:keystrokes) { test_case.dig('inputs', 'keystrokes') || [] }
let(:input_files) { test_case.dig('inputs', 'files') || [] }
let(:output_files) { test_case.dig('outputs', 'files') || [] }
subject { run_with_verbose_timeout }
# Script execution should stop without a reduced timeout
let(:interaction_timeout) { example_timeout }
it "in scenario: #{description}" do
delete_old_ouputs # just in case
@ -40,7 +61,7 @@ RSpec.describe Cli, feature_category: :service_ping do
queue_cli_inputs(keystrokes)
expect_file_creation
subject
execute
end
private
@ -117,7 +138,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"\n" # Copy & continue
])
run_with_timeout
execute
# Filter down to "dev" options
expect(plain_last_lines(9)).to eq <<~TEXT.chomp
@ -149,7 +170,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"\n" # Copy & continue
])
run_with_timeout
execute
# Filter down to "dev:create" options
expect(plain_last_lines(5)).to eq <<~TEXT.chomp
@ -185,7 +206,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"2\n" # Modify attributes
])
run_with_timeout
execute
# Filter down to "dev" options
expect(plain_last_lines(50)).to include 'Select one: Which group owns the metric?'
@ -262,7 +283,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"\n" # Select: config/events/internal_events_cli_used.yml
])
run_with_timeout
execute
end
end
@ -279,7 +300,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"\n" # Select: config/events/internal_events_cli_opened.yml
])
run_with_timeout
execute
expect(plain_last_lines(5)).to eq <<~TEXT.chomp
Monthly/Weekly count of unique users [who triggered internal_events_cli_opened] (user unavailable)
@ -318,7 +339,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"\n" # Select: config/events/00_event1.yml
])
run_with_timeout
execute
expect(plain_last_lines(15)).to include 'Looks like the potential metrics for this event ' \
'either already exist or are unsupported.'
@ -389,7 +410,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"8\n" # Exit
])
run_with_timeout
execute
output = plain_last_lines(100)
@ -556,7 +577,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"8\n" # Exit
])
run_with_timeout
execute
output = plain_last_lines(1000)
@ -616,7 +637,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"8\n" # Exit
])
run_with_timeout
execute
output = plain_last_lines(300)
@ -735,7 +756,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"n\n" # No --> Are you trying to track customer usage of a GitLab feature?
])
run_with_timeout
execute
expect(plain_last_lines(50)).to include("Oh no! This probably isn't the tool you need!")
end
@ -747,7 +768,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"n\n" # No --> Can usage for the feature be measured by tracking a specific user action?
])
run_with_timeout
execute
expect(plain_last_lines(50)).to include("Oh no! This probably isn't the tool you need!")
end
@ -761,7 +782,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"n\n" # No --> Ready to start?
])
run_with_timeout
execute
expect(plain_last_lines(30)).to include("Okay! The next step is adding a new event! (~5 min)")
end
@ -775,7 +796,7 @@ RSpec.describe Cli, feature_category: :service_ping do
"n\n" # No --> Ready to start?
])
run_with_timeout
execute
expect(plain_last_lines(30)).to include("Amazing! The next step is adding a new metric! (~8 min)")
end
@ -788,18 +809,8 @@ RSpec.describe Cli, feature_category: :service_ping do
prompt.input.rewind
end
def run_with_timeout(duration = 1)
Timeout.timeout(duration) { described_class.new(prompt).run }
rescue Timeout::Error
# Timeout is needed to break out of the CLI, but we may want
# to make assertions afterwards
end
def run_with_verbose_timeout(duration = 1)
Timeout.timeout(duration) { described_class.new(prompt).run }
rescue Timeout::Error => e
# Re-raise error so CLI output is printed with the error
message = <<~TEXT
def timeout_error_message
<<~TEXT
Awaiting input too long. Entire CLI output:
#{
@ -811,8 +822,6 @@ RSpec.describe Cli, feature_category: :service_ping do
TEXT
raise e.class, message, e.backtrace
end
def plain_last_lines(size)
@ -820,7 +829,8 @@ RSpec.describe Cli, feature_category: :service_ping do
.lines
.last(size)
.join('')
.gsub(/\e[^\sm]{2,4}[mh]/, '')
.gsub(/\e[^\sm]{2,4}[mh]/, '') # Ignore text colors
.gsub(/(\e\[(2K|1G|1A))+\z/, '') # Remove trailing characters if timeout occurs
end
def collect_file_writes(collector)
@ -844,7 +854,7 @@ RSpec.describe Cli, feature_category: :service_ping do
def stub_product_groups(body)
allow(Net::HTTP).to receive(:get)
.with(URI('https://gitlab.com/gitlab-com/www-gitlab-com/-/raw/master/data/stages.yml'))
.with(URI(InternalEventsCli::Helpers::GroupOwnership::STAGES_YML))
.and_return(body)
end

View File

@ -5,17 +5,30 @@
module AdminModeHelper
# Administrators are logged in by default in user mode and have to switch to admin
# mode for accessing any administrative functionality. This helper lets a user
# be in admin mode without requiring a second authentication step (provided
# the user is an admin)
# access the admin area in two different ways:
#
# * Fast (use_ui: false) and suitable form the most use cases: fakes calls and grants
# access to the admin area without requiring a second authentication step (provided the
# user is an admin)
# * Slow (use_ui: true): visits the admin UI and enters the users password. A second
# authentication step may be needed.
#
# See also tag :enable_admin_mode in spec/spec_helper.rb for a spec-wide
# alternative
def enable_admin_mode!(user)
fake_user_mode = instance_double(Gitlab::Auth::CurrentUserMode)
def enable_admin_mode!(user, use_ui: false)
if use_ui
visit new_admin_session_path
fill_in 'user_password', with: user.password
click_button 'Enter admin mode'
allow(Gitlab::Auth::CurrentUserMode).to receive(:new).and_call_original
wait_for_requests
else
fake_user_mode = instance_double(Gitlab::Auth::CurrentUserMode)
allow(Gitlab::Auth::CurrentUserMode).to receive(:new).with(user).and_return(fake_user_mode)
allow(fake_user_mode).to receive(:admin_mode?).and_return(user&.admin?)
allow(Gitlab::Auth::CurrentUserMode).to receive(:new).and_call_original
allow(Gitlab::Auth::CurrentUserMode).to receive(:new).with(user).and_return(fake_user_mode)
allow(fake_user_mode).to receive(:admin_mode?).and_return(user&.admin?)
end
end
end

View File

@ -49,18 +49,6 @@ module LoginHelpers
@current_user = user
end
def gitlab_enable_admin_mode_sign_in(user, use_mock_admin_mode: true)
if use_mock_admin_mode
enable_admin_mode!(user)
else
visit new_admin_session_path
fill_in 'user_password', with: user.password
click_button 'Enter admin mode'
wait_for_requests
end
end
def gitlab_sign_in_via(provider, user, uid, saml_response = nil)
mock_auth_hash_with_saml_xml(provider, uid, user.email, saml_response)
visit new_user_session_path

View File

@ -7,7 +7,7 @@ RSpec.shared_context 'instance integration activation' do
before do
sign_in(user)
gitlab_enable_admin_mode_sign_in(user)
enable_admin_mode!(user)
end
def visit_instance_integrations

View File

@ -9,7 +9,7 @@ RSpec.shared_examples 'inviting groups search results' do
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
enable_admin_mode!(admin)
end
it 'shows groups where the admin has no direct membership' do

View File

@ -1269,10 +1269,10 @@
stylelint-declaration-strict-value "1.9.2"
stylelint-scss "5.1.0"
"@gitlab/svgs@3.72.0":
version "3.72.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.72.0.tgz#5daaa7366913b52ea89439305067e030f967c8a5"
integrity sha512-VbSdwXxu9Y6NAXNFTROjZa83e2b8QeDAO7byqjJ0z+2Y3gGGXdw+HclAzz0Ns8B0+DMV5mV7dtmTlv/1xAXXYQ==
"@gitlab/svgs@3.74.0":
version "3.74.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.74.0.tgz#b6b41be65b9e70378c0cef0435f96edd5467e759"
integrity sha512-eHoywPSLrYb+I/IYGapei2Tum5vLtgWkFxN0fxmUUAnBnxFSA+67aheI33kQVV3WjANuZGkglfPBX3QAmN8BLA==
"@gitlab/ui@^72.0.0":
version "72.0.0"