Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-08 09:09:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-08 09:09:24 +0300
commitdabcc5d12d22ca30d83c986d6ca0b9b81e7ccbfc (patch)
tree402520b6779be27a17265dd10b978836e7955e53
parent72db8879531eb432b1d3b6957477543d59d94c49 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/organizations/shared/utils.js5
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue203
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue4
-rw-r--r--config/feature_flags/development/search_index_integrity.yml8
-rw-r--r--config/initializers/click_house.rb16
-rw-r--r--doc/development/documentation/testing.md16
-rw-r--r--doc/integration/advanced_search/elasticsearch.md5
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md12
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md27
-rw-r--r--gems/click_house-client/lib/click_house/client.rb4
-rw-r--r--gems/click_house-client/lib/click_house/client/configuration.rb12
-rw-r--r--gems/click_house-client/spec/click_house/client_spec.rb32
-rw-r--r--lib/click_house/logger.rb11
-rw-r--r--spec/frontend/organizations/shared/utils_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js13
-rw-r--r--spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js69
-rw-r--r--spec/frontend/vue_shared/components/groups_list/groups_list_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/groups_list/mock_data.js6
-rw-r--r--spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js17
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js7
-rw-r--r--spec/lib/gitlab/database/click_house_client_spec.rb19
24 files changed, 426 insertions, 104 deletions
diff --git a/app/assets/javascripts/organizations/shared/utils.js b/app/assets/javascripts/organizations/shared/utils.js
index 1a77242d6dc..c1aafefc553 100644
--- a/app/assets/javascripts/organizations/shared/utils.js
+++ b/app/assets/javascripts/organizations/shared/utils.js
@@ -17,7 +17,10 @@ export const formatProjects = (projects) =>
}));
export const formatGroups = (groups) =>
- groups.map(({ id, ...group }) => ({
+ groups.map(({ id, webUrl, ...group }) => ({
...group,
id: getIdFromGraphQLId(id),
+ webUrl,
+ editPath: `${webUrl}/-/edit`,
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
}));
diff --git a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
index 65a601ed927..a1ef1f30ebb 100644
--- a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
@@ -38,7 +38,16 @@ export default {
default: CONFIRM_DANGER_MODAL_CANCEL,
},
},
+ model: {
+ prop: 'visible',
+ event: 'change',
+ },
props: {
+ visible: {
+ type: Boolean,
+ required: false,
+ default: null,
+ },
modalId: {
type: String,
required: true,
@@ -89,12 +98,15 @@ export default {
<template>
<gl-modal
ref="modal"
+ :visible="visible"
:modal-id="modalId"
:data-testid="modalId"
:title="$options.i18n.CONFIRM_DANGER_MODAL_TITLE"
:action-primary="actionPrimary"
:action-cancel="actionCancel"
+ size="sm"
@primary="$emit('confirm')"
+ @change="$emit('change', $event)"
>
<gl-alert
v-if="confirmDangerMessage"
diff --git a/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue b/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue
index 7da45169fee..a375a167c68 100644
--- a/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue
+++ b/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue
@@ -24,6 +24,7 @@ export default {
:key="group.id"
:group="group"
:show-group-icon="showGroupIcon"
+ @delete="$emit('delete', $event)"
/>
</ul>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue b/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue
index 8a301cd0dd0..ca1e7400f2d 100644
--- a/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue
+++ b/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue
@@ -1,5 +1,6 @@
<script>
import { GlAvatarLabeled, GlIcon, GlTooltipDirective, GlTruncateText } from '@gitlab/ui';
+import uniqueId from 'lodash/uniqueId';
import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE } from '~/visibility_level/constants';
import { ACCESS_LEVEL_LABELS } from '~/access_level/constants';
@@ -7,6 +8,9 @@ import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.
import { __ } from '~/locale';
import { numberToMetricPrefix } from '~/lib/utils/number_utils';
import SafeHtml from '~/vue_shared/directives/safe_html';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+import ListActions from '~/vue_shared/components/list_actions/list_actions.vue';
+import DangerConfirmModal from '~/vue_shared/components/confirm_danger/confirm_danger_modal.vue';
export default {
i18n: {
@@ -25,6 +29,8 @@ export default {
GlIcon,
UserAccessRoleBadge,
GlTruncateText,
+ ListActions,
+ DangerConfirmModal,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -41,6 +47,12 @@ export default {
default: false,
},
},
+ data() {
+ return {
+ isDeleteModalVisible: false,
+ modalId: uniqueId('groups-list-item-modal-id-'),
+ };
+ },
computed: {
visibility() {
return this.group.visibility;
@@ -75,94 +87,131 @@ export default {
groupMembersCount() {
return numberToMetricPrefix(this.group.groupMembersCount);
},
+ actions() {
+ return {
+ [ACTION_EDIT]: {
+ href: this.group.editPath,
+ },
+ [ACTION_DELETE]: {
+ action: this.onActionDelete,
+ },
+ };
+ },
+ hasActions() {
+ return this.group.availableActions?.length;
+ },
+ hasActionDelete() {
+ return this.group.availableActions?.includes(ACTION_DELETE);
+ },
+ },
+ methods: {
+ onActionDelete() {
+ this.isDeleteModalVisible = true;
+ },
},
};
</script>
<template>
- <li class="groups-list-item gl-py-5 gl-md-display-flex gl-align-items-center gl-border-b">
- <div class="gl-display-flex gl-flex-grow-1">
- <gl-icon
- v-if="showGroupIcon"
- class="gl-mr-3 gl-mt-3 gl-md-mt-5 gl-flex-shrink-0 gl-text-secondary"
- :name="groupIconName"
- />
- <gl-avatar-labeled
- :entity-id="group.id"
- :entity-name="group.fullName"
- :label="group.fullName"
- :label-link="group.webUrl"
- shape="rect"
- :size="$options.avatarSize"
- >
- <template #meta>
- <div class="gl-px-2">
- <div class="gl-mx-n2 gl-display-flex gl-align-items-center gl-flex-wrap">
- <div class="gl-px-2">
- <gl-icon
- v-if="visibility"
- v-gl-tooltip="visibilityTooltip"
- :name="visibilityIcon"
- class="gl-text-secondary"
- />
- </div>
- <div class="gl-px-2">
- <user-access-role-badge v-if="shouldShowAccessLevel">{{
- accessLevelLabel
- }}</user-access-role-badge>
+ <li class="groups-list-item gl-py-5 gl-border-b gl-display-flex gl-align-items-flex-start">
+ <div class="gl-md-display-flex gl-align-items-center gl-flex-grow-1">
+ <div class="gl-display-flex gl-flex-grow-1">
+ <gl-icon
+ v-if="showGroupIcon"
+ class="gl-mr-3 gl-mt-3 gl-md-mt-5 gl-flex-shrink-0 gl-text-secondary"
+ :name="groupIconName"
+ />
+ <gl-avatar-labeled
+ :entity-id="group.id"
+ :entity-name="group.fullName"
+ :label="group.fullName"
+ :label-link="group.webUrl"
+ shape="rect"
+ :size="$options.avatarSize"
+ >
+ <template #meta>
+ <div class="gl-px-2">
+ <div class="gl-mx-n2 gl-display-flex gl-align-items-center gl-flex-wrap">
+ <div class="gl-px-2">
+ <gl-icon
+ v-if="visibility"
+ v-gl-tooltip="visibilityTooltip"
+ :name="visibilityIcon"
+ class="gl-text-secondary"
+ />
+ </div>
+ <div class="gl-px-2">
+ <user-access-role-badge v-if="shouldShowAccessLevel">{{
+ accessLevelLabel
+ }}</user-access-role-badge>
+ </div>
</div>
</div>
+ </template>
+ <gl-truncate-text
+ v-if="group.descriptionHtml"
+ :lines="2"
+ :mobile-lines="2"
+ :show-more-text="$options.i18n.showMore"
+ :show-less-text="$options.i18n.showLess"
+ class="gl-mt-2"
+ >
+ <div
+ v-safe-html:[$options.safeHtmlConfig]="group.descriptionHtml"
+ class="gl-font-sm md"
+ data-testid="group-description"
+ ></div>
+ </gl-truncate-text>
+ </gl-avatar-labeled>
+ </div>
+ <div
+ class="gl-md-display-flex gl-flex-direction-column gl-align-items-flex-end gl-flex-shrink-0 gl-mt-3 gl-md-pl-0 gl-md-mt-0 gl-md-ml-3"
+ :class="statsPadding"
+ >
+ <div class="gl-display-flex gl-align-items-center gl-gap-x-3">
+ <div
+ v-gl-tooltip="$options.i18n.subgroups"
+ :aria-label="$options.i18n.subgroups"
+ class="gl-text-secondary"
+ data-testid="subgroups-count"
+ >
+ <gl-icon name="subgroup" />
+ <span>{{ descendantGroupsCount }}</span>
</div>
- </template>
- <gl-truncate-text
- v-if="group.descriptionHtml"
- :lines="2"
- :mobile-lines="2"
- :show-more-text="$options.i18n.showMore"
- :show-less-text="$options.i18n.showLess"
- class="gl-mt-2"
- >
<div
- v-safe-html:[$options.safeHtmlConfig]="group.descriptionHtml"
- class="gl-font-sm md"
- data-testid="group-description"
- ></div>
- </gl-truncate-text>
- </gl-avatar-labeled>
- </div>
- <div
- class="gl-md-display-flex gl-flex-direction-column gl-align-items-flex-end gl-flex-shrink-0 gl-mt-3 gl-md-pl-0 gl-md-mt-0 gl-md-ml-3"
- :class="statsPadding"
- >
- <div class="gl-display-flex gl-align-items-center gl-gap-x-3">
- <div
- v-gl-tooltip="$options.i18n.subgroups"
- :aria-label="$options.i18n.subgroups"
- class="gl-text-secondary"
- data-testid="subgroups-count"
- >
- <gl-icon name="subgroup" />
- <span>{{ descendantGroupsCount }}</span>
- </div>
- <div
- v-gl-tooltip="$options.i18n.projects"
- :aria-label="$options.i18n.projects"
- class="gl-text-secondary"
- data-testid="projects-count"
- >
- <gl-icon name="project" />
- <span>{{ projectsCount }}</span>
- </div>
- <div
- v-gl-tooltip="$options.i18n.directMembers"
- :aria-label="$options.i18n.directMembers"
- class="gl-text-secondary"
- data-testid="members-count"
- >
- <gl-icon name="users" />
- <span>{{ groupMembersCount }}</span>
+ v-gl-tooltip="$options.i18n.projects"
+ :aria-label="$options.i18n.projects"
+ class="gl-text-secondary"
+ data-testid="projects-count"
+ >
+ <gl-icon name="project" />
+ <span>{{ projectsCount }}</span>
+ </div>
+ <div
+ v-gl-tooltip="$options.i18n.directMembers"
+ :aria-label="$options.i18n.directMembers"
+ class="gl-text-secondary"
+ data-testid="members-count"
+ >
+ <gl-icon name="users" />
+ <span>{{ groupMembersCount }}</span>
+ </div>
</div>
</div>
</div>
+ <list-actions
+ v-if="hasActions"
+ class="gl-ml-3 gl-md-align-self-center"
+ :actions="actions"
+ :available-actions="group.availableActions"
+ />
+
+ <danger-confirm-modal
+ v-if="hasActionDelete"
+ v-model="isDeleteModalVisible"
+ :modal-id="modalId"
+ :phrase="group.fullName"
+ @confirm="$emit('delete', group)"
+ />
</li>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue
index 96dc2007ecf..05ce007e615 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue
@@ -39,6 +39,13 @@ export default {
return n__('Apply %d suggestion', 'Apply %d suggestions', this.batchSuggestionsCount);
},
+ helperText() {
+ if (this.batchSuggestionsCount <= 1) {
+ return __('This also resolves this thread');
+ }
+
+ return __('This also resolves all related threads');
+ },
},
methods: {
onApply() {
@@ -78,6 +85,10 @@ export default {
@submit="onApply"
/>
+ <span class="gl-mt-2 gl-text-secondary">
+ {{ helperText }}
+ </span>
+
<gl-button
class="gl-w-auto! gl-mt-3 gl-align-self-end"
category="primary"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
index 855c7a449c4..8a0ca8ebac1 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
@@ -77,9 +77,7 @@ export default {
return this.inapplicableReason;
}
- return this.batchSuggestionsCount > 1
- ? __('This also resolves all related threads')
- : __('This also resolves this thread');
+ return false;
},
isDisableButton() {
return this.isApplying || !this.canApply;
diff --git a/config/feature_flags/development/search_index_integrity.yml b/config/feature_flags/development/search_index_integrity.yml
deleted file mode 100644
index 87a9536fede..00000000000
--- a/config/feature_flags/development/search_index_integrity.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: search_index_integrity
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112369
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392981
-milestone: '15.10'
-type: development
-group: group::global search
-default_enabled: true
diff --git a/config/initializers/click_house.rb b/config/initializers/click_house.rb
index 7230eab1b03..ecf1ccb97bf 100644
--- a/config/initializers/click_house.rb
+++ b/config/initializers/click_house.rb
@@ -17,6 +17,18 @@ ClickHouse::Client.configure do |config|
)
end
+ if Rails.env.development? || Rails.env.test?
+ config.logger = ::ClickHouse::Logger.build
+ config.log_proc = ->(query) do
+ structured_log(query.to_sql)
+ end
+ else
+ config.logger = Logger.new('/dev/null')
+ config.log_proc = ->(query) do
+ structured_log(query.to_redacted_sql)
+ end
+ end
+
config.json_parser = Gitlab::Json
config.http_post_proc = ->(url, headers, body) do
options = {
@@ -32,3 +44,7 @@ ClickHouse::Client.configure do |config|
ClickHouse::Client::Response.new(response.body, response.code, response.headers)
end
end
+
+def structured_log(query_string)
+ { query: query_string, correlation_id: Labkit::Correlation::CorrelationId.current_id.to_s }
+end
diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md
index 0c65e008436..c0f1d0028f9 100644
--- a/doc/development/documentation/testing.md
+++ b/doc/development/documentation/testing.md
@@ -507,7 +507,21 @@ To configure markdownlint in your editor, install one of the following as approp
To configure Vale in your editor, install one of the following as appropriate:
-- Sublime Text [`SublimeLinter-vale` package](https://packagecontrol.io/packages/SublimeLinter-vale).
+- 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:
+
+ ```json
+ "vale": {
+ "styles": [{
+ "mark_style": "outline",
+ "scope": "region.bluish",
+ "types": ["suggestion"]
+ }]
+ }
+ ```
+
+- [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).
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index 29554b405be..4af842915cf 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -547,10 +547,7 @@ Sometimes, you might want to abandon the unfinished reindex job and resume the i
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112369) in GitLab 15.10 [with a flag](../../administration/feature_flags.md) named `search_index_integrity`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/392981) in GitLab 16.0.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/392981) in GitLab 16.3.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the feature, an administrator can [disable the feature flag](../../administration/feature_flags.md) named `search_index_integrity`.
-On GitLab.com, this feature is available.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/392981) in GitLab 16.4. Feature flag `search_index_integrity` removed.
Index integrity detects and fixes missing repository data.
This feature is automatically used when code searches
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 531df693b4d..1ec04f5b3ee 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -98,6 +98,11 @@ the following sections and tables provide an alternative.
> - The `branch_type` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404774) in GitLab 16.1 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_type`. Disabled by default.
> - Generally available in GitLab 16.2. Feature flag `security_policies_branch_type` removed.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is not available.
This rule enforces the defined actions whenever the pipeline runs for a selected branch.
@@ -106,6 +111,7 @@ This rule enforces the defined actions whenever the pipeline runs for a selected
| `type` | `string` | true | `pipeline` | The rule's type. |
| `branches` <sup>1</sup> | `array` of `string` | true if `branch_type` field does not exist | `*` or the branch's name | The branch the given policy applies to (supports wildcard). |
| `branch_type` <sup>1</sup> | `string` | true if `branches` field does not exist | `default`, `protected` or `all` | The types of branches the given policy applies to. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
1. You must specify only one of `branches` or `branch_type`.
@@ -113,6 +119,11 @@ This rule enforces the defined actions whenever the pipeline runs for a selected
> - The `branch_type` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404774) in GitLab 16.1 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_type`. Disabled by default.
> - Generally available in GitLab 16.2. Feature flag `security_policies_branch_type` removed.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is not available.
This rule schedules a scan pipeline, enforcing the defined actions on the schedule defined in the `cadence` field. A scheduled pipeline does not run other jobs defined in the project's `.gitlab-ci.yml` file. When a project is linked to a security policy project, a security policy bot is created in the project and will become the author of any scheduled pipelines.
@@ -121,6 +132,7 @@ This rule schedules a scan pipeline, enforcing the defined actions on the schedu
| `type` | `string` | true | `schedule` | The rule's type. |
| `branches` <sup>1</sup> | `array` of `string` | true if either `branch_type` or `agents` fields does not exist | `*` or the branch's name | The branch the given policy applies to (supports wildcard). |
| `branch_type` <sup>1</sup> | `string` | true if either `branches` or `agents` fields does not exist | `default`, `protected` or `all` | The types of branches the given policy applies to. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `cadence` | `string` | true | CRON expression (for example, `0 0 * * *`) | A whitespace-separated string containing five fields that represents the scheduled time. Minimum of 15 minute intervals when used together with the `branches` field. |
| `timezone` | `string` | false | Time zone identifier (for example, `America/New_York`) | Time zone to apply to the cadence. Value must be an IANA Time Zone Database identifier. |
| `agents` <sup>1</sup> | `object` | true if either `branch_type` or `branches` fields do not exists | | The name of the [GitLab agents](../../clusters/agent/index.md) where [Operational Container Scanning](../../clusters/agent/vulnerabilities.md) runs. The object key is the name of the Kubernetes agent configured for your project in GitLab. |
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index f7b0f68e10c..60173bfb909 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -104,10 +104,16 @@ On GitLab.com, this feature is not available.
> - The scan result policy field `vulnerability_attributes` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123052) in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `enforce_vulnerability_attributes_rules`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/418784) in GitLab 16.3.
> - The scan result policy field `vulnerability_age` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123956) in GitLab 16.2.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Disabled by default.
FLAG:
On self-managed GitLab, by default the `vulnerability_attributes` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `enforce_vulnerability_attributes_rules`.
On GitLab.com, this feature is available.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is not available.
+
This rule enforces the defined actions based on security scan findings.
| Field | Type | Required | Possible values | Description |
@@ -115,6 +121,7 @@ This rule enforces the defined actions based on security scan findings.
| `type` | `string` | true | `scan_finding` | The rule's type. |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of branches the given policy applies to. Cannot be used with the `branches` field. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `scanners` | `array` of `string` | true | `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. `sast` includes results from both SAST and SAST IaC scanners. |
| `vulnerabilities_allowed` | `integer` | true | Greater than or equal to zero | Number of vulnerabilities allowed before this rule is considered. |
| `severity_levels` | `array` of `string` | true | `info`, `unknown`, `low`, `medium`, `high`, `critical` | The severity levels for this rule to consider. |
@@ -126,6 +133,11 @@ This rule enforces the defined actions based on security scan findings.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `license_scanning_policies`.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/397644) in GitLab 15.11. Feature flag `license_scanning_policies` removed.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is not available.
This rule enforces the defined actions based on license findings.
@@ -134,22 +146,29 @@ This rule enforces the defined actions based on license findings.
| `type` | `string` | true | `license_finding` | The rule's type. |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of branches the given policy applies to. Cannot be used with the `branches` field. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `match_on_inclusion` | `boolean` | true | `true`, `false` | Whether the rule matches inclusion or exclusion of licenses listed in `license_types`. |
| `license_types` | `array` of `string` | true | license types | [SPDX license names](https://spdx.org/licenses) to match on, for example `Affero General Public License v1.0` or `MIT License`. |
| `license_states` | `array` of `string` | true | `newly_detected`, `detected` | Whether to match newly detected and/or previously detected licenses. The `newly_detected` state triggers approval when either a new package is introduced or when a new license for an existing package is detected. |
## `any_merge_request` rule type
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418752) in GitLab 16.4.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418752) in GitLab 16.4.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is not available.
This rule enforces the defined actions for any merge request based on the commits signature.
| Field | Type | Required | Possible values | Description |
|---------------|---------------------|--------------------------------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `type` | `string` | true | `any_merge_request` | The rule's type. |
+| `type` | `string` | true | `any_merge_request` | The rule's type. |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
-| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of branches the given policy applies to. Cannot be used with the `branches` field. |
-| `commits` | `string` | true | `any`, `unsigned` | Whether the rule matches for any commits, or only if unsigned commits are detected in the merge request. |
+| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of branches the given policy applies to. Cannot be used with the `branches` field. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
+| `commits` | `string` | true | `any`, `unsigned` | Whether the rule matches for any commits, or only if unsigned commits are detected in the merge request. |
## `require_approval` action type
diff --git a/gems/click_house-client/lib/click_house/client.rb b/gems/click_house-client/lib/click_house/client.rb
index 2a9c5e402f5..1ca3653c45f 100644
--- a/gems/click_house-client/lib/click_house/client.rb
+++ b/gems/click_house-client/lib/click_house/client.rb
@@ -100,6 +100,10 @@ module ClickHouse
db = lookup_database(configuration, database)
query = ClickHouse::Client::Query.build(query)
+
+ log_contents = configuration.log_proc.call(query)
+ configuration.logger.info(log_contents)
+
ActiveSupport::Notifications.instrument('sql.click_house', { query: query, database: database }) do |instrument|
# Use a multipart POST request where the placeholders are sent with the param_ prefix
# See: https://github.com/ClickHouse/ClickHouse/issues/8842
diff --git a/gems/click_house-client/lib/click_house/client/configuration.rb b/gems/click_house-client/lib/click_house/client/configuration.rb
index 882b37993dc..4a71934466f 100644
--- a/gems/click_house-client/lib/click_house/client/configuration.rb
+++ b/gems/click_house-client/lib/click_house/client/configuration.rb
@@ -18,6 +18,9 @@ module ClickHouse
#
# *json_parser*: object for parsing JSON strings, it should respond to the "parse" method
#
+ # *logger*: object for receiving logger commands. Default `$stdout`
+ # *log_proc*: any output (e.g. structure) to wrap around the query for every statement
+ #
# Example:
#
# Gitlab::ClickHouse::Client.configure do |c|
@@ -31,6 +34,11 @@ module ClickHouse
# }
# )
#
+ # c.logger = MyLogger.new
+ # c.log_proc = ->(query) do
+ # { query_body: query.to_redacted_sql }
+ # end
+ #
# c.http_post_proc = lambda do |url, headers, body|
# options = {
# headers: headers,
@@ -44,13 +52,15 @@ module ClickHouse
#
# c.json_parser = JSON
# end
- attr_accessor :http_post_proc, :json_parser
+ attr_accessor :http_post_proc, :json_parser, :logger, :log_proc
attr_reader :databases
def initialize
@databases = {}
@http_post_proc = nil
@json_parser = JSON
+ @logger = ::Logger.new($stdout)
+ @log_proc = ->(query) { query.to_sql }
end
def register_database(name, **args)
diff --git a/gems/click_house-client/spec/click_house/client_spec.rb b/gems/click_house-client/spec/click_house/client_spec.rb
index 51cc097a228..ab2407a83d7 100644
--- a/gems/click_house-client/spec/click_house/client_spec.rb
+++ b/gems/click_house-client/spec/click_house/client_spec.rb
@@ -30,6 +30,9 @@ RSpec.describe ClickHouse::Client do
let(:configuration) do
ClickHouse::Client::Configuration.new.tap do |config|
+ config.log_proc = ->(query) do
+ { query_string: query.to_sql }
+ end
config.register_database(:test_db, **database_config)
config.http_post_proc = ->(_url, _headers, _query) {
body = File.read(query_result_fixture)
@@ -94,5 +97,34 @@ RSpec.describe ClickHouse::Client do
end.to raise_error(ClickHouse::Client::DatabaseError, 'some error')
end
end
+
+ describe 'default logging' do
+ let(:fake_logger) { instance_double("Logger", info: 'logged!') }
+ let(:query_string) { 'SELECT * FROM issues' }
+
+ before do
+ configuration.logger = fake_logger
+ end
+
+ shared_examples 'proper logging' do
+ it 'calls the custom logger and log_proc' do
+ expect(fake_logger).to receive(:info).at_least(:once).with({ query_string: query_string })
+
+ described_class.select(query_object, :test_db, configuration)
+ end
+ end
+
+ context 'when query is a string' do # rubocop:disable RSpec/MultipleMemoizedHelpers
+ let(:query_object) { query_string }
+
+ it_behaves_like 'proper logging'
+ end
+
+ context 'when query is a Query object' do # rubocop:disable RSpec/MultipleMemoizedHelpers
+ let(:query_object) { ClickHouse::Client::Query.new(raw_query: query_string) }
+
+ it_behaves_like 'proper logging'
+ end
+ end
end
end
diff --git a/lib/click_house/logger.rb b/lib/click_house/logger.rb
new file mode 100644
index 00000000000..90af644799b
--- /dev/null
+++ b/lib/click_house/logger.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module ClickHouse
+ class Logger < ::Gitlab::JsonLogger
+ exclude_context!
+
+ def self.file_name_noext
+ 'clickhouse'
+ end
+ end
+end
diff --git a/spec/frontend/organizations/shared/utils_spec.js b/spec/frontend/organizations/shared/utils_spec.js
index 2912db739c3..778a18ab2bc 100644
--- a/spec/frontend/organizations/shared/utils_spec.js
+++ b/spec/frontend/organizations/shared/utils_spec.js
@@ -29,7 +29,11 @@ describe('formatGroups', () => {
const formattedGroups = formatGroups(organizationGroups.nodes);
const [firstFormattedGroup] = formattedGroups;
- expect(firstFormattedGroup.id).toBe(getIdFromGraphQLId(firstMockGroup.id));
+ expect(firstFormattedGroup).toMatchObject({
+ id: getIdFromGraphQLId(firstMockGroup.id),
+ editPath: `${firstFormattedGroup.webUrl}/-/edit`,
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ });
expect(formattedGroups.length).toBe(organizationGroups.nodes.length);
});
});
diff --git a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
index 0b5c8d9afc3..53218d794c7 100644
--- a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
@@ -31,6 +31,7 @@ describe('Confirm Danger Modal', () => {
propsData: {
modalId,
phrase,
+ visible: false,
},
provide,
stubs: { GlSprintf },
@@ -103,4 +104,16 @@ describe('Confirm Danger Modal', () => {
expect(wrapper.emitted('confirm')).not.toBeUndefined();
});
});
+
+ describe('v-model', () => {
+ it('emit `change` event', () => {
+ findModal().vm.$emit('change', true);
+
+ expect(wrapper.emitted('change')).toEqual([[true]]);
+ });
+
+ it('sets `visible` prop', () => {
+ expect(findModal().props('visible')).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js b/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js
index 877de4f4695..cba9f78790d 100644
--- a/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js
+++ b/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js
@@ -9,6 +9,9 @@ import {
} from '~/visibility_level/constants';
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
import { ACCESS_LEVEL_LABELS } from '~/access_level/constants';
+import ListActions from '~/vue_shared/components/list_actions/list_actions.vue';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+import DangerConfirmModal from '~/vue_shared/components/confirm_danger/confirm_danger_modal.vue';
import { groups } from './mock_data';
describe('GroupsListItem', () => {
@@ -30,6 +33,8 @@ describe('GroupsListItem', () => {
const findAvatarLabeled = () => wrapper.findComponent(GlAvatarLabeled);
const findGroupDescription = () => wrapper.findByTestId('group-description');
const findVisibilityIcon = () => findAvatarLabeled().findComponent(GlIcon);
+ const findListActions = () => wrapper.findComponent(ListActions);
+ const findConfirmationModal = () => wrapper.findComponent(DangerConfirmModal);
it('renders group avatar', () => {
createComponent();
@@ -179,4 +184,68 @@ describe('GroupsListItem', () => {
expect(wrapper.findByTestId('group-icon').exists()).toBe(false);
});
});
+
+ describe('when group has actions', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays actions dropdown', () => {
+ expect(findListActions().props()).toMatchObject({
+ actions: {
+ [ACTION_EDIT]: {
+ href: group.editPath,
+ },
+ [ACTION_DELETE]: {
+ action: expect.any(Function),
+ },
+ },
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ });
+ });
+
+ describe('when delete action is fired', () => {
+ beforeEach(() => {
+ findListActions().props('actions')[ACTION_DELETE].action();
+ });
+
+ it('displays confirmation modal with correct props', () => {
+ expect(findConfirmationModal().props()).toMatchObject({
+ visible: true,
+ phrase: group.fullName,
+ });
+ });
+
+ describe('when deletion is confirmed', () => {
+ beforeEach(() => {
+ findConfirmationModal().vm.$emit('confirm');
+ });
+
+ it('emits `delete` event', () => {
+ expect(wrapper.emitted('delete')).toMatchObject([[group]]);
+ });
+ });
+ });
+ });
+
+ describe('when group does not have actions', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ group: {
+ ...group,
+ availableActions: [],
+ },
+ },
+ });
+ });
+
+ it('does not display actions dropdown', () => {
+ expect(findListActions().exists()).toBe(false);
+ });
+
+ it('does not display confirmation modal', () => {
+ expect(findConfirmationModal().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js b/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js
index c65aa347bcf..ec6a1dc9576 100644
--- a/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js
+++ b/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js
@@ -31,4 +31,18 @@ describe('GroupsList', () => {
})),
);
});
+
+ describe('when `GroupsListItem` emits `delete` event', () => {
+ const [firstGroup] = defaultPropsData.groups;
+
+ beforeEach(() => {
+ createComponent();
+
+ wrapper.findComponent(GroupsListItem).vm.$emit('delete', firstGroup);
+ });
+
+ it('emits `delete` event', () => {
+ expect(wrapper.emitted('delete')).toEqual([[firstGroup]]);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/groups_list/mock_data.js b/spec/frontend/vue_shared/components/groups_list/mock_data.js
index 0dad27f8311..08ee962892c 100644
--- a/spec/frontend/vue_shared/components/groups_list/mock_data.js
+++ b/spec/frontend/vue_shared/components/groups_list/mock_data.js
@@ -1,3 +1,5 @@
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+
export const groups = [
{
id: 1,
@@ -14,6 +16,8 @@ export const groups = [
accessLevel: {
integerValue: 10,
},
+ editPath: 'http://127.0.0.1:3000/groups/gitlab-org/-/edit',
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
},
{
id: 2,
@@ -31,5 +35,7 @@ export const groups = [
accessLevel: {
integerValue: 20,
},
+ editPath: 'http://127.0.0.1:3000/groups/gitlab-org/test-subgroup/-/edit',
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
},
];
diff --git a/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js b/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
index e3d896ca93e..cdbdbfab9d1 100644
--- a/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
@@ -14,6 +14,7 @@ describe('Apply Suggestion component', () => {
const findTextArea = () => wrapper.findComponent(GlFormTextarea);
const findApplyButton = () => wrapper.findComponent(GlButton);
const findAlert = () => wrapper.findComponent(GlAlert);
+ const findHelpText = () => wrapper.find('span');
beforeEach(() => createWrapper());
@@ -41,6 +42,22 @@ describe('Apply Suggestion component', () => {
});
});
+ describe('help text', () => {
+ describe('when applying a single suggestion', () => {
+ it('renders the correct help text', () => {
+ expect(findHelpText().text()).toEqual('This also resolves this thread');
+ });
+ });
+
+ describe('when applying in batch', () => {
+ it('renders the correct help text', () => {
+ createWrapper({ batchSuggestionsCount: 3 });
+
+ expect(findHelpText().text()).toEqual('This also resolves all related threads');
+ });
+ });
+ });
+
describe('disabled', () => {
it('disables the dropdown', () => {
createWrapper({ disabled: true });
diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
index 9768bc7a6dd..bc82357cb81 100644
--- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
@@ -219,12 +219,11 @@ describe('Suggestion Diff component', () => {
describe('tooltip message for apply button', () => {
const findTooltip = () => getBinding(findApplyButton().element, 'gl-tooltip');
- it('renders correct tooltip message when button is applicable', () => {
- createComponent({ batchSuggestionsCount: 0 });
+ it('renders no tooltip message when button is applicable', () => {
+ createComponent({ batchSuggestionsCount: 1, isBatched: true });
const tooltip = findTooltip();
- expect(tooltip.modifiers.viewport).toBe(true);
- expect(tooltip.value).toBe('This also resolves this thread');
+ expect(tooltip.value).toBe(false);
});
it('renders the inapplicable reason in the tooltip when button is not applicable', () => {
diff --git a/spec/lib/gitlab/database/click_house_client_spec.rb b/spec/lib/gitlab/database/click_house_client_spec.rb
index 8e4a474cc9b..6e63ae56557 100644
--- a/spec/lib/gitlab/database/click_house_client_spec.rb
+++ b/spec/lib/gitlab/database/click_house_client_spec.rb
@@ -115,4 +115,23 @@ RSpec.describe 'ClickHouse::Client', :click_house, feature_category: :database d
end
end
end
+
+ describe 'logging' do
+ let(:query_string) { "SELECT * FROM events WHERE id IN (4, 5, 6)" }
+
+ context 'on dev and test environments' do
+ it 'logs the un-redacted query' do
+ expect(ClickHouse::Client.configuration.logger).to receive(:info).with({
+ query: query_string,
+ correlation_id: a_kind_of(String)
+ })
+
+ ClickHouse::Client.select(query_string, :main)
+ end
+
+ it 'has a ClickHouse logger' do
+ expect(ClickHouse::Client.configuration.logger).to be_a(ClickHouse::Logger)
+ end
+ end
+ end
end