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,27 +1,46 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||||
import ActiveToggle from './components/active_toggle.vue';
|
import IntegrationForm from './components/integration_form.vue';
|
||||||
|
|
||||||
export default el => {
|
export default el => {
|
||||||
if (!el) {
|
if (!el) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { showActive: showActiveStr, activated: activatedStr } = el.dataset;
|
function parseBooleanInData(data) {
|
||||||
const showActive = parseBoolean(showActiveStr);
|
const result = {};
|
||||||
const activated = parseBoolean(activatedStr);
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
|
result[key] = parseBoolean(value);
|
||||||
if (!showActive) {
|
});
|
||||||
return null;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { type, commentDetail, ...booleanAttributes } = el.dataset;
|
||||||
|
const {
|
||||||
|
showActive,
|
||||||
|
activated,
|
||||||
|
commitEvents,
|
||||||
|
mergeRequestEvents,
|
||||||
|
enableComments,
|
||||||
|
} = parseBooleanInData(booleanAttributes);
|
||||||
|
|
||||||
return new Vue({
|
return new Vue({
|
||||||
el,
|
el,
|
||||||
render(createElement) {
|
render(createElement) {
|
||||||
return createElement(ActiveToggle, {
|
return createElement(IntegrationForm, {
|
||||||
props: {
|
props: {
|
||||||
|
activeToggleProps: {
|
||||||
initialActivated: activated,
|
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
|
# NOTE: Use @application_setting in this controller when you need to access
|
||||||
# application_settings after it has been modified. This is because the
|
# 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.
|
# cache might be stale immediately after an update.
|
||||||
# https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30233
|
# https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30233
|
||||||
before_action :set_application_setting, except: :integrations
|
before_action :set_application_setting, except: :integrations
|
||||||
|
|
|
@ -16,4 +16,8 @@ module X509Helper
|
||||||
rescue
|
rescue
|
||||||
{}
|
{}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def x509_signature?(sig)
|
||||||
|
sig.is_a?(X509CommitSignature) || sig.is_a?(Gitlab::X509::Signature)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -421,7 +421,7 @@ class ApplicationSetting < ApplicationRecord
|
||||||
# can cause a significant amount of load on Redis, let's cache it in
|
# can cause a significant amount of load on Redis, let's cache it in
|
||||||
# memory.
|
# memory.
|
||||||
def self.cache_backend
|
def self.cache_backend
|
||||||
Gitlab::ThreadMemoryCache.cache_backend
|
Gitlab::ProcessMemoryCache.cache_backend
|
||||||
end
|
end
|
||||||
|
|
||||||
def recaptcha_or_login_protection_enabled
|
def recaptcha_or_login_protection_enabled
|
||||||
|
|
|
@ -141,7 +141,7 @@ class MergeRequestDiff < ApplicationRecord
|
||||||
after_create :save_git_content, unless: :importing?
|
after_create :save_git_content, unless: :importing?
|
||||||
after_create_commit :set_as_latest_diff, 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)
|
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)
|
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
|
end
|
||||||
|
|
||||||
def update_external_diff_store
|
def update_external_diff_store
|
||||||
update_column(:external_diff_store, external_diff.object_store) if
|
return unless has_attribute?(:external_diff_store)
|
||||||
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
|
end
|
||||||
|
|
||||||
def saved_change_to_external_diff?
|
def saved_change_to_external_diff?
|
||||||
|
|
|
@ -177,6 +177,7 @@ class JiraService < IssueTrackerService
|
||||||
noteable_id = noteable.respond_to?(:iid) ? noteable.iid : noteable.id
|
noteable_id = noteable.respond_to?(:iid) ? noteable.iid : noteable.id
|
||||||
noteable_type = noteable_name(noteable)
|
noteable_type = noteable_name(noteable)
|
||||||
entity_url = build_entity_url(noteable_type, noteable_id)
|
entity_url = build_entity_url(noteable_type, noteable_id)
|
||||||
|
entity_meta = build_entity_meta(noteable)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
user: {
|
user: {
|
||||||
|
@ -185,12 +186,15 @@ class JiraService < IssueTrackerService
|
||||||
},
|
},
|
||||||
project: {
|
project: {
|
||||||
name: project.full_path,
|
name: project.full_path,
|
||||||
url: resource_url(namespace_project_path(project.namespace, project)) # rubocop:disable Cop/ProjectPathHelper
|
url: resource_url(project_path(project))
|
||||||
},
|
},
|
||||||
entity: {
|
entity: {
|
||||||
|
id: entity_meta[:id],
|
||||||
name: noteable_type.humanize.downcase,
|
name: noteable_type.humanize.downcase,
|
||||||
url: entity_url,
|
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
|
end
|
||||||
|
|
||||||
def add_comment(data, issue)
|
def add_comment(data, issue)
|
||||||
user_name = data[:user][:name]
|
|
||||||
user_url = data[:user][:url]
|
|
||||||
entity_name = data[:entity][:name]
|
entity_name = data[:entity][:name]
|
||||||
entity_url = data[:entity][:url]
|
entity_url = data[:entity][:url]
|
||||||
entity_title = data[:entity][:title]
|
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_title = "#{entity_name.capitalize} - #{entity_title}"
|
||||||
link_props = build_remote_link_props(url: entity_url, title: link_title)
|
link_props = build_remote_link_props(url: entity_url, title: link_title)
|
||||||
|
|
||||||
|
@ -280,6 +281,37 @@ class JiraService < IssueTrackerService
|
||||||
end
|
end
|
||||||
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)
|
def has_resolution?(issue)
|
||||||
issue.respond_to?(:resolution) && issue.resolution.present?
|
issue.respond_to?(:resolution) && issue.resolution.present?
|
||||||
end
|
end
|
||||||
|
@ -353,6 +385,23 @@ class JiraService < IssueTrackerService
|
||||||
)
|
)
|
||||||
end
|
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)
|
def noteable_name(noteable)
|
||||||
name = noteable.model_name.singular
|
name = noteable.model_name.singular
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ class SnippetRepository < ApplicationRecord
|
||||||
EMPTY_FILE_PATTERN = /^#{DEFAULT_EMPTY_FILE_NAME}(\d+)\.txt$/.freeze
|
EMPTY_FILE_PATTERN = /^#{DEFAULT_EMPTY_FILE_NAME}(\d+)\.txt$/.freeze
|
||||||
|
|
||||||
CommitError = Class.new(StandardError)
|
CommitError = Class.new(StandardError)
|
||||||
|
InvalidPathError = Class.new(CommitError)
|
||||||
|
|
||||||
belongs_to :snippet, inverse_of: :snippet_repository
|
belongs_to :snippet, inverse_of: :snippet_repository
|
||||||
|
|
||||||
|
@ -40,8 +41,9 @@ class SnippetRepository < ApplicationRecord
|
||||||
rescue Gitlab::Git::Index::IndexError,
|
rescue Gitlab::Git::Index::IndexError,
|
||||||
Gitlab::Git::CommitError,
|
Gitlab::Git::CommitError,
|
||||||
Gitlab::Git::PreReceiveError,
|
Gitlab::Git::PreReceiveError,
|
||||||
Gitlab::Git::CommandError => e
|
Gitlab::Git::CommandError => error
|
||||||
raise CommitError, e.message
|
|
||||||
|
raise commit_error_exception(error)
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform_file_entries(files)
|
def transform_file_entries(files)
|
||||||
|
@ -85,4 +87,16 @@ class SnippetRepository < ApplicationRecord
|
||||||
def build_empty_file_name(index)
|
def build_empty_file_name(index)
|
||||||
"#{DEFAULT_EMPTY_FILE_NAME}#{index}.txt"
|
"#{DEFAULT_EMPTY_FILE_NAME}#{index}.txt"
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -41,4 +41,8 @@ class X509CommitSignature < ApplicationRecord
|
||||||
|
|
||||||
Gitlab::X509::Commit.new(commit)
|
Gitlab::X509::Commit.new(commit)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user
|
||||||
|
commit.committer
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
- if signature
|
- 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 }
|
= render partial: "#{uri}#{signature.verification_status}_signature_badge", locals: { signature: signature }
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
- content = capture do
|
- content = capture do
|
||||||
- if show_user
|
- if show_user
|
||||||
.clearfix
|
.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 }
|
= 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 }
|
= 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
|
- else
|
||||||
= _('GPG Key ID:')
|
= _('GPG Key ID:')
|
||||||
%span.monospace= signature.gpg_key_primary_keyid
|
%span.monospace= signature.gpg_key_primary_keyid
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- user = signature.commit.committer
|
|
||||||
- user_email = signature.x509_certificate.email
|
- user_email = signature.x509_certificate.email
|
||||||
|
- user = signature.user
|
||||||
|
|
||||||
- if user
|
- if user
|
||||||
= link_to user_path(user), class: 'gpg-popover-user-link' do
|
= link_to user_path(user), class: 'gpg-popover-user-link' do
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
= markdown_field(release, :description)
|
= markdown_field(release, :description)
|
||||||
|
|
||||||
.row-fixed-content.controls.flex-row
|
.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]
|
= render 'projects/buttons/download', project: @project, ref: tag.name, pipeline: @tags_pipelines[tag.name]
|
||||||
|
|
||||||
- if can?(current_user, :admin_tag, @project)
|
- if can?(current_user, :admin_tag, @project)
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
= s_("TagsPage|Can't find HEAD commit for this tag")
|
= s_("TagsPage|Can't find HEAD commit for this tag")
|
||||||
|
|
||||||
.nav-controls
|
.nav-controls
|
||||||
|
- if @tag.has_signature?
|
||||||
|
= render partial: 'projects/commit/signature', object: @tag.signature
|
||||||
- if can?(current_user, :admin_tag, @project)
|
- 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
|
= 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")
|
= icon("pencil")
|
||||||
|
|
|
@ -8,9 +8,10 @@
|
||||||
= markdown @service.help
|
= markdown @service.help
|
||||||
|
|
||||||
.service-settings
|
.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
|
.form-group.row
|
||||||
%label.col-form-label.col-sm-2= _('Trigger')
|
%label.col-form-label.col-sm-2= _('Trigger')
|
||||||
|
|
||||||
|
@ -31,22 +32,6 @@
|
||||||
%p.text-muted
|
%p.text-muted
|
||||||
= @service.class.event_description(event)
|
= @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|
|
- @service.global_fields.each do |field|
|
||||||
- type = field[:type]
|
- 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_blocker_middleware'
|
||||||
require 'gitlab/testing/request_inspector_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
|
Rails.application.configure do
|
||||||
# Make sure the middleware is inserted first in middleware chain
|
# 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::RequestBlockerMiddleware)
|
||||||
config.middleware.insert_before(ActionDispatch::Static, Gitlab::Testing::RequestInspectorMiddleware)
|
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
|
# 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:
|
Example response:
|
||||||
|
|
||||||
```csv
|
```csv
|
||||||
Scanner Type,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE
|
Group Name,Project Name,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
|
Gitlab.org,Defend,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
|
Gitlab.org,Defend,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
|
Gitlab.org,Defend,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
|
Gitlab.org,Defend,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
|
Gitlab.org,Defend,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
|
Gitlab.org,Defend,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
|
Gitlab.org,Defend,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
|
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
|
||||||
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,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
|
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
|
||||||
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,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
|
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
|
||||||
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,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
|
the `Review-response` SLO, they are free to remind the reviewer through Slack or assign
|
||||||
another reviewer.
|
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
|
## 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.
|
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
|
## 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
|
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
|
signature includes the repository name. To move or rename a repository with a
|
||||||
Container Registry, you will have to delete all existing images.
|
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
|
## Troubleshooting the GitLab Container Registry
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
type: concepts, howto
|
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
|
[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).
|
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.
|
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 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
|
- 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:** 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
|
## Obtaining an X.509 key pair
|
||||||
|
|
||||||
If your organization has Public Key Infrastructure (PKI), that PKI will provide
|
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
|
```sh
|
||||||
git log --show-signature
|
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,12 +134,8 @@ class Feature
|
||||||
end
|
end
|
||||||
|
|
||||||
def l1_cache_backend
|
def l1_cache_backend
|
||||||
if Gitlab::Utils.to_boolean(ENV['USE_THREAD_MEMORY_CACHE'])
|
|
||||||
Gitlab::ThreadMemoryCache.cache_backend
|
|
||||||
else
|
|
||||||
Gitlab::ProcessMemoryCache.cache_backend
|
Gitlab::ProcessMemoryCache.cache_backend
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def l2_cache_backend
|
def l2_cache_backend
|
||||||
Rails.cache
|
Rails.cache
|
||||||
|
|
|
@ -117,7 +117,7 @@ module Gitlab
|
||||||
# the migration can succeed, to achieve that, we'll identify in migration retries
|
# the migration can succeed, to achieve that, we'll identify in migration retries
|
||||||
# that the path is invalid
|
# that the path is invalid
|
||||||
def set_file_path_error(error)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,6 +66,27 @@ module Gitlab
|
||||||
@raw_tag.tagger
|
@raw_tag.tagger
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def message_from_gitaly_tag
|
def message_from_gitaly_tag
|
||||||
|
|
|
@ -2,13 +2,25 @@
|
||||||
|
|
||||||
module Gitlab
|
module Gitlab
|
||||||
module Json
|
module Json
|
||||||
|
INVALID_LEGACY_TYPES = [String, TrueClass, FalseClass].freeze
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def parse(*args)
|
def parse(string, *args, **named_args)
|
||||||
adapter.parse(*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
|
end
|
||||||
|
|
||||||
def parse!(*args)
|
def parse!(string, *args, **named_args)
|
||||||
adapter.parse!(*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
|
end
|
||||||
|
|
||||||
def dump(*args)
|
def dump(*args)
|
||||||
|
@ -28,6 +40,20 @@ module Gitlab
|
||||||
def adapter
|
def adapter
|
||||||
::JSON
|
::JSON
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,7 +44,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.l1_cache_backend
|
def self.l1_cache_backend
|
||||||
Gitlab::ThreadMemoryCache.cache_backend
|
Gitlab::ProcessMemoryCache.cache_backend
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.l2_cache_backend
|
def self.l2_cache_backend
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
module Gitlab
|
module Gitlab
|
||||||
module Testing
|
module Testing
|
||||||
class ClearThreadMemoryCacheMiddleware
|
class ClearProcessMemoryCacheMiddleware
|
||||||
def initialize(app)
|
def initialize(app)
|
||||||
@app = app
|
@app = app
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
Gitlab::ThreadMemoryCache.cache_backend.clear
|
Gitlab::ProcessMemoryCache.cache_backend.clear
|
||||||
|
|
||||||
@app.call(env)
|
@app.call(env)
|
||||||
end
|
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?
|
X509Certificate.safe_create!(certificate_attributes) unless verified_signature.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user
|
||||||
|
User.find_by_any_email(@email)
|
||||||
|
end
|
||||||
|
|
||||||
def verified_signature
|
def verified_signature
|
||||||
strong_memoize(:verified_signature) { verified_signature? }
|
strong_memoize(:verified_signature) { verified_signature? }
|
||||||
end
|
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)"
|
msgid "Business metrics (Custom)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Buy EE"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Buy GitLab Enterprise Edition"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Buy more Pipeline minutes"
|
msgid "Buy more Pipeline minutes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -5593,18 +5587,9 @@ msgstr ""
|
||||||
msgid "Connection timed out"
|
msgid "Connection timed out"
|
||||||
msgstr ""
|
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"
|
msgid "Contact sales to upgrade"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Contact your Administrator to upgrade your license."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Container Registry"
|
msgid "Container Registry"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -8572,9 +8557,6 @@ msgstr ""
|
||||||
msgid "Estimated"
|
msgid "Estimated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Event Actions"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "EventFilterBy|Filter by all"
|
msgid "EventFilterBy|Filter by all"
|
||||||
msgstr ""
|
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."
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Geo|All"
|
msgid "Geo|All %{replicable_name}"
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Geo|All %{replicable_type}"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Geo|All projects"
|
msgid "Geo|All projects"
|
||||||
|
@ -11306,9 +11285,6 @@ msgstr ""
|
||||||
msgid "Improve Merge Requests and customer support with GitLab Enterprise Edition."
|
msgid "Improve Merge Requests and customer support with GitLab Enterprise Edition."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
|
msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -11411,6 +11387,12 @@ msgstr ""
|
||||||
msgid "Insights"
|
msgid "Insights"
|
||||||
msgstr ""
|
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"
|
msgid "Install"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -11461,6 +11443,30 @@ msgstr ""
|
||||||
msgid "Integrations allow you to integrate GitLab with other applications"
|
msgid "Integrations allow you to integrate GitLab with other applications"
|
||||||
msgstr ""
|
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."
|
msgid "Interested parties can even contribute by pushing commits if they want to."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -11764,6 +11770,12 @@ msgstr ""
|
||||||
msgid "Jira project: %{importProject}"
|
msgid "Jira project: %{importProject}"
|
||||||
msgstr ""
|
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."
|
msgid "JiraService|Events for %{noteable_model_name} are disabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -12189,6 +12201,9 @@ msgstr ""
|
||||||
msgid "Learn more about Web Terminal"
|
msgid "Learn more about Web Terminal"
|
||||||
msgstr ""
|
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}."
|
msgid "Learn more about adding certificates to your project by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -12210,9 +12225,6 @@ msgstr ""
|
||||||
msgid "Learn more about the dependency list"
|
msgid "Learn more about the dependency list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Learn more about x509 signed commits"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Learn more in the"
|
msgid "Learn more in the"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -16671,24 +16683,51 @@ msgstr ""
|
||||||
msgid "Promoted issue to an epic."
|
msgid "Promoted issue to an epic."
|
||||||
msgstr ""
|
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"
|
msgid "Promotions|Don't show me this again"
|
||||||
msgstr ""
|
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."
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Promotions|Improve issues management with Issue weight and GitLab Enterprise Edition."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Promotions|Learn more"
|
msgid "Promotions|Learn more"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Promotions|See the other features in the %{subscription_link_start}bronze plan%{subscription_link_end}"
|
msgid "Promotions|See the other features in the %{subscription_link_start}bronze plan%{subscription_link_end}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Promotions|Start GitLab Ultimate trial"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Promotions|This feature is locked."
|
msgid "Promotions|This feature is locked."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Promotions|Upgrade plan"
|
msgid "Promotions|Upgrade plan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Promotions|Upgrade your plan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Promotions|Weight"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Promotions|Weighting your issue"
|
msgid "Promotions|Weighting your issue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -19774,9 +19813,6 @@ msgstr ""
|
||||||
msgid "Stars"
|
msgid "Stars"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Start GitLab Ultimate trial"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Start Web Terminal"
|
msgid "Start Web Terminal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -22643,9 +22679,6 @@ msgstr ""
|
||||||
msgid "Upgrade plan to unlock Canary Deployments feature"
|
msgid "Upgrade plan to unlock Canary Deployments feature"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Upgrade your plan"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Upgrade your plan to activate Advanced Global Search."
|
msgid "Upgrade your plan to activate Advanced Global Search."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ describe('ActiveToggle', () => {
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
initialActivated: true,
|
initialActivated: true,
|
||||||
disabled: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createComponent = props => {
|
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
|
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
|
end
|
||||||
|
|
|
@ -146,14 +146,6 @@ describe Feature do
|
||||||
expect(described_class.enabled?(:enabled_feature_flag)).to be_truthy
|
expect(described_class.enabled?(:enabled_feature_flag)).to be_truthy
|
||||||
end
|
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.l1_cache_backend).to eq(Gitlab::ProcessMemoryCache.cache_backend) }
|
||||||
it { expect(described_class.l2_cache_backend).to eq(Rails.cache) }
|
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.target).to eq("f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8") }
|
||||||
it { expect(tag.dereferenced_target.sha).to eq("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") }
|
it { expect(tag.dereferenced_target.sha).to eq("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") }
|
||||||
it { expect(tag.message).to eq("Release") }
|
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
|
end
|
||||||
|
|
||||||
describe 'last tag' do
|
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.target).to eq("2ac1f24e253e08135507d0830508febaaccf02ee") }
|
||||||
it { expect(tag.dereferenced_target.sha).to eq("fa1b1e6c004a68b7d8763b86455da9e6b23e36d6") }
|
it { expect(tag.dereferenced_target.sha).to eq("fa1b1e6c004a68b7d8763b86455da9e6b23e36d6") }
|
||||||
it { expect(tag.message).to eq("Version 1.2.1") }
|
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
|
end
|
||||||
|
|
||||||
it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
|
it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
|
||||||
|
|
|
@ -3,7 +3,12 @@
|
||||||
require "spec_helper"
|
require "spec_helper"
|
||||||
|
|
||||||
RSpec.describe Gitlab::Json do
|
RSpec.describe Gitlab::Json do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(json_wrapper_legacy_mode: true)
|
||||||
|
end
|
||||||
|
|
||||||
describe ".parse" do
|
describe ".parse" do
|
||||||
|
context "legacy_mode is disabled by default" do
|
||||||
it "parses an object" do
|
it "parses an object" do
|
||||||
expect(subject.parse('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
expect(subject.parse('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
||||||
end
|
end
|
||||||
|
@ -12,6 +17,8 @@ RSpec.describe Gitlab::Json do
|
||||||
expect(subject.parse('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
expect(subject.parse('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# These tests will change expectations when the gem is upgraded
|
||||||
|
|
||||||
it "raises an error on a string" do
|
it "raises an error on a string" do
|
||||||
expect { subject.parse('"foo"') }.to raise_error(JSON::ParserError)
|
expect { subject.parse('"foo"') }.to raise_error(JSON::ParserError)
|
||||||
end
|
end
|
||||||
|
@ -25,7 +32,31 @@ RSpec.describe Gitlab::Json do
|
||||||
end
|
end
|
||||||
end
|
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 "parses an array" 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"', legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
describe ".parse!" do
|
||||||
|
context "legacy_mode is disabled by default" do
|
||||||
it "parses an object" do
|
it "parses an object" do
|
||||||
expect(subject.parse!('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
expect(subject.parse!('{ "foo": "bar" }')).to eq({ "foo" => "bar" })
|
||||||
end
|
end
|
||||||
|
@ -34,6 +65,8 @@ RSpec.describe Gitlab::Json do
|
||||||
expect(subject.parse!('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
expect(subject.parse!('[{ "foo": "bar" }]')).to eq([{ "foo" => "bar" }])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# These tests will change expectations when the gem is upgraded
|
||||||
|
|
||||||
it "raises an error on a string" do
|
it "raises an error on a string" do
|
||||||
expect { subject.parse!('"foo"') }.to raise_error(JSON::ParserError)
|
expect { subject.parse!('"foo"') }.to raise_error(JSON::ParserError)
|
||||||
end
|
end
|
||||||
|
@ -47,6 +80,29 @@ RSpec.describe Gitlab::Json do
|
||||||
end
|
end
|
||||||
end
|
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 "parses an array" 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"', legacy_mode: true) }.to raise_error(JSON::ParserError)
|
||||||
|
end
|
||||||
|
|
||||||
|
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 ".dump" do
|
describe ".dump" do
|
||||||
it "dumps an object" do
|
it "dumps an object" do
|
||||||
expect(subject.dump({ "foo" => "bar" })).to eq('{"foo":"bar"}')
|
expect(subject.dump({ "foo" => "bar" })).to eq('{"foo":"bar"}')
|
||||||
|
|
|
@ -38,7 +38,7 @@ describe Gitlab::PerformanceBar do
|
||||||
end
|
end
|
||||||
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) }
|
it { expect(described_class.l2_cache_backend).to eq(Rails.cache) }
|
||||||
|
|
||||||
describe '.enabled_for_user?' do
|
describe '.enabled_for_user?' do
|
||||||
|
|
|
@ -229,4 +229,164 @@ describe Gitlab::X509::Signature do
|
||||||
end
|
end
|
||||||
end
|
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
|
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
|
||||||
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
|
# Warm up the cache
|
||||||
create(:application_setting).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
|
expect(ApplicationSetting.cache_backend).to receive(:read).with(ApplicationSetting.cache_key).once.and_call_original
|
||||||
|
|
||||||
2.times { ApplicationSetting.current }
|
2.times { ApplicationSetting.current }
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe MergeRequestDiff do
|
describe MergeRequestDiff do
|
||||||
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
include RepoHelpers
|
include RepoHelpers
|
||||||
|
|
||||||
let(:diff_with_commits) { create(:merge_request).merge_request_diff }
|
let(:diff_with_commits) { create(:merge_request).merge_request_diff }
|
||||||
|
@ -125,18 +127,71 @@ describe MergeRequestDiff do
|
||||||
end
|
end
|
||||||
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
|
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 }
|
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
|
expect(diff).not_to be_stored_externally
|
||||||
|
|
||||||
stub_external_diffs_setting(enabled: true)
|
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!
|
diff.migrate_files_to_external_storage!
|
||||||
|
|
||||||
expect(diff).to be_stored_externally
|
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
|
end
|
||||||
|
|
||||||
it 'does nothing with an external diff' do
|
it 'does nothing with an external diff' do
|
||||||
|
|
|
@ -582,6 +582,79 @@ describe JiraService do
|
||||||
end
|
end
|
||||||
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
|
describe '#test' do
|
||||||
let(:jira_service) do
|
let(:jira_service) do
|
||||||
described_class.new(
|
described_class.new(
|
||||||
|
|
|
@ -202,6 +202,22 @@ describe SnippetRepository do
|
||||||
|
|
||||||
it_behaves_like 'snippet repository with file names', 'snippetfile10.txt', 'snippetfile11.txt'
|
it_behaves_like 'snippet repository with file names', 'snippetfile10.txt', 'snippetfile11.txt'
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
def blob_at(snippet, path)
|
def blob_at(snippet, path)
|
||||||
|
|
|
@ -9,6 +9,15 @@ RSpec.describe X509CommitSignature do
|
||||||
let(:x509_certificate) { create(:x509_certificate) }
|
let(:x509_certificate) { create(:x509_certificate) }
|
||||||
let(:x509_signature) { create(:x509_commit_signature, commit_sha: commit_sha) }
|
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'
|
it_behaves_like 'having unique enum values'
|
||||||
|
|
||||||
describe 'validation' do
|
describe 'validation' do
|
||||||
|
@ -23,15 +32,6 @@ RSpec.describe X509CommitSignature do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.safe_create!' do
|
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
|
it 'finds a signature by commit sha if it existed' do
|
||||||
x509_signature
|
x509_signature
|
||||||
|
|
||||||
|
@ -50,4 +50,18 @@ RSpec.describe X509CommitSignature do
|
||||||
expect(signature.x509_certificate_id).to eq(x509_certificate.id)
|
expect(signature.x509_certificate_id).to eq(x509_certificate.id)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -462,7 +462,8 @@ describe SystemNoteService do
|
||||||
describe "existing reference" do
|
describe "existing reference" do
|
||||||
before do
|
before do
|
||||||
allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
|
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_next_instance_of(JIRA::Resource::Issue) do |instance|
|
||||||
allow(instance).to receive(:comments).and_return([OpenStruct.new(body: message)])
|
allow(instance).to receive(:comments).and_return([OpenStruct.new(body: message)])
|
||||||
end
|
end
|
||||||
|
|
|
@ -209,9 +209,7 @@ RSpec.configure do |config|
|
||||||
# expect(Gitlab::Git::KeepAround).to receive(:execute).and_call_original
|
# expect(Gitlab::Git::KeepAround).to receive(:execute).and_call_original
|
||||||
allow(Gitlab::Git::KeepAround).to receive(:execute)
|
allow(Gitlab::Git::KeepAround).to receive(:execute)
|
||||||
|
|
||||||
[Gitlab::ThreadMemoryCache, Gitlab::ProcessMemoryCache].each do |cache|
|
Gitlab::ProcessMemoryCache.cache_backend.clear
|
||||||
cache.cache_backend.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
Sidekiq::Worker.clear_all
|
Sidekiq::Worker.clear_all
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ module StubObjectStorage
|
||||||
def stub_external_diffs_object_storage(uploader = described_class, **params)
|
def stub_external_diffs_object_storage(uploader = described_class, **params)
|
||||||
stub_object_storage_uploader(config: Gitlab.config.external_diffs.object_store,
|
stub_object_storage_uploader(config: Gitlab.config.external_diffs.object_store,
|
||||||
uploader: uploader,
|
uploader: uploader,
|
||||||
remote_directory: 'external_diffs',
|
remote_directory: 'external-diffs',
|
||||||
**params)
|
**params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -173,22 +173,155 @@ module X509Helpers
|
||||||
Time.at(1561027326)
|
Time.at(1561027326)
|
||||||
end
|
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
|
def certificate_crl
|
||||||
'http://ch.siemens.com/pki?ZZZZZZA2.crl'
|
'http://ch.siemens.com/pki?ZZZZZZA2.crl'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tag_certificate_crl
|
||||||
|
'http://ch.siemens.com/pki?ZZZZZZA6.crl'
|
||||||
|
end
|
||||||
|
|
||||||
def certificate_serial
|
def certificate_serial
|
||||||
1810356222
|
1810356222
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tag_certificate_serial
|
||||||
|
3664232660
|
||||||
|
end
|
||||||
|
|
||||||
def certificate_subject_key_identifier
|
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'
|
'EC:00:B5:28:02:5C:D3:A5:A1:AB:C2:A1:34:81:84:AA:BF:9B:CF:F8'
|
||||||
end
|
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
|
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'
|
'BD:BD:2A:43:22:3D:48:4A:57:7E:98:31:17:A9:70:9D:EE:9F:A8:99'
|
||||||
end
|
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
|
def certificate_email
|
||||||
'r.meier@siemens.com'
|
'r.meier@siemens.com'
|
||||||
end
|
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'
|
'CN=Siemens Issuing CA EE Auth 2016,OU=Siemens Trust Center,serialNumber=ZZZZZZA2,O=Siemens,L=Muenchen,ST=Bayern,C=DE'
|
||||||
end
|
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
|
def certificate_subject
|
||||||
'CN=Meier Roger,O=Siemens,SN=Meier,GN=Roger,serialNumber=Z000NWDH'
|
'CN=Meier Roger,O=Siemens,SN=Meier,GN=Roger,serialNumber=Z000NWDH'
|
||||||
end
|
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 commit is created/updated')
|
||||||
expect(rendered).to have_content('Event will be triggered when a merge request is created/updated/merged')
|
expect(rendered).to have_content('Event will be triggered when a merge request is created/updated/merged')
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue