Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
73886079f3
commit
5f0e3773e9
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
import ActiveToggle from './active_toggle.vue';
|
||||
import JiraTriggerFields from './jira_trigger_fields.vue';
|
||||
|
||||
export default {
|
||||
name: 'IntegrationForm',
|
||||
components: {
|
||||
ActiveToggle,
|
||||
JiraTriggerFields,
|
||||
},
|
||||
props: {
|
||||
activeToggleProps: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
showActive: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
triggerFieldsProps: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isJira() {
|
||||
return this.type === 'jira';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<active-toggle v-if="showActive" v-bind="activeToggleProps" />
|
||||
<jira-trigger-fields v-if="isJira" v-bind="triggerFieldsProps" />
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,99 @@
|
|||
<script>
|
||||
import { GlFormCheckbox, GlFormRadio } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
name: 'JiraTriggerFields',
|
||||
components: {
|
||||
GlFormCheckbox,
|
||||
GlFormRadio,
|
||||
},
|
||||
props: {
|
||||
initialTriggerCommit: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
initialTriggerMergeRequest: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
initialEnableComments: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
initialCommentDetail: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'standard',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
triggerCommit: this.initialTriggerCommit,
|
||||
triggerMergeRequest: this.initialTriggerMergeRequest,
|
||||
enableComments: this.initialEnableComments,
|
||||
commentDetail: this.initialCommentDetail,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-group row pt-2" role="group">
|
||||
<label for="service[trigger]" class="col-form-label col-sm-2 pt-0">{{ __('Trigger') }}</label>
|
||||
<div class="col-sm-10">
|
||||
<label class="weight-normal mb-2">
|
||||
{{
|
||||
s__(
|
||||
'Integrations|When a Jira issue is mentioned in a commit or merge request a remote link and comment (if enabled) will be created.',
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
|
||||
<input name="service[commit_events]" type="hidden" value="false" />
|
||||
<gl-form-checkbox v-model="triggerCommit" name="service[commit_events]">
|
||||
{{ __('Commit') }}
|
||||
</gl-form-checkbox>
|
||||
|
||||
<input name="service[merge_requests_events]" type="hidden" value="false" />
|
||||
<gl-form-checkbox v-model="triggerMergeRequest" name="service[merge_requests_events]">
|
||||
{{ __('Merge request') }}
|
||||
</gl-form-checkbox>
|
||||
|
||||
<div
|
||||
v-show="triggerCommit || triggerMergeRequest"
|
||||
class="mt-4"
|
||||
data-testid="comment-settings"
|
||||
>
|
||||
<label>
|
||||
{{ s__('Integrations|Comment settings:') }}
|
||||
</label>
|
||||
<input name="service[comment_on_event_enabled]" type="hidden" value="false" />
|
||||
<gl-form-checkbox v-model="enableComments" name="service[comment_on_event_enabled]">
|
||||
{{ s__('Integrations|Enable comments') }}
|
||||
</gl-form-checkbox>
|
||||
|
||||
<div v-show="enableComments" class="mt-4" data-testid="comment-detail">
|
||||
<label>
|
||||
{{ s__('Integrations|Comment detail:') }}
|
||||
</label>
|
||||
<gl-form-radio v-model="commentDetail" value="standard" name="service[comment_detail]">
|
||||
{{ s__('Integrations|Standard') }}
|
||||
<template #help>
|
||||
{{ s__('Integrations|Includes commit title and branch') }}
|
||||
</template>
|
||||
</gl-form-radio>
|
||||
<gl-form-radio v-model="commentDetail" value="all_details" name="service[comment_detail]">
|
||||
{{ s__('Integrations|All details') }}
|
||||
<template #help>
|
||||
{{
|
||||
s__(
|
||||
'Integrations|Includes Standard plus entire commit message, commit hash, and issue IDs',
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
</gl-form-radio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,26 +1,45 @@
|
|||
import Vue from 'vue';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import ActiveToggle from './components/active_toggle.vue';
|
||||
import IntegrationForm from './components/integration_form.vue';
|
||||
|
||||
export default el => {
|
||||
if (!el) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { showActive: showActiveStr, activated: activatedStr } = el.dataset;
|
||||
const showActive = parseBoolean(showActiveStr);
|
||||
const activated = parseBoolean(activatedStr);
|
||||
|
||||
if (!showActive) {
|
||||
return null;
|
||||
function parseBooleanInData(data) {
|
||||
const result = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
result[key] = parseBoolean(value);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const { type, commentDetail, ...booleanAttributes } = el.dataset;
|
||||
const {
|
||||
showActive,
|
||||
activated,
|
||||
commitEvents,
|
||||
mergeRequestEvents,
|
||||
enableComments,
|
||||
} = parseBooleanInData(booleanAttributes);
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
render(createElement) {
|
||||
return createElement(ActiveToggle, {
|
||||
return createElement(IntegrationForm, {
|
||||
props: {
|
||||
initialActivated: activated,
|
||||
activeToggleProps: {
|
||||
initialActivated: activated,
|
||||
},
|
||||
showActive,
|
||||
type,
|
||||
triggerFieldsProps: {
|
||||
initialTriggerCommit: commitEvents,
|
||||
initialTriggerMergeRequest: mergeRequestEvents,
|
||||
initialEnableComments: enableComments,
|
||||
initialCommentDetail: commentDetail,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
|
||||
# NOTE: Use @application_setting in this controller when you need to access
|
||||
# application_settings after it has been modified. This is because the
|
||||
# ApplicationSetting model uses Gitlab::ThreadMemoryCache for caching and the
|
||||
# ApplicationSetting model uses Gitlab::ProcessMemoryCache for caching and the
|
||||
# cache might be stale immediately after an update.
|
||||
# https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30233
|
||||
before_action :set_application_setting, except: :integrations
|
||||
|
|
|
@ -16,4 +16,8 @@ module X509Helper
|
|||
rescue
|
||||
{}
|
||||
end
|
||||
|
||||
def x509_signature?(sig)
|
||||
sig.is_a?(X509CommitSignature) || sig.is_a?(Gitlab::X509::Signature)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -421,7 +421,7 @@ class ApplicationSetting < ApplicationRecord
|
|||
# can cause a significant amount of load on Redis, let's cache it in
|
||||
# memory.
|
||||
def self.cache_backend
|
||||
Gitlab::ThreadMemoryCache.cache_backend
|
||||
Gitlab::ProcessMemoryCache.cache_backend
|
||||
end
|
||||
|
||||
def recaptcha_or_login_protection_enabled
|
||||
|
|
|
@ -141,7 +141,7 @@ class MergeRequestDiff < ApplicationRecord
|
|||
after_create :save_git_content, unless: :importing?
|
||||
after_create_commit :set_as_latest_diff, unless: :importing?
|
||||
|
||||
after_save :update_external_diff_store, if: -> { !importing? && saved_change_to_external_diff? }
|
||||
after_save :update_external_diff_store
|
||||
|
||||
def self.find_by_diff_refs(diff_refs)
|
||||
find_by(start_commit_sha: diff_refs.start_sha, head_commit_sha: diff_refs.head_sha, base_commit_sha: diff_refs.base_sha)
|
||||
|
@ -401,8 +401,10 @@ class MergeRequestDiff < ApplicationRecord
|
|||
end
|
||||
|
||||
def update_external_diff_store
|
||||
update_column(:external_diff_store, external_diff.object_store) if
|
||||
has_attribute?(:external_diff_store)
|
||||
return unless has_attribute?(:external_diff_store)
|
||||
return unless saved_change_to_external_diff? || saved_change_to_stored_externally?
|
||||
|
||||
update_column(:external_diff_store, external_diff.object_store)
|
||||
end
|
||||
|
||||
def saved_change_to_external_diff?
|
||||
|
|
|
@ -177,6 +177,7 @@ class JiraService < IssueTrackerService
|
|||
noteable_id = noteable.respond_to?(:iid) ? noteable.iid : noteable.id
|
||||
noteable_type = noteable_name(noteable)
|
||||
entity_url = build_entity_url(noteable_type, noteable_id)
|
||||
entity_meta = build_entity_meta(noteable)
|
||||
|
||||
data = {
|
||||
user: {
|
||||
|
@ -185,12 +186,15 @@ class JiraService < IssueTrackerService
|
|||
},
|
||||
project: {
|
||||
name: project.full_path,
|
||||
url: resource_url(namespace_project_path(project.namespace, project)) # rubocop:disable Cop/ProjectPathHelper
|
||||
url: resource_url(project_path(project))
|
||||
},
|
||||
entity: {
|
||||
id: entity_meta[:id],
|
||||
name: noteable_type.humanize.downcase,
|
||||
url: entity_url,
|
||||
title: noteable.title
|
||||
title: noteable.title,
|
||||
description: entity_meta[:description],
|
||||
branch: entity_meta[:branch]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,14 +268,11 @@ class JiraService < IssueTrackerService
|
|||
end
|
||||
|
||||
def add_comment(data, issue)
|
||||
user_name = data[:user][:name]
|
||||
user_url = data[:user][:url]
|
||||
entity_name = data[:entity][:name]
|
||||
entity_url = data[:entity][:url]
|
||||
entity_title = data[:entity][:title]
|
||||
project_name = data[:project][:name]
|
||||
|
||||
message = "[#{user_name}|#{user_url}] mentioned this issue in [a #{entity_name} of #{project_name}|#{entity_url}]:\n'#{entity_title.chomp}'"
|
||||
message = comment_message(data)
|
||||
link_title = "#{entity_name.capitalize} - #{entity_title}"
|
||||
link_props = build_remote_link_props(url: entity_url, title: link_title)
|
||||
|
||||
|
@ -280,6 +281,37 @@ class JiraService < IssueTrackerService
|
|||
end
|
||||
end
|
||||
|
||||
def comment_message(data)
|
||||
user_link = build_jira_link(data[:user][:name], data[:user][:url])
|
||||
|
||||
entity = data[:entity]
|
||||
entity_ref = all_details? ? "#{entity[:name]} #{entity[:id]}" : "a #{entity[:name]}"
|
||||
entity_link = build_jira_link(entity_ref, entity[:url])
|
||||
|
||||
project_link = build_jira_link(project.full_name, Gitlab::Routing.url_helpers.project_url(project))
|
||||
branch =
|
||||
if entity[:branch].present?
|
||||
s_('JiraService| on branch %{branch_link}') % {
|
||||
branch_link: build_jira_link(entity[:branch], project_tree_url(project, entity[:branch]))
|
||||
}
|
||||
end
|
||||
|
||||
entity_message = entity[:description].presence if all_details?
|
||||
entity_message ||= entity[:title].chomp
|
||||
|
||||
s_('JiraService|%{user_link} mentioned this issue in %{entity_link} of %{project_link}%{branch}:{quote}%{entity_message}{quote}') % {
|
||||
user_link: user_link,
|
||||
entity_link: entity_link,
|
||||
project_link: project_link,
|
||||
branch: branch,
|
||||
entity_message: entity_message
|
||||
}
|
||||
end
|
||||
|
||||
def build_jira_link(title, url)
|
||||
"[#{title}|#{url}]"
|
||||
end
|
||||
|
||||
def has_resolution?(issue)
|
||||
issue.respond_to?(:resolution) && issue.resolution.present?
|
||||
end
|
||||
|
@ -353,6 +385,23 @@ class JiraService < IssueTrackerService
|
|||
)
|
||||
end
|
||||
|
||||
def build_entity_meta(noteable)
|
||||
if noteable.is_a?(Commit)
|
||||
{
|
||||
id: noteable.short_id,
|
||||
description: noteable.safe_message,
|
||||
branch: noteable.ref_names(project.repository).first
|
||||
}
|
||||
elsif noteable.is_a?(MergeRequest)
|
||||
{
|
||||
id: noteable.to_reference,
|
||||
branch: noteable.source_branch
|
||||
}
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
def noteable_name(noteable)
|
||||
name = noteable.model_name.singular
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ class SnippetRepository < ApplicationRecord
|
|||
EMPTY_FILE_PATTERN = /^#{DEFAULT_EMPTY_FILE_NAME}(\d+)\.txt$/.freeze
|
||||
|
||||
CommitError = Class.new(StandardError)
|
||||
InvalidPathError = Class.new(CommitError)
|
||||
|
||||
belongs_to :snippet, inverse_of: :snippet_repository
|
||||
|
||||
|
@ -40,8 +41,9 @@ class SnippetRepository < ApplicationRecord
|
|||
rescue Gitlab::Git::Index::IndexError,
|
||||
Gitlab::Git::CommitError,
|
||||
Gitlab::Git::PreReceiveError,
|
||||
Gitlab::Git::CommandError => e
|
||||
raise CommitError, e.message
|
||||
Gitlab::Git::CommandError => error
|
||||
|
||||
raise commit_error_exception(error)
|
||||
end
|
||||
|
||||
def transform_file_entries(files)
|
||||
|
@ -85,4 +87,16 @@ class SnippetRepository < ApplicationRecord
|
|||
def build_empty_file_name(index)
|
||||
"#{DEFAULT_EMPTY_FILE_NAME}#{index}.txt"
|
||||
end
|
||||
|
||||
def commit_error_exception(error)
|
||||
if error.is_a?(Gitlab::Git::Index::IndexError) && invalid_path_error?(error.message)
|
||||
InvalidPathError.new('Invalid Path') # To avoid returning the message with the path included
|
||||
else
|
||||
CommitError.new(error.message)
|
||||
end
|
||||
end
|
||||
|
||||
def invalid_path_error?(message)
|
||||
message.downcase.start_with?('invalid path', 'path cannot include directory traversal')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -41,4 +41,8 @@ class X509CommitSignature < ApplicationRecord
|
|||
|
||||
Gitlab::X509::Commit.new(commit)
|
||||
end
|
||||
|
||||
def user
|
||||
commit.committer
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
- if signature
|
||||
- uri = "projects/commit/#{"x509/" if signature.instance_of?(X509CommitSignature)}"
|
||||
- uri = "projects/commit/#{"x509/" if x509_signature?(signature)}"
|
||||
= render partial: "#{uri}#{signature.verification_status}_signature_badge", locals: { signature: signature }
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
- content = capture do
|
||||
- if show_user
|
||||
.clearfix
|
||||
- uri_signature_badge_user = "projects/commit/#{"x509/" if signature.instance_of?(X509CommitSignature)}signature_badge_user"
|
||||
- uri_signature_badge_user = "projects/commit/#{"x509/" if x509_signature?(signature)}signature_badge_user"
|
||||
= render partial: "#{uri_signature_badge_user}", locals: { signature: signature }
|
||||
|
||||
- if signature.instance_of?(X509CommitSignature)
|
||||
- if x509_signature?(signature)
|
||||
= render partial: "projects/commit/x509/certificate_details", locals: { signature: signature }
|
||||
|
||||
= link_to(_('Learn more about x509 signed commits'), help_page_path('user/project/repository/x509_signed_commits/index.md'), class: 'gpg-popover-help-link')
|
||||
= link_to(_('Learn more about X.509 signed commits'), help_page_path('user/project/repository/x509_signed_commits/index.md'), class: 'gpg-popover-help-link')
|
||||
- else
|
||||
= _('GPG Key ID:')
|
||||
%span.monospace= signature.gpg_key_primary_keyid
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- user = signature.commit.committer
|
||||
- user_email = signature.x509_certificate.email
|
||||
- user = signature.user
|
||||
|
||||
- if user
|
||||
= link_to user_path(user), class: 'gpg-popover-user-link' do
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
= markdown_field(release, :description)
|
||||
|
||||
.row-fixed-content.controls.flex-row
|
||||
- if tag.has_signature?
|
||||
= render partial: 'projects/commit/signature', object: tag.signature
|
||||
|
||||
= render 'projects/buttons/download', project: @project, ref: tag.name, pipeline: @tags_pipelines[tag.name]
|
||||
|
||||
- if can?(current_user, :admin_tag, @project)
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
= s_("TagsPage|Can't find HEAD commit for this tag")
|
||||
|
||||
.nav-controls
|
||||
- if @tag.has_signature?
|
||||
= render partial: 'projects/commit/signature', object: @tag.signature
|
||||
- if can?(current_user, :admin_tag, @project)
|
||||
= link_to edit_project_tag_release_path(@project, @tag.name), class: 'btn btn-edit controls-item has-tooltip', title: s_('TagsPage|Edit release notes') do
|
||||
= icon("pencil")
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
= markdown @service.help
|
||||
|
||||
.service-settings
|
||||
.js-vue-integration-settings{ data: { show_active: @service.show_active_box?.to_s, activated: (@service.active || @service.new_record?).to_s } }
|
||||
.js-vue-integration-settings{ data: { show_active: @service.show_active_box?.to_s, activated: (@service.active || @service.new_record?).to_s, type: @service.to_param, merge_request_events: @service.merge_requests_events.to_s,
|
||||
commit_events: @service.commit_events.to_s, enable_comments: @service.comment_on_event_enabled.to_s, comment_detail: @service.comment_detail } }
|
||||
|
||||
- if @service.configurable_events.present?
|
||||
- if @service.configurable_events.present? && !@service.is_a?(JiraService)
|
||||
.form-group.row
|
||||
%label.col-form-label.col-sm-2= _('Trigger')
|
||||
|
||||
|
@ -31,22 +32,6 @@
|
|||
%p.text-muted
|
||||
= @service.class.event_description(event)
|
||||
|
||||
- if @service.configurable_event_actions.present?
|
||||
.form-group.row
|
||||
%label.col-form-label.col-sm-2= _('Event Actions')
|
||||
|
||||
.col-sm-10
|
||||
- @service.configurable_event_actions.each do |action|
|
||||
.form-group
|
||||
.form-check
|
||||
= form.check_box service_event_action_field_name(action), class: 'form-check-input'
|
||||
= form.label service_event_action_field_name(action), class: 'form-check-label' do
|
||||
%strong
|
||||
= event_action_description(action)
|
||||
|
||||
%p.text-muted
|
||||
= event_action_description(action)
|
||||
|
||||
- @service.global_fields.each do |field|
|
||||
- type = field[:type]
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update Jira comment to include more information
|
||||
merge_request: 30258
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Correctly track the store that external MR diffs are placed on
|
||||
merge_request: 31005
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Display x509 signed tags
|
||||
merge_request: 27211
|
||||
author: Roger Meier
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix 500 error loading environments index
|
||||
merge_request: 31184
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Use process-wide cache for application settings and performance bar
|
||||
merge_request: 31135
|
||||
author:
|
||||
type: performance
|
|
@ -1,12 +1,12 @@
|
|||
require 'gitlab/testing/request_blocker_middleware'
|
||||
require 'gitlab/testing/request_inspector_middleware'
|
||||
require 'gitlab/testing/clear_thread_memory_cache_middleware'
|
||||
require 'gitlab/testing/clear_process_memory_cache_middleware'
|
||||
|
||||
Rails.application.configure do
|
||||
# Make sure the middleware is inserted first in middleware chain
|
||||
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::RequestBlockerMiddleware)
|
||||
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::RequestInspectorMiddleware)
|
||||
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::ClearThreadMemoryCacheMiddleware)
|
||||
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::ClearProcessMemoryCacheMiddleware)
|
||||
|
||||
# Settings specified here will take precedence over those in config/application.rb
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Gitlab::ThreadMemoryCache.cache_backend
|
|
@ -151,18 +151,18 @@ The response will be `404 Not Found` if the vulnerability export is not finished
|
|||
Example response:
|
||||
|
||||
```csv
|
||||
Scanner Type,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE
|
||||
container_scanning,Clair,confirmed,CVE-2017-16997 in glibc,,CVE-2017-16997 in glibc,critical,CVE-2017-16997
|
||||
container_scanning,Clair,detected,CVE-2017-18269 in glibc,,CVE-2017-18269 in glibc,critical,CVE-2017-18269
|
||||
container_scanning,Clair,detected,CVE-2018-1000001 in glibc,,CVE-2018-1000001 in glibc,high,CVE-2018-1000001
|
||||
container_scanning,Clair,detected,CVE-2016-10228 in glibc,,CVE-2016-10228 in glibc,medium,CVE-2016-10228
|
||||
container_scanning,Clair,confirmed,CVE-2010-4052 in glibc,,CVE-2010-4052 in glibc,low,CVE-2010-4052
|
||||
container_scanning,Clair,detected,CVE-2018-18520 in elfutils,,CVE-2018-18520 in elfutils,low,CVE-2018-18520
|
||||
container_scanning,Clair,detected,CVE-2018-16869 in nettle,,CVE-2018-16869 in nettle,unknown,CVE-2018-16869
|
||||
dependency_scanning,Gemnasium,detected,Regular Expression Denial of Service in debug,,Regular Expression Denial of Service in debug,unknown,yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a
|
||||
dependency_scanning,Gemnasium,detected,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,unknown,yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98
|
||||
sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,818bf5dacb291e15d9e6dc3c5ac32178:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:47
|
||||
sast,Find Security Bugs,detected,Cipher with no integrity,,Cipher with no integrity,medium,e6449b89335daf53c0db4c0219bc1634:CIPHER_INTEGRITY:src/main/java/com/gitlab/security_products/tests/App.java:29
|
||||
sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,e8ff1d01f74cd372f78da8f5247d3e73:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:41
|
||||
sast,Find Security Bugs,confirmed,ECB mode is insecure 2,,ECB mode is insecure,medium,ea0f905fc76f2739d5f10a1fd1e37a10:ECB_MODE:src/main/java/com/gitlab/security_products/tests/App.java:29
|
||||
```
|
||||
Group Name,Project Name,Scanner Type,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE
|
||||
Gitlab.org,Defend,container_scanning,Clair,confirmed,CVE-2017-16997 in glibc,,CVE-2017-16997 in glibc,critical,CVE-2017-16997
|
||||
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2017-18269 in glibc,,CVE-2017-18269 in glibc,critical,CVE-2017-18269
|
||||
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2018-1000001 in glibc,,CVE-2018-1000001 in glibc,high,CVE-2018-1000001
|
||||
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2016-10228 in glibc,,CVE-2016-10228 in glibc,medium,CVE-2016-10228
|
||||
Gitlab.org,Defend,container_scanning,Clair,confirmed,CVE-2010-4052 in glibc,,CVE-2010-4052 in glibc,low,CVE-2010-4052
|
||||
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2018-18520 in elfutils,,CVE-2018-18520 in elfutils,low,CVE-2018-18520
|
||||
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2018-16869 in nettle,,CVE-2018-16869 in nettle,unknown,CVE-2018-16869
|
||||
Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Regular Expression Denial of Service in debug,,Regular Expression Denial of Service in debug,unknown,yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a
|
||||
Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,unknown,yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98
|
||||
Gitlab.org,Defend,sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,818bf5dacb291e15d9e6dc3c5ac32178:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:47
|
||||
Gitlab.org,Defend,sast,Find Security Bugs,detected,Cipher with no integrity,,Cipher with no integrity,medium,e6449b89335daf53c0db4c0219bc1634:CIPHER_INTEGRITY:src/main/java/com/gitlab/security_products/tests/App.java:29
|
||||
Gitlab.org,Defend,sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,e8ff1d01f74cd372f78da8f5247d3e73:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:41
|
||||
Gitlab.org,Defend,sast,Find Security Bugs,confirmed,ECB mode is insecure 2,,ECB mode is insecure,medium,ea0f905fc76f2739d5f10a1fd1e37a10:ECB_MODE:src/main/java/com/gitlab/security_products/tests/App.java:29
|
||||
Gitlab.org,Defend,```
|
||||
|
|
|
@ -468,6 +468,21 @@ When a merge request author has been blocked for longer than
|
|||
the `Review-response` SLO, they are free to remind the reviewer through Slack or assign
|
||||
another reviewer.
|
||||
|
||||
#### Customer critical merge requests
|
||||
|
||||
A merge request may benefit from being considered a customer critical priority because there is a significant benefit to the business in doing so.
|
||||
|
||||
Properties of customer critical merge requests:
|
||||
|
||||
- The [Senior Director of Development](https://about.gitlab.com/job-families/engineering/engineering-management/#senior-director-engineering) [@clefelhocz1](https://gitlab.com/clefelhocz1) is the DRI for deciding if a merge request will be customer critical.
|
||||
- The DRI will assign the `customer-critical-merge-request` label to the merge request.
|
||||
- It is required that the reviewer(s) and maintainer(s) involved with a customer critical merge request are engaged as soon as this decision is made.
|
||||
- It is required to prioritize work for those involved on a customer critical merge request so that they have the time available necessary to focus on it.
|
||||
- It is required to adhere to GitLab [values](https://about.gitlab.com/handbook/values.md) and processes when working on customer critical merge requests, taking particular note of family and friends first/work second, definition of done, iteration, and release when it's ready.
|
||||
- Customer critical merge requests are required to not reduce security, introduce data-loss risk, reduce availability, nor break existing functionality per the process for [prioritizing technical decisions](https://about.gitlab.com/handbook/engineering/#prioritizing-technical-decisions.md).
|
||||
- On customer critical requests, it is _recommended_ that those involved _consider_ coordinating synchronously (Zoom, Slack) in addition to asynchronously (merge requests comments) if they believe this will reduce elapsed time to merge even though this _may_ sacrifice [efficiency](https://about.gitlab.com/company/culture/all-remote/asynchronous/#evaluating-efficiency.md).
|
||||
- After a customer critical merge request is merged, a retrospective must be completed with the intention of reducing the frequency of future customer critical merge requests.
|
||||
|
||||
## Examples
|
||||
|
||||
How code reviews are conducted can surprise new contributors. Here are some examples of code reviews that should help to orient you as to what to expect.
|
||||
|
|
|
@ -552,10 +552,12 @@ being cleaned up will be minimal.
|
|||
|
||||
## Limitations
|
||||
|
||||
Moving or renaming existing Container Registry repositories is not supported
|
||||
- Moving or renaming existing Container Registry repositories is not supported
|
||||
once you have pushed images, because the images are signed, and the
|
||||
signature includes the repository name. To move or rename a repository with a
|
||||
Container Registry, you will have to delete all existing images.
|
||||
- Prior to GitLab 12.10, any tags that use the same image ID as the `latest` tag
|
||||
will not be deleted by the expiration policy.
|
||||
|
||||
## Troubleshooting the GitLab Container Registry
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
type: concepts, howto
|
||||
---
|
||||
|
||||
# Signing commits with X.509
|
||||
# Signing commits and tags with X.509
|
||||
|
||||
[X.509](https://en.wikipedia.org/wiki/X.509) is a standard format for public key
|
||||
certificates issued by a public or private Public Key Infrastructure (PKI).
|
||||
|
@ -16,7 +16,7 @@ instead of a web of trust with GPG.
|
|||
|
||||
GitLab uses its own certificate store and therefore defines the trust chain.
|
||||
|
||||
For a commit to be *verified* by GitLab:
|
||||
For a commit or tag to be *verified* by GitLab:
|
||||
|
||||
- The signing certificate email must match a verified email address used by the committer in GitLab.
|
||||
- The Certificate Authority has to be trusted by the GitLab instance, see also
|
||||
|
@ -27,6 +27,11 @@ For a commit to be *verified* by GitLab:
|
|||
|
||||
NOTE: **Note:** Certificate revocation lists are checked on a daily basis via background worker.
|
||||
|
||||
NOTE: **Note:** Self signed certificates without `authorityKeyIdentifier`,
|
||||
`subjectKeyIdentifier`, and `crlDistributionPoints` are not supported. We
|
||||
recommend using certificates from a PKI that are in line with
|
||||
[RFC 5280](https://tools.ietf.org/html/rfc5280).
|
||||
|
||||
## Obtaining an X.509 key pair
|
||||
|
||||
If your organization has Public Key Infrastructure (PKI), that PKI will provide
|
||||
|
@ -98,3 +103,31 @@ To verify that a commit is signed, you can use the `--show-signature` flag:
|
|||
```sh
|
||||
git log --show-signature
|
||||
```
|
||||
|
||||
## Signing tags
|
||||
|
||||
After you have [associated your X.509 certificate with Git](#associating-your-x509-certificate-with-git) you
|
||||
can start signing your tags:
|
||||
|
||||
1. Tag like you used to, the only difference is the addition of the `-s` flag:
|
||||
|
||||
```sh
|
||||
git tag -s v1.1.1 -m "My signed tag"
|
||||
```
|
||||
|
||||
1. Push to GitLab and check that your tags [are verified](#verifying-tags).
|
||||
|
||||
If you don't want to type the `-s` flag every time you tag, you can tell Git
|
||||
to sign your tags automatically:
|
||||
|
||||
```sh
|
||||
git config --global tag.gpgsign true
|
||||
```
|
||||
|
||||
## Verifying tags
|
||||
|
||||
To verify that a tag is signed, you can use the `--verify` flag:
|
||||
|
||||
```sh
|
||||
git tag --verify v1.1.1
|
||||
```
|
||||
|
|
|
@ -134,11 +134,7 @@ class Feature
|
|||
end
|
||||
|
||||
def l1_cache_backend
|
||||
if Gitlab::Utils.to_boolean(ENV['USE_THREAD_MEMORY_CACHE'])
|
||||
Gitlab::ThreadMemoryCache.cache_backend
|
||||
else
|
||||
Gitlab::ProcessMemoryCache.cache_backend
|
||||
end
|
||||
Gitlab::ProcessMemoryCache.cache_backend
|
||||
end
|
||||
|
||||
def l2_cache_backend
|
||||
|
|
|
@ -117,7 +117,7 @@ module Gitlab
|
|||
# the migration can succeed, to achieve that, we'll identify in migration retries
|
||||
# that the path is invalid
|
||||
def set_file_path_error(error)
|
||||
@invalid_path_error = error.message.downcase.start_with?('invalid path', 'path cannot include directory traversal')
|
||||
@invalid_path_error = error.is_a?(SnippetRepository::InvalidPathError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,6 +66,27 @@ module Gitlab
|
|||
@raw_tag.tagger
|
||||
end
|
||||
|
||||
def has_signature?
|
||||
signature_type != :NONE
|
||||
end
|
||||
|
||||
def signature_type
|
||||
@raw_tag.signature_type || :NONE
|
||||
end
|
||||
|
||||
def signature
|
||||
return unless has_signature?
|
||||
|
||||
case signature_type
|
||||
when :PGP
|
||||
nil # not implemented, see https://gitlab.com/gitlab-org/gitlab/issues/19260
|
||||
when :X509
|
||||
X509::Tag.new(@raw_tag).signature
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message_from_gitaly_tag
|
||||
|
|
|
@ -2,13 +2,25 @@
|
|||
|
||||
module Gitlab
|
||||
module Json
|
||||
INVALID_LEGACY_TYPES = [String, TrueClass, FalseClass].freeze
|
||||
|
||||
class << self
|
||||
def parse(*args)
|
||||
adapter.parse(*args)
|
||||
def parse(string, *args, **named_args)
|
||||
legacy_mode = legacy_mode_enabled?(named_args.delete(:legacy_mode))
|
||||
data = adapter.parse(string, *args, **named_args)
|
||||
|
||||
handle_legacy_mode!(data) if legacy_mode
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def parse!(*args)
|
||||
adapter.parse!(*args)
|
||||
def parse!(string, *args, **named_args)
|
||||
legacy_mode = legacy_mode_enabled?(named_args.delete(:legacy_mode))
|
||||
data = adapter.parse!(string, *args, **named_args)
|
||||
|
||||
handle_legacy_mode!(data) if legacy_mode
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def dump(*args)
|
||||
|
@ -28,6 +40,20 @@ module Gitlab
|
|||
def adapter
|
||||
::JSON
|
||||
end
|
||||
|
||||
def parser_error
|
||||
::JSON::ParserError
|
||||
end
|
||||
|
||||
def legacy_mode_enabled?(arg_value)
|
||||
arg_value.nil? ? false : arg_value
|
||||
end
|
||||
|
||||
def handle_legacy_mode!(data)
|
||||
return data unless Feature.enabled?(:json_wrapper_legacy_mode, default_enabled: true)
|
||||
|
||||
raise parser_error if INVALID_LEGACY_TYPES.any? { |type| data.is_a?(type) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -44,7 +44,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def self.l1_cache_backend
|
||||
Gitlab::ThreadMemoryCache.cache_backend
|
||||
Gitlab::ProcessMemoryCache.cache_backend
|
||||
end
|
||||
|
||||
def self.l2_cache_backend
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
module Gitlab
|
||||
module Testing
|
||||
class ClearThreadMemoryCacheMiddleware
|
||||
class ClearProcessMemoryCacheMiddleware
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
Gitlab::ThreadMemoryCache.cache_backend.clear
|
||||
Gitlab::ProcessMemoryCache.cache_backend.clear
|
||||
|
||||
@app.call(env)
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
class ThreadMemoryCache
|
||||
THREAD_KEY = :thread_memory_cache
|
||||
|
||||
def self.cache_backend
|
||||
# Note ActiveSupport::Cache::MemoryStore is thread-safe. Since
|
||||
# each backend is local per thread we probably don't need to worry
|
||||
# about synchronizing access, but this is a drop-in replacement
|
||||
# for ActiveSupport::Cache::RedisStore.
|
||||
Thread.current[THREAD_KEY] ||= ActiveSupport::Cache::MemoryStore.new
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,6 +22,10 @@ module Gitlab
|
|||
X509Certificate.safe_create!(certificate_attributes) unless verified_signature.nil?
|
||||
end
|
||||
|
||||
def user
|
||||
User.find_by_any_email(@email)
|
||||
end
|
||||
|
||||
def verified_signature
|
||||
strong_memoize(:verified_signature) { verified_signature? }
|
||||
end
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
require 'openssl'
|
||||
require 'digest'
|
||||
|
||||
module Gitlab
|
||||
module X509
|
||||
class Tag
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
def initialize(raw_tag)
|
||||
@raw_tag = raw_tag
|
||||
end
|
||||
|
||||
def signature
|
||||
signature = X509::Signature.new(signature_text, signed_text, @raw_tag.tagger.email, Time.at(@raw_tag.tagger.date.seconds))
|
||||
|
||||
return if signature.verified_signature.nil?
|
||||
|
||||
signature
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def signature_text
|
||||
@raw_tag.message.slice(@raw_tag.message.index("-----BEGIN SIGNED MESSAGE-----")..-1)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def signed_text
|
||||
# signed text is reconstructed as long as there is no specific gitaly function
|
||||
%{object #{@raw_tag.target_commit.id}
|
||||
type commit
|
||||
tag #{@raw_tag.name}
|
||||
tagger #{@raw_tag.tagger.name} <#{@raw_tag.tagger.email}> #{@raw_tag.tagger.date.seconds} #{@raw_tag.tagger.timezone}
|
||||
|
||||
#{@raw_tag.message.gsub(/-----BEGIN SIGNED MESSAGE-----(.*)-----END SIGNED MESSAGE-----/m, "")}}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3410,12 +3410,6 @@ msgstr ""
|
|||
msgid "Business metrics (Custom)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Buy EE"
|
||||
msgstr ""
|
||||
|
||||
msgid "Buy GitLab Enterprise Edition"
|
||||
msgstr ""
|
||||
|
||||
msgid "Buy more Pipeline minutes"
|
||||
msgstr ""
|
||||
|
||||
|
@ -5593,18 +5587,9 @@ msgstr ""
|
|||
msgid "Connection timed out"
|
||||
msgstr ""
|
||||
|
||||
msgid "Contact an owner of group %{namespace_name} to upgrade the plan."
|
||||
msgstr ""
|
||||
|
||||
msgid "Contact owner %{link_start}%{owner_name}%{link_end} to upgrade the plan."
|
||||
msgstr ""
|
||||
|
||||
msgid "Contact sales to upgrade"
|
||||
msgstr ""
|
||||
|
||||
msgid "Contact your Administrator to upgrade your license."
|
||||
msgstr ""
|
||||
|
||||
msgid "Container Registry"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8572,9 +8557,6 @@ msgstr ""
|
|||
msgid "Estimated"
|
||||
msgstr ""
|
||||
|
||||
msgid "Event Actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "EventFilterBy|Filter by all"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9793,10 +9775,7 @@ msgstr ""
|
|||
msgid "Geo|Adjust your filters/search criteria above. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|All"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|All %{replicable_type}"
|
||||
msgid "Geo|All %{replicable_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|All projects"
|
||||
|
@ -11306,9 +11285,6 @@ msgstr ""
|
|||
msgid "Improve Merge Requests and customer support with GitLab Enterprise Edition."
|
||||
msgstr ""
|
||||
|
||||
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
|
||||
msgstr ""
|
||||
|
||||
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
|
||||
msgstr ""
|
||||
|
||||
|
@ -11411,6 +11387,12 @@ msgstr ""
|
|||
msgid "Insights"
|
||||
msgstr ""
|
||||
|
||||
msgid "Insights|Some items are not visible beacuse the project was filtered out in the insights.yml file (see the projects.only config for more information)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Insights|This project is filtered out in the insights.yml file (see the projects.only config for more information)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Install"
|
||||
msgstr ""
|
||||
|
||||
|
@ -11461,6 +11443,30 @@ msgstr ""
|
|||
msgid "Integrations allow you to integrate GitLab with other applications"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|All details"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Comment detail:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Comment settings:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Enable comments"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Includes Standard plus entire commit message, commit hash, and issue IDs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Includes commit title and branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|Standard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Integrations|When a Jira issue is mentioned in a commit or merge request a remote link and comment (if enabled) will be created."
|
||||
msgstr ""
|
||||
|
||||
msgid "Interested parties can even contribute by pushing commits if they want to."
|
||||
msgstr ""
|
||||
|
||||
|
@ -11764,6 +11770,12 @@ msgstr ""
|
|||
msgid "Jira project: %{importProject}"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService| on branch %{branch_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|%{user_link} mentioned this issue in %{entity_link} of %{project_link}%{branch}:{quote}%{entity_message}{quote}"
|
||||
msgstr ""
|
||||
|
||||
msgid "JiraService|Events for %{noteable_model_name} are disabled."
|
||||
msgstr ""
|
||||
|
||||
|
@ -12189,6 +12201,9 @@ msgstr ""
|
|||
msgid "Learn more about Web Terminal"
|
||||
msgstr ""
|
||||
|
||||
msgid "Learn more about X.509 signed commits"
|
||||
msgstr ""
|
||||
|
||||
msgid "Learn more about adding certificates to your project by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
|
||||
msgstr ""
|
||||
|
||||
|
@ -12210,9 +12225,6 @@ msgstr ""
|
|||
msgid "Learn more about the dependency list"
|
||||
msgstr ""
|
||||
|
||||
msgid "Learn more about x509 signed commits"
|
||||
msgstr ""
|
||||
|
||||
msgid "Learn more in the"
|
||||
msgstr ""
|
||||
|
||||
|
@ -16671,24 +16683,51 @@ msgstr ""
|
|||
msgid "Promoted issue to an epic."
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Buy EE"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Buy GitLab Enterprise Edition"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Contact an owner of group %{namespace_name} to upgrade the plan."
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Contact owner %{link_start}%{owner_name}%{link_end} to upgrade the plan."
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Contact your Administrator to upgrade your license."
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Don't show me this again"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Epics let you manage your portfolio of projects more efficiently and with less effort by tracking groups of issues that share a theme, across projects and milestones."
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Improve issues management with Issue weight and GitLab Enterprise Edition."
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Learn more"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|See the other features in the %{subscription_link_start}bronze plan%{subscription_link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Start GitLab Ultimate trial"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|This feature is locked."
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Upgrade plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Upgrade your plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Weight"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promotions|Weighting your issue"
|
||||
msgstr ""
|
||||
|
||||
|
@ -19774,9 +19813,6 @@ msgstr ""
|
|||
msgid "Stars"
|
||||
msgstr ""
|
||||
|
||||
msgid "Start GitLab Ultimate trial"
|
||||
msgstr ""
|
||||
|
||||
msgid "Start Web Terminal"
|
||||
msgstr ""
|
||||
|
||||
|
@ -22643,9 +22679,6 @@ msgstr ""
|
|||
msgid "Upgrade plan to unlock Canary Deployments feature"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upgrade your plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upgrade your plan to activate Advanced Global Search."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ describe('ActiveToggle', () => {
|
|||
|
||||
const defaultProps = {
|
||||
initialActivated: true,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
const createComponent = props => {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import IntegrationForm from '~/integrations/edit/components/integration_form.vue';
|
||||
import ActiveToggle from '~/integrations/edit/components/active_toggle.vue';
|
||||
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
|
||||
|
||||
describe('IntegrationForm', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultProps = {
|
||||
activeToggleProps: {
|
||||
initialActivated: true,
|
||||
},
|
||||
showActive: true,
|
||||
triggerFieldsProps: {
|
||||
initialTriggerCommit: false,
|
||||
initialTriggerMergeRequest: false,
|
||||
initialEnableComments: false,
|
||||
},
|
||||
type: '',
|
||||
};
|
||||
|
||||
const createComponent = props => {
|
||||
wrapper = shallowMount(IntegrationForm, {
|
||||
propsData: { ...defaultProps, ...props },
|
||||
stubs: {
|
||||
ActiveToggle,
|
||||
JiraTriggerFields,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
}
|
||||
});
|
||||
|
||||
const findActiveToggle = () => wrapper.find(ActiveToggle);
|
||||
const findJiraTriggerFields = () => wrapper.find(JiraTriggerFields);
|
||||
|
||||
describe('template', () => {
|
||||
describe('showActive is true', () => {
|
||||
it('renders ActiveToggle', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findActiveToggle().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('showActive is false', () => {
|
||||
it('does not render ActiveToggle', () => {
|
||||
createComponent({
|
||||
showActive: false,
|
||||
});
|
||||
|
||||
expect(findActiveToggle().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('type is "slack"', () => {
|
||||
it('does not render JiraTriggerFields', () => {
|
||||
createComponent({
|
||||
type: 'slack',
|
||||
});
|
||||
|
||||
expect(findJiraTriggerFields().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('type is "jira"', () => {
|
||||
it('renders JiraTriggerFields', () => {
|
||||
createComponent({
|
||||
type: 'jira',
|
||||
});
|
||||
|
||||
expect(findJiraTriggerFields().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,94 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
|
||||
import { GlFormCheckbox } from '@gitlab/ui';
|
||||
|
||||
describe('JiraTriggerFields', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultProps = {
|
||||
initialTriggerCommit: false,
|
||||
initialTriggerMergeRequest: false,
|
||||
initialEnableComments: false,
|
||||
};
|
||||
|
||||
const createComponent = props => {
|
||||
wrapper = mount(JiraTriggerFields, {
|
||||
propsData: Object.assign({}, defaultProps, props),
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) wrapper.destroy();
|
||||
});
|
||||
|
||||
const findCommentSettings = () => wrapper.find('[data-testid="comment-settings"]');
|
||||
const findCommentDetail = () => wrapper.find('[data-testid="comment-detail"]');
|
||||
const findCommentSettingsCheckbox = () => findCommentSettings().find(GlFormCheckbox);
|
||||
|
||||
describe('template', () => {
|
||||
describe('initialTriggerCommit and initialTriggerMergeRequest are false', () => {
|
||||
it('does not show comment settings', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findCommentSettings().isVisible()).toBe(false);
|
||||
expect(findCommentDetail().isVisible()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialTriggerCommit is true', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
initialTriggerCommit: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('shows comment settings', () => {
|
||||
expect(findCommentSettings().isVisible()).toBe(true);
|
||||
expect(findCommentDetail().isVisible()).toBe(false);
|
||||
});
|
||||
|
||||
// As per https://vuejs.org/v2/guide/forms.html#Checkbox-1,
|
||||
// browsers don't include unchecked boxes in form submissions.
|
||||
it('includes comment settings as false even if unchecked', () => {
|
||||
expect(
|
||||
findCommentSettings()
|
||||
.find('input[name="service[comment_on_event_enabled]"]')
|
||||
.exists(),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
describe('on enable comments', () => {
|
||||
it('shows comment detail', () => {
|
||||
findCommentSettingsCheckbox().vm.$emit('input', true);
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(findCommentDetail().isVisible()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialTriggerMergeRequest is true', () => {
|
||||
it('shows comment settings', () => {
|
||||
createComponent({
|
||||
initialTriggerMergeRequest: true,
|
||||
});
|
||||
|
||||
expect(findCommentSettings().isVisible()).toBe(true);
|
||||
expect(findCommentDetail().isVisible()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialTriggerCommit is true, initialEnableComments is true', () => {
|
||||
it('shows comment settings and comment detail', () => {
|
||||
createComponent({
|
||||
initialTriggerCommit: true,
|
||||
initialEnableComments: true,
|
||||
});
|
||||
|
||||
expect(findCommentSettings().isVisible()).toBe(true);
|
||||
expect(findCommentDetail().isVisible()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -57,4 +57,22 @@ describe X509Helper do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#x509_signature?' do
|
||||
let(:x509_signature) { create(:x509_commit_signature) }
|
||||
let(:gpg_signature) { create(:gpg_signature) }
|
||||
|
||||
it 'detects a x509 signed commit' do
|
||||
signature = Gitlab::X509::Signature.new(
|
||||
X509Helpers::User1.signed_commit_signature,
|
||||
X509Helpers::User1.signed_commit_base_data,
|
||||
X509Helpers::User1.certificate_email,
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
|
||||
expect(x509_signature?(x509_signature)).to be_truthy
|
||||
expect(x509_signature?(signature)).to be_truthy
|
||||
expect(x509_signature?(gpg_signature)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -146,14 +146,6 @@ describe Feature do
|
|||
expect(described_class.enabled?(:enabled_feature_flag)).to be_truthy
|
||||
end
|
||||
|
||||
context 'with USE_THREAD_MEMORY_CACHE defined' do
|
||||
before do
|
||||
stub_env('USE_THREAD_MEMORY_CACHE', '1')
|
||||
end
|
||||
|
||||
it { expect(described_class.l1_cache_backend).to eq(Gitlab::ThreadMemoryCache.cache_backend) }
|
||||
end
|
||||
|
||||
it { expect(described_class.l1_cache_backend).to eq(Gitlab::ProcessMemoryCache.cache_backend) }
|
||||
it { expect(described_class.l2_cache_backend).to eq(Rails.cache) }
|
||||
|
||||
|
|
|
@ -13,6 +13,13 @@ describe Gitlab::Git::Tag, :seed_helper do
|
|||
it { expect(tag.target).to eq("f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8") }
|
||||
it { expect(tag.dereferenced_target.sha).to eq("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") }
|
||||
it { expect(tag.message).to eq("Release") }
|
||||
it { expect(tag.has_signature?).to be_falsey }
|
||||
it { expect(tag.signature_type).to eq(:NONE) }
|
||||
it { expect(tag.signature).to be_nil }
|
||||
it { expect(tag.tagger.name).to eq("Dmitriy Zaporozhets") }
|
||||
it { expect(tag.tagger.email).to eq("dmitriy.zaporozhets@gmail.com") }
|
||||
it { expect(tag.tagger.date).to eq(Google::Protobuf::Timestamp.new(seconds: 1393491299)) }
|
||||
it { expect(tag.tagger.timezone).to eq("+0200") }
|
||||
end
|
||||
|
||||
describe 'last tag' do
|
||||
|
@ -22,6 +29,29 @@ describe Gitlab::Git::Tag, :seed_helper do
|
|||
it { expect(tag.target).to eq("2ac1f24e253e08135507d0830508febaaccf02ee") }
|
||||
it { expect(tag.dereferenced_target.sha).to eq("fa1b1e6c004a68b7d8763b86455da9e6b23e36d6") }
|
||||
it { expect(tag.message).to eq("Version 1.2.1") }
|
||||
it { expect(tag.has_signature?).to be_falsey }
|
||||
it { expect(tag.signature_type).to eq(:NONE) }
|
||||
it { expect(tag.signature).to be_nil }
|
||||
it { expect(tag.tagger.name).to eq("Douwe Maan") }
|
||||
it { expect(tag.tagger.email).to eq("douwe@selenight.nl") }
|
||||
it { expect(tag.tagger.date).to eq(Google::Protobuf::Timestamp.new(seconds: 1427789449)) }
|
||||
it { expect(tag.tagger.timezone).to eq("+0200") }
|
||||
end
|
||||
|
||||
describe 'signed tag' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:tag) { project.repository.find_tag('v1.1.1') }
|
||||
|
||||
it { expect(tag.target).to eq("8f03acbcd11c53d9c9468078f32a2622005a4841") }
|
||||
it { expect(tag.dereferenced_target.sha).to eq("189a6c924013fc3fe40d6f1ec1dc20214183bc97") }
|
||||
it { expect(tag.message).to eq("x509 signed tag" + "\n" + X509Helpers::User1.signed_tag_signature.chomp) }
|
||||
it { expect(tag.has_signature?).to be_truthy }
|
||||
it { expect(tag.signature_type).to eq(:X509) }
|
||||
it { expect(tag.signature).not_to be_nil }
|
||||
it { expect(tag.tagger.name).to eq("Roger Meier") }
|
||||
it { expect(tag.tagger.email).to eq("r.meier@siemens.com") }
|
||||
it { expect(tag.tagger.date).to eq(Google::Protobuf::Timestamp.new(seconds: 1574261780)) }
|
||||
it { expect(tag.tagger.timezone).to eq("+0100") }
|
||||
end
|
||||
|
||||
it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
|
||||
|
|
|
@ -3,47 +3,103 @@
|
|||
require "spec_helper"
|
||||
|
||||
RSpec.describe Gitlab::Json do
|
||||
before do
|
||||
stub_feature_flags(json_wrapper_legacy_mode: true)
|
||||
end
|
||||
|
||||
describe ".parse" do
|
||||
it "parses an object" do
|
||||
expect(subject.parse('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
||||
context "legacy_mode is disabled by default" do
|
||||
it "parses an object" do
|
||||
expect(subject.parse('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
||||
end
|
||||
|
||||
it "parses an array" do
|
||||
expect(subject.parse('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
||||
end
|
||||
|
||||
# These tests will change expectations when the gem is upgraded
|
||||
|
||||
it "raises an error on a string" do
|
||||
expect { subject.parse('"foo"') }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a true bool" do
|
||||
expect { subject.parse("true") }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a false bool" do
|
||||
expect { subject.parse("false") }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
end
|
||||
|
||||
it "parses an array" do
|
||||
expect(subject.parse('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
||||
end
|
||||
context "legacy_mode is enabled" do
|
||||
it "parses an object" do
|
||||
expect(subject.parse('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" })
|
||||
end
|
||||
|
||||
it "raises an error on a string" do
|
||||
expect { subject.parse('"foo"') }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
it "parses an array" do
|
||||
expect(subject.parse('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }])
|
||||
end
|
||||
|
||||
it "raises an error on a true bool" do
|
||||
expect { subject.parse("true") }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
it "raises an error on a string" do
|
||||
expect { subject.parse('"foo"', legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a false bool" do
|
||||
expect { subject.parse("false") }.to raise_error(JSON::ParserError)
|
||||
it "raises an error on a true bool" do
|
||||
expect { subject.parse("true", legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a false bool" do
|
||||
expect { subject.parse("false", legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".parse!" do
|
||||
it "parses an object" do
|
||||
expect(subject.parse!('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
||||
context "legacy_mode is disabled by default" do
|
||||
it "parses an object" do
|
||||
expect(subject.parse!('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
||||
end
|
||||
|
||||
it "parses an array" do
|
||||
expect(subject.parse!('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
||||
end
|
||||
|
||||
# These tests will change expectations when the gem is upgraded
|
||||
|
||||
it "raises an error on a string" do
|
||||
expect { subject.parse!('"foo"') }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a true bool" do
|
||||
expect { subject.parse!("true") }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a false bool" do
|
||||
expect { subject.parse!("false") }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
end
|
||||
|
||||
it "parses an array" do
|
||||
expect(subject.parse!('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
||||
end
|
||||
context "legacy_mode is enabled" do
|
||||
it "parses an object" do
|
||||
expect(subject.parse!('{ "foo": "bar" }', legacy_mode: true)).to eq({ "foo" => "bar" })
|
||||
end
|
||||
|
||||
it "raises an error on a string" do
|
||||
expect { subject.parse!('"foo"') }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
it "parses an array" do
|
||||
expect(subject.parse!('[{ "foo": "bar" }]', legacy_mode: true)).to eq([{ "foo" => "bar" }])
|
||||
end
|
||||
|
||||
it "raises an error on a true bool" do
|
||||
expect { subject.parse!("true") }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
it "raises an error on a string" do
|
||||
expect { subject.parse!('"foo"', legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a false bool" do
|
||||
expect { subject.parse!("false") }.to raise_error(JSON::ParserError)
|
||||
it "raises an error on a true bool" do
|
||||
expect { subject.parse!("true", legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
|
||||
it "raises an error on a false bool" do
|
||||
expect { subject.parse!("false", legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ describe Gitlab::PerformanceBar do
|
|||
end
|
||||
end
|
||||
|
||||
it { expect(described_class.l1_cache_backend).to eq(Gitlab::ThreadMemoryCache.cache_backend) }
|
||||
it { expect(described_class.l1_cache_backend).to eq(Gitlab::ProcessMemoryCache.cache_backend) }
|
||||
it { expect(described_class.l2_cache_backend).to eq(Rails.cache) }
|
||||
|
||||
describe '.enabled_for_user?' do
|
||||
|
|
|
@ -229,4 +229,164 @@ describe Gitlab::X509::Signature do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#user' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature,
|
||||
X509Helpers::User1.signed_tag_base_data,
|
||||
X509Helpers::User1.certificate_email,
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
|
||||
context 'if email is assigned to a user' do
|
||||
let!(:user) { create(:user, email: X509Helpers::User1.certificate_email) }
|
||||
|
||||
it 'returns user' do
|
||||
expect(signature.user).to eq(user)
|
||||
end
|
||||
end
|
||||
|
||||
it 'if email is not assigned to a user, return nil' do
|
||||
expect(signature.user).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'tag signature' do
|
||||
let(:certificate_attributes) do
|
||||
{
|
||||
subject_key_identifier: X509Helpers::User1.tag_certificate_subject_key_identifier,
|
||||
subject: X509Helpers::User1.certificate_subject,
|
||||
email: X509Helpers::User1.certificate_email,
|
||||
serial_number: X509Helpers::User1.tag_certificate_serial
|
||||
}
|
||||
end
|
||||
|
||||
let(:issuer_attributes) do
|
||||
{
|
||||
subject_key_identifier: X509Helpers::User1.tag_issuer_subject_key_identifier,
|
||||
subject: X509Helpers::User1.tag_certificate_issuer,
|
||||
crl_url: X509Helpers::User1.tag_certificate_crl
|
||||
}
|
||||
end
|
||||
|
||||
context 'verified signature' do
|
||||
context 'with trusted certificate store' do
|
||||
before do
|
||||
store = OpenSSL::X509::Store.new
|
||||
certificate = OpenSSL::X509::Certificate.new X509Helpers::User1.trust_cert
|
||||
store.add_cert(certificate)
|
||||
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
|
||||
end
|
||||
|
||||
it 'returns a verified signature if email does match' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature,
|
||||
X509Helpers::User1.signed_tag_base_data,
|
||||
X509Helpers::User1.certificate_email,
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
|
||||
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
|
||||
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
|
||||
expect(signature.verified_signature).to be_truthy
|
||||
expect(signature.verification_status).to eq(:verified)
|
||||
end
|
||||
|
||||
it 'returns an unverified signature if email does not match' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature,
|
||||
X509Helpers::User1.signed_tag_base_data,
|
||||
"gitlab@example.com",
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
|
||||
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
|
||||
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
|
||||
expect(signature.verified_signature).to be_truthy
|
||||
expect(signature.verification_status).to eq(:unverified)
|
||||
end
|
||||
|
||||
it 'returns an unverified signature if email does match and time is wrong' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature,
|
||||
X509Helpers::User1.signed_tag_base_data,
|
||||
X509Helpers::User1.certificate_email,
|
||||
Time.new(2020, 2, 22)
|
||||
)
|
||||
|
||||
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
|
||||
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
|
||||
expect(signature.verified_signature).to be_falsey
|
||||
expect(signature.verification_status).to eq(:unverified)
|
||||
end
|
||||
|
||||
it 'returns an unverified signature if certificate is revoked' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature,
|
||||
X509Helpers::User1.signed_tag_base_data,
|
||||
X509Helpers::User1.certificate_email,
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
|
||||
expect(signature.verification_status).to eq(:verified)
|
||||
|
||||
signature.x509_certificate.revoked!
|
||||
|
||||
expect(signature.verification_status).to eq(:unverified)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without trusted certificate within store' do
|
||||
before do
|
||||
store = OpenSSL::X509::Store.new
|
||||
allow(OpenSSL::X509::Store).to receive(:new)
|
||||
.and_return(
|
||||
store
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns an unverified signature' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature,
|
||||
X509Helpers::User1.signed_tag_base_data,
|
||||
X509Helpers::User1.certificate_email,
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
|
||||
expect(signature.x509_certificate).to have_attributes(certificate_attributes)
|
||||
expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
|
||||
expect(signature.verified_signature).to be_falsey
|
||||
expect(signature.verification_status).to eq(:unverified)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid signature' do
|
||||
it 'returns nil' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature.tr('A', 'B'),
|
||||
X509Helpers::User1.signed_tag_base_data,
|
||||
X509Helpers::User1.certificate_email,
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
expect(signature.x509_certificate).to be_nil
|
||||
expect(signature.verified_signature).to be_falsey
|
||||
expect(signature.verification_status).to eq(:unverified)
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid message' do
|
||||
it 'returns nil' do
|
||||
signature = described_class.new(
|
||||
X509Helpers::User1.signed_tag_signature,
|
||||
'x',
|
||||
X509Helpers::User1.certificate_email,
|
||||
X509Helpers::User1.signed_commit_time
|
||||
)
|
||||
expect(signature.x509_certificate).to be_nil
|
||||
expect(signature.verified_signature).to be_falsey
|
||||
expect(signature.verification_status).to eq(:unverified)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::X509::Tag do
|
||||
subject(:signature) { described_class.new(tag).signature }
|
||||
|
||||
describe '#signature' do
|
||||
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
describe 'signed tag' do
|
||||
let(:tag) { project.repository.find_tag('v1.1.1') }
|
||||
let(:certificate_attributes) do
|
||||
{
|
||||
subject_key_identifier: X509Helpers::User1.tag_certificate_subject_key_identifier,
|
||||
subject: X509Helpers::User1.certificate_subject,
|
||||
email: X509Helpers::User1.certificate_email,
|
||||
serial_number: X509Helpers::User1.tag_certificate_serial
|
||||
}
|
||||
end
|
||||
|
||||
let(:issuer_attributes) do
|
||||
{
|
||||
subject_key_identifier: X509Helpers::User1.tag_issuer_subject_key_identifier,
|
||||
subject: X509Helpers::User1.tag_certificate_issuer,
|
||||
crl_url: X509Helpers::User1.tag_certificate_crl
|
||||
}
|
||||
end
|
||||
|
||||
it { expect(signature).not_to be_nil }
|
||||
it { expect(signature.verification_status).to eq(:unverified) }
|
||||
it { expect(signature.x509_certificate).to have_attributes(certificate_attributes) }
|
||||
it { expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) }
|
||||
end
|
||||
|
||||
context 'unsigned tag' do
|
||||
let(:tag) { project.repository.find_tag('v1.0.0') }
|
||||
|
||||
it { expect(signature).to be_nil }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -205,11 +205,11 @@ describe CacheableAttributes do
|
|||
end
|
||||
end
|
||||
|
||||
it 'uses RequestStore in addition to Thread memory cache', :request_store do
|
||||
it 'uses RequestStore in addition to process memory cache', :request_store do
|
||||
# Warm up the cache
|
||||
create(:application_setting).cache!
|
||||
|
||||
expect(ApplicationSetting.cache_backend).to eq(Gitlab::ThreadMemoryCache.cache_backend)
|
||||
expect(ApplicationSetting.cache_backend).to eq(Gitlab::ProcessMemoryCache.cache_backend)
|
||||
expect(ApplicationSetting.cache_backend).to receive(:read).with(ApplicationSetting.cache_key).once.and_call_original
|
||||
|
||||
2.times { ApplicationSetting.current }
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe MergeRequestDiff do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
include RepoHelpers
|
||||
|
||||
let(:diff_with_commits) { create(:merge_request).merge_request_diff }
|
||||
|
@ -125,18 +127,71 @@ describe MergeRequestDiff do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#update_external_diff_store' do
|
||||
let_it_be(:merge_request) { create(:merge_request) }
|
||||
|
||||
let(:diff) { merge_request.merge_request_diff }
|
||||
let(:store) { diff.external_diff.object_store }
|
||||
|
||||
where(:change_stored_externally, :change_external_diff) do
|
||||
false | false
|
||||
false | true
|
||||
true | false
|
||||
true | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
it do
|
||||
diff.stored_externally = true if change_stored_externally
|
||||
diff.external_diff = "new-filename" if change_external_diff
|
||||
|
||||
update_store = receive(:update_column).with(:external_diff_store, store)
|
||||
|
||||
if change_stored_externally || change_external_diff
|
||||
expect(diff).to update_store
|
||||
else
|
||||
expect(diff).not_to update_store
|
||||
end
|
||||
|
||||
diff.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#migrate_files_to_external_storage!' do
|
||||
let(:uploader) { ExternalDiffUploader }
|
||||
let(:file_store) { uploader::Store::LOCAL }
|
||||
let(:remote_store) { uploader::Store::REMOTE }
|
||||
let(:diff) { create(:merge_request).merge_request_diff }
|
||||
|
||||
it 'converts from in-database to external storage' do
|
||||
it 'converts from in-database to external file storage' do
|
||||
expect(diff).not_to be_stored_externally
|
||||
|
||||
stub_external_diffs_setting(enabled: true)
|
||||
expect(diff).to receive(:save!)
|
||||
|
||||
expect(diff).to receive(:save!).and_call_original
|
||||
|
||||
diff.migrate_files_to_external_storage!
|
||||
|
||||
expect(diff).to be_stored_externally
|
||||
expect(diff.external_diff_store).to eq(file_store)
|
||||
end
|
||||
|
||||
it 'converts from in-database to external object storage' do
|
||||
expect(diff).not_to be_stored_externally
|
||||
|
||||
stub_external_diffs_setting(enabled: true)
|
||||
|
||||
# Without direct_upload: true, the files would be saved to disk, and a
|
||||
# background job would be enqueued to move the file to object storage
|
||||
stub_external_diffs_object_storage(uploader, direct_upload: true)
|
||||
|
||||
expect(diff).to receive(:save!).and_call_original
|
||||
|
||||
diff.migrate_files_to_external_storage!
|
||||
|
||||
expect(diff).to be_stored_externally
|
||||
expect(diff.external_diff_store).to eq(remote_store)
|
||||
end
|
||||
|
||||
it 'does nothing with an external diff' do
|
||||
|
|
|
@ -582,6 +582,79 @@ describe JiraService do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#create_cross_reference_note' do
|
||||
let_it_be(:user) { build_stubbed(:user) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:jira_service) do
|
||||
described_class.new(
|
||||
project: project,
|
||||
url: url,
|
||||
username: username,
|
||||
password: password
|
||||
)
|
||||
end
|
||||
let(:jira_issue) { ExternalIssue.new('JIRA-123', project) }
|
||||
|
||||
subject { jira_service.create_cross_reference_note(jira_issue, resource, user) }
|
||||
|
||||
shared_examples 'creates a comment on Jira' do
|
||||
let(:issue_url) { "#{url}/rest/api/2/issue/JIRA-123" }
|
||||
let(:comment_url) { "#{issue_url}/comment" }
|
||||
let(:remote_link_url) { "#{issue_url}/remotelink" }
|
||||
|
||||
before do
|
||||
allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
|
||||
stub_request(:get, issue_url).with(basic_auth: [username, password])
|
||||
stub_request(:post, comment_url).with(basic_auth: [username, password])
|
||||
stub_request(:post, remote_link_url).with(basic_auth: [username, password])
|
||||
end
|
||||
|
||||
it 'creates a comment on Jira' do
|
||||
subject
|
||||
|
||||
expect(WebMock).to have_requested(:post, comment_url).with(
|
||||
body: /mentioned this issue in/
|
||||
).once
|
||||
end
|
||||
end
|
||||
|
||||
context 'when resource is a commit' do
|
||||
let(:resource) { project.commit('master') }
|
||||
|
||||
context 'when disabled' do
|
||||
before do
|
||||
allow_next_instance_of(JiraService) do |instance|
|
||||
allow(instance).to receive(:commit_events) { false }
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to eq('Events for commits are disabled.') }
|
||||
end
|
||||
|
||||
context 'when enabled' do
|
||||
it_behaves_like 'creates a comment on Jira'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when resource is a merge request' do
|
||||
let(:resource) { build_stubbed(:merge_request, source_project: project) }
|
||||
|
||||
context 'when disabled' do
|
||||
before do
|
||||
allow_next_instance_of(JiraService) do |instance|
|
||||
allow(instance).to receive(:merge_requests_events) { false }
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to eq('Events for merge requests are disabled.') }
|
||||
end
|
||||
|
||||
context 'when enabled' do
|
||||
it_behaves_like 'creates a comment on Jira'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#test' do
|
||||
let(:jira_service) do
|
||||
described_class.new(
|
||||
|
|
|
@ -202,6 +202,22 @@ describe SnippetRepository do
|
|||
|
||||
it_behaves_like 'snippet repository with file names', 'snippetfile10.txt', 'snippetfile11.txt'
|
||||
end
|
||||
|
||||
shared_examples 'snippet repository with git errors' do |path, error|
|
||||
let(:new_file) { { file_path: path, content: 'bar' } }
|
||||
|
||||
it 'raises a path specific error' do
|
||||
expect do
|
||||
snippet_repository.multi_files_action(user, data, commit_opts)
|
||||
end.to raise_error(error)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with git errors' do
|
||||
it_behaves_like 'snippet repository with git errors', 'invalid://path/here', described_class::InvalidPathError
|
||||
it_behaves_like 'snippet repository with git errors', '../../path/traversal/here', described_class::InvalidPathError
|
||||
it_behaves_like 'snippet repository with git errors', 'README', described_class::CommitError
|
||||
end
|
||||
end
|
||||
|
||||
def blob_at(snippet, path)
|
||||
|
|
|
@ -9,6 +9,15 @@ RSpec.describe X509CommitSignature do
|
|||
let(:x509_certificate) { create(:x509_certificate) }
|
||||
let(:x509_signature) { create(:x509_commit_signature, commit_sha: commit_sha) }
|
||||
|
||||
let(:attributes) do
|
||||
{
|
||||
commit_sha: commit_sha,
|
||||
project: project,
|
||||
x509_certificate_id: x509_certificate.id,
|
||||
verification_status: "verified"
|
||||
}
|
||||
end
|
||||
|
||||
it_behaves_like 'having unique enum values'
|
||||
|
||||
describe 'validation' do
|
||||
|
@ -23,15 +32,6 @@ RSpec.describe X509CommitSignature do
|
|||
end
|
||||
|
||||
describe '.safe_create!' do
|
||||
let(:attributes) do
|
||||
{
|
||||
commit_sha: commit_sha,
|
||||
project: project,
|
||||
x509_certificate_id: x509_certificate.id,
|
||||
verification_status: "verified"
|
||||
}
|
||||
end
|
||||
|
||||
it 'finds a signature by commit sha if it existed' do
|
||||
x509_signature
|
||||
|
||||
|
@ -50,4 +50,18 @@ RSpec.describe X509CommitSignature do
|
|||
expect(signature.x509_certificate_id).to eq(x509_certificate.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#user' do
|
||||
context 'if email is assigned to a user' do
|
||||
let!(:user) { create(:user, email: X509Helpers::User1.certificate_email) }
|
||||
|
||||
it 'returns user' do
|
||||
expect(described_class.safe_create!(attributes).user).to eq(user)
|
||||
end
|
||||
end
|
||||
|
||||
it 'if email is not assigned to a user, return nil' do
|
||||
expect(described_class.safe_create!(attributes).user).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -462,7 +462,8 @@ describe SystemNoteService do
|
|||
describe "existing reference" do
|
||||
before do
|
||||
allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
|
||||
message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.full_path}|http://localhost/#{project.full_path}/-/commit/#{commit.id}]:\n'#{commit.title.chomp}'"
|
||||
message = double('message')
|
||||
allow(message).to receive(:include?) { true }
|
||||
allow_next_instance_of(JIRA::Resource::Issue) do |instance|
|
||||
allow(instance).to receive(:comments).and_return([OpenStruct.new(body: message)])
|
||||
end
|
||||
|
|
|
@ -209,9 +209,7 @@ RSpec.configure do |config|
|
|||
# expect(Gitlab::Git::KeepAround).to receive(:execute).and_call_original
|
||||
allow(Gitlab::Git::KeepAround).to receive(:execute)
|
||||
|
||||
[Gitlab::ThreadMemoryCache, Gitlab::ProcessMemoryCache].each do |cache|
|
||||
cache.cache_backend.clear
|
||||
end
|
||||
Gitlab::ProcessMemoryCache.cache_backend.clear
|
||||
|
||||
Sidekiq::Worker.clear_all
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ module StubObjectStorage
|
|||
def stub_external_diffs_object_storage(uploader = described_class, **params)
|
||||
stub_object_storage_uploader(config: Gitlab.config.external_diffs.object_store,
|
||||
uploader: uploader,
|
||||
remote_directory: 'external_diffs',
|
||||
remote_directory: 'external-diffs',
|
||||
**params)
|
||||
end
|
||||
|
||||
|
|
|
@ -173,22 +173,155 @@ module X509Helpers
|
|||
Time.at(1561027326)
|
||||
end
|
||||
|
||||
def signed_tag_signature
|
||||
<<~SIGNATURE
|
||||
-----BEGIN SIGNED MESSAGE-----
|
||||
MIISfwYJKoZIhvcNAQcCoIIScDCCEmwCAQExDTALBglghkgBZQMEAgEwCwYJKoZI
|
||||
hvcNAQcBoIIP8zCCB3QwggVcoAMCAQICBBXXLOIwDQYJKoZIhvcNAQELBQAwgbYx
|
||||
CzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVu
|
||||
MRAwDgYDVQQKDAdTaWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwU
|
||||
U2llbWVucyBUcnVzdCBDZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBD
|
||||
QSBNZWRpdW0gU3RyZW5ndGggQXV0aGVudGljYXRpb24gMjAxNjAeFw0xNzAyMDMw
|
||||
NjU4MzNaFw0yMDAyMDMwNjU4MzNaMFsxETAPBgNVBAUTCFowMDBOV0RIMQ4wDAYD
|
||||
VQQqDAVSb2dlcjEOMAwGA1UEBAwFTWVpZXIxEDAOBgNVBAoMB1NpZW1lbnMxFDAS
|
||||
BgNVBAMMC01laWVyIFJvZ2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEAuBNea/68ZCnHYQjpm/k3ZBG0wBpEKSwG6lk9CEQlSxsqVLQHAoAKBIlJm1in
|
||||
YVLcK/Sq1yhYJ/qWcY/M53DhK2rpPuhtrWJUdOUy8EBWO20F4bd4Fw9pO7jt8bme
|
||||
u33TSrK772vKjuppzB6SeG13Cs08H+BIeD106G27h7ufsO00pvsxoSDL+uc4slnr
|
||||
pBL+2TAL7nSFnB9QHWmRIK27SPqJE+lESdb0pse11x1wjvqKy2Q7EjL9fpqJdHzX
|
||||
NLKHXd2r024TOORTa05DFTNR+kQEKKV96XfpYdtSBomXNQ44cisiPBJjFtYvfnFE
|
||||
wgrHa8fogn/b0C+A+HAoICN12wIDAQABo4IC4jCCAt4wHQYDVR0OBBYEFCF+gkUp
|
||||
XQ6xGc0kRWXuDFxzA14zMEMGA1UdEQQ8MDqgIwYKKwYBBAGCNxQCA6AVDBNyLm1l
|
||||
aWVyQHNpZW1lbnMuY29tgRNyLm1laWVyQHNpZW1lbnMuY29tMA4GA1UdDwEB/wQE
|
||||
AwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwgcoGA1UdHwSBwjCB
|
||||
vzCBvKCBuaCBtoYmaHR0cDovL2NoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBNi5j
|
||||
cmyGQWxkYXA6Ly9jbC5zaWVtZW5zLm5ldC9DTj1aWlpaWlpBNixMPVBLST9jZXJ0
|
||||
aWZpY2F0ZVJldm9jYXRpb25MaXN0hklsZGFwOi8vY2wuc2llbWVucy5jb20vQ049
|
||||
WlpaWlpaQTYsbz1UcnVzdGNlbnRlcj9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0
|
||||
MEUGA1UdIAQ+MDwwOgYNKwYBBAGhaQcCAgMBAzApMCcGCCsGAQUFBwIBFhtodHRw
|
||||
Oi8vd3d3LnNpZW1lbnMuY29tL3BraS8wDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAW
|
||||
gBT4FV1HDGx3e3LEAheRaKK292oJRDCCAQQGCCsGAQUFBwEBBIH3MIH0MDIGCCsG
|
||||
AQUFBzAChiZodHRwOi8vYWguc2llbWVucy5jb20vcGtpP1paWlpaWkE2LmNydDBB
|
||||
BggrBgEFBQcwAoY1bGRhcDovL2FsLnNpZW1lbnMubmV0L0NOPVpaWlpaWkE2LEw9
|
||||
UEtJP2NBQ2VydGlmaWNhdGUwSQYIKwYBBQUHMAKGPWxkYXA6Ly9hbC5zaWVtZW5z
|
||||
LmNvbS9DTj1aWlpaWlpBNixvPVRydXN0Y2VudGVyP2NBQ2VydGlmaWNhdGUwMAYI
|
||||
KwYBBQUHMAGGJGh0dHA6Ly9vY3NwLnBraS1zZXJ2aWNlcy5zaWVtZW5zLmNvbTAN
|
||||
BgkqhkiG9w0BAQsFAAOCAgEAXPVcX6vaEcszJqg5IemF9aFTlwTrX5ITNIpzcqG+
|
||||
kD5haOf2mZYLjl+MKtLC1XfmIsGCUZNb8bjP6QHQEI+2d6x/ZOqPq7Kd7PwVu6x6
|
||||
xZrkDjUyhUbUntT5+RBy++l3Wf6Cq6Kx+K8ambHBP/bu90/p2U8KfFAG3Kr2gI2q
|
||||
fZrnNMOxmJfZ3/sXxssgLkhbZ7hRa+MpLfQ6uFsSiat3vlawBBvTyHnoZ/7oRc8y
|
||||
qi6QzWcd76CPpMElYWibl+hJzKbBZUWvc71AzHR6i1QeZ6wubYz7vr+FF5Y7tnxB
|
||||
Vz6omPC9XAg0F+Dla6Zlz3Awj5imCzVXa+9SjtnsidmJdLcKzTAKyDewewoxYOOJ
|
||||
j3cJU7VSjJPl+2fVmDBaQwcNcUcu/TPAKApkegqO7tRF9IPhjhW8QkRnkqMetO3D
|
||||
OXmAFVIsEI0Hvb2cdb7B6jSpjGUuhaFm9TCKhQtCk2p8JCDTuaENLm1x34rrJKbT
|
||||
2vzyYN0CZtSkUdgD4yQxK9VWXGEzexRisWb4AnZjD2NAquLPpXmw8N0UwFD7MSpC
|
||||
dpaX7FktdvZmMXsnGiAdtLSbBgLVWOD1gmJFDjrhNbI8NOaOaNk4jrfGqNh5lhGU
|
||||
4DnBT2U6Cie1anLmFH/oZooAEXR2o3Nu+1mNDJChnJp0ovs08aa3zZvBdcloOvfU
|
||||
qdowggh3MIIGX6ADAgECAgQtyi/nMA0GCSqGSIb3DQEBCwUAMIGZMQswCQYDVQQG
|
||||
EwJERTEPMA0GA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQMA4GA1UE
|
||||
CgwHU2llbWVuczERMA8GA1UEBRMIWlpaWlpaQTExHTAbBgNVBAsMFFNpZW1lbnMg
|
||||
VHJ1c3QgQ2VudGVyMSIwIAYDVQQDDBlTaWVtZW5zIFJvb3QgQ0EgVjMuMCAyMDE2
|
||||
MB4XDTE2MDcyMDEzNDYxMFoXDTIyMDcyMDEzNDYxMFowgbYxCzAJBgNVBAYTAkRF
|
||||
MQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVuMRAwDgYDVQQKDAdT
|
||||
aWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwUU2llbWVucyBUcnVz
|
||||
dCBDZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBDQSBNZWRpdW0gU3Ry
|
||||
ZW5ndGggQXV0aGVudGljYXRpb24gMjAxNjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
|
||||
ADCCAgoCggIBAL9UfK+JAZEqVMVvECdYF9IK4KSw34AqyNl3rYP5x03dtmKaNu+2
|
||||
0fQqNESA1NGzw3s6LmrKLh1cR991nB2cvKOXu7AvEGpSuxzIcOROd4NpvRx+Ej1p
|
||||
JIPeqf+ScmVK7lMSO8QL/QzjHOpGV3is9sG+ZIxOW9U1ESooy4Hal6ZNs4DNItsz
|
||||
piCKqm6G3et4r2WqCy2RRuSqvnmMza7Y8BZsLy0ZVo5teObQ37E/FxqSrbDI8nxn
|
||||
B7nVUve5ZjrqoIGSkEOtyo11003dVO1vmWB9A0WQGDqE/q3w178hGhKfxzRaqzyi
|
||||
SoADUYS2sD/CglGTUxVq6u0pGLLsCFjItcCWqW+T9fPYfJ2CEd5b3hvqdCn+pXjZ
|
||||
/gdX1XAcdUF5lRnGWifaYpT9n4s4adzX8q6oHSJxTppuAwLRKH6eXALbGQ1I9lGQ
|
||||
DSOipD/09xkEsPw6HOepmf2U3YxZK1VU2sHqugFJboeLcHMzp6E1n2ctlNG1GKE9
|
||||
FDHmdyFzDi0Nnxtf/GgVjnHF68hByEE1MYdJ4nJLuxoT9hyjYdRW9MpeNNxxZnmz
|
||||
W3zh7QxIqP0ZfIz6XVhzrI9uZiqwwojDiM5tEOUkQ7XyW6grNXe75yt6mTj89LlB
|
||||
H5fOW2RNmCy/jzBXDjgyskgK7kuCvUYTuRv8ITXbBY5axFA+CpxZqokpAgMBAAGj
|
||||
ggKmMIICojCCAQUGCCsGAQUFBwEBBIH4MIH1MEEGCCsGAQUFBzAChjVsZGFwOi8v
|
||||
YWwuc2llbWVucy5uZXQvQ049WlpaWlpaQTEsTD1QS0k/Y0FDZXJ0aWZpY2F0ZTAy
|
||||
BggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBMS5j
|
||||
cnQwSgYIKwYBBQUHMAKGPmxkYXA6Ly9hbC5zaWVtZW5zLmNvbS91aWQ9WlpaWlpa
|
||||
QTEsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUFBzABhiRodHRw
|
||||
Oi8vb2NzcC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wHwYDVR0jBBgwFoAUcG2g
|
||||
UOyp0CxnnRkV/v0EczXD4tQwEgYDVR0TAQH/BAgwBgEB/wIBADBABgNVHSAEOTA3
|
||||
MDUGCCsGAQQBoWkHMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuc2llbWVucy5j
|
||||
b20vcGtpLzCBxwYDVR0fBIG/MIG8MIG5oIG2oIGzhj9sZGFwOi8vY2wuc2llbWVu
|
||||
cy5uZXQvQ049WlpaWlpaQTEsTD1QS0k/YXV0aG9yaXR5UmV2b2NhdGlvbkxpc3SG
|
||||
Jmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTEuY3JshkhsZGFwOi8v
|
||||
Y2wuc2llbWVucy5jb20vdWlkPVpaWlpaWkExLG89VHJ1c3RjZW50ZXI/YXV0aG9y
|
||||
aXR5UmV2b2NhdGlvbkxpc3QwJwYDVR0lBCAwHgYIKwYBBQUHAwIGCCsGAQUFBwME
|
||||
BggrBgEFBQcDCTAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPgVXUcMbHd7csQC
|
||||
F5Foorb3aglEMA0GCSqGSIb3DQEBCwUAA4ICAQBw+sqMp3SS7DVKcILEmXbdRAg3
|
||||
lLO1r457KY+YgCT9uX4VG5EdRKcGfWXK6VHGCi4Dos5eXFV34Mq/p8nu1sqMuoGP
|
||||
YjHn604eWDprhGy6GrTYdxzcE/GGHkpkuE3Ir/45UcmZlOU41SJ9SNjuIVrSHMOf
|
||||
ccSY42BCspR/Q1Z/ykmIqQecdT3/Kkx02GzzSN2+HlW6cEO4GBW5RMqsvd2n0h2d
|
||||
fe2zcqOgkLtx7u2JCR/U77zfyxG3qXtcymoz0wgSHcsKIl+GUjITLkHfS9Op8V7C
|
||||
Gr/dX437sIg5pVHmEAWadjkIzqdHux+EF94Z6kaHywohc1xG0KvPYPX7iSNjkvhz
|
||||
4NY53DHmxl4YEMLffZnaS/dqyhe1GTpcpyN8WiR4KuPfxrkVDOsuzWFtMSvNdlOV
|
||||
gdI0MXcLMP+EOeANZWX6lGgJ3vWyemo58nzgshKd24MY3w3i6masUkxJH2KvI7UH
|
||||
/1Db3SC8oOUjInvSRej6M3ZhYWgugm6gbpUgFoDw/o9Cg6Qm71hY0JtcaPC13rzm
|
||||
N8a2Br0+Fa5e2VhwLmAxyfe1JKzqPwuHT0S5u05SQghL5VdzqfA8FCL/j4XC9yI6
|
||||
csZTAQi73xFQYVjZt3+aoSz84lOlTmVo/jgvGMY/JzH9I4mETGgAJRNj34Z/0meh
|
||||
M+pKWCojNH/dgyJSwDGCAlIwggJOAgEBMIG/MIG2MQswCQYDVQQGEwJERTEPMA0G
|
||||
A1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQMA4GA1UECgwHU2llbWVu
|
||||
czERMA8GA1UEBRMIWlpaWlpaQTYxHTAbBgNVBAsMFFNpZW1lbnMgVHJ1c3QgQ2Vu
|
||||
dGVyMT8wPQYDVQQDDDZTaWVtZW5zIElzc3VpbmcgQ0EgTWVkaXVtIFN0cmVuZ3Ro
|
||||
IEF1dGhlbnRpY2F0aW9uIDIwMTYCBBXXLOIwCwYJYIZIAWUDBAIBoGkwHAYJKoZI
|
||||
hvcNAQkFMQ8XDTE5MTEyMDE0NTYyMFowLwYJKoZIhvcNAQkEMSIEIJDnZUpcVLzC
|
||||
OdtpkH8gtxwLPIDE0NmAmFC9uM8q2z+OMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0B
|
||||
BwEwCwYJKoZIhvcNAQEBBIIBAH/Pqv2xp3a0jSPkwU1K3eGA/1lfoNJMUny4d/PS
|
||||
LVWlkgrmedXdLmuBzAGEaaZOJS0lEpNd01pR/reHs7xxZ+RZ0olTs2ufM0CijQSx
|
||||
OL9HDl2O3OoD77NWx4tl3Wy1yJCeV3XH/cEI7AkKHCmKY9QMoMYWh16ORBtr+YcS
|
||||
YK+gONOjpjgcgTJgZ3HSFgQ50xiD4WT1kFBHsuYsLqaOSbTfTN6Ayyg4edjrPQqa
|
||||
VcVf1OQcIrfWA3yMQrnEZfOYfN/D4EPjTfxBV+VCi/F2bdZmMbJ7jNk1FbewSwWO
|
||||
SDH1i0K32NyFbnh0BSos7njq7ELqKlYBsoB/sZfaH2vKy5U=
|
||||
-----END SIGNED MESSAGE-----
|
||||
SIGNATURE
|
||||
end
|
||||
|
||||
def signed_tag_base_data
|
||||
<<~SIGNEDDATA
|
||||
object 189a6c924013fc3fe40d6f1ec1dc20214183bc97
|
||||
type commit
|
||||
tag v1.1.1
|
||||
tagger Roger Meier <r.meier@siemens.com> 1574261780 +0100
|
||||
|
||||
x509 signed tag
|
||||
SIGNEDDATA
|
||||
end
|
||||
|
||||
def certificate_crl
|
||||
'http://ch.siemens.com/pki?ZZZZZZA2.crl'
|
||||
end
|
||||
|
||||
def tag_certificate_crl
|
||||
'http://ch.siemens.com/pki?ZZZZZZA6.crl'
|
||||
end
|
||||
|
||||
def certificate_serial
|
||||
1810356222
|
||||
end
|
||||
|
||||
def tag_certificate_serial
|
||||
3664232660
|
||||
end
|
||||
|
||||
def certificate_subject_key_identifier
|
||||
'EC:00:B5:28:02:5C:D3:A5:A1:AB:C2:A1:34:81:84:AA:BF:9B:CF:F8'
|
||||
end
|
||||
|
||||
def tag_certificate_subject_key_identifier
|
||||
'21:7E:82:45:29:5D:0E:B1:19:CD:24:45:65:EE:0C:5C:73:03:5E:33'
|
||||
end
|
||||
|
||||
def issuer_subject_key_identifier
|
||||
'BD:BD:2A:43:22:3D:48:4A:57:7E:98:31:17:A9:70:9D:EE:9F:A8:99'
|
||||
end
|
||||
|
||||
def tag_issuer_subject_key_identifier
|
||||
'F8:15:5D:47:0C:6C:77:7B:72:C4:02:17:91:68:A2:B6:F7:6A:09:44'
|
||||
end
|
||||
|
||||
def certificate_email
|
||||
'r.meier@siemens.com'
|
||||
end
|
||||
|
@ -197,6 +330,10 @@ module X509Helpers
|
|||
'CN=Siemens Issuing CA EE Auth 2016,OU=Siemens Trust Center,serialNumber=ZZZZZZA2,O=Siemens,L=Muenchen,ST=Bayern,C=DE'
|
||||
end
|
||||
|
||||
def tag_certificate_issuer
|
||||
'CN=Siemens Issuing CA Medium Strength Authentication 2016,OU=Siemens Trust Center,serialNumber=ZZZZZZA6,O=Siemens,L=Muenchen,ST=Bayern,C=DE'
|
||||
end
|
||||
|
||||
def certificate_subject
|
||||
'CN=Meier Roger,O=Siemens,SN=Meier,GN=Roger,serialNumber=Z000NWDH'
|
||||
end
|
||||
|
|
|
@ -29,20 +29,5 @@ describe 'projects/services/_form' do
|
|||
expect(rendered).to have_content('Event will be triggered when a commit is created/updated')
|
||||
expect(rendered).to have_content('Event will be triggered when a merge request is created/updated/merged')
|
||||
end
|
||||
|
||||
context 'when service is Jira' do
|
||||
let(:project) { create(:jira_project) }
|
||||
|
||||
before do
|
||||
assign(:service, project.jira_service)
|
||||
end
|
||||
|
||||
it 'display merge_request_events and commit_events descriptions' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_content('Jira comments will be created when an issue gets referenced in a commit.')
|
||||
expect(rendered).to have_content('Jira comments will be created when an issue gets referenced in a merge request.')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue