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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-16 03:09:09 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-16 03:09:09 +0300
commit72179bac11e9c18ea623e30594d6d427ef63db36 (patch)
tree601bc4fbb0a6c30ac866f11f278d80f920440c11
parent9922389a501dfde79037426fa6d09144ee5f7e1a (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_manual_todo.yml3
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.vue6
-rw-r--r--app/assets/javascripts/jobs/components/sidebar_job_details_container.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue10
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue10
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue38
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue269
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue79
-rw-r--r--app/controllers/projects/commit_controller.rb6
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/controllers/projects/pipelines_controller.rb1
-rw-r--r--app/helpers/application_settings_helper.rb3
-rw-r--r--app/models/application_setting.rb8
-rw-r--r--app/models/application_setting_implementation.rb3
-rw-r--r--app/serializers/runner_entity.rb2
-rw-r--r--app/views/admin/runners/_runner.html.haml17
-rw-r--r--app/views/admin/runners/index.html.haml3
-rw-r--r--app/views/groups/runners/_index.html.haml3
-rw-r--r--app/views/groups/runners/_runner.html.haml17
-rw-r--r--app/views/profiles/keys/_key.html.haml2
-rw-r--r--changelogs/unreleased/326197-change-runner-identifiers-job-sidebar-admin-list.yml6
-rw-r--r--changelogs/unreleased/326995-refer-to-expired-ssh-keys-in-the-past-tense.yml5
-rw-r--r--changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-services-design-management.yml5
-rw-r--r--changelogs/unreleased/mobsf_version.yml5
-rw-r--r--changelogs/unreleased/pb-flip-on-new-pipelines-table-ff.yml5
-rw-r--r--changelogs/unreleased/validation-service-token-to-config.yml5
-rw-r--r--config/feature_flags/development/new_pipelines_table.yml8
-rw-r--r--db/migrate/20210414131600_add_external_pipeline_validation_to_application_setting.rb19
-rw-r--r--db/migrate/20210415142700_add_url_limit_to_pipeline_validation.rb17
-rw-r--r--db/schema_migrations/202104141316001
-rw-r--r--db/schema_migrations/202104151427001
-rw-r--r--db/structure.sql5
-rw-r--r--doc/api/settings.md13
-rw-r--r--doc/user/application_security/dependency_list/img/dependency_list_v12_10.pngbin76835 -> 0 bytes
-rw-r--r--doc/user/application_security/dependency_list/img/dependency_list_v13_11.pngbin0 -> 85626 bytes
-rw-r--r--doc/user/application_security/dependency_list/index.md5
-rw-r--r--doc/user/packages/conan_repository/index.md2
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/external.rb6
-rw-r--r--lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml12
-rw-r--r--lib/gitlab/ci/templates/Security/API-Fuzzing.latest.gitlab-ci.yml270
-rw-r--r--lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml4
-rw-r--r--locale/gitlab.pot9
-rw-r--r--qa/qa/page/project/pipeline/index.rb5
-rw-r--r--spec/frontend/jobs/components/job_sidebar_details_container_spec.js15
-rw-r--r--spec/frontend/jobs/mock_data.js1
-rw-r--r--spec/frontend/pipelines/pipelines_table_row_spec.js239
-rw-r--r--spec/frontend/pipelines/pipelines_table_spec.js56
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb24
-rw-r--r--spec/serializers/runner_entity_spec.rb1
-rw-r--r--spec/services/design_management/copy_design_collection/copy_service_spec.rb1
-rw-r--r--spec/services/design_management/delete_designs_service_spec.rb1
-rw-r--r--spec/services/design_management/save_designs_service_spec.rb1
-rw-r--r--spec/views/profiles/keys/_key.html.haml_spec.rb14
53 files changed, 515 insertions, 731 deletions
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index dc21c6a62d5..32fe4c954cd 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -930,9 +930,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- spec/services/clusters/applications/prometheus_health_check_service_spec.rb
- spec/services/container_expiration_policy_service_spec.rb
- spec/services/dependency_proxy/find_or_create_manifest_service_spec.rb
- - spec/services/design_management/copy_design_collection/copy_service_spec.rb
- - spec/services/design_management/delete_designs_service_spec.rb
- - spec/services/design_management/save_designs_service_spec.rb
- spec/services/discussions/resolve_service_spec.rb
- spec/services/discussions/unresolve_service_spec.rb
- spec/services/feature_flags/create_service_spec.rb
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
index 7cd63ac152c..ddca5bc7d4f 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
@@ -90,9 +90,6 @@ export default {
canRenderPipelineButton() {
return this.latestPipelineDetachedFlag;
},
- pipelineButtonClass() {
- return !this.glFeatures.newPipelinesTable ? 'gl-md-display-none' : 'gl-lg-display-none';
- },
isForkMergeRequest() {
return this.sourceProjectFullPath !== this.targetProjectFullPath;
},
@@ -195,8 +192,7 @@ export default {
<gl-button
v-if="canRenderPipelineButton"
block
- class="gl-mt-3 gl-mb-3"
- :class="pipelineButtonClass"
+ class="gl-mt-3 gl-mb-3 gl-lg-display-none"
variant="confirm"
data-testid="run_pipeline_button_mobile"
:loading="state.isRunningMergeRequestPipeline"
diff --git a/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue b/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
index b20d58b6ffe..98badb96ed7 100644
--- a/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
+++ b/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
@@ -51,7 +51,9 @@ export default {
});
},
runnerId() {
- return `${this.job.runner.description} (#${this.job.runner.id})`;
+ const { id, short_sha: token, description } = this.job?.runner;
+
+ return `#${id} (${token}) ${description}`;
},
shouldRenderBlock() {
return Boolean(this.hasAnyDetail || this.hasTimeout || this.hasTags);
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
index c707b395192..0528e4c147c 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
@@ -17,19 +17,11 @@ export default {
user() {
return this.pipeline.user;
},
- classes() {
- const triggererClass = 'pipeline-triggerer';
-
- if (this.glFeatures.newPipelinesTable) {
- return triggererClass;
- }
- return `table-section section-10 d-none d-md-block ${triggererClass}`;
- },
},
};
</script>
<template>
- <div :class="classes" data-testid="pipeline-triggerer">
+ <div class="pipeline-triggerer" data-testid="pipeline-triggerer">
<user-avatar-link
v-if="user"
:link-href="user.path"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
index 0de520a2ca7..d39e120dc6c 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
@@ -49,19 +49,11 @@ export default {
autoDevopsHelpPath() {
return helpPagePath('topics/autodevops/index.md');
},
- classes() {
- const tagsClass = 'pipeline-tags';
-
- if (this.glFeatures.newPipelinesTable) {
- return tagsClass;
- }
- return `table-section section-10 d-none d-md-block ${tagsClass}`;
- },
},
};
</script>
<template>
- <div :class="classes" data-testid="pipeline-url-table-cell">
+ <div class="pipeline-tags" data-testid="pipeline-url-table-cell">
<gl-link
:href="pipeline.path"
data-testid="pipeline-url-link"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
index aa27aa7e50d..47fc7023222 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
@@ -1,7 +1,6 @@
<script>
import { GlTable, GlTooltipDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../../event_hub';
import PipelineMiniGraph from './pipeline_mini_graph.vue';
import PipelineOperations from './pipeline_operations.vue';
@@ -10,7 +9,6 @@ import PipelineTriggerer from './pipeline_triggerer.vue';
import PipelineUrl from './pipeline_url.vue';
import PipelinesCommit from './pipelines_commit.vue';
import PipelinesStatusBadge from './pipelines_status_badge.vue';
-import PipelinesTableRowComponent from './pipelines_table_row.vue';
import PipelinesTimeago from './time_ago.vue';
const DEFAULT_TD_CLASS = 'gl-p-5!';
@@ -83,7 +81,6 @@ export default {
PipelineOperations,
PipelinesStatusBadge,
PipelineStopModal,
- PipelinesTableRowComponent,
PipelinesTimeago,
PipelineTriggerer,
PipelineUrl,
@@ -91,7 +88,6 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [glFeatureFlagMixin()],
props: {
pipelines: {
type: Array,
@@ -149,41 +145,7 @@ export default {
</script>
<template>
<div class="ci-table">
- <div v-if="!glFeatures.newPipelinesTable" data-testid="legacy-ci-table">
- <div class="gl-responsive-table-row table-row-header" role="row">
- <div class="table-section section-10 js-pipeline-status" role="rowheader">
- {{ s__('Pipeline|Status') }}
- </div>
- <div class="table-section section-10 js-pipeline-info pipeline-info" role="rowheader">
- {{ s__('Pipeline|Pipeline') }}
- </div>
- <div class="table-section section-10 js-triggerer-info triggerer-info" role="rowheader">
- {{ s__('Pipeline|Triggerer') }}
- </div>
- <div class="table-section section-20 js-pipeline-commit pipeline-commit" role="rowheader">
- {{ s__('Pipeline|Commit') }}
- </div>
- <div class="table-section section-15 js-pipeline-stages pipeline-stages" role="rowheader">
- {{ s__('Pipeline|Stages') }}
- </div>
- <div class="table-section section-15" role="rowheader"></div>
- <div class="table-section section-20" role="rowheader">
- <slot name="table-header-actions"></slot>
- </div>
- </div>
- <pipelines-table-row-component
- v-for="model in pipelines"
- :key="model.id"
- :pipeline="model"
- :pipeline-schedule-url="pipelineScheduleUrl"
- :update-graph-dropdown="updateGraphDropdown"
- :view-type="viewType"
- :canceling-pipeline="cancelingPipeline"
- />
- </div>
-
<gl-table
- v-else
:fields="$options.fields"
:items="pipelines"
tbody-tr-class="commit"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue
deleted file mode 100644
index f684a0b0fcd..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue
+++ /dev/null
@@ -1,269 +0,0 @@
-<script>
-import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
-import { __ } from '~/locale';
-import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
-import CommitComponent from '~/vue_shared/components/commit.vue';
-import eventHub from '../../event_hub';
-import PipelineMiniGraph from './pipeline_mini_graph.vue';
-import PipelineTriggerer from './pipeline_triggerer.vue';
-import PipelineUrl from './pipeline_url.vue';
-import PipelinesArtifactsComponent from './pipelines_artifacts.vue';
-import PipelinesManualActionsComponent from './pipelines_manual_actions.vue';
-import PipelinesTimeago from './time_ago.vue';
-
-export default {
- i18n: {
- cancelTitle: __('Cancel'),
- redeployTitle: __('Retry'),
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- GlModalDirective,
- },
- components: {
- PipelinesManualActionsComponent,
- PipelinesArtifactsComponent,
- CommitComponent,
- PipelineMiniGraph,
- PipelineUrl,
- PipelineTriggerer,
- CiBadge,
- PipelinesTimeago,
- GlButton,
- },
- props: {
- pipeline: {
- type: Object,
- required: true,
- },
- pipelineScheduleUrl: {
- type: String,
- required: false,
- default: '',
- },
- updateGraphDropdown: {
- type: Boolean,
- required: false,
- default: false,
- },
- viewType: {
- type: String,
- required: true,
- },
- cancelingPipeline: {
- type: Number,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- isRetrying: false,
- };
- },
- computed: {
- actions() {
- if (!this.pipeline || !this.pipeline.details) {
- return [];
- }
- const { details } = this.pipeline;
- return [...(details.manual_actions || []), ...(details.scheduled_actions || [])];
- },
- /**
- * If provided, returns the commit tag.
- * Needed to render the commit component column.
- *
- * This field needs a lot of verification, because of different possible cases:
- *
- * 1. person who is an author of a commit might be a GitLab user
- * 2. if person who is an author of a commit is a GitLab user, they can have a GitLab avatar
- * 3. If GitLab user does not have avatar they might have a Gravatar
- * 4. If committer is not a GitLab User they can have a Gravatar
- * 5. We do not have consistent API object in this case
- * 6. We should improve API and the code
- *
- * @returns {Object|Undefined}
- */
- commitAuthor() {
- let commitAuthorInformation;
-
- if (!this.pipeline || !this.pipeline.commit) {
- return null;
- }
-
- // 1. person who is an author of a commit might be a GitLab user
- if (this.pipeline.commit.author) {
- // 2. if person who is an author of a commit is a GitLab user
- // they can have a GitLab avatar
- if (this.pipeline.commit.author.avatar_url) {
- commitAuthorInformation = this.pipeline.commit.author;
-
- // 3. If GitLab user does not have avatar, they might have a Gravatar
- } else if (this.pipeline.commit.author_gravatar_url) {
- commitAuthorInformation = {
- ...this.pipeline.commit.author,
- avatar_url: this.pipeline.commit.author_gravatar_url,
- };
- }
- // 4. If committer is not a GitLab User, they can have a Gravatar
- } else {
- commitAuthorInformation = {
- avatar_url: this.pipeline.commit.author_gravatar_url,
- path: `mailto:${this.pipeline.commit.author_email}`,
- username: this.pipeline.commit.author_name,
- };
- }
-
- return commitAuthorInformation;
- },
- commitTag() {
- return this.pipeline?.ref?.tag;
- },
- commitRef() {
- return this.pipeline?.ref;
- },
- commitUrl() {
- return this.pipeline?.commit?.commit_path;
- },
- commitShortSha() {
- return this.pipeline?.commit?.short_id;
- },
- commitTitle() {
- return this.pipeline?.commit?.title;
- },
- pipelineStatus() {
- return this.pipeline?.details?.status ?? {};
- },
- hasStages() {
- return this.pipeline?.details?.stages?.length > 0;
- },
- displayPipelineActions() {
- return (
- this.pipeline.flags.retryable ||
- this.pipeline.flags.cancelable ||
- this.pipeline.details.manual_actions.length ||
- this.pipeline.details.artifacts.length
- );
- },
- isChildView() {
- return this.viewType === 'child';
- },
- isCancelling() {
- return this.cancelingPipeline === this.pipeline.id;
- },
- },
- watch: {
- pipeline() {
- this.isRetrying = false;
- },
- },
- methods: {
- handleCancelClick() {
- eventHub.$emit('openConfirmationModal', {
- pipeline: this.pipeline,
- endpoint: this.pipeline.cancel_path,
- });
- },
- handleRetryClick() {
- this.isRetrying = true;
- eventHub.$emit('retryPipeline', this.pipeline.retry_path);
- },
- handlePipelineActionRequestComplete() {
- // warn the pipelines table to update
- eventHub.$emit('refreshPipelinesTable');
- },
- },
-};
-</script>
-<template>
- <div class="commit gl-responsive-table-row">
- <div class="table-section section-10 commit-link">
- <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Status') }}</div>
- <div class="table-mobile-content">
- <ci-badge
- :status="pipelineStatus"
- :show-text="!isChildView"
- :icon-classes="'gl-vertical-align-middle!'"
- data-qa-selector="pipeline_commit_status"
- />
- </div>
- </div>
-
- <pipeline-url :pipeline="pipeline" :pipeline-schedule-url="pipelineScheduleUrl" />
- <pipeline-triggerer :pipeline="pipeline" />
-
- <div class="table-section section-wrap section-20">
- <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Commit') }}</div>
- <div class="table-mobile-content">
- <commit-component
- :tag="commitTag"
- :commit-ref="commitRef"
- :commit-url="commitUrl"
- :merge-request-ref="pipeline.merge_request"
- :short-sha="commitShortSha"
- :title="commitTitle"
- :author="commitAuthor"
- :show-ref-info="!isChildView"
- />
- </div>
- </div>
-
- <div class="table-section section-wrap section-15 stage-cell">
- <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Stages') }}</div>
- <div class="table-mobile-content">
- <pipeline-mini-graph
- v-if="hasStages"
- :stages="pipeline.details.stages"
- :update-dropdown="updateGraphDropdown"
- @pipelineActionRequestComplete="handlePipelineActionRequestComplete"
- />
- </div>
- </div>
-
- <pipelines-timeago class="gl-text-right" :pipeline="pipeline" />
-
- <div
- v-if="displayPipelineActions"
- class="table-section section-20 table-button-footer pipeline-actions"
- >
- <div class="btn-group table-action-buttons">
- <pipelines-manual-actions-component v-if="actions.length > 0" :actions="actions" />
-
- <pipelines-artifacts-component
- v-if="pipeline.details.artifacts.length"
- :artifacts="pipeline.details.artifacts"
- />
-
- <gl-button
- v-if="pipeline.flags.retryable"
- v-gl-tooltip.hover
- :aria-label="$options.i18n.redeployTitle"
- :title="$options.i18n.redeployTitle"
- :disabled="isRetrying"
- :loading="isRetrying"
- class="js-pipelines-retry-button"
- data-qa-selector="pipeline_retry_button"
- icon="repeat"
- variant="default"
- category="secondary"
- @click="handleRetryClick"
- />
-
- <gl-button
- v-if="pipeline.flags.cancelable"
- v-gl-tooltip.hover
- v-gl-modal-directive="'confirmation-modal'"
- :aria-label="$options.i18n.cancelTitle"
- :title="$options.i18n.cancelTitle"
- :loading="isCancelling"
- :disabled="isCancelling"
- icon="close"
- variant="danger"
- category="primary"
- class="js-pipelines-cancel-button"
- @click="handleCancelClick"
- />
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
index 7082446d60e..e6b03751350 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
@@ -48,12 +48,6 @@ export default {
return `${hh}:${mm}:${ss}`;
},
- legacySectionClass() {
- return !this.glFeatures.newPipelinesTable ? 'table-section section-15' : '';
- },
- legacyTableMobileClass() {
- return !this.glFeatures.newPipelinesTable ? 'table-mobile-content' : '';
- },
showInProgress() {
return !this.duration && !this.finishedTime && !this.skipped;
},
@@ -64,51 +58,40 @@ export default {
};
</script>
<template>
- <div :class="legacySectionClass">
- <div v-if="!glFeatures.newPipelinesTable" class="table-mobile-header" role="rowheader">
- {{ s__('Pipeline|Duration') }}
- </div>
- <div :class="legacyTableMobileClass">
- <span v-if="showInProgress" data-testid="pipeline-in-progress">
- <gl-icon
- v-if="stuck"
- name="warning"
- class="gl-mr-2"
- :size="12"
- data-testid="warning-icon"
- />
- <gl-icon
- v-else
- name="hourglass"
- class="gl-vertical-align-baseline! gl-mr-2"
- :size="12"
- data-testid="hourglass-icon"
- />
- {{ s__('Pipeline|In progress') }}
- </span>
+ <div>
+ <span v-if="showInProgress" data-testid="pipeline-in-progress">
+ <gl-icon v-if="stuck" name="warning" class="gl-mr-2" :size="12" data-testid="warning-icon" />
+ <gl-icon
+ v-else
+ name="hourglass"
+ class="gl-vertical-align-baseline! gl-mr-2"
+ :size="12"
+ data-testid="hourglass-icon"
+ />
+ {{ s__('Pipeline|In progress') }}
+ </span>
- <span v-if="showSkipped" data-testid="pipeline-skipped">
- <gl-icon name="status_skipped_borderless" class="gl-mr-2" :size="16" />
- {{ s__('Pipeline|Skipped') }}
- </span>
+ <span v-if="showSkipped" data-testid="pipeline-skipped">
+ <gl-icon name="status_skipped_borderless" class="gl-mr-2" :size="16" />
+ {{ s__('Pipeline|Skipped') }}
+ </span>
- <p v-if="duration" class="duration">
- <gl-icon name="timer" class="gl-vertical-align-baseline!" :size="12" />
- {{ durationFormatted }}
- </p>
+ <p v-if="duration" class="duration">
+ <gl-icon name="timer" class="gl-vertical-align-baseline!" :size="12" />
+ {{ durationFormatted }}
+ </p>
- <p v-if="finishedTime" class="finished-at d-none d-md-block">
- <gl-icon name="calendar" class="gl-vertical-align-baseline!" :size="12" />
+ <p v-if="finishedTime" class="finished-at d-none d-md-block">
+ <gl-icon name="calendar" class="gl-vertical-align-baseline!" :size="12" />
- <time
- v-gl-tooltip
- :title="tooltipTitle(finishedTime)"
- data-placement="top"
- data-container="body"
- >
- {{ timeFormatted(finishedTime) }}
- </time>
- </p>
- </div>
+ <time
+ v-gl-tooltip
+ :title="tooltipTitle(finishedTime)"
+ data-placement="top"
+ data-container="body"
+ >
+ {{ timeFormatted(finishedTime) }}
+ </time>
+ </p>
</div>
</template>
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 3853797e0bf..0c3ff07bc76 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -54,8 +54,6 @@ class Projects::CommitController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def pipelines
- set_pipeline_feature_flag
-
@pipelines = @commit.pipelines.order(id: :desc)
@pipelines = @pipelines.where(ref: params[:ref]).page(params[:page]).per(30) if params[:ref]
@@ -135,10 +133,6 @@ class Projects::CommitController < Projects::ApplicationController
private
- def set_pipeline_feature_flag
- push_frontend_feature_flag(:new_pipelines_table, @project, default_enabled: :yaml)
- end
-
def create_new_branch?
params[:create_merge_request].present? || !can?(current_user, :push_code, @project)
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 4d612cd45d0..1f370fce48d 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -39,7 +39,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:diffs_gradual_load, @project, default_enabled: true)
push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml)
push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml)
- push_frontend_feature_flag(:new_pipelines_table, @project, default_enabled: :yaml)
push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:usage_data_i_testing_summary_widget_total, @project, default_enabled: :yaml)
push_frontend_feature_flag(:improved_emoji_picker, project, default_enabled: :yaml)
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 1828c6466e6..ee1e10221ec 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -19,7 +19,6 @@ class Projects::PipelinesController < Projects::ApplicationController
push_frontend_feature_flag(:graphql_pipeline_details, project, type: :development, default_enabled: :yaml)
push_frontend_feature_flag(:graphql_pipeline_details_users, current_user, type: :development, default_enabled: :yaml)
push_frontend_feature_flag(:jira_for_vulnerabilities, project, type: :development, default_enabled: :yaml)
- push_frontend_feature_flag(:new_pipelines_table, project, default_enabled: :yaml)
end
before_action :ensure_pipeline, only: [:show]
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 6b65b1c0bff..504ebb5606e 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -229,6 +229,9 @@ module ApplicationSettingsHelper
:email_author_in_body,
:enabled_git_access_protocol,
:enforce_terms,
+ :external_pipeline_validation_service_timeout,
+ :external_pipeline_validation_service_token,
+ :external_pipeline_validation_service_url,
:first_day_of_week,
:force_pages_access_control,
:gitaly_timeout_default,
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index dbc09a3c9b2..f405f5ca5d3 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -468,6 +468,13 @@ class ApplicationSetting < ApplicationRecord
validates :admin_mode,
inclusion: { in: [true, false], message: _('must be a boolean value') }
+ validates :external_pipeline_validation_service_url,
+ addressable_url: true, allow_blank: true
+
+ validates :external_pipeline_validation_service_timeout,
+ allow_nil: true,
+ numericality: { only_integer: true, greater_than: 0 }
+
attr_encrypted :asset_proxy_secret_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
@@ -496,6 +503,7 @@ class ApplicationSetting < ApplicationRecord
attr_encrypted :ci_jwt_signing_key, encryption_options_base_truncated_aes_256_gcm
attr_encrypted :secret_detection_token_revocation_token, encryption_options_base_truncated_aes_256_gcm
attr_encrypted :cloud_license_auth_token, encryption_options_base_truncated_aes_256_gcm
+ attr_encrypted :external_pipeline_validation_service_token, encryption_options_base_truncated_aes_256_gcm
validates :disable_feed_token,
inclusion: { in: [true, false], message: _('must be a boolean value') }
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index dba72f88986..e67d261d3b4 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -72,6 +72,9 @@ module ApplicationSettingImplementation
eks_secret_access_key: nil,
email_restrictions_enabled: false,
email_restrictions: nil,
+ external_pipeline_validation_service_timeout: nil,
+ external_pipeline_validation_service_token: nil,
+ external_pipeline_validation_service_url: nil,
first_day_of_week: 0,
gitaly_timeout_default: 55,
gitaly_timeout_fast: 10,
diff --git a/app/serializers/runner_entity.rb b/app/serializers/runner_entity.rb
index 97e5b336a35..6d6ba920a3b 100644
--- a/app/serializers/runner_entity.rb
+++ b/app/serializers/runner_entity.rb
@@ -3,7 +3,7 @@
class RunnerEntity < Grape::Entity
include RequestAwareEntity
- expose :id, :description
+ expose :id, :description, :short_sha
expose :edit_path, if: -> (*) { can_edit_runner? } do |runner|
edit_project_runner_path(project, runner)
diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml
index 8882bab2e57..c3e4626c14e 100644
--- a/app/views/admin/runners/_runner.html.haml
+++ b/app/views/admin/runners/_runner.html.haml
@@ -1,3 +1,6 @@
+-# Note: This file should stay aligned with:
+-# `app/views/groups/runners/_runner.html.haml`
+
.gl-responsive-table-row{ id: dom_id(runner) }
.table-section.section-10.section-wrap
.table-mobile-header{ role: 'rowheader' }= _('Type')
@@ -13,15 +16,13 @@
- unless runner.active?
%span.badge.badge-pill.gl-badge.sm.badge-danger= _("paused")
- .table-section.section-10
- .table-mobile-header{ role: 'rowheader' }= _('Runner token')
+ .table-section.section-30
+ .table-mobile-header{ role: 'rowheader' }= s_('Runners|Runner')
.table-mobile-content
- = link_to runner.short_sha, admin_runner_path(runner)
-
- .table-section.section-20
- .table-mobile-header{ role: 'rowheader' }= _('Description')
- .table-mobile-content.str-truncated.has-tooltip{ title: runner.description }
- = runner.description
+ = link_to("##{runner.id} (#{runner.short_sha})", admin_runner_path(runner))
+ .gl-text-truncate
+ %span{ title: runner.description, data: { toggle: 'tooltip', container: 'body' } }
+ = runner.description
.table-section.section-10
.table-mobile-header{ role: 'rowheader' }= _('Version')
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 564d6000bc1..a38615d9b1b 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -122,8 +122,7 @@
.table-holder
.gl-responsive-table-row.table-row-header{ role: 'row' }
.table-section.section-10{ role: 'rowheader' }= _('Type/State')
- .table-section.section-10{ role: 'rowheader' }= _('Runner token')
- .table-section.section-20{ role: 'rowheader' }= _('Description')
+ .table-section.section-30{ role: 'rowheader' }= s_('Runners|Runner')
.table-section.section-10{ role: 'rowheader' }= _('Version')
.table-section.section-10{ role: 'rowheader' }= _('IP Address')
.table-section.section-5{ role: 'rowheader' }= _('Projects')
diff --git a/app/views/groups/runners/_index.html.haml b/app/views/groups/runners/_index.html.haml
index 724a41b84e6..187588f5f11 100644
--- a/app/views/groups/runners/_index.html.haml
+++ b/app/views/groups/runners/_index.html.haml
@@ -86,8 +86,7 @@
.table-holder
.gl-responsive-table-row.table-row-header{ role: 'row' }
.table-section.section-10{ role: 'rowheader' }= _('Type/State')
- .table-section.section-10{ role: 'rowheader' }= _('Runner token')
- .table-section.section-20{ role: 'rowheader' }= _('Description')
+ .table-section.section-30{ role: 'rowheader' }= s_('Runners|Runner')
.table-section.section-10{ role: 'rowheader' }= _('Version')
.table-section.section-10{ role: 'rowheader' }= _('IP Address')
.table-section.section-5{ role: 'rowheader' }= _('Projects')
diff --git a/app/views/groups/runners/_runner.html.haml b/app/views/groups/runners/_runner.html.haml
index c687167e519..89e32c0999c 100644
--- a/app/views/groups/runners/_runner.html.haml
+++ b/app/views/groups/runners/_runner.html.haml
@@ -1,3 +1,6 @@
+-# Note: This file should stay aligned with:
+-# `app/views/admin/runners/_runner.html.haml`
+
.gl-responsive-table-row{ id: dom_id(runner) }
.table-section.section-10.section-wrap
.table-mobile-header{ role: 'rowheader' }= _('Type')
@@ -15,15 +18,13 @@
%span.badge.badge-pill.gl-badge.sm.badge-danger
= _('paused')
- .table-section.section-10
- .table-mobile-header{ role: 'rowheader' }= _('Runner token')
+ .table-section.section-30
+ .table-mobile-header{ role: 'rowheader' }= s_('Runners|Runner')
.table-mobile-content
- = link_to runner.short_sha, group_runner_path(@group, runner)
-
- .table-section.section-20
- .table-mobile-header{ role: 'rowheader' }= _('Description')
- .table-mobile-content.str-truncated.has-tooltip{ title: runner.description }
- = runner.description
+ = link_to("##{runner.id} (#{runner.short_sha})", group_runner_path(@group, runner))
+ .gl-text-truncate
+ %span{ title: runner.description, data: { toggle: 'tooltip', container: 'body' } }
+ = runner.description
.table-section.section-10
.table-mobile-header{ role: 'rowheader' }= _('Version')
diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml
index 6a87e052272..4eb321050ad 100644
--- a/app/views/profiles/keys/_key.html.haml
+++ b/app/views/profiles/keys/_key.html.haml
@@ -23,7 +23,7 @@
= s_('Profiles|Last used:')
= key.last_used_at ? time_ago_with_tooltip(key.last_used_at) : _('Never')
%span.expires.gl-mr-3
- = s_('Profiles|Expires:')
+ = key.expired? ? s_('Profiles|Expired:') : s_('Profiles|Expires:')
= key.expires_at ? key.expires_at.to_date : _('Never')
%span.key-created-at.gl-display-flex.gl-align-items-center
- if key.can_delete?
diff --git a/changelogs/unreleased/326197-change-runner-identifiers-job-sidebar-admin-list.yml b/changelogs/unreleased/326197-change-runner-identifiers-job-sidebar-admin-list.yml
new file mode 100644
index 00000000000..79991023375
--- /dev/null
+++ b/changelogs/unreleased/326197-change-runner-identifiers-job-sidebar-admin-list.yml
@@ -0,0 +1,6 @@
+---
+title: Display runner token and description consistently in the job sidebar and admin
+ list
+merge_request: 58904
+author:
+type: changed
diff --git a/changelogs/unreleased/326995-refer-to-expired-ssh-keys-in-the-past-tense.yml b/changelogs/unreleased/326995-refer-to-expired-ssh-keys-in-the-past-tense.yml
new file mode 100644
index 00000000000..59caecce8f3
--- /dev/null
+++ b/changelogs/unreleased/326995-refer-to-expired-ssh-keys-in-the-past-tense.yml
@@ -0,0 +1,5 @@
+---
+title: Update profile SSH key labels to refer to expired keys as "Expired"
+merge_request: 59381
+author:
+type: changed
diff --git a/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-services-design-management.yml b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-services-design-management.yml
new file mode 100644
index 00000000000..4a2c45c7117
--- /dev/null
+++ b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-services-design-management.yml
@@ -0,0 +1,5 @@
+---
+title: Fix EmptyLineAfterFinalLetItBe in spec/services/design_management
+merge_request: 58416
+author: Huzaifa Iftikhar @huzaifaiftikhar
+type: fixed
diff --git a/changelogs/unreleased/mobsf_version.yml b/changelogs/unreleased/mobsf_version.yml
new file mode 100644
index 00000000000..d26a3d6726d
--- /dev/null
+++ b/changelogs/unreleased/mobsf_version.yml
@@ -0,0 +1,5 @@
+---
+title: Update MobSF to version 3.4.0 in the SAST template
+merge_request: 58594
+author:
+type: changed
diff --git a/changelogs/unreleased/pb-flip-on-new-pipelines-table-ff.yml b/changelogs/unreleased/pb-flip-on-new-pipelines-table-ff.yml
new file mode 100644
index 00000000000..6759962cd59
--- /dev/null
+++ b/changelogs/unreleased/pb-flip-on-new-pipelines-table-ff.yml
@@ -0,0 +1,5 @@
+---
+title: Use GlTable design system component for pipelines table
+merge_request: 58581
+author:
+type: changed
diff --git a/changelogs/unreleased/validation-service-token-to-config.yml b/changelogs/unreleased/validation-service-token-to-config.yml
new file mode 100644
index 00000000000..1242e3f02ba
--- /dev/null
+++ b/changelogs/unreleased/validation-service-token-to-config.yml
@@ -0,0 +1,5 @@
+---
+title: Obtain pipeline validation service token from config not ENV.
+merge_request: 59101
+author:
+type: other
diff --git a/config/feature_flags/development/new_pipelines_table.yml b/config/feature_flags/development/new_pipelines_table.yml
deleted file mode 100644
index 33a7226dd34..00000000000
--- a/config/feature_flags/development/new_pipelines_table.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: new_pipelines_table
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54958
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/322599
-milestone: '13.10'
-type: development
-group: group::continuous integration
-default_enabled: true
diff --git a/db/migrate/20210414131600_add_external_pipeline_validation_to_application_setting.rb b/db/migrate/20210414131600_add_external_pipeline_validation_to_application_setting.rb
new file mode 100644
index 00000000000..537f7727691
--- /dev/null
+++ b/db/migrate/20210414131600_add_external_pipeline_validation_to_application_setting.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddExternalPipelineValidationToApplicationSetting < ActiveRecord::Migration[6.0]
+ def up
+ add_column :application_settings, :external_pipeline_validation_service_timeout, :integer
+ # rubocop:disable Migration/AddLimitToTextColumns
+ add_column :application_settings, :encrypted_external_pipeline_validation_service_token, :text
+ add_column :application_settings, :encrypted_external_pipeline_validation_service_token_iv, :text
+ add_column :application_settings, :external_pipeline_validation_service_url, :text
+ # rubocop:enable Migration/AddLimitToTextColumns
+ end
+
+ def down
+ remove_column :application_settings, :external_pipeline_validation_service_timeout
+ remove_column :application_settings, :encrypted_external_pipeline_validation_service_token
+ remove_column :application_settings, :encrypted_external_pipeline_validation_service_token_iv
+ remove_column :application_settings, :external_pipeline_validation_service_url
+ end
+end
diff --git a/db/migrate/20210415142700_add_url_limit_to_pipeline_validation.rb b/db/migrate/20210415142700_add_url_limit_to_pipeline_validation.rb
new file mode 100644
index 00000000000..9c38e04a96b
--- /dev/null
+++ b/db/migrate/20210415142700_add_url_limit_to_pipeline_validation.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddUrlLimitToPipelineValidation < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = 'app_settings_ext_pipeline_validation_service_url_text_limit'
+
+ def up
+ add_text_limit :application_settings, :external_pipeline_validation_service_url, 255, constraint_name: CONSTRAINT_NAME
+ end
+
+ def down
+ remove_check_constraint(:application_settings, CONSTRAINT_NAME)
+ end
+end
diff --git a/db/schema_migrations/20210414131600 b/db/schema_migrations/20210414131600
new file mode 100644
index 00000000000..2ed1c9856ae
--- /dev/null
+++ b/db/schema_migrations/20210414131600
@@ -0,0 +1 @@
+199c8a540cb4a0dd30a86a81f993798afb3e7384f1176b71a780d5950a52eb5f \ No newline at end of file
diff --git a/db/schema_migrations/20210415142700 b/db/schema_migrations/20210415142700
new file mode 100644
index 00000000000..22b10173911
--- /dev/null
+++ b/db/schema_migrations/20210415142700
@@ -0,0 +1 @@
+2d6d62b036c937136dfbb11becfd3c2c705f0db1e3a38fdcefe676106168ab29 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 6df80a14d0f..710a112d521 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -9441,7 +9441,12 @@ CREATE TABLE application_settings (
admin_mode boolean DEFAULT false NOT NULL,
delayed_project_removal boolean DEFAULT false NOT NULL,
lock_delayed_project_removal boolean DEFAULT false NOT NULL,
+ external_pipeline_validation_service_timeout integer,
+ encrypted_external_pipeline_validation_service_token text,
+ encrypted_external_pipeline_validation_service_token_iv text,
+ external_pipeline_validation_service_url text,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
+ CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 913a3699fe4..6322f14442c 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -87,7 +87,10 @@ Example response:
"personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null,
"keep_latest_artifact": true,
- "admin_mode": false
+ "admin_mode": false,
+ "external_pipeline_validation_service_timeout": null,
+ "external_pipeline_validation_service_token": null,
+ "external_pipeline_validation_service_url": null
}
```
@@ -183,7 +186,10 @@ Example response:
"personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null,
"keep_latest_artifact": true,
- "admin_mode": false
+ "admin_mode": false,
+ "external_pipeline_validation_service_timeout": null,
+ "external_pipeline_validation_service_token": null,
+ "external_pipeline_validation_service_url": null
}
```
@@ -283,6 +289,9 @@ listed in the descriptions of the relevant settings.
| `external_authorization_service_enabled` | boolean | no | (**If enabled, requires:** `external_authorization_service_default_label`, `external_authorization_service_timeout` and `external_authorization_service_url`) Enable using an external authorization service for accessing projects |
| `external_authorization_service_timeout` | float | required by:<br>`external_authorization_service_enabled` | The timeout after which an authorization request is aborted, in seconds. When a request times out, access is denied to the user. (min: 0.001, max: 10, step: 0.001). |
| `external_authorization_service_url` | string | required by:<br>`external_authorization_service_enabled` | URL to which authorization requests are directed. |
+| `external_pipeline_validation_service_url` | string | no | URL to which pipeline validation requests are directed. |
+| `external_pipeline_validation_service_token` | string | no | An optional token to include as the `X-Gitlab-Token` header in requests to the URL in external_pipeline_validation_service_url. |
+| `external_pipeline_validation_service_timeout` | integer | no | How long to wait for a response from the pipeline validation service before giving up and assuming 'OK'. |
| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from |
| `first_day_of_week` | integer | no | Start day of the week for calendar views and date pickers. Valid values are `0` (default) for Sunday, `1` for Monday, and `6` for Saturday. |
| `geo_node_allowed_ips` | string | yes | **(PREMIUM)** Comma-separated list of IPs and CIDRs of allowed secondary nodes. For example, `1.1.1.1, 2.2.2.0/24`. |
diff --git a/doc/user/application_security/dependency_list/img/dependency_list_v12_10.png b/doc/user/application_security/dependency_list/img/dependency_list_v12_10.png
deleted file mode 100644
index 2755b42f1e4..00000000000
--- a/doc/user/application_security/dependency_list/img/dependency_list_v12_10.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/dependency_list/img/dependency_list_v13_11.png b/doc/user/application_security/dependency_list/img/dependency_list_v13_11.png
new file mode 100644
index 00000000000..5b2bd985ce4
--- /dev/null
+++ b/doc/user/application_security/dependency_list/img/dependency_list_v13_11.png
Binary files differ
diff --git a/doc/user/application_security/dependency_list/index.md b/doc/user/application_security/dependency_list/index.md
index 6ed3b15d829..25b7615a8ae 100644
--- a/doc/user/application_security/dependency_list/index.md
+++ b/doc/user/application_security/dependency_list/index.md
@@ -26,7 +26,7 @@ To view your project's dependencies, ensure you meet the following requirements:
## View a project's dependencies
-![Dependency list](img/dependency_list_v12_10.png)
+![Dependency list](img/dependency_list_v13_11.png)
GitLab displays dependencies with the following information:
@@ -44,7 +44,8 @@ can also be sorted by name or by the packager that installed them.
If a dependency has known vulnerabilities, view them by clicking the arrow next to the
dependency's name or the badge that indicates how many known vulnerabilities exist. For each
-vulnerability, its severity and description appears below it.
+vulnerability, its severity and description appears below it. To view more details of a vulnerability,
+select the vulnerability’s description. The [vulnerability's details](../vulnerabilities) page is opened.
### Dependency paths
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index a519f07da77..9df4aeb404a 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -128,7 +128,7 @@ To add the remote:
For example:
```shell
- conan search Hello* --all --remote=gitlab
+ conan search Hello* --remote=gitlab
```
### Add a remote for your instance
diff --git a/lib/gitlab/ci/pipeline/chain/validate/external.rb b/lib/gitlab/ci/pipeline/chain/validate/external.rb
index 9d1aeb75ccc..93f4bebd41d 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/external.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/external.rb
@@ -82,18 +82,18 @@ module Gitlab
end
def validation_service_timeout
- timeout = ENV['EXTERNAL_VALIDATION_SERVICE_TIMEOUT'].to_i
+ timeout = Gitlab::CurrentSettings.external_pipeline_validation_service_timeout || ENV['EXTERNAL_VALIDATION_SERVICE_TIMEOUT'].to_i
return timeout if timeout > 0
DEFAULT_VALIDATION_REQUEST_TIMEOUT
end
def validation_service_url
- ENV['EXTERNAL_VALIDATION_SERVICE_URL']
+ Gitlab::CurrentSettings.external_pipeline_validation_service_url || ENV['EXTERNAL_VALIDATION_SERVICE_URL']
end
def validation_service_token
- ENV['EXTERNAL_VALIDATION_SERVICE_TOKEN']
+ Gitlab::CurrentSettings.external_pipeline_validation_service_token || ENV['EXTERNAL_VALIDATION_SERVICE_TOKEN']
end
def validation_service_payload
diff --git a/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
index 654a03ced5f..bf42cd52605 100644
--- a/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
@@ -12,7 +12,7 @@ stages:
variables:
FUZZAPI_PROFILE: Quick
- FUZZAPI_VERSION: latest
+ FUZZAPI_VERSION: "1.6"
FUZZAPI_CONFIG: .gitlab-api-fuzzing.yml
FUZZAPI_TIMEOUT: 30
FUZZAPI_REPORT: gl-api-fuzzing-report.json
@@ -45,7 +45,7 @@ apifuzzer_fuzz:
entrypoint: ["/bin/bash", "-l", "-c"]
variables:
FUZZAPI_PROJECT: $CI_PROJECT_PATH
- FUZZAPI_API: http://localhost:80
+ FUZZAPI_API: http://localhost:5000
FUZZAPI_NEW_REPORT: 1
FUZZAPI_LOG_SCANNER: gl-apifuzzing-api-scanner.log
TZ: America/Los_Angeles
@@ -107,7 +107,7 @@ apifuzzer_fuzz_dnd:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
FUZZAPI_PROJECT: $CI_PROJECT_PATH
- FUZZAPI_API: http://apifuzzer:80
+ FUZZAPI_API: http://apifuzzer:5000
allow_failure: true
rules:
- if: $FUZZAPI_D_TARGET_IMAGE == null && $FUZZAPI_D_WORKER_IMAGE == null
@@ -142,6 +142,7 @@ apifuzzer_fuzz_dnd:
-e TZ=America/Los_Angeles \
-e GITLAB_FEATURES \
-p 80:80 \
+ -p 5000:5000 \
-p 8000:8000 \
-p 514:514 \
--restart=no \
@@ -168,7 +169,7 @@ apifuzzer_fuzz_dnd:
docker run \
--name worker \
--network $FUZZAPI_D_NETWORK \
- -e FUZZAPI_API=http://apifuzzer:80 \
+ -e FUZZAPI_API=http://apifuzzer:5000 \
-e FUZZAPI_PROJECT \
-e FUZZAPI_PROFILE \
-e FUZZAPI_CONFIG \
@@ -211,7 +212,7 @@ apifuzzer_fuzz_dnd:
--name worker \
--network $FUZZAPI_D_NETWORK \
-e TZ=America/Los_Angeles \
- -e FUZZAPI_API=http://apifuzzer:80 \
+ -e FUZZAPI_API=http://apifuzzer:5000 \
-e FUZZAPI_PROJECT \
-e FUZZAPI_PROFILE \
-e FUZZAPI_CONFIG \
@@ -237,6 +238,7 @@ apifuzzer_fuzz_dnd:
-v $CI_PROJECT_DIR:/app \
-v `pwd`/$FUZZAPI_REPORT_ASSET_PATH:/app/$FUZZAPI_REPORT_ASSET_PATH:rw \
-p 81:80 \
+ -p 5001:5000 \
-p 8001:8000 \
-p 515:514 \
--restart=no \
diff --git a/lib/gitlab/ci/templates/Security/API-Fuzzing.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/API-Fuzzing.latest.gitlab-ci.yml
new file mode 100644
index 00000000000..215029dc952
--- /dev/null
+++ b/lib/gitlab/ci/templates/Security/API-Fuzzing.latest.gitlab-ci.yml
@@ -0,0 +1,270 @@
+# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/api_fuzzing/
+
+# Configure the scanning tool through the environment variables.
+# List of the variables: https://docs.gitlab.com/ee/user/application_security/api_fuzzing/#available-variables
+# How to set: https://docs.gitlab.com/ee/ci/yaml/#variables
+
+variables:
+ FUZZAPI_PROFILE: Quick
+ FUZZAPI_VERSION: latest
+ FUZZAPI_CONFIG: .gitlab-api-fuzzing.yml
+ FUZZAPI_TIMEOUT: 30
+ FUZZAPI_REPORT: gl-api-fuzzing-report.json
+ FUZZAPI_REPORT_ASSET_PATH: assets
+ #
+ FUZZAPI_D_NETWORK: testing-net
+ #
+ # Wait up to 5 minutes for API Fuzzer and target url to become
+ # available (non 500 response to HTTP(s))
+ FUZZAPI_SERVICE_START_TIMEOUT: "300"
+ #
+ FUZZAPI_IMAGE: registry.gitlab.com/gitlab-org/security-products/analyzers/api-fuzzing:${FUZZAPI_VERSION}-engine
+ #
+
+apifuzzer_fuzz_unlicensed:
+ stage: fuzz
+ allow_failure: true
+ rules:
+ - if: '$GITLAB_FEATURES !~ /\bapi_fuzzing\b/ && $API_FUZZING_DISABLED == null'
+ - when: never
+ script:
+ - |
+ echo "Error: Your GitLab project is not licensed for API Fuzzing."
+ - exit 1
+
+apifuzzer_fuzz:
+ stage: fuzz
+ image:
+ name: $FUZZAPI_IMAGE
+ entrypoint: ["/bin/bash", "-l", "-c"]
+ variables:
+ FUZZAPI_PROJECT: $CI_PROJECT_PATH
+ FUZZAPI_API: http://localhost:80
+ FUZZAPI_NEW_REPORT: 1
+ FUZZAPI_LOG_SCANNER: gl-apifuzzing-api-scanner.log
+ TZ: America/Los_Angeles
+ allow_failure: true
+ rules:
+ - if: $FUZZAPI_D_TARGET_IMAGE
+ when: never
+ - if: $FUZZAPI_D_WORKER_IMAGE
+ when: never
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bapi_fuzzing\b/
+ script:
+ #
+ # Validate options
+ - |
+ if [ "$FUZZAPI_HAR$FUZZAPI_OPENAPI$FUZZAPI_POSTMAN_COLLECTION" == "" ]; then \
+ echo "Error: One of FUZZAPI_HAR, FUZZAPI_OPENAPI, or FUZZAPI_POSTMAN_COLLECTION must be provided."; \
+ echo "See https://docs.gitlab.com/ee/user/application_security/api_fuzzing/ for information on how to configure API Fuzzing."; \
+ exit 1; \
+ fi
+ #
+ # Run user provided pre-script
+ - sh -c "$FUZZAPI_PRE_SCRIPT"
+ #
+ # Make sure asset path exists
+ - mkdir -p $FUZZAPI_REPORT_ASSET_PATH
+ #
+ # Start API Security background process
+ - dotnet /peach/Peach.Web.dll &> $FUZZAPI_LOG_SCANNER &
+ - APISEC_PID=$!
+ #
+ # Start scanning
+ - worker-entry
+ #
+ # Run user provided post-script
+ - sh -c "$FUZZAPI_POST_SCRIPT"
+ #
+ # Shutdown API Security
+ - kill $APISEC_PID
+ - wait $APISEC_PID
+ #
+ artifacts:
+ when: always
+ paths:
+ - $FUZZAPI_REPORT_ASSET_PATH
+ - $FUZZAPI_REPORT
+ - $FUZZAPI_LOG_SCANNER
+ reports:
+ api_fuzzing: $FUZZAPI_REPORT
+
+apifuzzer_fuzz_dnd:
+ stage: fuzz
+ image: docker:19.03.12
+ variables:
+ DOCKER_DRIVER: overlay2
+ DOCKER_TLS_CERTDIR: ""
+ FUZZAPI_PROJECT: $CI_PROJECT_PATH
+ FUZZAPI_API: http://apifuzzer:80
+ allow_failure: true
+ rules:
+ - if: $FUZZAPI_D_TARGET_IMAGE == null && $FUZZAPI_D_WORKER_IMAGE == null
+ when: never
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bapi_fuzzing\b/
+ services:
+ - docker:19.03.12-dind
+ script:
+ #
+ #
+ - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
+ #
+ - docker network create --driver bridge $FUZZAPI_D_NETWORK
+ #
+ # Run user provided pre-script
+ - sh -c "$FUZZAPI_PRE_SCRIPT"
+ #
+ # Make sure asset path exists
+ - mkdir -p $FUZZAPI_REPORT_ASSET_PATH
+ #
+ # Start peach testing engine container
+ - |
+ docker run -d \
+ --name apifuzzer \
+ --network $FUZZAPI_D_NETWORK \
+ -e Proxy:Port=8000 \
+ -e TZ=America/Los_Angeles \
+ -e GITLAB_FEATURES \
+ -p 80:80 \
+ -p 8000:8000 \
+ -p 514:514 \
+ --restart=no \
+ $FUZZAPI_IMAGE \
+ dotnet /peach/Peach.Web.dll
+ #
+ # Start target container
+ - |
+ if [ "$FUZZAPI_D_TARGET_IMAGE" != "" ]; then \
+ docker run -d \
+ --name target \
+ --network $FUZZAPI_D_NETWORK \
+ $FUZZAPI_D_TARGET_ENV \
+ $FUZZAPI_D_TARGET_PORTS \
+ $FUZZAPI_D_TARGET_VOLUME \
+ --restart=no \
+ $FUZZAPI_D_TARGET_IMAGE \
+ ; fi
+ #
+ # Start worker container if provided
+ - |
+ if [ "$FUZZAPI_D_WORKER_IMAGE" != "" ]; then \
+ echo "Starting worker image $FUZZAPI_D_WORKER_IMAGE"; \
+ docker run \
+ --name worker \
+ --network $FUZZAPI_D_NETWORK \
+ -e FUZZAPI_API=http://apifuzzer:80 \
+ -e FUZZAPI_PROJECT \
+ -e FUZZAPI_PROFILE \
+ -e FUZZAPI_CONFIG \
+ -e FUZZAPI_REPORT \
+ -e FUZZAPI_REPORT_ASSET_PATH \
+ -e FUZZAPI_NEW_REPORT=1 \
+ -e FUZZAPI_HAR \
+ -e FUZZAPI_OPENAPI \
+ -e FUZZAPI_POSTMAN_COLLECTION \
+ -e FUZZAPI_POSTMAN_COLLECTION_VARIABLES \
+ -e FUZZAPI_TARGET_URL \
+ -e FUZZAPI_OVERRIDES_FILE \
+ -e FUZZAPI_OVERRIDES_ENV \
+ -e FUZZAPI_OVERRIDES_CMD \
+ -e FUZZAPI_OVERRIDES_INTERVAL \
+ -e FUZZAPI_TIMEOUT \
+ -e FUZZAPI_VERBOSE \
+ -e FUZZAPI_SERVICE_START_TIMEOUT \
+ -e FUZZAPI_HTTP_USERNAME \
+ -e FUZZAPI_HTTP_PASSWORD \
+ -e CI_PROJECT_URL \
+ -e CI_JOB_ID \
+ -e CI_COMMIT_BRANCH=${CI_COMMIT_BRANCH} \
+ $FUZZAPI_D_WORKER_ENV \
+ $FUZZAPI_D_WORKER_PORTS \
+ $FUZZAPI_D_WORKER_VOLUME \
+ --restart=no \
+ $FUZZAPI_D_WORKER_IMAGE \
+ ; fi
+ #
+ # Start API Fuzzing provided worker if no other worker present
+ - |
+ if [ "$FUZZAPI_D_WORKER_IMAGE" == "" ]; then \
+ if [ "$FUZZAPI_HAR$FUZZAPI_OPENAPI$FUZZAPI_POSTMAN_COLLECTION" == "" ]; then \
+ echo "Error: One of FUZZAPI_HAR, FUZZAPI_OPENAPI, or FUZZAPI_POSTMAN_COLLECTION must be provided."; \
+ echo "See https://docs.gitlab.com/ee/user/application_security/api_fuzzing/ for information on how to configure API Fuzzing."; \
+ exit 1; \
+ fi; \
+ docker run \
+ --name worker \
+ --network $FUZZAPI_D_NETWORK \
+ -e TZ=America/Los_Angeles \
+ -e FUZZAPI_API=http://apifuzzer:80 \
+ -e FUZZAPI_PROJECT \
+ -e FUZZAPI_PROFILE \
+ -e FUZZAPI_CONFIG \
+ -e FUZZAPI_REPORT \
+ -e FUZZAPI_REPORT_ASSET_PATH \
+ -e FUZZAPI_NEW_REPORT=1 \
+ -e FUZZAPI_HAR \
+ -e FUZZAPI_OPENAPI \
+ -e FUZZAPI_POSTMAN_COLLECTION \
+ -e FUZZAPI_POSTMAN_COLLECTION_VARIABLES \
+ -e FUZZAPI_TARGET_URL \
+ -e FUZZAPI_OVERRIDES_FILE \
+ -e FUZZAPI_OVERRIDES_ENV \
+ -e FUZZAPI_OVERRIDES_CMD \
+ -e FUZZAPI_OVERRIDES_INTERVAL \
+ -e FUZZAPI_TIMEOUT \
+ -e FUZZAPI_VERBOSE \
+ -e FUZZAPI_SERVICE_START_TIMEOUT \
+ -e FUZZAPI_HTTP_USERNAME \
+ -e FUZZAPI_HTTP_PASSWORD \
+ -e CI_PROJECT_URL \
+ -e CI_JOB_ID \
+ -v $CI_PROJECT_DIR:/app \
+ -v `pwd`/$FUZZAPI_REPORT_ASSET_PATH:/app/$FUZZAPI_REPORT_ASSET_PATH:rw \
+ -p 81:80 \
+ -p 8001:8000 \
+ -p 515:514 \
+ --restart=no \
+ $FUZZAPI_IMAGE \
+ worker-entry \
+ ; fi
+ #
+ # Propagate exit code from api fuzzing scanner (if any)
+ - if [[ $(docker inspect apifuzzer --format='{{.State.ExitCode}}') != "0" ]]; then echo "API Fuzzing scanner exited with an error. Logs are available as job artifacts."; exit 1; fi
+ #
+ # Run user provided post-script
+ - sh -c "$FUZZAPI_POST_SCRIPT"
+ #
+ after_script:
+ #
+ # Shutdown all containers
+ - echo "Stopping all containers"
+ - if [ "$FUZZAPI_D_TARGET_IMAGE" != "" ]; then docker stop target; fi
+ - docker stop worker
+ - docker stop apifuzzer
+ #
+ # Save docker logs
+ - docker logs apifuzzer &> gl-api_fuzzing-logs.log
+ - if [ "$FUZZAPI_D_TARGET_IMAGE" != "" ]; then docker logs target &> gl-api_fuzzing-target-logs.log; fi
+ - docker logs worker &> gl-api_fuzzing-worker-logs.log
+ #
+ artifacts:
+ when: always
+ paths:
+ - ./gl-api_fuzzing*.log
+ - ./gl-api_fuzzing*.zip
+ - $FUZZAPI_REPORT_ASSET_PATH
+ - $FUZZAPI_REPORT
+ reports:
+ api_fuzzing: $FUZZAPI_REPORT
+
+# end
diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
index 90dc80a3fc0..a1f0d2e5a48 100644
--- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
@@ -160,7 +160,7 @@ mobsf-android-sast:
services:
# this version must match with analyzer version mentioned in: https://gitlab.com/gitlab-org/security-products/analyzers/mobsf/-/blob/master/Dockerfile
# Unfortunately, we need to keep track of mobsf version in 2 different places for now.
- - name: opensecurity/mobile-security-framework-mobsf:v3.3.3
+ - name: opensecurity/mobile-security-framework-mobsf:v3.4.0
alias: mobsf
image:
name: "$SAST_ANALYZER_IMAGE"
@@ -186,7 +186,7 @@ mobsf-ios-sast:
services:
# this version must match with analyzer version mentioned in: https://gitlab.com/gitlab-org/security-products/analyzers/mobsf/-/blob/master/Dockerfile
# Unfortunately, we need to keep track of mobsf version in 2 different places for now.
- - name: opensecurity/mobile-security-framework-mobsf:v3.3.3
+ - name: opensecurity/mobile-security-framework-mobsf:v3.4.0
alias: mobsf
image:
name: "$SAST_ANALYZER_IMAGE"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index de282b4ca5f..f611b8a6a86 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -24167,6 +24167,9 @@ msgstr ""
msgid "Profiles|Expired key is not valid."
msgstr ""
+msgid "Profiles|Expired:"
+msgstr ""
+
msgid "Profiles|Expires at"
msgstr ""
@@ -27178,9 +27181,6 @@ msgstr ""
msgid "Runner API"
msgstr ""
-msgid "Runner token"
-msgstr ""
-
msgid "Runner tokens"
msgstr ""
@@ -27268,6 +27268,9 @@ msgstr ""
msgid "Runners|Revision"
msgstr ""
+msgid "Runners|Runner"
+msgstr ""
+
msgid "Runners|Runner #%{runner_id}"
msgstr ""
diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb
index 98c12a4086e..3cb466abce9 100644
--- a/qa/qa/page/project/pipeline/index.rb
+++ b/qa/qa/page/project/pipeline/index.rb
@@ -9,8 +9,11 @@ module QA
element :pipeline_url_link
end
- view 'app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue' do
+ view 'app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue' do
element :pipeline_commit_status
+ end
+
+ view 'app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue' do
element :pipeline_retry_button
end
diff --git a/spec/frontend/jobs/components/job_sidebar_details_container_spec.js b/spec/frontend/jobs/components/job_sidebar_details_container_spec.js
index 2b56bd2d558..ad0368555fa 100644
--- a/spec/frontend/jobs/components/job_sidebar_details_container_spec.js
+++ b/spec/frontend/jobs/components/job_sidebar_details_container_spec.js
@@ -34,11 +34,22 @@ describe('Job Sidebar Details Container', () => {
});
describe('when no details are available', () => {
- it('should render an empty container', () => {
+ beforeEach(() => {
createWrapper();
+ });
+ it('should render an empty container', () => {
expect(wrapper.html()).toBe('');
});
+
+ it.each(['duration', 'erased_at', 'finished_at', 'queued', 'runner', 'coverage'])(
+ 'should not render %s details when missing',
+ async (detail) => {
+ await store.dispatch('receiveJobSuccess', { [detail]: undefined });
+
+ expect(findAllDetailsRow()).toHaveLength(0);
+ },
+ );
});
describe('when some of the details are available', () => {
@@ -49,7 +60,7 @@ describe('Job Sidebar Details Container', () => {
['erased_at', 'Erased: 3 weeks ago'],
['finished_at', 'Finished: 3 weeks ago'],
['queued', 'Queued: 9 seconds'],
- ['runner', 'Runner: local ci runner (#1)'],
+ ['runner', 'Runner: #1 (ABCDEFGH) local ci runner'],
['coverage', 'Coverage: 20%'],
])('uses %s to render job-%s', async (detail, value) => {
await store.dispatch('receiveJobSuccess', { [detail]: job[detail] });
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
index 3db3584c8fd..c3115dd78e2 100644
--- a/spec/frontend/jobs/mock_data.js
+++ b/spec/frontend/jobs/mock_data.js
@@ -958,6 +958,7 @@ export default {
artifacts: [null],
runner: {
id: 1,
+ short_sha: 'ABCDEFGH',
description: 'local ci runner',
edit_path: '/root/ci-mock/runners/1/edit',
},
diff --git a/spec/frontend/pipelines/pipelines_table_row_spec.js b/spec/frontend/pipelines/pipelines_table_row_spec.js
deleted file mode 100644
index 68d46575081..00000000000
--- a/spec/frontend/pipelines/pipelines_table_row_spec.js
+++ /dev/null
@@ -1,239 +0,0 @@
-import { mount } from '@vue/test-utils';
-import waitForPromises from 'helpers/wait_for_promises';
-import PipelinesTableRowComponent from '~/pipelines/components/pipelines_list/pipelines_table_row.vue';
-import eventHub from '~/pipelines/event_hub';
-
-describe('Pipelines Table Row', () => {
- const jsonFixtureName = 'pipelines/pipelines.json';
-
- const createWrapper = (pipeline) =>
- mount(PipelinesTableRowComponent, {
- propsData: {
- pipeline,
- viewType: 'root',
- },
- });
-
- let wrapper;
- let pipeline;
- let pipelineWithoutAuthor;
- let pipelineWithoutCommit;
-
- beforeEach(() => {
- const { pipelines } = getJSONFixture(jsonFixtureName);
-
- pipeline = pipelines.find((p) => p.user !== null && p.commit !== null);
- pipelineWithoutAuthor = pipelines.find((p) => p.user === null && p.commit !== null);
- pipelineWithoutCommit = pipelines.find((p) => p.user === null && p.commit === null);
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('should render a table row', () => {
- wrapper = createWrapper(pipeline);
-
- expect(wrapper.attributes('class')).toContain('gl-responsive-table-row');
- });
-
- describe('status column', () => {
- beforeEach(() => {
- wrapper = createWrapper(pipeline);
- });
-
- it('should render a pipeline link', () => {
- expect(wrapper.find('.table-section.commit-link a').attributes('href')).toEqual(
- pipeline.path,
- );
- });
-
- it('should render status text', () => {
- expect(wrapper.find('.table-section.commit-link a').text()).toContain(
- pipeline.details.status.text,
- );
- });
- });
-
- describe('information column', () => {
- beforeEach(() => {
- wrapper = createWrapper(pipeline);
- });
-
- it('should render a pipeline link', () => {
- expect(wrapper.find('.table-section:nth-child(2) a').attributes('href')).toEqual(
- pipeline.path,
- );
- });
-
- it('should render pipeline ID', () => {
- expect(wrapper.find('.table-section:nth-child(2) a > span').text()).toEqual(
- `#${pipeline.id}`,
- );
- });
-
- describe('when a user is provided', () => {
- it('should render user information', () => {
- expect(
- wrapper.find('.table-section:nth-child(3) .js-pipeline-url-user').attributes('href'),
- ).toEqual(pipeline.user.path);
-
- expect(
- wrapper.find('.table-section:nth-child(3) .js-user-avatar-image-tooltip').text().trim(),
- ).toEqual(pipeline.user.name);
- });
- });
- });
-
- describe('commit column', () => {
- it('should render link to commit', () => {
- wrapper = createWrapper(pipeline);
-
- const commitLink = wrapper.find('.branch-commit .commit-sha');
-
- expect(commitLink.attributes('href')).toEqual(pipeline.commit.commit_path);
- });
-
- const findElements = () => {
- const commitTitleElement = wrapper.find('.branch-commit .commit-title');
- const commitAuthorElement = commitTitleElement.find('a.avatar-image-container');
-
- if (!commitAuthorElement.exists()) {
- return {
- commitAuthorElement,
- };
- }
-
- const commitAuthorLink = commitAuthorElement.attributes('href');
- const commitAuthorName = commitAuthorElement
- .find('.js-user-avatar-image-tooltip')
- .text()
- .trim();
-
- return {
- commitAuthorElement,
- commitAuthorLink,
- commitAuthorName,
- };
- };
-
- it('renders nothing without commit', () => {
- expect(pipelineWithoutCommit.commit).toBe(null);
-
- wrapper = createWrapper(pipelineWithoutCommit);
- const { commitAuthorElement } = findElements();
-
- expect(commitAuthorElement.exists()).toBe(false);
- });
-
- it('renders commit author', () => {
- wrapper = createWrapper(pipeline);
- const { commitAuthorLink, commitAuthorName } = findElements();
-
- expect(commitAuthorLink).toEqual(pipeline.commit.author.path);
- expect(commitAuthorName).toEqual(pipeline.commit.author.username);
- });
-
- it('renders commit with unregistered author', () => {
- expect(pipelineWithoutAuthor.commit.author).toBe(null);
-
- wrapper = createWrapper(pipelineWithoutAuthor);
- const { commitAuthorLink, commitAuthorName } = findElements();
-
- expect(commitAuthorLink).toEqual(`mailto:${pipelineWithoutAuthor.commit.author_email}`);
- expect(commitAuthorName).toEqual(pipelineWithoutAuthor.commit.author_name);
- });
- });
-
- describe('stages column', () => {
- const findAllMiniPipelineStages = () =>
- wrapper.findAll('.table-section:nth-child(5) [data-testid="mini-pipeline-graph-dropdown"]');
-
- it('should render an icon for each stage', () => {
- wrapper = createWrapper(pipeline);
-
- expect(findAllMiniPipelineStages()).toHaveLength(pipeline.details.stages.length);
- });
-
- it('should not render stages when stages are empty', () => {
- const withoutStages = { ...pipeline };
- withoutStages.details = { ...withoutStages.details, stages: null };
-
- wrapper = createWrapper(withoutStages);
-
- expect(findAllMiniPipelineStages()).toHaveLength(0);
- });
- });
-
- describe('actions column', () => {
- const scheduledJobAction = {
- name: 'some scheduled job',
- };
-
- beforeEach(() => {
- const withActions = { ...pipeline };
- withActions.details.scheduled_actions = [scheduledJobAction];
- withActions.flags.cancelable = true;
- withActions.flags.retryable = true;
- withActions.cancel_path = '/cancel';
- withActions.retry_path = '/retry';
-
- wrapper = createWrapper(withActions);
- });
-
- it('should render the provided actions', () => {
- expect(wrapper.find('.js-pipelines-retry-button').exists()).toBe(true);
- expect(wrapper.find('.js-pipelines-retry-button').attributes('title')).toMatch('Retry');
- expect(wrapper.find('.js-pipelines-cancel-button').exists()).toBe(true);
- expect(wrapper.find('.js-pipelines-cancel-button').attributes('title')).toMatch('Cancel');
- });
-
- it('should render the manual actions', async () => {
- const manualActions = wrapper.find('[data-testid="pipelines-manual-actions-dropdown"]');
-
- // Click on the dropdown and wait for `lazy` dropdown items
- manualActions.find('.dropdown-toggle').trigger('click');
- await waitForPromises();
-
- expect(manualActions.text()).toContain(scheduledJobAction.name);
- });
-
- it('emits `retryPipeline` event when retry button is clicked and toggles loading', () => {
- eventHub.$on('retryPipeline', (endpoint) => {
- expect(endpoint).toBe('/retry');
- });
-
- wrapper.find('.js-pipelines-retry-button').trigger('click');
- expect(wrapper.vm.isRetrying).toBe(true);
- });
-
- it('emits `openConfirmationModal` event when cancel button is clicked and toggles loading', () => {
- eventHub.$once('openConfirmationModal', (data) => {
- const { id, ref, commit } = pipeline;
-
- expect(data.endpoint).toBe('/cancel');
- expect(data.pipeline).toEqual(
- expect.objectContaining({
- id,
- ref,
- commit,
- }),
- );
- });
-
- wrapper.find('.js-pipelines-cancel-button').trigger('click');
- });
-
- it('renders a loading icon when `cancelingPipeline` matches pipeline id', (done) => {
- wrapper.setProps({ cancelingPipeline: pipeline.id });
- wrapper.vm
- .$nextTick()
- .then(() => {
- expect(wrapper.vm.isCancelling).toBe(true);
- })
- .then(done)
- .catch(done.fail);
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
index 952bea81052..70e47b98575 100644
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_spec.js
@@ -30,23 +30,17 @@ describe('Pipelines Table', () => {
return pipelines.find((p) => p.user !== null && p.commit !== null);
};
- const createComponent = (props = {}, flagState = false) => {
+ const createComponent = (props = {}) => {
wrapper = extendedWrapper(
mount(PipelinesTable, {
propsData: {
...defaultProps,
...props,
},
- provide: {
- glFeatures: {
- newPipelinesTable: flagState,
- },
- },
}),
);
};
- const findRows = () => wrapper.findAll('.commit.gl-responsive-table-row');
const findGlTable = () => wrapper.findComponent(GlTable);
const findStatusBadge = () => wrapper.findComponent(PipelinesStatusBadge);
const findPipelineInfo = () => wrapper.findComponent(PipelineUrl);
@@ -56,8 +50,7 @@ describe('Pipelines Table', () => {
const findTimeAgo = () => wrapper.findComponent(PipelinesTimeago);
const findActions = () => wrapper.findComponent(PipelineOperations);
- const findLegacyTable = () => wrapper.findByTestId('legacy-ci-table');
- const findTableRows = () => wrapper.findAll('[data-testid="pipeline-table-row"]');
+ const findTableRows = () => wrapper.findAllByTestId('pipeline-table-row');
const findStatusTh = () => wrapper.findByTestId('status-th');
const findPipelineTh = () => wrapper.findByTestId('pipeline-th');
const findTriggererTh = () => wrapper.findByTestId('triggerer-th');
@@ -75,52 +68,13 @@ describe('Pipelines Table', () => {
wrapper = null;
});
- describe('table with feature flag off', () => {
- describe('renders the table correctly', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('should render a table', () => {
- expect(wrapper.classes()).toContain('ci-table');
- });
-
- it('should render table head with correct columns', () => {
- expect(wrapper.find('.table-section.js-pipeline-status').text()).toEqual('Status');
-
- expect(wrapper.find('.table-section.js-pipeline-info').text()).toEqual('Pipeline');
-
- expect(wrapper.find('.table-section.js-pipeline-commit').text()).toEqual('Commit');
-
- expect(wrapper.find('.table-section.js-pipeline-stages').text()).toEqual('Stages');
- });
- });
-
- describe('without data', () => {
- it('should render an empty table', () => {
- createComponent();
-
- expect(findRows()).toHaveLength(0);
- });
- });
-
- describe('with data', () => {
- it('should render rows', () => {
- createComponent({ pipelines: [pipeline], viewType: 'root' });
-
- expect(findRows()).toHaveLength(1);
- });
- });
- });
-
- describe('table with feature flag on', () => {
+ describe('Pipelines Table', () => {
beforeEach(() => {
- createComponent({ pipelines: [pipeline], viewType: 'root' }, true);
+ createComponent({ pipelines: [pipeline], viewType: 'root' });
});
- it('displays new table', () => {
+ it('displays table', () => {
expect(findGlTable().exists()).toBe(true);
- expect(findLegacyTable().exists()).toBe(false);
});
it('should render table head with correct columns', () => {
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
index 980efed3c04..2bf4ee1a9fd 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -60,6 +60,30 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('correlation-id')
end
+ context 'with configuration values in ApplicationSetting' do
+ let(:alternate_validation_service_url) { 'https://alternate-validation-service.external/' }
+ let(:validation_service_token) { 'SECURE_TOKEN' }
+ let(:shorter_timeout) { described_class::DEFAULT_VALIDATION_REQUEST_TIMEOUT - 1 }
+
+ before do
+ stub_env('EXTERNAL_VALIDATION_SERVICE_TOKEN', 'TOKEN_IN_ENV')
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:external_pipeline_validation_service_timeout).and_return(shorter_timeout)
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:external_pipeline_validation_service_token).and_return(validation_service_token)
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:external_pipeline_validation_service_url).and_return(alternate_validation_service_url)
+ end
+
+ it 'uses those values rather than env vars or defaults' do
+ expect(::Gitlab::HTTP).to receive(:post) do |url, params|
+ expect(url).to eq(alternate_validation_service_url)
+ expect(params[:timeout]).to eq(shorter_timeout)
+ expect(params[:headers]).to include('X-Gitlab-Token' => validation_service_token)
+ expect(params[:timeout]).to eq(shorter_timeout)
+ end
+
+ perform!
+ end
+ end
+
it 'respects the defined payload schema' do
expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
expect(params[:body]).to match_schema('/external_validation')
diff --git a/spec/serializers/runner_entity_spec.rb b/spec/serializers/runner_entity_spec.rb
index e864b52c0f2..39cac65c5ac 100644
--- a/spec/serializers/runner_entity_spec.rb
+++ b/spec/serializers/runner_entity_spec.rb
@@ -20,6 +20,7 @@ RSpec.describe RunnerEntity do
it 'contains required fields' do
expect(subject).to include(:id, :description)
expect(subject).to include(:edit_path)
+ expect(subject).to include(:short_sha)
end
end
end
diff --git a/spec/services/design_management/copy_design_collection/copy_service_spec.rb b/spec/services/design_management/copy_design_collection/copy_service_spec.rb
index ddbed91815f..03242487b53 100644
--- a/spec/services/design_management/copy_design_collection/copy_service_spec.rb
+++ b/spec/services/design_management/copy_design_collection/copy_service_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe DesignManagement::CopyDesignCollection::CopyService, :clean_gitla
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:issue, refind: true) { create(:issue, project: project) }
+
let(:target_issue) { create(:issue) }
subject { described_class.new(project, user, issue: issue, target_issue: target_issue).execute }
diff --git a/spec/services/design_management/delete_designs_service_spec.rb b/spec/services/design_management/delete_designs_service_spec.rb
index ed161b4c8ff..341f71fa62c 100644
--- a/spec/services/design_management/delete_designs_service_spec.rb
+++ b/spec/services/design_management/delete_designs_service_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe DesignManagement::DeleteDesignsService do
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user) }
+
let(:designs) { create_designs }
subject(:service) { described_class.new(project, user, issue: issue, designs: designs) }
diff --git a/spec/services/design_management/save_designs_service_spec.rb b/spec/services/design_management/save_designs_service_spec.rb
index 5348c0908b2..5bc763cc95e 100644
--- a/spec/services/design_management/save_designs_service_spec.rb
+++ b/spec/services/design_management/save_designs_service_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe DesignManagement::SaveDesignsService do
let_it_be_with_reload(:issue) { create(:issue) }
let_it_be(:developer) { create(:user, developer_projects: [issue.project]) }
+
let(:project) { issue.project }
let(:user) { developer }
let(:files) { [rails_sample] }
diff --git a/spec/views/profiles/keys/_key.html.haml_spec.rb b/spec/views/profiles/keys/_key.html.haml_spec.rb
index a29b8ecc3d5..bb101198ac3 100644
--- a/spec/views/profiles/keys/_key.html.haml_spec.rb
+++ b/spec/views/profiles/keys/_key.html.haml_spec.rb
@@ -58,6 +58,20 @@ RSpec.describe 'profiles/keys/_key.html.haml' do
end
end
+ context 'when the key has expired' do
+ let_it_be(:key) do
+ create(:personal_key,
+ user: user,
+ expires_at: 2.days.ago)
+ end
+
+ it 'renders "Expired:" as the expiration date label' do
+ render
+
+ expect(rendered).to have_text('Expired:')
+ end
+ end
+
context 'when the key is not deletable' do
# Turns out key.can_delete? is only false for LDAP keys
# but LDAP keys don't exist outside EE