diff options
33 files changed, 370 insertions, 204 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1531b1d6b96..c1355e78945 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -65,6 +65,8 @@ variables: # we override the max_old_space_size to prevent OOM errors NODE_OPTIONS: --max_old_space_size=3584 GIT_DEPTH: "20" + # 'GIT_STRATEGY: clone' optimizes the pack-objects cache hit ratio + GIT_STRATEGY: "clone" GIT_SUBMODULE_STRATEGY: "none" GET_SOURCES_ATTEMPTS: "3" DEBIAN_VERSION: "bullseye" diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index abdacad93b5..ab8671d3cb2 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -231,7 +231,7 @@ build-components: - .rails:rules:build-components script: - source scripts/gitlab_workhorse_component_helpers.sh - - 'gitlab_workhorse_package_doesnt_exist || { echoinfo "INFO: Exiting early as package exists."; exit 0; }' + - 'gitlab_workhorse_archive_doesnt_exist || { echoinfo "INFO: Exiting early as package exists."; exit 0; }' - run_timed_command "scripts/setup-test-env" - run_timed_command "select_gitlab_workhorse_essentials" - run_timed_command "create_gitlab_workhorse_package" diff --git a/.rubocop_todo/database/multiple_databases.yml b/.rubocop_todo/database/multiple_databases.yml index 69bc0b64a30..e390f81f030 100644 --- a/.rubocop_todo/database/multiple_databases.yml +++ b/.rubocop_todo/database/multiple_databases.yml @@ -20,7 +20,6 @@ Database/MultipleDatabases: - lib/gitlab/database.rb - lib/gitlab/gitlab_import/importer.rb - lib/gitlab/health_checks/db_check.rb - - lib/gitlab/import_export/base/relation_factory.rb - lib/gitlab/import_export/group/relation_tree_restorer.rb - lib/gitlab/legacy_github_import/importer.rb - lib/gitlab/seeder.rb diff --git a/app/assets/javascripts/projects/pipelines/charts/index.js b/app/assets/javascripts/projects/pipelines/charts/index.js index 94d32609e5d..28b77f6defd 100644 --- a/app/assets/javascripts/projects/pipelines/charts/index.js +++ b/app/assets/javascripts/projects/pipelines/charts/index.js @@ -11,7 +11,13 @@ const apolloProvider = new VueApollo({ }); const mountPipelineChartsApp = (el) => { - const { projectPath, failedPipelinesLink, coverageChartPath, defaultBranch } = el.dataset; + const { + projectPath, + failedPipelinesLink, + coverageChartPath, + defaultBranch, + testRunsEmptyStateImagePath, + } = el.dataset; const shouldRenderDoraCharts = parseBoolean(el.dataset.shouldRenderDoraCharts); const shouldRenderQualitySummary = parseBoolean(el.dataset.shouldRenderQualitySummary); @@ -30,6 +36,7 @@ const mountPipelineChartsApp = (el) => { shouldRenderQualitySummary, coverageChartPath, defaultBranch, + testRunsEmptyStateImagePath, }, render: (createElement) => createElement(ProjectPipelinesCharts, {}), }); diff --git a/app/models/integration.rb b/app/models/integration.rb index a5b5e238410..e64fff2d811 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -414,7 +414,10 @@ class Integration < ApplicationRecord end def api_field_names - fields.pluck(:name).grep_v(/password|token|key|title|description/) + fields + .reject { _1[:type] == 'password' } + .pluck(:name) + .grep_v(/password|token|key/) end def global_fields diff --git a/app/views/projects/pages/_ssl_limitations_warning.html.haml b/app/views/projects/pages/_ssl_limitations_warning.html.haml index de74b703e95..24f51aa91e6 100644 --- a/app/views/projects/pages/_ssl_limitations_warning.html.haml +++ b/app/views/projects/pages/_ssl_limitations_warning.html.haml @@ -2,6 +2,6 @@ = sprite_icon("warning-solid", css_class: "gl-text-orange-600") %strong= _("Warning:") - pages_host = Gitlab.config.pages.host - - docs_link_start = "<a href='#{help_page_path('user/project/pages/introduction', anchor: 'limitations')}' target='_blank' rel='noopener noreferrer'>".html_safe + - docs_link_start = "<a href='#{help_page_path('user/project/pages/introduction', anchor: 'subdomains-of-subdomains')}' target='_blank' rel='noopener noreferrer'>".html_safe - link_end = '</a>'.html_safe - = s_("GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with sub-subdomains. This means that if your username/groupname contains a dot it will not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages will continue to work provided you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}").html_safe % { pages_host: pages_host, docs_link_start: docs_link_start, link_end: link_end } + = s_("GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}").html_safe % { pages_host: pages_host, docs_link_start: docs_link_start, link_end: link_end } diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml index 547e2c8a7f4..5a655e7e83d 100644 --- a/app/views/projects/pipelines/charts.html.haml +++ b/app/views/projects/pipelines/charts.html.haml @@ -5,4 +5,5 @@ should_render_quality_summary: should_render_quality_summary.to_s, failed_pipelines_link: project_pipelines_path(@project, page: '1', scope: 'all', status: 'failed'), coverage_chart_path: charts_project_graph_path(@project, @project.default_branch), + test_runs_empty_state_image_path: image_path('illustrations/pipeline.svg'), default_branch: @project.default_branch } } diff --git a/app/workers/web_hook_worker.rb b/app/workers/web_hook_worker.rb index fdcd22128a3..301f3720991 100644 --- a/app/workers/web_hook_worker.rb +++ b/app/workers/web_hook_worker.rb @@ -13,9 +13,6 @@ class WebHookWorker worker_has_external_dependencies! - # Webhook recursion detection properties may be passed through the `data` arg. - # This will be migrated to the `params` arg over the next few releases. - # See https://gitlab.com/gitlab-org/gitlab/-/issues/347389. def perform(hook_id, data, hook_name, params = {}) hook = WebHook.find_by_id(hook_id) return unless hook @@ -23,9 +20,6 @@ class WebHookWorker data = data.with_indifferent_access params.symbolize_keys! - # TODO: Remove in 14.9 https://gitlab.com/gitlab-org/gitlab/-/issues/347389 - params[:recursion_detection_request_uuid] ||= data.delete(:_gitlab_recursion_detection_request_uuid) - # Before executing the hook, reapply any recursion detection UUID that was initially # present in the request header so the hook can pass this same header value in its request. Gitlab::WebHooks::RecursionDetection.set_request_uuid(params[:recursion_detection_request_uuid]) diff --git a/db/migrate/20220120211831_temp_index_for_group_namespace_member_backfill.rb b/db/migrate/20220120211831_temp_index_for_group_namespace_member_backfill.rb new file mode 100644 index 00000000000..527d8783a0f --- /dev/null +++ b/db/migrate/20220120211831_temp_index_for_group_namespace_member_backfill.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class TempIndexForGroupNamespaceMemberBackfill < Gitlab::Database::Migration[1.0] + INDEX_NAME = 'tmp_index_for_namespace_id_migration_on_group_members' + + disable_ddl_transaction! + + def up + # Temporary index to be removed in 14.10 + # https://gitlab.com/gitlab-org/gitlab/-/issues/353538 + add_concurrent_index :members, :id, where: "members.member_namespace_id IS NULL and members.type = 'GroupMember'", name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :members, INDEX_NAME + end +end diff --git a/db/post_migrate/20220120211832_backfill_member_namespace_id_for_group_members.rb b/db/post_migrate/20220120211832_backfill_member_namespace_id_for_group_members.rb new file mode 100644 index 00000000000..947c0a1edd0 --- /dev/null +++ b/db/post_migrate/20220120211832_backfill_member_namespace_id_for_group_members.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class BackfillMemberNamespaceIdForGroupMembers < Gitlab::Database::Migration[1.0] + MIGRATION = 'BackfillMemberNamespaceForGroupMembers' + INTERVAL = 2.minutes + BATCH_SIZE = 1_000 + MAX_BATCH_SIZE = 2_000 + SUB_BATCH_SIZE = 100 + + def up + queue_batched_background_migration( + MIGRATION, + :members, + :id, + job_interval: INTERVAL, + batch_size: BATCH_SIZE, + max_batch_size: MAX_BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + Gitlab::Database::BackgroundMigration::BatchedMigration + .for_configuration(MIGRATION, :members, :id, []) + .delete_all + end +end diff --git a/db/schema_migrations/20220120211831 b/db/schema_migrations/20220120211831 new file mode 100644 index 00000000000..7601916df62 --- /dev/null +++ b/db/schema_migrations/20220120211831 @@ -0,0 +1 @@ +68b45f97a2165c934f097ca976fb27ffcb533c57facee95344e3985b5cfd8347
\ No newline at end of file diff --git a/db/schema_migrations/20220120211832 b/db/schema_migrations/20220120211832 new file mode 100644 index 00000000000..ed7679d4573 --- /dev/null +++ b/db/schema_migrations/20220120211832 @@ -0,0 +1 @@ +dd3a4209a72b470a14a3acc5d06db1f5fec67cb4f19b20b2e4d7d94b302fe122
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index ab87ddf896c..e1e6a79bccd 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -29524,6 +29524,8 @@ CREATE INDEX tmp_idx_vulnerability_occurrences_on_id_where_report_type_7_99 ON v CREATE INDEX tmp_index_container_repositories_on_id_migration_state ON container_repositories USING btree (id, migration_state); +CREATE INDEX tmp_index_for_namespace_id_migration_on_group_members ON members USING btree (id) WHERE ((member_namespace_id IS NULL) AND ((type)::text = 'GroupMember'::text)); + CREATE INDEX tmp_index_for_namespace_id_migration_on_routes ON routes USING btree (id) WHERE ((namespace_id IS NULL) AND ((source_type)::text = 'Namespace'::text)); CREATE INDEX tmp_index_members_on_state ON members USING btree (state) WHERE (state = 2); diff --git a/doc/administration/get_started.md b/doc/administration/get_started.md index f3b4400c8c3..e6a2e833af3 100644 --- a/doc/administration/get_started.md +++ b/doc/administration/get_started.md @@ -39,8 +39,8 @@ Get started: - Create a [project](../user/project/working_with_projects.md#create-a-project). - Create a [group](../user/group/index.md#create-a-group). - [Add members](../user/group/index.md#add-users-to-a-group) to the group. -- Create a [subgroup](../user/group/subgroups/index.md#creating-a-subgroup). -- [Add members](../user/group/subgroups/index.md#membership) to the subgroup. +- Create a [subgroup](../user/group/subgroups/index.md#create-a-subgroup). +- [Add members](../user/group/subgroups/index.md#subgroup-membership) to the subgroup. - Enable [external authorization control](../user/admin_area/settings/external_authorization.md#configuration). **More resources** @@ -49,7 +49,7 @@ Get started: - Sync group memberships [by using LDAP](../administration/auth/ldap/ldap_synchronization.md#group-sync). - Manage user access with inherited permissions. Use up to 20 levels of subgroups to organize both teams and projects. - Learn more about [inherited permissions](../user/project/members/index.md#inherited-membership). - - View [nested category examples](../user/group/subgroups/index.md#overview). + - View an [example](../user/group/subgroups/index.md). ## Import projects diff --git a/doc/api/alert_management_alerts.md b/doc/api/alert_management_alerts.md index 68ffd7dd6e7..2323cecfd6a 100644 --- a/doc/api/alert_management_alerts.md +++ b/doc/api/alert_management_alerts.md @@ -106,3 +106,24 @@ Example response: "url_text": "Example website" } ``` + +## Delete metric image + +```plaintext +DELETE /projects/:id/alert_management_alerts/:alert_iid/metric_images/:image_id +``` + +| Attribute | Type | Required | Description | +|-------------|---------|----------|--------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. | +| `alert_iid` | integer | yes | The internal ID of a project's alert. | +| `image_id` | integer | yes | The ID of the image. | + +```shell +curl --header "PRIVATE-TOKEN: <your_access_token>" --request DELETE "https://gitlab.example.com/api/v4/projects/5/alert_management_alerts/93/metric_images/1" +``` + +Can return the following status codes: + +- `204 No Content`: if the image was deleted successfully. +- `422 Unprocessable`: if the image could not be deleted. diff --git a/doc/api/groups.md b/doc/api/groups.md index ce671de2999..d4a0b4fed95 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -796,7 +796,7 @@ Parameters: | `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). | | `project_creation_level` | string | no | Determine if developers can create projects in the group. Can be `noone` (No one), `maintainer` (users with the Maintainer role), or `developer` (users with the Developer or Maintainer role). | | `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. | -| `subgroup_creation_level` | string | no | Allowed to [create subgroups](../user/group/subgroups/index.md#creating-a-subgroup). Can be `owner` (Owners), or `maintainer` (users with the Maintainer role). | +| `subgroup_creation_level` | string | no | Allowed to [create subgroups](../user/group/subgroups/index.md#create-a-subgroup). Can be `owner` (Owners), or `maintainer` (users with the Maintainer role). | | `emails_disabled` | boolean | no | Disable email notifications | | `avatar` | mixed | no | Image file for avatar of the group. [Introduced in GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/issues/36681) | | `mentions_disabled` | boolean | no | Disable the capability of a group from getting mentioned | @@ -859,7 +859,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \ Transfer a group to a new parent group or turn a subgroup to a top-level group. Available to administrators and users: - With the Owner role for the group to transfer. -- With permission to [create a subgroup](../user/group/subgroups/index.md#creating-a-subgroup) in the new parent group if transferring a group. +- With permission to [create a subgroup](../user/group/subgroups/index.md#create-a-subgroup) in the new parent group if transferring a group. - With [permission to create a top-level group](../administration/user_settings.md#prevent-users-from-creating-top-level-groups) if turning a subgroup into a top-level group. ```plaintext @@ -899,7 +899,7 @@ PUT /groups/:id | `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). | | `project_creation_level` | string | no | Determine if developers can create projects in the group. Can be `noone` (No one), `maintainer` (users with the Maintainer role), or `developer` (users with the Developer or Maintainer role). | | `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. | -| `subgroup_creation_level` | string | no | Allowed to [create subgroups](../user/group/subgroups/index.md#creating-a-subgroup). Can be `owner` (Owners), or `maintainer` (users with the Maintainer role). | +| `subgroup_creation_level` | string | no | Allowed to [create subgroups](../user/group/subgroups/index.md#create-a-subgroup). Can be `owner` (Owners), or `maintainer` (users with the Maintainer role). | | `emails_disabled` | boolean | no | Disable email notifications | | `avatar` | mixed | no | Image file for avatar of the group. [Introduced in GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/issues/36681) | | `mentions_disabled` | boolean | no | Disable the capability of a group from getting mentioned | diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md index bc42a35f57a..02f2f5e7f75 100644 --- a/doc/user/admin_area/index.md +++ b/doc/user/admin_area/index.md @@ -224,6 +224,17 @@ You must be an administrator to manually add emails to users: The [Cohorts](user_cohorts.md) tab displays the monthly cohorts of new users and their activities over time. +### Prevent a user from creating groups + +By default, users can create groups. To prevent a user from creating groups: + +1. On the top bar, select **Menu > Admin**. +1. On the left sidebar, select **Overview > Users** (`/admin/users`). +1. Locate the user and select them. +1. Select **Edit**. +1. Clear the **Can create group** checkbox. +1. Select **Save changes**. + ### Administering Groups You can administer all groups in the GitLab instance from the Admin Area's Groups page. diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md index e6c21d6653a..a6343e0d1cf 100644 --- a/doc/user/discussions/index.md +++ b/doc/user/discussions/index.md @@ -36,10 +36,9 @@ Each object can have as many as 5,000 comments. ## Mentions -You can mention a user or a group present in your GitLab instance with `@username` or -`@groupname`. All mentioned users are notified with to-do items and emails. -Users can change this setting for themselves in the -[notification settings](../profile/notifications.md). +You can mention a user or a group (including [subgroups](../group/subgroups/index.md#mention-subgroups)) in your GitLab +instance with `@username` or `@groupname`. All mentioned users are notified with to-do items and emails. +Users can change this setting for themselves in the [notification settings](../profile/notifications.md). You can quickly see which comments involve you, because mentions for yourself (the user currently signed in) are highlighted diff --git a/doc/user/group/subgroups/img/mention_subgroups.png b/doc/user/group/subgroups/img/mention_subgroups.png Binary files differdeleted file mode 100644 index ec370add4f9..00000000000 --- a/doc/user/group/subgroups/img/mention_subgroups.png +++ /dev/null diff --git a/doc/user/group/subgroups/index.md b/doc/user/group/subgroups/index.md index d5fd1c7115a..a8107fecc88 100644 --- a/doc/user/group/subgroups/index.md +++ b/doc/user/group/subgroups/index.md @@ -2,118 +2,92 @@ stage: Manage group: Authentication and Authorization info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -type: reference, howto, concepts --- # Subgroups **(FREE)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/2772) in GitLab 9.0. -GitLab supports up to 20 levels of subgroups, also known as nested groups or hierarchical groups. - -By using subgroups you can do the following: - -- **Separate internal / external organizations.** Since every group - can have its own visibility level ([public, internal, or private](../../../development/permissions.md#general-permissions)), - you're able to host groups for different purposes under the same umbrella. -- **Organize large projects.** For large projects, subgroups makes it - potentially easier to separate permissions on parts of the source code. -- **Make it easier to manage people and control visibility.** Give people - different [permissions](../../permissions.md#group-members-permissions) depending on their group [membership](#membership). - -For more information on allowed permissions in groups and projects, see -[visibility levels](../../../development/permissions.md#general-permissions). - -## Overview - -A group can have many subgroups inside it, and at the same time a group can have -only one immediate parent group. It resembles a directory behavior or a nested items list: - -- Group 1 - - Group 1.1 - - Group 1.2 - - Group 1.2.1 - - Group 1.2.2 - - Group 1.2.2.1 - -In a real world example, imagine maintaining a GNU/Linux distribution with the -first group being the name of the distribution, and subsequent groups split as follows: - -- Organization Group - GNU/Linux distro - - Category Subgroup - Packages - - (project) Package01 - - (project) Package02 - - Category Subgroup - Software - - (project) Core - - (project) CLI - - (project) Android app - - (project) iOS app - - Category Subgroup - Infra tools - - (project) Ansible playbooks - -Another example of GitLab as a company would be the following: - -- Organization Group - GitLab - - Category Subgroup - Marketing - - (project) Design - - (project) General - - Category Subgroup - Software - - (project) GitLab CE - - (project) GitLab EE - - (project) Omnibus GitLab - - (project) GitLab Runner - - (project) GitLab Pages daemon - - Category Subgroup - Infra tools - - (project) Chef cookbooks - - Category Subgroup - Executive team - -When performing actions such as transferring or importing a project between -subgroups, the behavior is the same as when performing these actions at the -`group/project` level. - -## Creating a subgroup - -Users can create subgroups if they are explicitly added as an Owner (or -Maintainer, if that setting is enabled) to an immediate parent group, even if group -creation is disabled by an administrator in their settings. +You can organize GitLab [groups](../index.md) into subgroups. You can use subgroups to: + +- Separate internal and external organizations. Because every subgroup can have its own + [visibility level](../../../development/permissions.md#general-permissions), you can host groups for different + purposes under the same parent group. +- Organize large projects. You can use subgroups to give different access to parts of + the source code. +- Manage people and control visibility. Give a user a different + [role](../../permissions.md#group-members-permissions) for each group they're [a member of](#subgroup-membership). + +Subgroups can: + +- Belong to one immediate parent group. +- Have many subgroups. +- Be nested up to 20 levels. +- Use [runners](../../../ci/runners/index.md) registered to parent groups: + - Secrets configured for the parent group are available to subgroup jobs. + - Users with the Maintainer role in projects that belong to subgroups can see the details of runners registered to + parent groups. + +For example: + +```mermaid +graph TD + subgraph "Parent group" + subgraph "Subgroup A" + subgraph "Subgroup A1" + G["Project E"] + end + C["Project A"] + D["Project B"] + E["Project C"] + end + subgraph "Subgroup B" + F["Project D"] + end + end +``` + +## Create a subgroup + +Users with the at least the Maintainer role on a group can create subgroups immediately below the group, unless +[configured otherwise](#change-who-can-create-subgroups). These users can create subgroups even if group creation is +[disabled by an Administrator](../../admin_area/index.md#prevent-a-user-from-creating-groups) in the user's settings. To create a subgroup: 1. On the top bar, select **Menu > Groups** and find the parent group. 1. In the top right, select **New subgroup**. 1. Select **Create group**. -1. Fill in the fields. View a list of [reserved names](../../reserved_names.md) - that cannot be used as group names. +1. Fill in the fields. View a list of [reserved names](../../reserved_names.md) that cannot be used as group names. 1. Select **Create group**. ### Change who can create subgroups -To create a subgroup you must either be an Owner or a Maintainer of the -group, depending on the group's setting. +To create a subgroup, you must have at least the Maintainer role on the group, depending on the group's setting. By +default: -By default: +- In GitLab 12.2 or later, users with at least the Maintainer role can create subgroups. +- In GitLab 12.1 or earlier, only users with the Owner role can create subgroups. -- In GitLab 12.2 or later, both Owners and Maintainers can create subgroups. -- In GitLab 12.1 or earlier, only Owners can create subgroups. +To change who can create subgroups on a group: -You can change this setting: - -- As group owner: - 1. Select the group. +- As a user with the Owner role on the group: + 1. On the top bar, select **Menu > Groups** and find the group. 1. On the left sidebar, select **Settings > General**. 1. Expand **Permissions and group features**. + 1. Select a role from the **Allowed to create subgroups** dropdown. - As an administrator: 1. On the top bar, select **Menu > Admin**. 1. On the left sidebar, select **Overview > Groups**. 1. Select the group, and select **Edit**. + 1. Select a role from the **Allowed to create subgroups** dropdown. For more information, view the [permissions table](../../permissions.md#group-members-permissions). -## Membership +## Subgroup membership -When you add a member to a group, that member is also added to all subgroups. -Permission level is inherited from the group's parent. This model allows access to -subgroups if you have membership in one of its parents. +When you add a member to a group, that member is also added to all subgroups. The user's permissions are inherited from +the group's parent. Subgroup members can: @@ -145,76 +119,59 @@ flowchart RL G-->|Group C shared with Subgroup A|E ``` -Jobs for pipelines in subgroups can use [runners](../../../ci/runners/index.md) registered to the parent group(s). -This means secrets configured for the parent group are available to subgroup jobs. - -In addition, maintainers of projects that belong to subgroups can see the details of runners registered to parent group(s). +Group permissions for a member can be changed only by: -The group permissions for a member can be changed only by Owners, and only on -the **Members** page of the group the member was added. +- Users with the Owner role on the group. +- Changing the configuration of the group the member was added to. -You can tell if a member has inherited the permissions from a parent group by -looking at the group's **Members** page. +### Determine membership inheritance -![Group members page](img/group_members_v14_4.png) +To see if a member has inherited the permissions from a parent group: -From the image above, we can deduce the following things: +1. On the top bar, select **Menu > Groups** and find the group. +1. Select **Group information > Members**. -- There are 5 members that have access to the group `four`. -- User 0 is a Reporter and has inherited their permissions from group `one` - which is above the hierarchy of group `four`. -- User 1 is a Developer and has inherited their permissions from group - `one/two` which is above the hierarchy of group `four`. -- User 2 is a Developer and has inherited their permissions from group - `one/two/three` which is above the hierarchy of group `four`. -- For User 3 the **Source** column indicates **Direct member**, therefore they belong to - group `four`, the one we're inspecting. -- Administrator is the Owner and member of **all** subgroups and for that reason, - as with User 3, the **Source** column indicates **Direct member**. - -Members can be [filtered by inherited or direct membership](../index.md#filter-a-group). +Members list for an example subgroup _Four_: -### Overriding the ancestor group membership - -NOTE: -You must be an Owner of a group to be able to add members to it. - -NOTE: -A user's permissions in a subgroup cannot be lower than in any of its ancestor groups. -Therefore, you cannot reduce a user's permissions in a subgroup with respect to its ancestor groups. +![Group members page](img/group_members_v14_4.png) -To override a user's membership of an ancestor group (the first group they were -added to), add the user to the new subgroup again with a higher set of permissions. +In the screenshot above: + +- Five members have access to group _Four_. +- User 0 has the Reporter role on group _Four_, and has inherited their permissions from group _One_: + - User 0 is a direct member of group _One_. + - Group _One_ is above group _Four_ in the hierarchy. +- User 1 has the Developer role on group _Four_ and inherited their permissions from group _Two_: + - User 0 is a direct member of group _Two_, which is a subgroup of group _One_. + - Groups _One / Two_ are above group _Four_ in the hierarchy. +- User 2 has the Developer role on group _Four_ and has inherited their permissions from group _Three_: + - User 0 is a direct member of group _Three_, which is a subgroup of group _Two_. Group _Two_ is a subgroup of group + _One_. + - Groups _One / Two / Three_ are above group _Four_ the hierarchy. +- User 3 is a direct member of group _Four_. This means they get their Maintainer role directly from group _Four_. +- Administrator has the Owner role on group _Four_ and is a member of all subgroups. For that reason, as with User 3, + the **Source** column indicates they are a direct member. -For example, if User 1 was first added to group `one/two` with Developer -permissions, then they inherit those permissions in every other subgroup -of `one/two`. To give them the Maintainer role for group `one/two/three/four`, -you would add them again in that group as Maintainer. Removing them from that group, -the permissions fall back to those of the ancestor group. +Members can be [filtered by inherited or direct membership](../index.md#filter-a-group). -## Mentioning subgroups +### Override ancestor group membership -Mentioning groups (`@group`) in issues, commits and merge requests, would -notify all members of that group. Now with subgroups, there is more granular -support if you want to split your group's structure. Mentioning works as before -and you can choose the group of people to be notified. +Users with the Owner role on a subgroup can add members to it. -![Mentioning subgroups](img/mention_subgroups.png) +You can't give a user a role on a subgroup that's lower than the roles they have on ancestor groups. To override a user's +role on an ancestor group, add the user to the subgroup again with a higher role. For example: -## Limitations +- If User 1 is added to group _Two_ with the Developer role, they inherit that role in every subgroup of group _Two_. +- To give User 1 the Maintainer role on group _Four_ (under _One / Two / Three_), add them again to group _Four_ with + the Maintainer role. +- If User 1 is removed from group _Four_, their role falls back to their role on group _Two_. They have the Developer + role on group _Four_ again. -Here's a list of what you can't do with subgroups: +## Mention subgroups -- [GitLab Pages](../../project/pages/index.md) supports projects hosted under - a subgroup, but not subgroup websites. - That means that only the highest-level group supports - [group websites](../../project/pages/getting_started_part_one.md#gitlab-pages-default-domain-names), - although you can have project websites under a subgroup. -- It is not possible to share a project with a group that's an ancestor of - the group the project is in. That means you can only share as you walk down - the hierarchy. For example, `group/subgroup01/project` **cannot** be shared - with `group`, but can be shared with `group/subgroup02` or - `group/subgroup01/subgroup03`. +Mentioning subgroups ([`@<subgroup_name>`](../../discussions/index.md#mentions)) in issues, commits, and merge requests +notifies all members of that group. Mentioning works the same as for projects and groups, and you can choose the group +of people to be notified. <!-- ## Troubleshooting diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 3e22435d154..2e686e1d70b 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -274,13 +274,13 @@ More details about the permissions for some project-level features follow. | Stop [environments](../ci/environments/index.md) | | | | ✓ | ✓ | ✓ | | View a job with [debug logging](../ci/variables/index.md#debug-logging) | | | | ✓ | ✓ | ✓ | | Use pipeline editor | | | | ✓ | ✓ | ✓ | +| Run [interactive web terminals](../ci/interactive_web_terminal/index.md) | | | | ✓ | ✓ | ✓ | | Add specific runners to project | | | | | ✓ | ✓ | | Clear runner caches manually | | | | | ✓ | ✓ | | Enable shared runners in project | | | | | ✓ | ✓ | | Manage CI/CD settings | | | | | ✓ | ✓ | | Manage job triggers | | | | | ✓ | ✓ | | Manage project-level CI/CD variables | | | | | ✓ | ✓ | -| Run [interactive web terminals](../ci/interactive_web_terminal/index.md) | | | | | ✓ | ✓ | | Use [environment terminals](../ci/environments/index.md#web-terminals-deprecated) | | | | | ✓ | ✓ | | Delete pipelines | | | | | | ✓ | @@ -431,8 +431,7 @@ The following table lists group permissions available for each role: <!-- markdownlint-disable MD029 --> -1. Groups can be set to [allow either Owners or Owners and - Maintainers to create subgroups](group/subgroups/index.md#creating-a-subgroup) +1. Groups can be set to allow either Owners, or Owners and users with the Maintainer role, to [create subgroups](group/subgroups/index.md#create-a-subgroup). 2. Introduced in GitLab 12.2. 3. Default project creation role can be changed at: - The [instance level](admin_area/settings/visibility_and_access_controls.md#define-which-roles-can-create-projects). @@ -451,7 +450,7 @@ permission level from the parent group(s). This model allows access to nested groups if you have membership in one of its parents. To learn more, read through the documentation on -[subgroups memberships](group/subgroups/index.md#membership). +[subgroups memberships](group/subgroups/index.md#subgroup-membership). ## External users **(FREE SELF)** diff --git a/doc/user/project/members/share_project_with_groups.md b/doc/user/project/members/share_project_with_groups.md index 4e3bae2dc30..bebd0734151 100644 --- a/doc/user/project/members/share_project_with_groups.md +++ b/doc/user/project/members/share_project_with_groups.md @@ -15,7 +15,7 @@ Groups are used primarily to [create collections of projects](../../group/index. take advantage of the fact that groups define collections of _users_, namely the group members. -## Sharing a project with a group of users +## Share a project with a group of users NOTE: In GitLab 13.11, you can [replace this form with a modal window](#share-a-project-modal-window). @@ -89,7 +89,15 @@ Feature.disable(:invite_members_group_modal) In the example above, the maximum access level of 'Developer' for members from 'Engineering' means that users with higher access levels in 'Engineering' ('Maintainer' or 'Owner') only have 'Developer' access to 'Project Acme'. -## Sharing public project with private group +### Share a project with a subgroup + +You can't share a project with a group that's an ancestor of a [subgroup](../../group/subgroups/index.md) the project is +in. That means you can only share down the hierarchy. For example, `group/subgroup01/project`: + +- Can not be shared with `group`. +- Can be shared with `group/subgroup02` or `group/subgroup01/subgroup03`. + +## Share public project with private group When sharing a public project with a private group, owners and maintainers of the project see the name of the group in the `members` page. Owners also have the possibility to see members of the private group they don't have access to when mentioning them in the issue or merge request. diff --git a/doc/user/project/merge_requests/approvals/rules.md b/doc/user/project/merge_requests/approvals/rules.md index fa447ea35af..01772e59127 100644 --- a/doc/user/project/merge_requests/approvals/rules.md +++ b/doc/user/project/merge_requests/approvals/rules.md @@ -175,7 +175,7 @@ granting them push access: 1. [Create a new group](../../../group/index.md#create-a-group). 1. [Add the user to the group](../../../group/index.md#add-users-to-a-group), and select the Reporter role for the user. -1. [Share the project with your group](../../members/share_project_with_groups.md#sharing-a-project-with-a-group-of-users), +1. [Share the project with your group](../../members/share_project_with_groups.md#share-a-project-with-a-group-of-users), based on the Reporter role. 1. Go to your project and select **Settings > General**. 1. Expand **Merge request (MR) approvals**. diff --git a/doc/user/project/pages/getting_started_part_one.md b/doc/user/project/pages/getting_started_part_one.md index 32826346eab..5773dd1f2c0 100644 --- a/doc/user/project/pages/getting_started_part_one.md +++ b/doc/user/project/pages/getting_started_part_one.md @@ -34,7 +34,7 @@ Pages domains are `*.gitlab.io`. | Project pages owned by a subgroup | `subgroup/projectname` | `http(s)://groupname.example.io/subgroup/projectname`| WARNING: -There are some known [limitations](introduction.md#limitations) +There are some known [limitations](introduction.md#subdomains-of-subdomains) regarding namespaces served under the general domain name and HTTPS. Make sure to read that section. diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md index 65e1579001b..e4bc58854ef 100644 --- a/doc/user/project/pages/introduction.md +++ b/doc/user/project/pages/introduction.md @@ -76,17 +76,21 @@ website. ![Remove pages](img/remove_pages.png) -## Limitations +## Subdomains of subdomains -When using Pages under the general domain of a GitLab instance (`*.example.io`), -you _cannot_ use HTTPS with sub-subdomains. That means that if your -username or group name contains a dot, for example `foo.bar`, the domain -`https://foo.bar.example.io` does _not_ work. This is a limitation of the -[HTTP Over TLS protocol](https://tools.ietf.org/html/rfc2818#section-3.1). -HTTP pages continue to work provided you don't redirect HTTP to HTTPS. +When using Pages under the top-level domain of a GitLab instance (`*.example.io`), you can't use HTTPS with subdomains +of subdomains. If your namespace or group name contains a dot (for example, `foo.bar`) the domain +`https://foo.bar.example.io` does _not_ work. -GitLab Pages [does **not** support group websites for subgroups](../../group/subgroups/index.md#limitations). -You can only create the highest-level group website. +This limitation is because of the [HTTP Over TLS protocol](https://tools.ietf.org/html/rfc2818#section-3.1). HTTP pages +work as long as you don't redirect HTTP to HTTPS. + +## GitLab Pages and subgroups + +You must host your GitLab Pages website in a project. This project can belong to a [group](../../group/index.md) or +[subgroup](../../group/subgroups/index.md). For +[group websites](../../project/pages/getting_started_part_one.md#gitlab-pages-default-domain-names), the group must be +at the top level and not a subgroup. ## Specific configuration options for Pages diff --git a/lib/api/entities/project_integration.rb b/lib/api/entities/project_integration.rb index 649e4d015b8..155136d2f80 100644 --- a/lib/api/entities/project_integration.rb +++ b/lib/api/entities/project_integration.rb @@ -5,19 +5,8 @@ module API class ProjectIntegration < Entities::ProjectIntegrationBasic # Expose serialized properties expose :properties do |integration, options| - # TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 - - attributes = - if integration.data_fields_present? - integration.data_fields.as_json.keys - else - integration.properties.keys - end - - attributes &= integration.api_field_names - - attributes.each_with_object({}) do |attribute, hash| - hash[attribute] = integration.public_send(attribute) # rubocop:disable GitlabSecurity/PublicSend + integration.api_field_names.to_h do |name| + [name, integration.public_send(name)] # rubocop:disable GitlabSecurity/PublicSend end end end diff --git a/lib/gitlab/background_migration/backfill_member_namespace_for_group_members.rb b/lib/gitlab/background_migration/backfill_member_namespace_for_group_members.rb new file mode 100644 index 00000000000..1ed147d67c7 --- /dev/null +++ b/lib/gitlab/background_migration/backfill_member_namespace_for_group_members.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # Backfills the `members.member_namespace_id` column for `type=GroupMember` + class BackfillMemberNamespaceForGroupMembers + include Gitlab::Database::DynamicModelHelpers + + def perform(start_id, end_id, batch_table, batch_column, sub_batch_size, pause_ms) + parent_batch_relation = relation_scoped_to_range(batch_table, batch_column, start_id, end_id) + + parent_batch_relation.each_batch(column: batch_column, of: sub_batch_size) do |sub_batch| + batch_metrics.time_operation(:update_all) do + sub_batch.update_all('member_namespace_id=source_id') + end + + pause_ms = [0, pause_ms].max + sleep(pause_ms * 0.001) + end + end + + def batch_metrics + @batch_metrics ||= Gitlab::Database::BackgroundMigration::BatchMetrics.new + end + + private + + def relation_scoped_to_range(source_table, source_key_column, start_id, stop_id) + define_batchable_model(source_table, connection: ActiveRecord::Base.connection) + .joins('INNER JOIN namespaces ON members.source_id = namespaces.id') + .where(source_key_column => start_id..stop_id) + .where(type: 'GroupMember') + .where(source_type: 'Namespace') + .where(member_namespace_id: nil) + end + end + end +end diff --git a/lib/gitlab/import_export/base/relation_factory.rb b/lib/gitlab/import_export/base/relation_factory.rb index 8a8c74c302d..53dd6f8cd55 100644 --- a/lib/gitlab/import_export/base/relation_factory.rb +++ b/lib/gitlab/import_export/base/relation_factory.rb @@ -300,7 +300,7 @@ module Gitlab return cache[table_name] if cache.has_key?(table_name) index_exists = - ActiveRecord::Base.connection.index_exists?( + relation_class.connection.index_exists?( relation_class.table_name, importable_foreign_key, unique: true) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 64cc883dc68..91146bf5318 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -16705,7 +16705,7 @@ msgstr "" msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}" msgstr "" -msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with sub-subdomains. This means that if your username/groupname contains a dot it will not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages will continue to work provided you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}" +msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}" msgstr "" msgid "GitLabPages|With GitLab Pages you can host your static website directly from your GitLab repository. %{docs_link_start}Learn more.%{link_end}" @@ -28487,6 +28487,9 @@ msgstr "" msgid "ProjectQualitySummary|Failure" msgstr "" +msgid "ProjectQualitySummary|Get insight into the overall percentage of tests in your project that succeed, fail and are skipped." +msgstr "" + msgid "ProjectQualitySummary|Latest pipeline results" msgstr "" @@ -28505,6 +28508,12 @@ msgstr "" msgid "ProjectQualitySummary|See project Code Coverage Statistics" msgstr "" +msgid "ProjectQualitySummary|Set up test runs" +msgstr "" + +msgid "ProjectQualitySummary|Set up test runs (opens in a new tab)" +msgstr "" + msgid "ProjectQualitySummary|Skipped" msgstr "" diff --git a/spec/lib/gitlab/background_migration/backfill_member_namespace_for_group_members_spec.rb b/spec/lib/gitlab/background_migration/backfill_member_namespace_for_group_members_spec.rb new file mode 100644 index 00000000000..e1ef12a1479 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_member_namespace_for_group_members_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillMemberNamespaceForGroupMembers, :migration, schema: 20220120211832 do + let(:migration) { described_class.new } + let(:members_table) { table(:members) } + let(:namespaces_table) { table(:namespaces) } + + let(:table_name) { 'members' } + let(:batch_column) { :id } + let(:sub_batch_size) { 100 } + let(:pause_ms) { 0 } + + subject(:perform_migration) { migration.perform(1, 10, table_name, batch_column, sub_batch_size, pause_ms) } + + before do + namespaces_table.create!(id: 100, name: 'test1', path: 'test1', type: 'Group') + namespaces_table.create!(id: 101, name: 'test2', path: 'test2', type: 'Group') + namespaces_table.create!(id: 102, name: 'test3', path: 'test3', type: 'Group') + namespaces_table.create!(id: 201, name: 'test4', path: 'test4', type: 'Project') + + members_table.create!(id: 1, source_id: 100, source_type: 'Namespace', type: 'GroupMember', member_namespace_id: nil, access_level: 10, notification_level: 3) + members_table.create!(id: 2, source_id: 101, source_type: 'Namespace', type: 'GroupMember', member_namespace_id: nil, access_level: 10, notification_level: 3) + members_table.create!(id: 3, source_id: 102, source_type: 'Namespace', type: 'GroupMember', member_namespace_id: 102, access_level: 10, notification_level: 3) + members_table.create!(id: 4, source_id: 103, source_type: 'Project', type: 'ProjectMember', member_namespace_id: nil, access_level: 10, notification_level: 3) + members_table.create!(id: 5, source_id: 104, source_type: 'Project', type: 'ProjectMember', member_namespace_id: 201, access_level: 10, notification_level: 3) + end + + it 'backfills `member_namespace_id` for the selected records', :aggregate_failures do + expect(members_table.where(type: 'GroupMember', member_namespace_id: nil).count).to eq 2 + expect(members_table.where(type: 'ProjectMember', member_namespace_id: nil).count).to eq 1 + + queries = ActiveRecord::QueryRecorder.new do + perform_migration + end + + expect(queries.count).to eq(3) + expect(members_table.where(type: 'GroupMember', member_namespace_id: nil).count).to eq 0 + expect(members_table.where(type: 'GroupMember').pluck(:member_namespace_id)).to match_array([100, 101, 102]) + expect(members_table.where(type: 'ProjectMember', member_namespace_id: nil).count).to eq 1 + expect(members_table.where(type: 'ProjectMember').pluck(:member_namespace_id)).to match_array([nil, 201]) + end + + it 'tracks timings of queries' do + expect(migration.batch_metrics.timings).to be_empty + + expect { perform_migration }.to change { migration.batch_metrics.timings } + end +end diff --git a/spec/migrations/backfill_member_namespace_id_for_group_members_spec.rb b/spec/migrations/backfill_member_namespace_id_for_group_members_spec.rb new file mode 100644 index 00000000000..0c0acf85d41 --- /dev/null +++ b/spec/migrations/backfill_member_namespace_id_for_group_members_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe BackfillMemberNamespaceIdForGroupMembers do + let_it_be(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules background jobs for each batch of group members' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :members, + column_name: :id, + interval: described_class::INTERVAL + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/models/integration_spec.rb b/spec/models/integration_spec.rb index b8f75e8595e..c0bb0ba636d 100644 --- a/spec/models/integration_spec.rb +++ b/spec/models/integration_spec.rb @@ -732,14 +732,21 @@ RSpec.describe Integration do { name: 'password' }, { name: 'password_field' }, { name: 'some_safe_field' }, - { name: 'safe_field' } + { name: 'safe_field' }, + { name: 'url' }, + { name: 'trojan_horse', type: 'password' }, + { name: 'trojan_gift', type: 'gift' } ].shuffle end end end it 'filters out sensitive fields' do - expect(fake_integration.new).to have_attributes(api_field_names: match_array(%w[some_safe_field safe_field])) + safe_fields = %w[some_safe_field safe_field url trojan_gift] + + expect(fake_integration.new).to have_attributes( + api_field_names: match_array(safe_fields) + ) end end diff --git a/spec/workers/web_hook_worker_spec.rb b/spec/workers/web_hook_worker_spec.rb index dbdf7a2b978..e2ff36975c4 100644 --- a/spec/workers/web_hook_worker_spec.rb +++ b/spec/workers/web_hook_worker_spec.rb @@ -28,15 +28,6 @@ RSpec.describe WebHookWorker do .to change { Gitlab::WebHooks::RecursionDetection::UUID.instance.request_uuid }.to(uuid) end - it 'retrieves recursion detection data, reinstates it, and cleans it from payload when passed through as data', :request_store, :aggregate_failures do - uuid = SecureRandom.uuid - full_data = data.merge({ _gitlab_recursion_detection_request_uuid: uuid }) - - expect_next(WebHookService, project_hook, data.with_indifferent_access, hook_name, anything).to receive(:execute) - expect { subject.perform(project_hook.id, full_data, hook_name) } - .to change { Gitlab::WebHooks::RecursionDetection::UUID.instance.request_uuid }.to(uuid) - end - it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed |