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:
-rw-r--r--.browserslistrc4
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml4
-rw-r--r--app/assets/javascripts/diffs/components/diff_row.vue32
-rw-r--r--app/assets/javascripts/diffs/components/pre_renderer.vue9
-rw-r--r--app/assets/javascripts/pages/projects/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue12
-rw-r--r--app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue68
-rw-r--r--app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql4
-rw-r--r--app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue5
-rw-r--r--app/assets/javascripts/projects/terraform_notification/components/terraform_notification.vue65
-rw-r--r--app/assets/javascripts/projects/terraform_notification/index.js18
-rw-r--r--app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue41
-rw-r--r--app/assets/javascripts/security_configuration/components/redesigned_app.vue24
-rw-r--r--app/assets/javascripts/security_configuration/index.js10
-rw-r--r--app/assets/stylesheets/utilities.scss31
-rw-r--r--app/helpers/projects_helper.rb7
-rw-r--r--app/models/repository_language.rb4
-rw-r--r--app/models/user_callout.rb3
-rw-r--r--app/views/admin/application_settings/_help_page.html.haml6
-rw-r--r--app/views/admin/application_settings/preferences.html.haml5
-rw-r--r--app/views/help/index.html.haml2
-rw-r--r--app/views/layouts/minimal.html.haml2
-rw-r--r--app/views/projects/_flash_messages.html.haml1
-rw-r--r--app/views/projects/_terraform_banner.html.haml5
-rw-r--r--babel.config.js4
-rw-r--r--config/feature_flags/development/ci_scoped_job_token.yml2
-rw-r--r--db/migrate/20210709132707_change_default_job_token_scope_enabled.rb17
-rw-r--r--db/schema_migrations/202107091327071
-rw-r--r--db/structure.sql2
-rw-r--r--doc/administration/geo/setup/database.md18
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md1
-rw-r--r--doc/administration/postgresql/replication_and_failover.md205
-rw-r--r--doc/administration/reference_architectures/10k_users.md10
-rw-r--r--doc/administration/reference_architectures/25k_users.md12
-rw-r--r--doc/administration/reference_architectures/3k_users.md12
-rw-r--r--doc/administration/reference_architectures/50k_users.md14
-rw-r--r--doc/administration/reference_architectures/5k_users.md10
-rw-r--r--doc/api/graphql/reference/index.md1
-rw-r--r--doc/api/index.md26
-rw-r--r--doc/ci/pipeline_editor/index.md3
-rw-r--r--doc/subscriptions/bronze_starter.md2
-rw-r--r--doc/user/admin_area/settings/help_page.md47
-rw-r--r--doc/user/admin_area/settings/img/help_page_help_text_ex_v12_3.pngbin48882 -> 0 bytes
-rw-r--r--doc/user/admin_area/settings/img/help_page_help_text_v12_3.pngbin19190 -> 0 bytes
-rw-r--r--doc/user/search/advanced_search.md6
-rw-r--r--lib/gitlab/ci/pipeline/seed/build.rb11
-rw-r--r--lib/gitlab/kas/client.rb8
-rw-r--r--lib/gitlab/metrics/subscribers/action_cable.rb22
-rw-r--r--locale/gitlab.pot60
-rw-r--r--spec/features/admin/admin_settings_spec.rb4
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js31
-rw-r--r--spec/frontend/pipeline_editor/pipeline_editor_app_spec.js10
-rw-r--r--spec/frontend/projects/terraform_notification/terraform_notification_spec.js62
-rw-r--r--spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js55
-rw-r--r--spec/frontend/security_configuration/components/redesigned_app_spec.js45
-rw-r--r--spec/helpers/projects_helper_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb14
-rw-r--r--spec/lib/gitlab/kas/client_spec.rb19
-rw-r--r--spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb13
-rw-r--r--spec/models/project_ci_cd_setting_spec.rb4
-rw-r--r--spec/requests/git_http_spec.rb8
-rw-r--r--spec/requests/lfs_http_spec.rb4
-rw-r--r--spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb144
-rw-r--r--spec/views/projects/_flash_messages.html.haml_spec.rb69
65 files changed, 1142 insertions, 231 deletions
diff --git a/.browserslistrc b/.browserslistrc
index 7c2e6fb4b75..a608ac7c734 100644
--- a/.browserslistrc
+++ b/.browserslistrc
@@ -6,11 +6,11 @@
# - We should support the latest ESR of Firefox: 78, because it used quite a lot.
# - We use Edge/Chrome >= 84 because 83 had an annoying bug which would mean we
# need to polyfill Array.reduce: https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
-# - Safari 13 because it is the second latest major version of Safari
+# - Safari 13.1 because it is the current minor version of the previous major version
#
# See also this epic: https://gitlab.com/groups/gitlab-org/-/epics/3957
#
chrome >= 84
edge >= 84
firefox >= 78
-safari >= 13.0.4
+safari >= 13.1
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 8d030b33cbc..c97ef4fc868 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -224,6 +224,7 @@
.code-patterns: &code-patterns
- "{package.json,yarn.lock}"
+ - ".browserslistrc"
- "babel.config.js"
- "jest.config.{base,integration,unit}.js"
- ".csscomb.json"
@@ -249,6 +250,7 @@
.code-backstage-patterns: &code-backstage-patterns
- "{package.json,yarn.lock}"
+ - ".browserslistrc"
- "babel.config.js"
- "jest.config.{base,integration,unit}.js"
- ".csscomb.json"
@@ -277,6 +279,7 @@
.code-qa-patterns: &code-qa-patterns
- "{package.json,yarn.lock}"
+ - ".browserslistrc"
- "babel.config.js"
- "jest.config.{base,integration,unit}.js"
- ".csscomb.json"
@@ -301,6 +304,7 @@
.code-backstage-qa-patterns: &code-backstage-qa-patterns
- "{package.json,yarn.lock}"
+ - ".browserslistrc"
- "babel.config.js"
- "jest.config.{base,integration,unit}.js"
- ".csscomb.json"
diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue
index 734f9258c58..c310bd9f31a 100644
--- a/app/assets/javascripts/diffs/components/diff_row.vue
+++ b/app/assets/javascripts/diffs/components/diff_row.vue
@@ -140,6 +140,16 @@ export default {
},
(line) => line.type,
),
+ lineContent: memoize(
+ (line) => {
+ if (line.isConflictMarker) {
+ return line.type === CONFLICT_MARKER_THEIR ? 'HEAD//our changes' : 'origin//their changes';
+ }
+
+ return line.rich_text;
+ },
+ (line) => line.line_code,
+ ),
CONFLICT_MARKER,
CONFLICT_MARKER_THEIR,
CONFLICT_OUR,
@@ -261,15 +271,14 @@ export default {
</div>
<div
:key="props.line.left.line_code"
- :class="[$options.parallelViewLeftLineType(props), { parallel: !props.inline }]"
+ :class="[
+ $options.parallelViewLeftLineType(props),
+ { parallel: !props.inline, 'gl-font-weight-bold': props.line.left.isConflictMarker },
+ ]"
class="diff-td line_content with-coverage left-side"
data-testid="left-content"
- >
- <strong v-if="props.line.left.isConflictMarker">{{
- $options.conflictText(props.line.left)
- }}</strong>
- <span v-else v-html="props.line.left.rich_text"></span>
- </div>
+ v-html="$options.lineContent(props.line.left)"
+ ></div>
</template>
<template
v-else-if="
@@ -386,15 +395,12 @@ export default {
{
hll: props.isHighlighted,
hll: props.isCommented,
+ 'gl-font-weight-bold': props.line.right.type === $options.CONFLICT_MARKER_THEIR,
},
]"
class="diff-td line_content with-coverage right-side parallel"
- >
- <strong v-if="props.line.right.type === $options.CONFLICT_MARKER_THEIR">{{
- $options.conflictText(props.line.right)
- }}</strong>
- <span v-else v-html="props.line.right.rich_text"></span>
- </div>
+ v-html="$options.lineContent(props.line.right)"
+ ></div>
</template>
<template v-else>
<div data-testid="right-empty-cell" class="diff-td diff-line-num old_line empty-cell"></div>
diff --git a/app/assets/javascripts/diffs/components/pre_renderer.vue b/app/assets/javascripts/diffs/components/pre_renderer.vue
index 4e69a2c064e..c357aa2d924 100644
--- a/app/assets/javascripts/diffs/components/pre_renderer.vue
+++ b/app/assets/javascripts/diffs/components/pre_renderer.vue
@@ -17,6 +17,7 @@ export default {
},
mounted() {
this.width = this.$el.parentNode.offsetWidth;
+ window.test = this;
this.$_itemsWithSizeWatcher = this.$watch('vscrollParent.itemsWithSize', async () => {
await this.$nextTick();
@@ -27,6 +28,14 @@ export default {
this.startedRender = true;
requestIdleCallback(() => {
this.nextItem = nextItem;
+
+ if (this.nextIndex === this.maxLength - 1) {
+ this.$nextTick(() => {
+ if (this.vscrollParent.itemsWithSize[this.maxLength - 1].size !== 0) {
+ this.clearRendering();
+ }
+ });
+ }
});
} else if (this.startedRender) {
this.clearRendering();
diff --git a/app/assets/javascripts/pages/projects/index.js b/app/assets/javascripts/pages/projects/index.js
index 1eab3becbc3..8ec6e5e66b3 100644
--- a/app/assets/javascripts/pages/projects/index.js
+++ b/app/assets/javascripts/pages/projects/index.js
@@ -1,7 +1,9 @@
import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation';
+import initTerraformNotification from '../../projects/terraform_notification';
import { initSidebarTracking } from '../shared/nav/sidebar_tracking';
import Project from './project';
new Project(); // eslint-disable-line no-new
new ShortcutsNavigation(); // eslint-disable-line no-new
initSidebarTracking();
+initTerraformNotification();
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
index 11e6b4577e0..6fcaa3ab04b 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
@@ -104,6 +104,11 @@ export default {
required: false,
default: '',
},
+ issuesHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
lfsHelpPath: {
type: String,
required: false,
@@ -438,8 +443,13 @@ export default {
>
<project-setting-row
ref="issues-settings"
+ :help-path="issuesHelpPath"
:label="$options.i18n.issuesLabel"
- :help-text="s__('ProjectSettings|Lightweight issue tracking system.')"
+ :help-text="
+ s__(
+ 'ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project.',
+ )
+ "
>
<project-feature-setting
v-model="issuesAccessLevel"
diff --git a/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue b/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue
index 73c91839f04..853e839a7ab 100644
--- a/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue
+++ b/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue
@@ -1,27 +1,18 @@
<script>
-import { GlAlert, GlLink, GlSprintf, GlIcon } from '@gitlab/ui';
+import { GlIcon } from '@gitlab/ui';
import { uniqueId } from 'lodash';
-import { helpPagePath } from '~/helpers/help_page_helper';
import { s__ } from '~/locale';
import SourceEditor from '~/vue_shared/components/source_editor.vue';
-import getCurrentBranch from '../../graphql/queries/client/current_branch.graphql';
export default {
i18n: {
viewOnlyMessage: s__('Pipelines|Merged YAML is view only'),
- unavailableDefaultTitle: s__('Pipelines|Merged YAML unavailable'),
- unavailableDefaultText: s__(
- 'Pipelines|The merged YAML view is only available for the default branch. %{linkStart}Learn more.%{linkEnd}',
- ),
},
components: {
SourceEditor,
- GlAlert,
GlIcon,
- GlLink,
- GlSprintf,
},
- inject: ['ciConfigPath', 'defaultBranch'],
+ inject: ['ciConfigPath'],
props: {
ciConfigData: {
type: Object,
@@ -33,15 +24,6 @@ export default {
failureType: null,
};
},
- // This is not the best practice, don't copy me (@samdbeckham)
- // This is a temporary workaround to unblock a release.
- // See this comment for more information on this approach
- // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65972#note_626095648
- apollo: {
- currentBranch: {
- query: getCurrentBranch,
- },
- },
computed: {
fileGlobalId() {
return `${this.ciConfigPath}-${uniqueId()}`;
@@ -49,44 +31,24 @@ export default {
mergedYaml() {
return this.ciConfigData.mergedYaml;
},
- isOnDefaultBranch() {
- return this.currentBranch === this.defaultBranch;
- },
- expandedConfigHelpPath() {
- return helpPagePath('ci/pipeline_editor/index', { anchor: 'view-expanded-configuration' });
- },
},
};
</script>
<template>
<div>
- <div v-if="isOnDefaultBranch">
- <div class="gl-display-flex gl-align-items-center">
- <gl-icon :size="16" name="lock" class="gl-text-gray-500 gl-mr-3" />
- {{ $options.i18n.viewOnlyMessage }}
- </div>
- <div class="gl-mt-3 gl-border-solid gl-border-gray-100 gl-border-1">
- <source-editor
- ref="editor"
- :value="mergedYaml"
- :file-name="ciConfigPath"
- :file-global-id="fileGlobalId"
- :editor-options="{ readOnly: true }"
- v-on="$listeners"
- />
- </div>
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-icon :size="16" name="lock" class="gl-text-gray-500 gl-mr-3" />
+ {{ $options.i18n.viewOnlyMessage }}
+ </div>
+ <div class="gl-mt-3 gl-border-solid gl-border-gray-100 gl-border-1">
+ <source-editor
+ ref="editor"
+ :value="mergedYaml"
+ :file-name="ciConfigPath"
+ :file-global-id="fileGlobalId"
+ :editor-options="{ readOnly: true }"
+ v-on="$listeners"
+ />
</div>
- <gl-alert
- v-else
- variant="info"
- :dismissible="false"
- :title="$options.i18n.unavailableDefaultTitle"
- >
- <gl-sprintf :message="$options.i18n.unavailableDefaultText">
- <template #link="{ content }">
- <gl-link :href="expandedConfigHelpPath" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </gl-alert>
</div>
</template>
diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql
index 30c18a96536..df7de6a1f54 100644
--- a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql
+++ b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql
@@ -1,7 +1,7 @@
#import "~/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql"
-query getCiConfigData($projectPath: ID!, $content: String!) {
- ciConfig(projectPath: $projectPath, content: $content) {
+query getCiConfigData($projectPath: ID!, $sha: String, $content: String!) {
+ ciConfig(projectPath: $projectPath, sha: $sha, content: $content) {
errors
mergedYaml
status
diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue
index 758c8c51a5b..0e8a6805a59 100644
--- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue
+++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue
@@ -20,6 +20,7 @@ import updateCommitShaMutation from './graphql/mutations/update_commit_sha.mutat
import getBlobContent from './graphql/queries/blob_content.graphql';
import getCiConfigData from './graphql/queries/ci_config.graphql';
import getAppStatus from './graphql/queries/client/app_status.graphql';
+import getCommitSha from './graphql/queries/client/commit_sha.graphql';
import getCurrentBranch from './graphql/queries/client/current_branch.graphql';
import getIsNewCiConfigFile from './graphql/queries/client/is_new_ci_config_file.graphql';
import getTemplate from './graphql/queries/get_starter_template.query.graphql';
@@ -128,6 +129,7 @@ export default {
variables() {
return {
projectPath: this.projectFullPath,
+ sha: this.commitSha,
content: this.currentCiFileContent,
};
},
@@ -153,6 +155,9 @@ export default {
appStatus: {
query: getAppStatus,
},
+ commitSha: {
+ query: getCommitSha,
+ },
currentBranch: {
query: getCurrentBranch,
},
diff --git a/app/assets/javascripts/projects/terraform_notification/components/terraform_notification.vue b/app/assets/javascripts/projects/terraform_notification/components/terraform_notification.vue
new file mode 100644
index 00000000000..0b398eddc9c
--- /dev/null
+++ b/app/assets/javascripts/projects/terraform_notification/components/terraform_notification.vue
@@ -0,0 +1,65 @@
+<script>
+import { GlBanner } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { parseBoolean, setCookie, getCookie } from '~/lib/utils/common_utils';
+import { s__ } from '~/locale';
+
+export default {
+ name: 'TerraformNotification',
+ i18n: {
+ title: s__('TerraformBanner|Using Terraform? Try the GitLab Managed Terraform State'),
+ description: s__(
+ 'TerraformBanner|The GitLab managed Terraform state backend can store your Terraform state easily and securely, and spares you from setting up additional remote resources. Its features include: versioning, encryption of the state file both in transit and at rest, locking, and remote Terraform plan/apply execution.',
+ ),
+ buttonText: s__("TerraformBanner|Learn more about GitLab's Backend State"),
+ },
+ components: {
+ GlBanner,
+ },
+ props: {
+ projectId: {
+ type: Number,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isVisible: true,
+ };
+ },
+ computed: {
+ bannerDissmisedKey() {
+ return `terraform_notification_dismissed_for_project_${this.projectId}`;
+ },
+ docsUrl() {
+ return helpPagePath('user/infrastructure/terraform_state');
+ },
+ },
+ created() {
+ if (parseBoolean(getCookie(this.bannerDissmisedKey))) {
+ this.isVisible = false;
+ }
+ },
+ methods: {
+ handleClose() {
+ setCookie(this.bannerDissmisedKey, true);
+ this.isVisible = false;
+ },
+ },
+};
+</script>
+<template>
+ <div v-if="isVisible">
+ <div class="gl-py-5">
+ <gl-banner
+ :title="$options.i18n.title"
+ :button-text="$options.i18n.buttonText"
+ :button-link="docsUrl"
+ variant="introduction"
+ @close="handleClose"
+ >
+ <p>{{ $options.i18n.description }}</p>
+ </gl-banner>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/projects/terraform_notification/index.js b/app/assets/javascripts/projects/terraform_notification/index.js
new file mode 100644
index 00000000000..eb04f109a8e
--- /dev/null
+++ b/app/assets/javascripts/projects/terraform_notification/index.js
@@ -0,0 +1,18 @@
+import Vue from 'vue';
+import TerraformNotification from './components/terraform_notification.vue';
+
+export default () => {
+ const el = document.querySelector('.js-terraform-notification');
+
+ if (!el) {
+ return false;
+ }
+
+ const { projectId } = el.dataset;
+
+ return new Vue({
+ el,
+ render: (createElement) =>
+ createElement(TerraformNotification, { props: { projectId: Number(projectId) } }),
+ });
+};
diff --git a/app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue b/app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue
new file mode 100644
index 00000000000..ce6a1b4888b
--- /dev/null
+++ b/app/assets/javascripts/security_configuration/components/auto_dev_ops_alert.vue
@@ -0,0 +1,41 @@
+<script>
+import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+export default {
+ components: {
+ GlSprintf,
+ GlAlert,
+ GlLink,
+ },
+ inject: ['autoDevopsHelpPagePath', 'autoDevopsPath'],
+ i18n: {
+ primaryButtonText: s__('SecurityConfiguration|Enable Auto DevOps'),
+ body: s__(
+ 'SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}',
+ ),
+ },
+ methods: {
+ dismissMethod() {
+ this.$emit('dismiss');
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-alert
+ variant="info"
+ :primary-button-link="autoDevopsPath"
+ :primary-button-text="$options.i18n.primaryButtonText"
+ @dismiss="dismissMethod"
+ >
+ <gl-sprintf :message="$options.i18n.body">
+ <template #link="{ content }">
+ <gl-link :href="autoDevopsHelpPagePath">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
+</template>
diff --git a/app/assets/javascripts/security_configuration/components/redesigned_app.vue b/app/assets/javascripts/security_configuration/components/redesigned_app.vue
index 717a568e7d8..915da378a4f 100644
--- a/app/assets/javascripts/security_configuration/components/redesigned_app.vue
+++ b/app/assets/javascripts/security_configuration/components/redesigned_app.vue
@@ -2,6 +2,7 @@
import { GlTab, GlTabs, GlSprintf, GlLink } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
+import AutoDevOpsAlert from './auto_dev_ops_alert.vue';
import FeatureCard from './feature_card.vue';
import SectionLayout from './section_layout.vue';
import UpgradeBanner from './upgrade_banner.vue';
@@ -31,6 +32,7 @@ export default {
FeatureCard,
SectionLayout,
UpgradeBanner,
+ AutoDevOpsAlert,
UserCalloutDismisser,
},
props: {
@@ -47,6 +49,16 @@ export default {
required: false,
default: false,
},
+ autoDevopsEnabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ canEnableAutoDevops: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
gitlabCiHistoryPath: {
type: String,
required: false,
@@ -67,16 +79,26 @@ export default {
canViewCiHistory() {
return Boolean(this.gitlabCiPresent && this.gitlabCiHistoryPath);
},
+ shouldShowDevopsAlert() {
+ return !this.autoDevopsEnabled && !this.gitlabCiPresent && this.canEnableAutoDevops;
+ },
},
};
</script>
<template>
<article>
+ <user-callout-dismisser
+ v-if="shouldShowDevopsAlert"
+ feature-name="security_configuration_devops_alert"
+ >
+ <template #default="{ dismiss, shouldShowCallout }">
+ <auto-dev-ops-alert v-if="shouldShowCallout" class="gl-mt-3" @dismiss="dismiss" />
+ </template>
+ </user-callout-dismisser>
<header>
<h1 class="gl-font-size-h1">{{ $options.i18n.securityConfiguration }}</h1>
</header>
-
<user-callout-dismisser v-if="canUpgrade" feature-name="security_configuration_upgrade_banner">
<template #default="{ dismiss, shouldShowCallout }">
<upgrade-banner v-if="shouldShowCallout" @close="dismiss" />
diff --git a/app/assets/javascripts/security_configuration/index.js b/app/assets/javascripts/security_configuration/index.js
index 0aafb2653d8..f05bd79258e 100644
--- a/app/assets/javascripts/security_configuration/index.js
+++ b/app/assets/javascripts/security_configuration/index.js
@@ -20,6 +20,8 @@ export const initRedesignedSecurityConfiguration = (el) => {
features,
latestPipelinePath,
gitlabCiHistoryPath,
+ autoDevopsHelpPagePath,
+ autoDevopsPath,
} = el.dataset;
const { augmentedSecurityFeatures, augmentedComplianceFeatures } = augmentFeatures(
@@ -34,6 +36,8 @@ export const initRedesignedSecurityConfiguration = (el) => {
provide: {
projectPath,
upgradePath,
+ autoDevopsHelpPagePath,
+ autoDevopsPath,
},
render(createElement) {
return createElement(RedesignedSecurityConfigurationApp, {
@@ -42,7 +46,11 @@ export const initRedesignedSecurityConfiguration = (el) => {
augmentedSecurityFeatures,
latestPipelinePath,
gitlabCiHistoryPath,
- ...parseBooleanDataAttributes(el, ['gitlabCiPresent']),
+ ...parseBooleanDataAttributes(el, [
+ 'gitlabCiPresent',
+ 'autoDevopsEnabled',
+ 'canEnableAutoDevops',
+ ]),
},
});
},
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index 5e2ec774655..10334d771b8 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -125,17 +125,22 @@
}
}
-// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1462
-.gl-md-mt-11 {
+// Will be moved to @gitlab/ui (without the !important) in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1462
+// We only need the bang (!) version until the non-bang version is added to
+// @gitlab/ui utitlities.scss. Once there, it will get loaded in the correct
+// order to properly override `.gl-mt-6` which is used for narrower screen
+// widths (currently that style gets added to the application.css stylesheet
+// after this one, so it takes precedence).
+.gl-md-mt-11\! {
@media (min-width: $breakpoint-md) {
- margin-top: $gl-spacing-scale-11;
+ margin-top: $gl-spacing-scale-11 !important;
}
}
-// Same as above
-.gl-md-pt-11 {
+// Same as above (also without the !important) but for overriding `.gl-pt-6`
+.gl-md-pt-11\! {
@media (min-width: $breakpoint-md) {
- padding-top: $gl-spacing-scale-11;
+ padding-top: $gl-spacing-scale-11 !important;
}
}
@@ -160,13 +165,6 @@
}
}
-// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1463
-.gl-xs-mt-6 {
- @media (max-width: $breakpoint-sm) {
- margin-top: $gl-spacing-scale-6;
- }
-}
-
// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1165
.gl-xs-mb-4 {
@media (max-width: $breakpoint-sm) {
@@ -181,13 +179,6 @@
}
}
-// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1463
-.gl-xs-pt-6 {
- @media (max-width: $breakpoint-sm) {
- padding-top: $gl-spacing-scale-6;
- }
-}
-
// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1168
.gl-sm-pr-3 {
@media (min-width: $breakpoint-sm) {
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 8df03c39690..752e91df9c4 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -350,6 +350,10 @@ module ProjectsHelper
nil
end
+ def show_terraform_banner?(project)
+ project.repository_languages.with_programming_language('HCL').exists? && project.terraform_states.empty?
+ end
+
private
def tab_ability_map
@@ -530,7 +534,8 @@ module ProjectsHelper
pagesAvailable: Gitlab.config.pages.enabled,
pagesAccessControlEnabled: Gitlab.config.pages.access_control,
pagesAccessControlForced: ::Gitlab::Pages.access_control_is_forced?,
- pagesHelpPath: help_page_path('user/project/pages/introduction', anchor: 'gitlab-pages-access-control')
+ pagesHelpPath: help_page_path('user/project/pages/introduction', anchor: 'gitlab-pages-access-control'),
+ issuesHelpPath: help_page_path('user/project/issues/index')
}
end
diff --git a/app/models/repository_language.rb b/app/models/repository_language.rb
index b7a96211fb1..2816aa4cc5b 100644
--- a/app/models/repository_language.rb
+++ b/app/models/repository_language.rb
@@ -8,6 +8,10 @@ class RepositoryLanguage < ApplicationRecord
default_scope { includes(:programming_language) } # rubocop:disable Cop/DefaultScope
+ scope :with_programming_language, ->(name) do
+ joins(:programming_language).merge(ProgrammingLanguage.with_name_case_insensitive(name))
+ end
+
validates :project, presence: true
validates :share, inclusion: { in: 0..100, message: "The share of a language is between 0 and 100" }
validates :programming_language, uniqueness: { scope: :project_id }
diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb
index e14ba035cc8..854992dcd1e 100644
--- a/app/models/user_callout.rb
+++ b/app/models/user_callout.rb
@@ -34,7 +34,8 @@ class UserCallout < ApplicationRecord
security_configuration_upgrade_banner: 32,
cloud_licensing_subscription_activation_banner: 33, # EE-only
trial_status_reminder_d14: 34, # EE-only
- trial_status_reminder_d3: 35 # EE-only
+ trial_status_reminder_d3: 35, # EE-only
+ security_configuration_devops_alert: 36 # EE-only
}
validates :user, presence: true
diff --git a/app/views/admin/application_settings/_help_page.html.haml b/app/views/admin/application_settings/_help_page.html.haml
index e7816f5a1c0..b71e8ca831e 100644
--- a/app/views/admin/application_settings/_help_page.html.haml
+++ b/app/views/admin/application_settings/_help_page.html.haml
@@ -5,18 +5,18 @@
= render_if_exists 'admin/application_settings/help_text_setting', form: f
.form-group
- = f.label :help_page_text, class: 'label-bold'
+ = f.label :help_page_text, _('Additional text to show on the Help page'), class: 'label-bold'
= f.text_area :help_page_text, class: 'form-control gl-form-input', rows: 4
.form-text.text-muted= _('Markdown enabled')
.form-group
.form-check
= f.check_box :help_page_hide_commercial_content, class: 'form-check-input'
= f.label :help_page_hide_commercial_content, class: 'form-check-label' do
- = _('Hide marketing-related entries from help')
+ = _('Hide marketing-related entries from the Help page.')
.form-group
= f.label :help_page_support_url, _('Support page URL'), class: 'label-bold'
= f.text_field :help_page_support_url, class: 'form-control gl-form-input', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block'
- %span.form-text.text-muted#support_help_block= _('Alternate support URL for help page and help dropdown')
+ %span.form-text.text-muted#support_help_block= _('Alternate support URL for Help page and Help dropdown')
- if show_documentation_base_url_field?
.form-group
diff --git a/app/views/admin/application_settings/preferences.html.haml b/app/views/admin/application_settings/preferences.html.haml
index 52aed0b36e7..0dfc3d7a60d 100644
--- a/app/views/admin/application_settings/preferences.html.haml
+++ b/app/views/admin/application_settings/preferences.html.haml
@@ -27,11 +27,12 @@
%section.settings.as-help-page.no-animate#js-help-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
- = _('Help page')
+ = _('Sign-in and Help page')
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
- = _('Help page text and support page url.')
+ = _('Additional text for the sign-in and Help page.')
+ = link_to s_('Learn more.'), help_page_path('user/admin_area/settings/help_page.md'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
= render 'help_page'
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index a56eaaf685f..95888963947 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -38,7 +38,7 @@
.card-header
= _('Quick help')
%ul.content-list
- %li= link_to _('See our website for getting help'), support_url
+ %li= link_to _('See our website for help'), support_url
%li
%button.btn-blank.btn-link.js-trigger-search-bar{ type: 'button' }
= _('Use the search bar on the top of this page')
diff --git a/app/views/layouts/minimal.html.haml b/app/views/layouts/minimal.html.haml
index ec909fcc279..b5cb8f2af37 100644
--- a/app/views/layouts/minimal.html.haml
+++ b/app/views/layouts/minimal.html.haml
@@ -8,7 +8,7 @@
= render 'peek/bar'
= render "layouts/header/empty"
.layout-page
- .content-wrapper.content-wrapper-margin.gl-md-pt-11.gl-xs-pt-6
+ .content-wrapper.content-wrapper-margin.gl-pt-6{ class: 'gl-md-pt-11!' }
.alert-wrapper.gl-force-block-formatting-context
= render "layouts/broadcast"
.limit-container-width{ class: container_class }
diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml
index f9222387e97..7395495b537 100644
--- a/app/views/projects/_flash_messages.html.haml
+++ b/app/views/projects/_flash_messages.html.haml
@@ -9,3 +9,4 @@
= render 'shared/auto_devops_implicitly_enabled_banner', project: project
= render_if_exists 'projects/above_size_limit_warning', project: project
= render_if_exists 'shared/shared_runners_minutes_limit', project: project, classes: [container_class, ("limit-container-width" unless fluid_layout)]
+ = render_if_exists 'projects/terraform_banner', project: project
diff --git a/app/views/projects/_terraform_banner.html.haml b/app/views/projects/_terraform_banner.html.haml
new file mode 100644
index 00000000000..a30c4a2d624
--- /dev/null
+++ b/app/views/projects/_terraform_banner.html.haml
@@ -0,0 +1,5 @@
+- @content_class = "container-limited limit-container-width" unless fluid_layout
+
+- if show_terraform_banner?(project)
+ .container-fluid{ class: @content_class }
+ .js-terraform-notification{ data: { project_id: project.id } }
diff --git a/babel.config.js b/babel.config.js
index 4dfca8f6144..d10de05258b 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -19,6 +19,10 @@ const plugins = [
'@babel/plugin-proposal-private-methods',
// See: https://gitlab.com/gitlab-org/gitlab/-/issues/229146
'@babel/plugin-transform-arrow-functions',
+ // See: https://gitlab.com/gitlab-org/gitlab/-/issues/336216
+ '@babel/plugin-proposal-optional-chaining',
+ // See: https://gitlab.com/gitlab-org/gitlab/-/issues/336216
+ '@babel/plugin-proposal-nullish-coalescing-operator',
'lodash',
];
diff --git a/config/feature_flags/development/ci_scoped_job_token.yml b/config/feature_flags/development/ci_scoped_job_token.yml
index a7fa0244839..a885a1e6391 100644
--- a/config/feature_flags/development/ci_scoped_job_token.yml
+++ b/config/feature_flags/development/ci_scoped_job_token.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332272
milestone: '14.0'
type: development
group: group::pipeline execution
-default_enabled: false
+default_enabled: true
diff --git a/db/migrate/20210709132707_change_default_job_token_scope_enabled.rb b/db/migrate/20210709132707_change_default_job_token_scope_enabled.rb
new file mode 100644
index 00000000000..fbd9f7baa61
--- /dev/null
+++ b/db/migrate/20210709132707_change_default_job_token_scope_enabled.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class ChangeDefaultJobTokenScopeEnabled < ActiveRecord::Migration[6.1]
+ include Gitlab::Database::MigrationHelpers
+
+ def up
+ with_lock_retries do
+ change_column_default :project_ci_cd_settings, :job_token_scope_enabled, from: false, to: true
+ end
+ end
+
+ def down
+ with_lock_retries do
+ change_column_default :project_ci_cd_settings, :job_token_scope_enabled, from: true, to: false
+ end
+ end
+end
diff --git a/db/schema_migrations/20210709132707 b/db/schema_migrations/20210709132707
new file mode 100644
index 00000000000..04ba096a692
--- /dev/null
+++ b/db/schema_migrations/20210709132707
@@ -0,0 +1 @@
+e0a2de69a3c9d616b87207b764e33fa3326627e065f28fc200c1414f08ee9fff \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 07cbad0f69d..0a1b53400d8 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -16753,7 +16753,7 @@ CREATE TABLE project_ci_cd_settings (
auto_rollback_enabled boolean DEFAULT false NOT NULL,
keep_latest_artifact boolean DEFAULT true NOT NULL,
restrict_user_defined_variables boolean DEFAULT false NOT NULL,
- job_token_scope_enabled boolean DEFAULT false NOT NULL
+ job_token_scope_enabled boolean DEFAULT true NOT NULL
);
CREATE SEQUENCE project_ci_cd_settings_id_seq
diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md
index a3b48476941..03908e6fc45 100644
--- a/doc/administration/geo/setup/database.md
+++ b/doc/administration/geo/setup/database.md
@@ -487,7 +487,7 @@ The replication process is now complete.
PostgreSQL connections, which can improve performance even when using in a
single instance installation.
-We recommend using PgBouncer if you use GitLab in a highly available
+We recommend using PgBouncer if you use GitLab in a highly available
configuration with a cluster of nodes supporting a Geo **primary** site and
two other clusters of nodes supporting a Geo **secondary** site. One for the
main database and the other for the tracking database. For more information,
@@ -550,12 +550,12 @@ Leader instance**:
```ruby
roles(['patroni_role'])
-
+
consul['services'] = %w(postgresql)
consul['configuration'] = {
retry_join: %w[CONSUL_PRIMARY1_IP CONSUL_PRIMARY2_IP CONSUL_PRIMARY3_IP]
}
-
+
# You need one entry for each secondary, with a unique name following PostgreSQL slot_name constraints:
#
# Configuration syntax is: 'unique_slotname' => { 'type' => 'physical' },
@@ -567,6 +567,8 @@ Leader instance**:
patroni['use_pg_rewind'] = true
patroni['postgresql']['max_wal_senders'] = 8 # Use double of the amount of patroni/reserved slots (3 patronis + 1 reserved slot for a Geo secondary).
patroni['postgresql']['max_replication_slots'] = 8 # Use double of the amount of patroni/reserved slots (3 patronis + 1 reserved slot for a Geo secondary).
+ patroni['username'] = 'PATRONI_API_USERNAME'
+ patroni['password'] = 'PATRONI_API_PASSWORD'
patroni['replication_password'] = 'PLAIN_TEXT_POSTGRESQL_REPLICATION_PASSWORD'
# We list all secondary instances as they can all become a Standby Leader
@@ -727,16 +729,18 @@ For each Patroni instance on the secondary site:
patroni['standby_cluster']['host'] = 'INTERNAL_LOAD_BALANCER_PRIMARY_IP'
patroni['standby_cluster']['port'] = INTERNAL_LOAD_BALANCER_PRIMARY_PORT
patroni['standby_cluster']['primary_slot_name'] = 'geo_secondary' # Or the unique replication slot name you setup before
+ patroni['username'] = 'PATRONI_API_USERNAME'
+ patroni['password'] = 'PATRONI_API_PASSWORD'
patroni['replication_password'] = 'PLAIN_TEXT_POSTGRESQL_REPLICATION_PASSWORD'
patroni['use_pg_rewind'] = true
patroni['postgresql']['max_wal_senders'] = 5 # A minimum of three for one replica, plus two for each additional replica
patroni['postgresql']['max_replication_slots'] = 5 # A minimum of three for one replica, plus two for each additional replica
-
+
postgresql['pgbouncer_user_password'] = 'PGBOUNCER_PASSWORD_HASH'
postgresql['sql_replication_password'] = 'POSTGRESQL_REPLICATION_PASSWORD_HASH'
postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
postgresql['listen_address'] = '0.0.0.0' # You can use a public or VPC address here instead
-
+
gitlab_rails['dbpassword'] = 'POSTGRESQL_PASSWORD'
gitlab_rails['enable'] = true
gitlab_rails['auto_migrate'] = false
@@ -754,7 +758,7 @@ For each Patroni instance on the secondary site:
- If you are configuring a Patroni standby cluster on a site that previously had a working Patroni cluster:
```shell
- gitlab-ctl stop patroni
+ gitlab-ctl stop patroni
rm -rf /var/opt/gitlab/postgresql/data
/opt/gitlab/embedded/bin/patronictl -c /var/opt/gitlab/patroni/patroni.yaml remove postgresql-ha
gitlab-ctl reconfigure
@@ -900,6 +904,8 @@ For each Patroni instance on the secondary site for the tracking database:
]
# Patroni configuration
+ patroni['username'] = 'PATRONI_API_USERNAME'
+ patroni['password'] = 'PATRONI_API_PASSWORD'
patroni['replication_password'] = 'PLAIN_TEXT_POSTGRESQL_REPLICATION_PASSWORD'
patroni['postgresql']['max_wal_senders'] = 5 # A minimum of three for one replica, plus two for each additional replica
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index 4a9e525ead5..8b9ba55bd3c 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -121,6 +121,7 @@ The following metrics are available:
| `action_cable_single_client_transmissions_total` | Counter | 13.10 | The number of ActionCable messages transmitted to any client in any channel | `server_mode` |
| `action_cable_subscription_confirmations_total` | Counter | 13.10 | The number of ActionCable subscriptions from clients confirmed | `server_mode` |
| `action_cable_subscription_rejections_total` | Counter | 13.10 | The number of ActionCable subscriptions from clients rejected | `server_mode` |
+| `action_cable_transmitted_bytes` | Histogram | 14.1 | Message size, in bytes, transmitted over action cable | `operation`, `channel` |
| `gitlab_issuable_fast_count_by_state_total` | Counter | 13.5 | Total number of row count operations on issue/merge request list pages | |
| `gitlab_issuable_fast_count_by_state_failures_total` | Counter | 13.5 | Number of soft-failed row count operations on issue/merge request list pages | |
| `gitlab_external_http_total` | Counter | 13.8 | Total number of HTTP calls to external systems | `controller`, `action` |
diff --git a/doc/administration/postgresql/replication_and_failover.md b/doc/administration/postgresql/replication_and_failover.md
index 3c10a245c3f..870b1f6aea2 100644
--- a/doc/administration/postgresql/replication_and_failover.md
+++ b/doc/administration/postgresql/replication_and_failover.md
@@ -157,6 +157,13 @@ We will need the following password information for the application's database u
sudo gitlab-ctl pg-password-md5 POSTGRESQL_USERNAME
```
+#### Patroni information
+
+We will need the following password information for the Patroni API:
+
+- `PATRONI_API_USERNAME`. A username for basic auth to the API
+- `PATRONI_API_PASSWORD`. A password for basic auth to the API
+
#### PgBouncer information
When using default setup, minimum configuration requires:
@@ -236,6 +243,11 @@ postgresql['sql_replication_password'] = 'POSTGRESQL_REPLICATION_PASSWORD_HASH'
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
+# Replace PATRONI_API_USERNAME with a username for Patroni Rest API calls (use the same username in all nodes)
+patroni['username'] = 'PATRONI_API_USERNAME'
+# Replace PATRONI_API_PASSWORD with a password for Patroni Rest API calls (use the same password in all nodes)
+patroni['password'] = 'PATRONI_API_PASSWORD'
+
# Sets `max_replication_slots` to double the number of database nodes.
# Patroni uses one extra slot per node when initiating the replication.
patroni['postgresql']['max_replication_slots'] = X
@@ -246,7 +258,7 @@ patroni['postgresql']['max_replication_slots'] = X
patroni['postgresql']['max_wal_senders'] = X+1
# Replace XXX.XXX.XXX.XXX/YY with Network Address
-postgresql['trust_auth_cidr_addresses'] = %w(XXX.XXX.XXX.XXX/YY)
+postgresql['trust_auth_cidr_addresses'] = %w(XXX.XXX.XXX.XXX/YY 127.0.0.1/32)
# Replace placeholders:
#
@@ -259,8 +271,8 @@ consul['configuration'] = {
# END user configuration
```
-You do not need an additional or different configuration for replica nodes. As a matter of fact, you don't have to have
-a predetermined primary node. Therefore all database nodes use the same configuration.
+All database nodes use the same configuration. The leader node is not determined in configuration,
+and there is no additional or different configuration for either leader or replica nodes.
Once the configuration of a node is done, you must [reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure)
on each node for the changes to take effect.
@@ -555,10 +567,12 @@ gitlab_rails['auto_migrate'] = false
postgresql['pgbouncer_user_password'] = '771a8625958a529132abe6f1a4acb19c'
postgresql['sql_user_password'] = '450409b85a0223a214b5fb1484f34d0f'
+patroni['username'] = 'PATRONI_API_USERNAME'
+patroni['password'] = 'PATRONI_API_PASSWORD'
patroni['postgresql']['max_replication_slots'] = 6
patroni['postgresql']['max_wal_senders'] = 7
-postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/16)
+postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/16 127.0.0.1/32)
# Configure the Consul agent
consul['services'] = %w(postgresql)
@@ -642,12 +656,15 @@ postgresql['sql_user_password'] = '450409b85a0223a214b5fb1484f34d0f'
# Patroni uses one extra slot per node when initiating the replication.
patroni['postgresql']['max_replication_slots'] = 6
+patroni['username'] = 'PATRONI_API_USERNAME'
+patroni['password'] = 'PATRONI_API_PASSWORD'
+
# Set `max_wal_senders` to one more than the number of replication slots in the cluster.
# This is used to prevent replication from using up all of the
# available database connections.
patroni['postgresql']['max_wal_senders'] = 7
-postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/16)
+postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/16 127.0.0.1/32)
consul['configuration'] = {
server: true,
@@ -721,6 +738,97 @@ functional or does not have a leader, Patroni and by extension PostgreSQL will n
API which can be accessed via its [default port](https://docs.gitlab.com/omnibus/package-information/defaults.html#patroni)
on each node.
+### Check replication status
+
+Run `gitlab-ctl patroni members` to query Patroni for a summary of the cluster status:
+
+```plaintext
++ Cluster: postgresql-ha (6970678148837286213) ------+---------+---------+----+-----------+
+| Member | Host | Role | State | TL | Lag in MB |
++-------------------------------------+--------------+---------+---------+----+-----------+
+| gitlab-database-1.example.com | 172.18.0.111 | Replica | running | 5 | 0 |
+| gitlab-database-2.example.com | 172.18.0.112 | Replica | running | 5 | 100 |
+| gitlab-database-3.example.com | 172.18.0.113 | Leader | running | 5 | |
++-------------------------------------+--------------+---------+---------+----+-----------+
+```
+
+To verify the status of replication:
+
+```shell
+echo 'select * from pg_stat_wal_receiver\x\g\x \n select * from pg_stat_replication\x\g\x' | gitlab-psql
+```
+
+The same command can be run on all three database servers, and will return any information
+about replication available depending on the role the server is performing.
+
+The leader should return one record per replica:
+
+```sql
+-[ RECORD 1 ]----+------------------------------
+pid | 371
+usesysid | 16384
+usename | gitlab_replicator
+application_name | gitlab-database-1.example.com
+client_addr | 172.18.0.111
+client_hostname |
+client_port | 42900
+backend_start | 2021-06-14 08:01:59.580341+00
+backend_xmin |
+state | streaming
+sent_lsn | 0/EA13220
+write_lsn | 0/EA13220
+flush_lsn | 0/EA13220
+replay_lsn | 0/EA13220
+write_lag |
+flush_lag |
+replay_lag |
+sync_priority | 0
+sync_state | async
+reply_time | 2021-06-18 19:17:14.915419+00
+```
+
+Investigate further if:
+
+- There are missing or extra records.
+- `reply_time` is not current.
+
+The `lsn` fields relate to which write-ahead-log segments have been replicated.
+Run the following on the leader to find out the current LSN:
+
+```shell
+echo 'SELECT pg_current_wal_lsn();' | gitlab-psql
+```
+
+If a replica is not in sync, `gitlab-ctl patroni members` indicates the volume
+of missing data, and the `lag` fields indicate the elapsed time.
+
+Read more about the data returned by the leader
+[in the PostgreSQL documentation](https://www.postgresql.org/docs/12/monitoring-stats.html#PG-STAT-REPLICATION-VIEW),
+including other values for the `state` field.
+
+The replicas should return:
+
+```sql
+-[ RECORD 1 ]---------+-------------------------------------------------------------------------------------------------
+pid | 391
+status | streaming
+receive_start_lsn | 0/D000000
+receive_start_tli | 5
+received_lsn | 0/EA13220
+received_tli | 5
+last_msg_send_time | 2021-06-18 19:16:54.807375+00
+last_msg_receipt_time | 2021-06-18 19:16:54.807512+00
+latest_end_lsn | 0/EA13220
+latest_end_time | 2021-06-18 19:07:23.844879+00
+slot_name | gitlab-database-1.example.com
+sender_host | 172.18.0.113
+sender_port | 5432
+conninfo | user=gitlab_replicator host=172.18.0.113 port=5432 application_name=gitlab-database-1.example.com
+```
+
+Read more about the data returned by the replica
+[in the PostgreSQL documentation](https://www.postgresql.org/docs/12/monitoring-stats.html#PG-STAT-WAL-RECEIVER-VIEW).
+
### Selecting the appropriate Patroni replication method
[Review the Patroni documentation carefully](https://patroni.readthedocs.io/en/latest/SETTINGS.html#postgresql)
@@ -1017,6 +1125,29 @@ postgresql['trust_auth_cidr_addresses'] = %w(123.123.123.123/32 <other_cidrs>)
[Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+### Reinitialize a replica
+
+If replication is not occurring, it may be necessary to reinitialize a replica.
+
+1. On any server in the cluster, determine the Cluster and Member names,
+ and check the replication lag by running `gitlab-ctl patroni members`. Here is an example:
+
+ ```plaintext
+ + Cluster: postgresql-ha (6970678148837286213) ------+---------+---------+----+-----------+
+ | Member | Host | Role | State | TL | Lag in MB |
+ +-------------------------------------+--------------+---------+---------+----+-----------+
+ | gitlab-database-1.example.com | 172.18.0.111 | Replica | running | 5 | 0 |
+ | gitlab-database-2.example.com | 172.18.0.112 | Replica | running | 5 | 100 |
+ | gitlab-database-3.example.com | 172.18.0.113 | Leader | running | 5 | |
+ +-------------------------------------+--------------+---------+---------+----+-----------+
+ ```
+
+1. Reinitialize the affected replica server:
+
+ ```plaintext
+ gitlab-ctl patroni reinitialize-replica postgresql-ha gitlab-database-2.example.com
+ ```
+
### Reset the Patroni state in Consul
WARNING:
@@ -1058,6 +1189,70 @@ To reset the Patroni state in Consul:
If you are still seeing issues, the next step is restoring the last healthy backup.
+### Errors in the Patroni log about a `pg_hba.conf` entry for `127.0.0.1`
+
+The following log entry in the Patroni log indicates the replication is not working
+and a configuration change is needed:
+
+```plaintext
+FATAL: no pg_hba.conf entry for replication connection from host "127.0.0.1", user "gitlab_replicator"
+```
+
+To fix the problem, ensure the loopback interface is included in the CIDR addresses list:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ postgresql['trust_auth_cidr_addresses'] = %w(<other_cidrs> 127.0.0.1/32)
+ ```
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+1. Check that [all the replicas are synchronized](#check-replication-status)
+
+### Errors in Patroni logs: the requested start point is ahead of the WAL flush position
+
+This error indicates that the database is not replicating:
+
+```plaintext
+FATAL: could not receive data from WAL stream: ERROR: requested starting point 0/5000000 is ahead of the WAL flush position of this server 0/4000388
+```
+
+This example error is from a replica that was initially misconfigured, and had never replicated.
+
+Fix it [by reinitializing the replica](#reinitialize-a-replica).
+
+### Patroni fails to start with `MemoryError`
+
+Patroni may fail to start, logging an error and stack trace:
+
+```plaintext
+MemoryError
+Traceback (most recent call last):
+ File "/opt/gitlab/embedded/bin/patroni", line 8, in <module>
+ sys.exit(main())
+[..]
+ File "/opt/gitlab/embedded/lib/python3.7/ctypes/__init__.py", line 273, in _reset_cache
+ CFUNCTYPE(c_int)(lambda: None)
+```
+
+If the stack trace ends with `CFUNCTYPE(c_int)(lambda: None)`, this code triggers `MemoryError`
+if the Linux server has been hardened for security.
+
+The code causes Python to write temporary executable files, and if it cannot find a filesystem
+in which to do this, for example if `noexec` is set on the `/tmp` filesystem, it fails with
+`MemoryError` ([read more in the issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6184)).
+
+Workarounds:
+
+- Remove `noexec` from the mount options for filesystems like `/tmp` and `/var/tmp`.
+- If set to enforcing, SELinux may also prevent these operations. Verify the issue is fixed by setting
+ SELinux to permissive.
+
+Omnibus GitLab has shipped with Patroni since 13.1 along with a build of Python 3.7.
+Workarounds should stop being required when GitLab 14.x starts shipping with
+[a later version of Python](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6164) as
+the code which causes this was removed from Python 3.8.
+
### Issues with other components
If you're running into an issue with a component not outlined here, be sure to check the troubleshooting section of their specific documentation page:
diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md
index e554f5c3693..862f35f4b5c 100644
--- a/doc/administration/reference_architectures/10k_users.md
+++ b/doc/administration/reference_architectures/10k_users.md
@@ -598,8 +598,12 @@ in the second step, do not supply the `EXTERNAL_URL` value.
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = '<postgresql_password_hash>'
+ # Set up basic authentication for the Patroni API (use the same username/password in all nodes).
+ patroni['username'] = '<patroni_api_username>'
+ patroni['password'] = '<patroni_api_password>'
+
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -1403,7 +1407,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
postgresql['sql_user_password'] = "<praefect_postgresql_password_hash>"
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -1681,7 +1685,7 @@ On each node:
# balancer.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
- # Gitaly
+ # Gitaly
gitaly['enable'] = true
# Make Gitaly accept connections on all network interfaces. You must use
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index 920ed5a7652..76477a6ffb2 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -600,8 +600,12 @@ in the second step, do not supply the `EXTERNAL_URL` value.
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = '<postgresql_password_hash>'
+ # Set up basic authentication for the Patroni API (use the same username/password in all nodes).
+ patroni['username'] = '<patroni_api_username>'
+ patroni['password'] = '<patroni_api_password>'
+
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -863,7 +867,7 @@ a node and change its status from primary to replica (and vice versa).
redis_exporter['flags'] = {
'redis.addr' => 'redis://10.6.0.51:6379',
'redis.password' => 'redis-password-goes-here',
- }
+ }
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
@@ -1421,7 +1425,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
postgresql['sql_user_password'] = "<praefect_postgresql_password_hash>"
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -1699,7 +1703,7 @@ On each node:
# balancer.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
- # Gitaly
+ # Gitaly
gitaly['enable'] = true
# Make Gitaly accept connections on all network interfaces. You must use
diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md
index 71ca67075d3..655afc58343 100644
--- a/doc/administration/reference_architectures/3k_users.md
+++ b/doc/administration/reference_architectures/3k_users.md
@@ -848,7 +848,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
```ruby
# Disable all components except Patroni and Consul
roles(['patroni_role'])
-
+
# PostgreSQL configuration
postgresql['listen_address'] = '0.0.0.0'
@@ -866,7 +866,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
-
+
# Configure the Consul agent
consul['services'] = %w(postgresql)
## Enable service discovery for Prometheus
@@ -882,8 +882,12 @@ in the second step, do not supply the `EXTERNAL_URL` value.
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = '<postgresql_password_hash>'
+ # Set up basic authentication for the Patroni API (use the same username/password in all nodes).
+ patroni['username'] = '<patroni_api_username>'
+ patroni['password'] = '<patroni_api_password>'
+
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -1127,7 +1131,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
postgresql['sql_user_password'] = "<praefect_postgresql_password_hash>"
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md
index 3b3b1cf8ced..3b362f91a61 100644
--- a/doc/administration/reference_architectures/50k_users.md
+++ b/doc/administration/reference_architectures/50k_users.md
@@ -608,8 +608,12 @@ in the second step, do not supply the `EXTERNAL_URL` value.
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = '<postgresql_password_hash>'
+ # Set up basic authentication for the Patroni API (use the same username/password in all nodes).
+ patroni['username'] = '<patroni_api_username>'
+ patroni['password'] = '<patroni_api_password>'
+
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -872,7 +876,7 @@ a node and change its status from primary to replica (and vice versa).
'redis.addr' => 'redis://10.6.0.51:6379',
'redis.password' => 'redis-password-goes-here',
}
-
+
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
```
@@ -1425,7 +1429,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
postgresql['sql_user_password'] = "<praefect_postgresql_password_hash>"
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -1703,7 +1707,7 @@ On each node:
# balancer.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
- # Gitaly
+ # Gitaly
gitaly['enable'] = true
# Make Gitaly accept connections on all network interfaces. You must use
@@ -1929,7 +1933,7 @@ To configure the Sidekiq nodes, on each one:
## Set number of Sidekiq threads per queue process to the recommend number of 10
sidekiq['max_concurrency'] = 10
- # Monitoring
+ # Monitoring
consul['enable'] = true
consul['monitoring_service_discovery'] = true
diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md
index b5001068945..960f7148eda 100644
--- a/doc/administration/reference_architectures/5k_users.md
+++ b/doc/administration/reference_architectures/5k_users.md
@@ -844,7 +844,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
# Sets `max_replication_slots` to double the number of database nodes.
# Patroni uses one extra slot per node when initiating the replication.
patroni['postgresql']['max_replication_slots'] = 8
-
+
# Set `max_wal_senders` to one more than the number of replication slots in the cluster.
# This is used to prevent replication from using up all of the
# available database connections.
@@ -871,8 +871,12 @@ in the second step, do not supply the `EXTERNAL_URL` value.
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = '<postgresql_password_hash>'
+ # Set up basic authentication for the Patroni API (use the same username/password in all nodes).
+ patroni['username'] = '<patroni_api_username>'
+ patroni['password'] = '<patroni_api_password>'
+
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
@@ -1116,7 +1120,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
postgresql['sql_user_password'] = "<praefect_postgresql_password_hash>"
# Replace XXX.XXX.XXX.XXX/YY with Network Address
- postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24)
+ postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 4a0572569a3..de07d601c4f 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -15290,6 +15290,7 @@ Name of the feature that the callout is for.
| <a id="usercalloutfeaturenameenumpipeline_needs_banner"></a>`PIPELINE_NEEDS_BANNER` | Callout feature name for pipeline_needs_banner. |
| <a id="usercalloutfeaturenameenumpipeline_needs_hover_tip"></a>`PIPELINE_NEEDS_HOVER_TIP` | Callout feature name for pipeline_needs_hover_tip. |
| <a id="usercalloutfeaturenameenumregistration_enabled_callout"></a>`REGISTRATION_ENABLED_CALLOUT` | Callout feature name for registration_enabled_callout. |
+| <a id="usercalloutfeaturenameenumsecurity_configuration_devops_alert"></a>`SECURITY_CONFIGURATION_DEVOPS_ALERT` | Callout feature name for security_configuration_devops_alert. |
| <a id="usercalloutfeaturenameenumsecurity_configuration_upgrade_banner"></a>`SECURITY_CONFIGURATION_UPGRADE_BANNER` | Callout feature name for security_configuration_upgrade_banner. |
| <a id="usercalloutfeaturenameenumservice_templates_deprecated_callout"></a>`SERVICE_TEMPLATES_DEPRECATED_CALLOUT` | Callout feature name for service_templates_deprecated_callout. |
| <a id="usercalloutfeaturenameenumsuggest_pipeline"></a>`SUGGEST_PIPELINE` | Callout feature name for suggest_pipeline. |
diff --git a/doc/api/index.md b/doc/api/index.md
index f1059904ac3..d80f4ecf19b 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -248,13 +248,13 @@ tries to steal tokens from other jobs.
#### Limit GitLab CI/CD job token access
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328553) in GitLab 14.1.
-> - [Deployed behind a feature flag](../user/feature_flags.md), disabled by default.
-> - Disabled on GitLab.com.
-> - Not recommended for production use.
-> - To use in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-ci-job-token-scope-limit). **(FREE SELF)**
+> - [Deployed behind a feature flag](../user/feature_flags.md), enabled by default.
+> - Enabled on GitLab.com.
+> - Recommended for production use.
+> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-ci-job-token-scope-limit). **(FREE SELF)**
-This in-development feature might not be available for your use. There can be
-[risks when enabling features still in development](../user/feature_flags.md#risks-when-enabling-features-still-in-development).
+There can be
+[risks when disabling released features](../user/feature_flags.md#risks-when-disabling-released-features).
Refer to this feature's version history for more details.
You can limit the access scope of a project's CI/CD job token to increase the
@@ -292,21 +292,21 @@ the feature with more strategic control of the access permissions.
##### Enable or disable CI job token scope limit **(FREE SELF)**
-The GitLab CI/CD job token access scope limit is under development and not ready for production
-use. It is deployed behind a feature flag that is **disabled by default**.
+The GitLab CI/CD job token access scope limit is under development but ready for production
+use. It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
-can enable it.
+can disable the feature.
-To enable it:
+To disable it:
```ruby
-Feature.enable(:ci_scoped_job_token)
+Feature.disable(:ci_scoped_job_token)
```
-To disable it:
+To enable it:
```ruby
-Feature.disable(:ci_scoped_job_token)
+Feature.enable(:ci_scoped_job_token)
```
### Impersonation tokens
diff --git a/doc/ci/pipeline_editor/index.md b/doc/ci/pipeline_editor/index.md
index 96df93848dc..7132d47d324 100644
--- a/doc/ci/pipeline_editor/index.md
+++ b/doc/ci/pipeline_editor/index.md
@@ -85,9 +85,6 @@ where:
[extended configuration merged into the job](../yaml/index.md#merge-details).
- YAML anchors are [replaced with the linked configuration](../yaml/index.md#anchors).
-NOTE:
-You can only see the expanded view when editing the [default branch](../../user/project/repository/branches/default.md).
-
## Commit changes to CI configuration
The commit form appears at the bottom of each tab in the editor so you can commit
diff --git a/doc/subscriptions/bronze_starter.md b/doc/subscriptions/bronze_starter.md
index 7d3af5979fb..410759aa506 100644
--- a/doc/subscriptions/bronze_starter.md
+++ b/doc/subscriptions/bronze_starter.md
@@ -16,7 +16,7 @@ The following features remain available to Bronze and Starter customers, even th
the tiers are no longer mentioned in GitLab documentation:
- [Activate GitLab EE with a license](../user/admin_area/license.md)
-- [Adding a help message to the login page](../user/admin_area/settings/help_page.md#adding-a-help-message-to-the-login-page)
+- [Add a help message to the sign-in page](../user/admin_area/settings/help_page.md#add-a-help-message-to-the-sign-in-page)
- [Burndown and burnup charts](../user/project/milestones/burndown_and_burnup_charts.md),
including [per-project charts](../user/project/milestones/index.md#project-burndown-charts) and
[per-group charts](../user/project/milestones/index.md#group-burndown-charts)
diff --git a/doc/user/admin_area/settings/help_page.md b/doc/user/admin_area/settings/help_page.md
index e11527db49a..d2f99a51ec3 100644
--- a/doc/user/admin_area/settings/help_page.md
+++ b/doc/user/admin_area/settings/help_page.md
@@ -5,41 +5,58 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: howto
---
-# Customizing the 'Help' and login page messages
+# Customize the Help and sign-in page messages
In large organizations, it is useful to have information about who to contact or where
-to go for help. You can customize and display this information on the GitLab server's
-`/help` page and on the GitLab login page.
+to go for help. You can customize and display this information on the GitLab `/help` page and on
+the GitLab sign-in page.
-## Adding a help message to the help page
+## Add a help message to the Help page
-You can add a help message, which is shown on the GitLab `/help` page (for example,
-<https://gitlab.com/help>) in a new section at the top of the `/help` page:
+You can add a help message, which is shown at the top of the GitLab `/help` page (for example,
+<https://gitlab.com/help>):
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Preferences**, then expand **Help page**.
-1. Under **Help page text**, fill in the information you wish to display on `/help`.
-1. Save your changes. You can now see the message on `/help`.
+1. Under **Additional text to show on the Help page**, fill in the information you wish to display on `/help`.
+1. Select **Save changes**. You can now see the message on `/help`.
NOTE:
By default, `/help` is visible to unauthenticated users. However, if the
[**Public** visibility level](visibility_and_access_controls.md#restricted-visibility-levels)
is restricted, `/help` is visible only to signed-in users.
-## Adding a help message to the login page **(STARTER)**
+## Add a help message to the sign-in page **(STARTER)**
-You can add a help message, which is shown on the GitLab login page in a new section
-titled `Need Help?`, located below the login page message:
+You can add a help message, which is shown on the GitLab sign-in page. The message appears in a new
+section titled **Need Help?**, located below the sign-in page message:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Preferences**, then expand **Help page**.
-1. Under **Help text**, fill in the information you wish to display on the login page.
+1. Under **Additional text to show on the sign-in page**, fill in the information you wish to
+ display on the sign-in page.
+1. Select **Save changes**. You can now see the message on the sign-in page.
- ![help message on login page](img/help_page_help_text_v12_3.png)
+## Hide marketing-related entries from the Help page
-1. Save your changes.
+GitLab marketing-related entries are occasionally shown on the Help page. To hide these entries:
-![help message on login page example](img/help_page_help_text_ex_v12_3.png)
+1. On the top bar, select **Menu >** **{admin}** **Admin**.
+1. In the left sidebar, select **Settings > Preferences**, then expand **Help page**.
+1. Select the **Hide marketing-related entries from the Help page** checkbox.
+1. Select **Save changes**.
+
+## Set a custom Support page URL
+
+You can specify a custom URL to which users are directed when they:
+
+- Select **Support** from the Help dropdown.
+- Select **See our website for help** on the Help page.
+
+1. On the top bar, select **Menu >** **{admin}** **Admin**.
+1. In the left sidebar, select **Settings > Preferences**, then expand **Help page**.
+1. Enter the URL in the **Support page URL** field.
+1. Select **Save changes**.
<!-- ## Troubleshooting
diff --git a/doc/user/admin_area/settings/img/help_page_help_text_ex_v12_3.png b/doc/user/admin_area/settings/img/help_page_help_text_ex_v12_3.png
deleted file mode 100644
index 973be2e8b6e..00000000000
--- a/doc/user/admin_area/settings/img/help_page_help_text_ex_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/admin_area/settings/img/help_page_help_text_v12_3.png b/doc/user/admin_area/settings/img/help_page_help_text_v12_3.png
deleted file mode 100644
index 8848ea55cf3..00000000000
--- a/doc/user/admin_area/settings/img/help_page_help_text_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/search/advanced_search.md b/doc/user/search/advanced_search.md
index 20a2a7263c3..bb74a035121 100644
--- a/doc/user/search/advanced_search.md
+++ b/doc/user/search/advanced_search.md
@@ -12,6 +12,7 @@ type: reference
NOTE:
This is the user documentation. To configure the Advanced Search,
visit the [administrator documentation](../../integration/elasticsearch.md).
+Advanced Search is enabled in GitLab.com.
GitLab Advanced Search expands on the Basic Search with an additional set of
features for faster, more advanced searches across the entire GitLab instance
@@ -34,6 +35,11 @@ The Advanced Search can be useful in various scenarios:
Advanced Search is based on Elasticsearch, which is a purpose-built full
text search engine that can be horizontally scaled so that it can provide
search results in 1-2 seconds in most cases.
+- **Code Maintenance:**
+ Finding all the code that needs to be updated at once across an entire
+ instance can save time spent maintaining code.
+ This is especially helpful for organizations with more than 10 active projects.
+ This can also help build confidence is code refactoring to identify unknown impacts.
- **Promote innersourcing:**
Your company may consist of many different developer teams each of which has
their own group where the various projects are hosted. Some of your applications
diff --git a/lib/gitlab/ci/pipeline/seed/build.rb b/lib/gitlab/ci/pipeline/seed/build.rb
index fd05e542430..54d92745992 100644
--- a/lib/gitlab/ci/pipeline/seed/build.rb
+++ b/lib/gitlab/ci/pipeline/seed/build.rb
@@ -72,6 +72,7 @@ module Gitlab
.deep_merge(rules_attributes)
.deep_merge(allow_failure_criteria_attributes)
.deep_merge(@cache.cache_attributes)
+ .deep_merge(runner_tags)
end
def bridge?
@@ -211,6 +212,16 @@ module Gitlab
end
end
+ def runner_tags
+ { tag_list: evaluate_runner_tags }.compact
+ end
+
+ def evaluate_runner_tags
+ @seed_attributes[:tag_list]&.map do |tag|
+ ExpandVariables.expand_existing(tag, evaluate_context.variables)
+ end
+ end
+
# If a job uses `allow_failure:exit_codes` and `rules:allow_failure`
# we need to prevent the exit codes from being persisted because they
# would break the behavior defined by `rules:allow_failure`.
diff --git a/lib/gitlab/kas/client.rb b/lib/gitlab/kas/client.rb
index 6675903e692..842ee98e4da 100644
--- a/lib/gitlab/kas/client.rb
+++ b/lib/gitlab/kas/client.rb
@@ -49,14 +49,14 @@ module Gitlab
end
def kas_endpoint_url
- Gitlab::Kas.internal_url.delete_prefix('grpc://')
+ Gitlab::Kas.internal_url.sub(%r{^grpc://|^grpcs://}, '')
end
def credentials
- if Rails.env.test? || Rails.env.development?
- :this_channel_is_insecure
- else
+ if URI(Gitlab::Kas.internal_url).scheme == 'grpcs'
GRPC::Core::ChannelCredentials.new
+ else
+ :this_channel_is_insecure
end
end
diff --git a/lib/gitlab/metrics/subscribers/action_cable.rb b/lib/gitlab/metrics/subscribers/action_cable.rb
index a9355eeae40..631b9209f14 100644
--- a/lib/gitlab/metrics/subscribers/action_cable.rb
+++ b/lib/gitlab/metrics/subscribers/action_cable.rb
@@ -12,6 +12,7 @@ module Gitlab
TRANSMIT_SUBSCRIPTION_CONFIRMATION = :action_cable_subscription_confirmations_total
TRANSMIT_SUBSCRIPTION_REJECTION = :action_cable_subscription_rejections_total
BROADCAST = :action_cable_broadcasts_total
+ DATA_TRANSMITTED_BYTES = :action_cable_transmitted_bytes
def transmit_subscription_confirmation(event)
confirm_subscription_counter.increment
@@ -23,6 +24,14 @@ module Gitlab
def transmit(event)
transmit_counter.increment
+
+ if event.payload.present?
+ channel = event.payload[:channel_class]
+ operation = operation_name_from(event.payload)
+ data_size = ::ActiveSupport::JSON.encode(event.payload[:data]).bytesize
+
+ transmitted_bytes_histogram.observe({ channel: channel, operation: operation }, data_size)
+ end
end
def broadcast(event)
@@ -31,6 +40,13 @@ module Gitlab
private
+ # When possible tries to query operation name
+ def operation_name_from(payload)
+ data = payload.dig(:data, 'result', 'data') || {}
+
+ data.each_key.first
+ end
+
def transmit_counter
strong_memoize("transmission_counter") do
::Gitlab::Metrics.counter(
@@ -66,6 +82,12 @@ module Gitlab
)
end
end
+
+ def transmitted_bytes_histogram
+ strong_memoize("transmitted_bytes_histogram") do
+ ::Gitlab::Metrics.histogram(DATA_TRANSMITTED_BYTES, 'Message size, in bytes, transmitted over action cable')
+ end
+ end
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index df97469d47d..565d8fc76c2 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2188,6 +2188,15 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Additional text for the sign-in and Help page."
+msgstr ""
+
+msgid "Additional text to show on the Help page"
+msgstr ""
+
+msgid "Additional text to show on the sign-in page"
+msgstr ""
+
msgid "Address"
msgstr ""
@@ -3459,7 +3468,7 @@ msgstr ""
msgid "Also unassign this user from related issues and merge requests"
msgstr ""
-msgid "Alternate support URL for help page and help dropdown"
+msgid "Alternate support URL for Help page and Help dropdown"
msgstr ""
msgid "Alternatively, you can convert your account to a managed account by the %{group_name} group."
@@ -6409,12 +6418,18 @@ msgstr ""
msgid "Checkout"
msgstr ""
+msgid "Checkout|$%{selectedPlanPrice} per pack per year"
+msgstr ""
+
msgid "Checkout|$%{selectedPlanPrice} per user per year"
msgstr ""
msgid "Checkout|%{cardType} ending in %{lastFourDigits}"
msgstr ""
+msgid "Checkout|%{name}'s CI minutes"
+msgstr ""
+
msgid "Checkout|%{name}'s GitLab subscription"
msgstr ""
@@ -6433,6 +6448,9 @@ msgstr ""
msgid "Checkout|(x%{numberOfUsers})"
msgstr ""
+msgid "Checkout|(x%{quantity})"
+msgstr ""
+
msgid "Checkout|Billing address"
msgstr ""
@@ -16183,12 +16201,6 @@ msgstr ""
msgid "Help"
msgstr ""
-msgid "Help page"
-msgstr ""
-
-msgid "Help page text and support page url."
-msgstr ""
-
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -16248,7 +16260,7 @@ msgstr ""
msgid "Hide list"
msgstr ""
-msgid "Hide marketing-related entries from help"
+msgid "Hide marketing-related entries from the Help page."
msgstr ""
msgid "Hide payload"
@@ -24227,9 +24239,6 @@ msgstr ""
msgid "Pipelines|Merged YAML is view only"
msgstr ""
-msgid "Pipelines|Merged YAML unavailable"
-msgstr ""
-
msgid "Pipelines|More Information"
msgstr ""
@@ -24266,9 +24275,6 @@ msgstr ""
msgid "Pipelines|The GitLab CI configuration could not be updated."
msgstr ""
-msgid "Pipelines|The merged YAML view is only available for the default branch. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
-
msgid "Pipelines|There are currently no finished pipelines."
msgstr ""
@@ -25838,6 +25844,9 @@ msgstr ""
msgid "ProjectSettings|Fast-forward merges only."
msgstr ""
+msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -25859,9 +25868,6 @@ msgstr ""
msgid "ProjectSettings|LFS objects from this repository are available to forks. %{linkStart}How do I remove them?%{linkEnd}"
msgstr ""
-msgid "ProjectSettings|Lightweight issue tracking system."
-msgstr ""
-
msgid "ProjectSettings|Manages large files such as audio, video, and graphics files."
msgstr ""
@@ -29033,6 +29039,9 @@ msgstr ""
msgid "SecurityConfiguration|Enable %{feature}"
msgstr ""
+msgid "SecurityConfiguration|Enable Auto DevOps"
+msgstr ""
+
msgid "SecurityConfiguration|Enabled"
msgstr ""
@@ -29066,6 +29075,9 @@ msgstr ""
msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan."
msgstr ""
+msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
+msgstr ""
+
msgid "SecurityConfiguration|Runtime security metrics for application environments."
msgstr ""
@@ -29408,7 +29420,7 @@ msgstr ""
msgid "See metrics"
msgstr ""
-msgid "See our website for getting help"
+msgid "See our website for help"
msgstr ""
msgid "See the affected projects in the GitLab admin panel"
@@ -30330,6 +30342,9 @@ msgstr ""
msgid "Sign up was successful! Please confirm your email to sign in."
msgstr ""
+msgid "Sign-in and Help page"
+msgstr ""
+
msgid "Sign-in count:"
msgstr ""
@@ -32187,6 +32202,15 @@ msgstr ""
msgid "Terraform"
msgstr ""
+msgid "TerraformBanner|Learn more about GitLab's Backend State"
+msgstr ""
+
+msgid "TerraformBanner|The GitLab managed Terraform state backend can store your Terraform state easily and securely, and spares you from setting up additional remote resources. Its features include: versioning, encryption of the state file both in transit and at rest, locking, and remote Terraform plan/apply execution."
+msgstr ""
+
+msgid "TerraformBanner|Using Terraform? Try the GitLab Managed Terraform State"
+msgstr ""
+
msgid "Terraform|%{name} successfully removed"
msgstr ""
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 59bf397adf2..20238d0a027 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -571,8 +571,8 @@ RSpec.describe 'Admin updates settings' do
new_documentation_url = 'https://docs.gitlab.com'
page.within('.as-help-page') do
- fill_in 'Help page text', with: 'Example text'
- check 'Hide marketing-related entries from help'
+ fill_in 'Additional text to show on the Help page', with: 'Example text'
+ check 'Hide marketing-related entries from the Help page.'
fill_in 'Support page URL', with: new_support_url
fill_in 'Documentation pages URL', with: new_documentation_url
click_button 'Save changes'
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index 90647305281..66ba4dc987c 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -65,7 +65,7 @@ RSpec.describe 'Help Pages' do
end
it 'uses a custom support url' do
- expect(page).to have_link "See our website for getting help", href: "http://example.com/help"
+ expect(page).to have_link "See our website for help", href: "http://example.com/help"
end
end
end
diff --git a/spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js b/spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
index b797a664b75..7dd8a77d055 100644
--- a/spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
+++ b/spec/frontend/pipeline_editor/components/editor/ci_config_merged_preview_spec.js
@@ -1,12 +1,10 @@
-import { GlIcon, GlAlert } from '@gitlab/ui';
+import { GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { EDITOR_READY_EVENT } from '~/editor/constants';
import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue';
import { mockLintResponse, mockCiConfigPath } from '../../mock_data';
-const DEFAULT_BRANCH = 'main';
-
describe('Text editor component', () => {
let wrapper;
@@ -18,7 +16,7 @@ describe('Text editor component', () => {
},
};
- const createComponent = ({ props = {}, currentBranch = DEFAULT_BRANCH } = {}) => {
+ const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMount(CiConfigMergedPreview, {
propsData: {
ciConfigData: mockLintResponse,
@@ -26,45 +24,20 @@ describe('Text editor component', () => {
},
provide: {
ciConfigPath: mockCiConfigPath,
- defaultBranch: DEFAULT_BRANCH,
},
stubs: {
SourceEditor: MockSourceEditor,
},
- data() {
- return {
- currentBranch,
- };
- },
});
};
const findIcon = () => wrapper.findComponent(GlIcon);
- const findAlert = () => wrapper.findComponent(GlAlert);
const findEditor = () => wrapper.findComponent(MockSourceEditor);
afterEach(() => {
wrapper.destroy();
});
- // This is testing a temporary feature.
- // It may be slightly hacky code that doesn't follow best practice.
- // See the related MR for more information.
- // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65972#note_626095644
- describe('on a non-default branch', () => {
- beforeEach(() => {
- createComponent({ currentBranch: 'feature' });
- });
-
- it('does not load the editor', () => {
- expect(findEditor().exists()).toBe(false);
- });
-
- it('renders an informational alert', () => {
- expect(findAlert().exists()).toBe(true);
- });
- });
-
describe('when status is valid', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js
index 3dd09c583d6..b0d1a69ee56 100644
--- a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js
+++ b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js
@@ -23,9 +23,10 @@ import {
mockBlobContentQueryResponse,
mockBlobContentQueryResponseEmptyCiFile,
mockBlobContentQueryResponseNoCiFile,
+ mockCiYml,
+ mockCommitSha,
mockDefaultBranch,
mockProjectFullPath,
- mockCiYml,
mockNewCommitShaResults,
} from './mock_data';
@@ -95,10 +96,16 @@ describe('Pipeline editor app component', () => {
];
const resolvers = {
+ Query: {
+ commitSha() {
+ return mockCommitSha;
+ },
+ },
Mutation: {
updateCommitSha: mockUpdateCommitSha,
},
};
+
mockApollo = createMockApollo(handlers, resolvers);
const options = {
@@ -170,6 +177,7 @@ describe('Pipeline editor app component', () => {
expect(mockCiConfigData).toHaveBeenCalledWith({
content: mockCiYml,
projectPath: mockProjectFullPath,
+ sha: mockCommitSha,
});
});
});
diff --git a/spec/frontend/projects/terraform_notification/terraform_notification_spec.js b/spec/frontend/projects/terraform_notification/terraform_notification_spec.js
new file mode 100644
index 00000000000..be34b207c4b
--- /dev/null
+++ b/spec/frontend/projects/terraform_notification/terraform_notification_spec.js
@@ -0,0 +1,62 @@
+import { GlBanner } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { setCookie, parseBoolean } from '~/lib/utils/common_utils';
+import TerraformNotification from '~/projects/terraform_notification/components/terraform_notification.vue';
+
+jest.mock('~/lib/utils/common_utils');
+
+const bannerDissmisedKey = 'terraform_notification_dismissed_for_project_1';
+
+describe('TerraformNotificationBanner', () => {
+ let wrapper;
+
+ const propsData = {
+ projectId: 1,
+ };
+ const findBanner = () => wrapper.findComponent(GlBanner);
+
+ beforeEach(() => {
+ wrapper = shallowMount(TerraformNotification, {
+ propsData,
+ stubs: { GlBanner },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ parseBoolean.mockReturnValue(false);
+ });
+
+ describe('when the dismiss cookie is set', () => {
+ beforeEach(() => {
+ parseBoolean.mockReturnValue(true);
+ wrapper = shallowMount(TerraformNotification, {
+ propsData,
+ });
+ });
+
+ it('should not render the banner', () => {
+ expect(findBanner().exists()).toBe(false);
+ });
+ });
+
+ describe('when the dismiss cookie is not set', () => {
+ it('should render the banner', () => {
+ expect(findBanner().exists()).toBe(true);
+ });
+ });
+
+ describe('when close button is clicked', () => {
+ beforeEach(async () => {
+ await findBanner().vm.$emit('close');
+ });
+
+ it('should set the cookie with the bannerDissmisedKey', () => {
+ expect(setCookie).toHaveBeenCalledWith(bannerDissmisedKey, true);
+ });
+
+ it('should remove the banner', () => {
+ expect(findBanner().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js b/spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js
new file mode 100644
index 00000000000..467ae35408c
--- /dev/null
+++ b/spec/frontend/security_configuration/components/auto_dev_ops_alert_spec.js
@@ -0,0 +1,55 @@
+import { GlAlert } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import AutoDevopsAlert from '~/security_configuration/components/auto_dev_ops_alert.vue';
+
+const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath';
+const autoDevopsPath = '/enableAutoDevopsPath';
+
+describe('AutoDevopsAlert component', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = mount(AutoDevopsAlert, {
+ provide: {
+ autoDevopsHelpPagePath,
+ autoDevopsPath,
+ },
+ });
+ };
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('contains correct body text', () => {
+ expect(wrapper.text()).toContain('Quickly enable all');
+ });
+
+ it('renders the link correctly', () => {
+ const link = wrapper.find('a');
+
+ expect(link.attributes('href')).toBe(autoDevopsHelpPagePath);
+ expect(link.text()).toBe('Auto DevOps');
+ });
+
+ it('bubbles up dismiss events from the GlAlert', () => {
+ expect(wrapper.emitted('dismiss')).toBe(undefined);
+
+ findAlert().vm.$emit('dismiss');
+
+ expect(wrapper.emitted('dismiss')).toEqual([[]]);
+ });
+
+ it('has a button pointing to autoDevopsPath', () => {
+ expect(findAlert().props()).toMatchObject({
+ primaryButtonText: 'Enable Auto DevOps',
+ primaryButtonLink: autoDevopsPath,
+ });
+ });
+});
diff --git a/spec/frontend/security_configuration/components/redesigned_app_spec.js b/spec/frontend/security_configuration/components/redesigned_app_spec.js
index 69c79082f5a..119a25a77c1 100644
--- a/spec/frontend/security_configuration/components/redesigned_app_spec.js
+++ b/spec/frontend/security_configuration/components/redesigned_app_spec.js
@@ -2,6 +2,7 @@ import { GlTab } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import AutoDevopsAlert from '~/security_configuration/components/auto_dev_ops_alert.vue';
import {
SAST_NAME,
SAST_SHORT_NAME,
@@ -13,6 +14,7 @@ import {
LICENSE_COMPLIANCE_HELP_PATH,
} from '~/security_configuration/components/constants';
import FeatureCard from '~/security_configuration/components/feature_card.vue';
+
import RedesignedSecurityConfigurationApp, {
i18n,
} from '~/security_configuration/components/redesigned_app.vue';
@@ -23,6 +25,8 @@ import {
} from '~/vue_shared/security_reports/constants';
const upgradePath = '/upgrade';
+const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath';
+const autoDevopsPath = '/autoDevopsPath';
const gitlabCiHistoryPath = 'test/historyPath';
describe('redesigned App component', () => {
@@ -37,6 +41,8 @@ describe('redesigned App component', () => {
propsData,
provide: {
upgradePath,
+ autoDevopsHelpPagePath,
+ autoDevopsPath,
},
stubs: {
UserCalloutDismisser: makeMockUserCalloutDismisser({
@@ -76,6 +82,7 @@ describe('redesigned App component', () => {
container: findByTestId('compliance-testing-tab'),
});
const findUpgradeBanner = () => wrapper.findComponent(UpgradeBanner);
+ const findAutoDevopsAlert = () => wrapper.findComponent(AutoDevopsAlert);
const securityFeaturesMock = [
{
@@ -154,6 +161,44 @@ describe('redesigned App component', () => {
});
});
+ describe('autoDevOpsAlert', () => {
+ describe('given the right props', () => {
+ beforeEach(() => {
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ autoDevopsEnabled: false,
+ gitlabCiPresent: false,
+ canEnableAutoDevops: true,
+ });
+ });
+
+ it('should show AutoDevopsAlert', () => {
+ expect(findAutoDevopsAlert().exists()).toBe(true);
+ });
+
+ it('calls the dismiss callback when closing the AutoDevopsAlert', () => {
+ expect(userCalloutDismissSpy).not.toHaveBeenCalled();
+
+ findAutoDevopsAlert().vm.$emit('dismiss');
+
+ expect(userCalloutDismissSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('given the wrong props', () => {
+ beforeEach(() => {
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ });
+ });
+ it('should not show AutoDevopsAlert', () => {
+ expect(findAutoDevopsAlert().exists()).toBe(false);
+ });
+ });
+ });
+
describe('upgrade banner', () => {
const makeAvailable = (available) => (feature) => ({ ...feature, available });
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 1804a9a99cf..10be0975225 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -876,6 +876,37 @@ RSpec.describe ProjectsHelper do
end
end
+ describe '#show_terraform_banner?' do
+ let_it_be(:ruby) { create(:programming_language, name: 'Ruby') }
+ let_it_be(:hcl) { create(:programming_language, name: 'HCL') }
+
+ subject { helper.show_terraform_banner?(project) }
+
+ before do
+ create(:repository_language, project: project, programming_language: language, share: 1)
+ end
+
+ context 'the project does not contain terraform files' do
+ let(:language) { ruby }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'the project contains terraform files' do
+ let(:language) { hcl }
+
+ it { is_expected.to be_truthy }
+
+ context 'the project already has a terraform state' do
+ before do
+ create(:terraform_state, project: project)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+
describe '#project_title' do
subject { helper.project_title(project) }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 42878b508de..58938251ca1 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -91,6 +91,20 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
end
end
+ context 'with job:tags' do
+ let(:attributes) do
+ {
+ name: 'rspec',
+ ref: 'master',
+ job_variables: [{ key: 'VARIABLE', value: 'value', public: true }],
+ tag_list: ['static-tag', '$VARIABLE', '$NO_VARIABLE']
+ }
+ end
+
+ it { is_expected.to include(tag_list: ['static-tag', 'value', '$NO_VARIABLE']) }
+ it { is_expected.to include(yaml_variables: [{ key: 'VARIABLE', value: 'value', public: true }]) }
+ end
+
context 'with cache:key' do
let(:attributes) do
{
diff --git a/spec/lib/gitlab/kas/client_spec.rb b/spec/lib/gitlab/kas/client_spec.rb
index 7bf2d30ca48..40e18f58ee4 100644
--- a/spec/lib/gitlab/kas/client_spec.rb
+++ b/spec/lib/gitlab/kas/client_spec.rb
@@ -30,10 +30,11 @@ RSpec.describe Gitlab::Kas::Client do
describe 'gRPC calls' do
let(:token) { instance_double(JSONWebToken::HMACToken, encoded: 'test-token') }
+ let(:kas_url) { 'grpc://example.kas.internal' }
before do
allow(Gitlab::Kas).to receive(:enabled?).and_return(true)
- allow(Gitlab::Kas).to receive(:internal_url).and_return('grpc://example.kas.internal')
+ allow(Gitlab::Kas).to receive(:internal_url).and_return(kas_url)
expect(JSONWebToken::HMACToken).to receive(:new)
.with(Gitlab::Kas.secret)
@@ -80,5 +81,21 @@ RSpec.describe Gitlab::Kas::Client do
it { expect(subject).to eq(agent_configurations) }
end
+
+ describe 'with grpcs' do
+ let(:stub) { instance_double(Gitlab::Agent::ConfigurationProject::Rpc::ConfigurationProject::Stub) }
+ let(:kas_url) { 'grpcs://example.kas.internal' }
+
+ it 'uses a ChannelCredentials object' do
+ expect(Gitlab::Agent::ConfigurationProject::Rpc::ConfigurationProject::Stub).to receive(:new)
+ .with('example.kas.internal', instance_of(GRPC::Core::ChannelCredentials), timeout: described_class::TIMEOUT)
+ .and_return(stub)
+
+ allow(stub).to receive(:list_agent_config_files)
+ .and_return(double(config_files: []))
+
+ described_class.new.list_agent_config_files(project: project)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb b/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb
index 153cf43be0a..0516091a8ec 100644
--- a/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb
+++ b/spec/lib/gitlab/metrics/subscribers/action_cable_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Metrics::Subscribers::ActionCable, :request_store do
let(:subscriber) { described_class.new }
let(:counter) { double(:counter) }
- let(:data) { { data: { event: 'updated' } } }
+ let(:data) { { 'result' => { 'data' => { 'event' => 'updated' } } } }
let(:channel_class) { 'IssuesChannel' }
let(:event) do
double(
@@ -35,6 +35,17 @@ RSpec.describe Gitlab::Metrics::Subscribers::ActionCable, :request_store do
subscriber.transmit(event)
end
+
+ it 'tracks size of payload as JSON' do
+ allow(::Gitlab::Metrics).to receive(:histogram).with(
+ :action_cable_transmitted_bytes, /transmit/
+ ).and_return(counter)
+ message_size = ::ActiveSupport::JSON.encode(data).bytesize
+
+ expect(counter).to receive(:observe).with({ channel: channel_class, operation: 'event' }, message_size)
+
+ subscriber.transmit(event)
+ end
end
describe '#broadcast' do
diff --git a/spec/models/project_ci_cd_setting_spec.rb b/spec/models/project_ci_cd_setting_spec.rb
index caab182cda8..c206ba27ec1 100644
--- a/spec/models/project_ci_cd_setting_spec.rb
+++ b/spec/models/project_ci_cd_setting_spec.rb
@@ -22,8 +22,8 @@ RSpec.describe ProjectCiCdSetting do
end
describe '#job_token_scope_enabled' do
- it 'is false by default' do
- expect(described_class.new.job_token_scope_enabled).to be_falsey
+ it 'is true by default' do
+ expect(described_class.new.job_token_scope_enabled).to be_truthy
end
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 3fb683ea0fa..b80b3f4e159 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -889,10 +889,10 @@ RSpec.describe 'Git HTTP requests' do
context 'when admin mode is enabled', :enable_admin_mode do
it_behaves_like 'can download code only'
- it 'downloads from other project get status 403' do
+ it 'downloads from other project get status 404' do
clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
@@ -1490,10 +1490,10 @@ RSpec.describe 'Git HTTP requests' do
context 'when admin mode is enabled', :enable_admin_mode do
it_behaves_like 'can download code only'
- it 'downloads from other project get status 403' do
+ it 'downloads from other project get status 404' do
clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb
index 02eb4262690..833889431e9 100644
--- a/spec/requests/lfs_http_spec.rb
+++ b/spec/requests/lfs_http_spec.rb
@@ -574,7 +574,7 @@ RSpec.describe 'Git LFS API and storage' do
let(:pipeline) { create(:ci_empty_pipeline, project: other_project) }
# I'm not sure what this tests that is different from the previous test
- it_behaves_like 'LFS http 403 response'
+ it_behaves_like 'LFS http 404 response'
end
end
@@ -1049,7 +1049,7 @@ RSpec.describe 'Git LFS API and storage' do
let(:pipeline) { create(:ci_empty_pipeline, project: other_project) }
# I'm not sure what this tests that is different from the previous test
- it_behaves_like 'LFS http 403 response'
+ it_behaves_like 'LFS http 404 response'
end
end
diff --git a/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb
new file mode 100644
index 00000000000..df881c1ac8f
--- /dev/null
+++ b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::CreatePipelineService do
+ let_it_be(:group) { create(:group, :private) }
+ let_it_be(:group_variable) { create(:ci_group_variable, group: group, key: 'RUNNER_TAG', value: 'group')}
+ let_it_be(:project) { create(:project, :repository, group: group) }
+ let_it_be(:user) { create(:user) }
+
+ let(:service) { described_class.new(project, user, ref: 'master') }
+ let(:pipeline) { service.execute(:push) }
+ let(:job) { pipeline.builds.find_by(name: 'job') }
+
+ before do
+ project.add_developer(user)
+ stub_ci_pipeline_yaml_file config
+ end
+
+ context 'when the variable is set' do
+ let(:config) do
+ <<~EOS
+ variables:
+ KUBERNETES_RUNNER: kubernetes
+
+ job:
+ tags:
+ - docker
+ - $KUBERNETES_RUNNER
+ script:
+ - echo "Hello runner selector feature"
+ EOS
+ end
+
+ it 'uses the evaluated variable' do
+ expect(pipeline).to be_created_successfully
+ expect(job.tags.pluck(:name)).to match_array(%w[docker kubernetes])
+ end
+ end
+
+ context 'when the tag is composed by two variables' do
+ let(:config) do
+ <<~EOS
+ variables:
+ CLOUD_PROVIDER: aws
+ KUBERNETES_RUNNER: kubernetes
+ ENVIRONMENT_NAME: prod
+
+ job:
+ tags:
+ - docker
+ - $CLOUD_PROVIDER-$KUBERNETES_RUNNER-$ENVIRONMENT_NAME
+ script:
+ - echo "Hello runner selector feature"
+ EOS
+ end
+
+ it 'uses the evaluated variables' do
+ expect(pipeline).to be_created_successfully
+ expect(job.tags.pluck(:name)).to match_array(%w[docker aws-kubernetes-prod])
+ end
+ end
+
+ context 'when the variable is not set' do
+ let(:config) do
+ <<~EOS
+ job:
+ tags:
+ - docker
+ - $KUBERNETES_RUNNER
+ script:
+ - echo "Hello runner selector feature"
+ EOS
+ end
+
+ it 'uses the variable as a regular string' do
+ expect(pipeline).to be_created_successfully
+ expect(job.tags.pluck(:name)).to match_array(%w[docker $KUBERNETES_RUNNER])
+ end
+ end
+
+ context 'when the tag uses group variables' do
+ let(:config) do
+ <<~EOS
+ job:
+ tags:
+ - docker
+ - $RUNNER_TAG
+ script:
+ - echo "Hello runner selector feature"
+ EOS
+ end
+
+ it 'uses the evaluated variables' do
+ expect(pipeline).to be_created_successfully
+ expect(job.tags.pluck(:name)).to match_array(%w[docker group])
+ end
+ end
+
+ context 'when the tag has the same variable name defined for both group and project' do
+ let_it_be(:project_variable) { create(:ci_variable, project: project, key: 'RUNNER_TAG', value: 'project') }
+
+ let(:config) do
+ <<~EOS
+ variables:
+ RUNNER_TAG: pipeline
+ job:
+ tags:
+ - docker
+ - $RUNNER_TAG
+ script:
+ - echo "Hello runner selector feature"
+ EOS
+ end
+
+ it 'uses the project variable instead of group due to variable precedence' do
+ expect(pipeline).to be_created_successfully
+ expect(job.tags.pluck(:name)).to match_array(%w[docker project])
+ end
+ end
+
+ context 'with parallel:matrix config' do
+ let(:tags) { pipeline.builds.map(&:tags).flatten.pluck(:name) }
+
+ let(:config) do
+ <<~EOS
+ job:
+ parallel:
+ matrix:
+ - PROVIDER: [aws, gcp]
+ STACK: [monitoring, backup, app]
+ tags:
+ - ${PROVIDER}-${STACK}
+ script:
+ - echo "Hello runner selector feature"
+ EOS
+ end
+
+ it 'uses the evaluated variables' do
+ expect(pipeline).to be_created_successfully
+ expect(tags).to match_array(%w[aws-monitoring aws-backup aws-app gcp-monitoring gcp-backup gcp-app])
+ end
+ end
+end
diff --git a/spec/views/projects/_flash_messages.html.haml_spec.rb b/spec/views/projects/_flash_messages.html.haml_spec.rb
new file mode 100644
index 00000000000..e1858229208
--- /dev/null
+++ b/spec/views/projects/_flash_messages.html.haml_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'projects/_flash_messages' do
+ let_it_be(:template) { 'projects/flash_messages' }
+ let_it_be(:user) { create(:user) }
+
+ let_it_be(:ruby) { create(:programming_language, name: 'Ruby') }
+ let_it_be(:html) { create(:programming_language, name: 'HTML') }
+ let_it_be(:hcl) { create(:programming_language, name: 'HCL') }
+
+ before do
+ allow(view).to receive(:current_user).and_return(user)
+ allow(view).to receive(:can?).with(user, :download_code, project).and_return(true)
+ end
+
+ context 'when current_user has download_code permission' do
+ context 'when user has a terraform state' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:terraform_state) { create(:terraform_state, :locked, :with_version, project: project) }
+
+ it "doesn't show the terraform notification banner" do
+ render(template, project: project)
+ expect(view.content_for(:flash_message)).not_to have_selector('.js-terraform-notification')
+ end
+ end
+
+ context 'when there are no .tf files in the repository' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:mock_repo_languages) do
+ { project => { ruby => 0.5, html => 0.5 } }
+ end
+
+ before do
+ mock_repo_languages.each do |project, lang_shares|
+ lang_shares.each do |lang, share|
+ create(:repository_language, project: project, programming_language: lang, share: share)
+ end
+ end
+ end
+
+ it "doesn't show the terraform notification banner" do
+ render(template, project: project)
+ expect(view.content_for(:flash_message)).not_to have_selector('.js-terraform-notification')
+ end
+ end
+
+ context 'when .tf files are present in the repository and user does not have any terraform states' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:mock_repo_languages) do
+ { project => { ruby => 0.5, hcl => 0.5 } }
+ end
+
+ before do
+ mock_repo_languages.each do |project, lang_shares|
+ lang_shares.each do |lang, share|
+ create(:repository_language, project: project, programming_language: lang, share: share)
+ end
+ end
+ end
+
+ it 'shows the terraform notification banner' do
+ render(template, project: project)
+ expect(view.content_for(:flash_message)).to have_selector('.js-terraform-notification')
+ end
+ end
+ end
+end