Skip to content
Snippets Groups Projects
Commit 61687210 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent a89cb5cb
No related branches found
No related tags found
No related merge requests found
Showing
with 318 additions and 27 deletions
<script>
import FileIcon from '~/vue_shared/components/file_icon.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { numberToHumanSize } from '~/lib/utils/number_utils';
export default {
components: {
FileIcon,
ClipboardButton,
},
props: {
blob: {
type: Object,
required: true,
},
},
computed: {
blobSize() {
return numberToHumanSize(this.blob.size);
},
gfmCopyText() {
return `\`${this.blob.path}\``;
},
},
};
</script>
<template>
<div class="file-header-content d-flex align-items-center lh-100">
<slot name="filepathPrepend"></slot>
<file-icon :file-name="blob.path" :size="18" aria-hidden="true" css-classes="mr-2" />
<strong
v-if="blob.name"
class="file-title-name qa-file-title-name mr-1 js-blob-header-filepath"
>{{ blob.name }}</strong
>
<small class="mr-2">{{ blobSize }}</small>
<clipboard-button
:text="blob.path"
:gfm="gfmCopyText"
:title="__('Copy file path')"
css-class="btn-clipboard btn-transparent lh-100 position-static"
/>
</div>
</template>
Loading
Loading
@@ -110,8 +110,8 @@ export const timeRanges = [
duration: { seconds: 60 * 60 * 24 * 7 * 1 },
},
{
label: __('2 weeks'),
duration: { seconds: 60 * 60 * 24 * 7 * 2 },
label: __('1 month'),
duration: { seconds: 60 * 60 * 24 * 30 },
},
];
 
Loading
Loading
Loading
Loading
@@ -32,10 +32,6 @@
 
.snippet-file-content {
border-radius: 3px;
.file-title-flex-parent .btn-clipboard {
line-height: 28px;
}
}
 
.snippet-header {
Loading
Loading
Loading
Loading
@@ -321,6 +321,16 @@
}
}
 
.gpg-popover-certificate-details {
ul {
padding-left: $gl-padding;
}
li.unstyled {
list-style-type: none;
}
}
.gpg-popover-status {
display: flex;
align-items: center;
Loading
Loading
Loading
Loading
@@ -25,7 +25,7 @@ class Commit
attr_accessor :redacted_description_html
attr_accessor :redacted_title_html
attr_accessor :redacted_full_title_html
attr_reader :gpg_commit, :container
attr_reader :container
 
delegate :repository, to: :container
delegate :project, to: :repository, allow_nil: true
Loading
Loading
@@ -123,7 +123,6 @@ class Commit
 
@raw = raw_commit
@container = container
@gpg_commit = Gitlab::Gpg::Commit.new(self) if container
end
 
delegate \
Loading
Loading
@@ -320,13 +319,34 @@ class Commit
)
end
 
def signature
return @signature if defined?(@signature)
def has_signature?
signature_type && signature_type != :NONE
end
def raw_signature_type
strong_memoize(:raw_signature_type) do
next unless @raw.instance_of?(Gitlab::Git::Commit)
@raw.raw_commit.signature_type if defined? @raw.raw_commit.signature_type
end
end
 
@signature = gpg_commit.signature
def signature_type
@signature_type ||= raw_signature_type || :NONE
end
 
delegate :has_signature?, to: :gpg_commit
def signature
strong_memoize(:signature) do
case signature_type
when :PGP
Gitlab::Gpg::Commit.new(self).signature
when :X509
Gitlab::X509::Commit.new(self).signature
else
nil
end
end
end
 
def revert_branch_name
"revert-#{short_id}"
Loading
Loading
# frozen_string_literal: true
module X509SerialNumberAttribute
extend ActiveSupport::Concern
class_methods do
def x509_serial_number_attribute(name)
return if ENV['STATIC_VERIFICATION']
validate_binary_column_exists!(name) unless Rails.env.production?
attribute(name, Gitlab::Database::X509SerialNumberAttribute.new)
end
# This only gets executed in non-production environments as an additional check to ensure
# the column is the correct type. In production it should behave like any other attribute.
# See https://gitlab.com/gitlab-org/gitlab/merge_requests/5502 for more discussion
def validate_binary_column_exists!(name)
return unless database_exists?
unless table_exists?
warn "WARNING: x509_serial_number_attribute #{name.inspect} is invalid since the table doesn't exist - you may need to run database migrations"
return
end
column = columns.find { |c| c.name == name.to_s }
unless column
warn "WARNING: x509_serial_number_attribute #{name.inspect} is invalid since the column doesn't exist - you may need to run database migrations"
return
end
unless column.type == :binary
raise ArgumentError.new("x509_serial_number_attribute #{name.inspect} is invalid since the column type is not :binary")
end
rescue => error
Gitlab::AppLogger.error "X509SerialNumberAttribute initialization: #{error.message}"
raise
end
def database_exists?
Gitlab::Database.exists?
end
end
end
Loading
Loading
@@ -190,6 +190,12 @@ class User < ApplicationRecord
validate :owns_commit_email, if: :commit_email_changed?
validate :signup_domain_valid?, on: :create, if: ->(user) { !user.created_by_id }
 
validates :theme_id, allow_nil: true, inclusion: { in: Gitlab::Themes.valid_ids,
message: _("%{placeholder} is not a valid theme") % { placeholder: '%{value}' } }
validates :color_scheme_id, allow_nil: true, inclusion: { in: Gitlab::ColorSchemes.valid_ids,
message: _("%{placeholder} is not a valid color scheme") % { placeholder: '%{value}' } }
before_validation :sanitize_attrs
before_validation :set_notification_email, if: :new_record?
before_validation :set_public_email, if: :public_email_changed?
Loading
Loading
# frozen_string_literal: true
class X509Certificate < ApplicationRecord
include X509SerialNumberAttribute
x509_serial_number_attribute :serial_number
enum certificate_status: {
good: 0,
revoked: 1
}
belongs_to :x509_issuer, class_name: 'X509Issuer', foreign_key: 'x509_issuer_id', optional: false
has_many :x509_commit_signatures, inverse_of: 'x509_certificate'
# rfc 5280 - 4.2.1.2 Subject Key Identifier
validates :subject_key_identifier, presence: true, format: { with: /\A(\h{2}:){19}\h{2}\z/ }
# rfc 5280 - 4.1.2.6 Subject
validates :subject, presence: true
# rfc 5280 - 4.1.2.6 Subject (subjectAltName contains the email address)
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
# rfc 5280 - 4.1.2.2 Serial number
validates :serial_number, presence: true, numericality: { only_integer: true }
validates :x509_issuer_id, presence: true
def self.safe_create!(attributes)
create_with(attributes)
.safe_find_or_create_by!(subject_key_identifier: attributes[:subject_key_identifier])
end
end
# frozen_string_literal: true
class X509CommitSignature < ApplicationRecord
include ShaAttribute
sha_attribute :commit_sha
enum verification_status: {
unverified: 0,
verified: 1
}
belongs_to :project, class_name: 'Project', foreign_key: 'project_id', optional: false
belongs_to :x509_certificate, class_name: 'X509Certificate', foreign_key: 'x509_certificate_id', optional: false
validates :commit_sha, presence: true
validates :project_id, presence: true
validates :x509_certificate_id, presence: true
scope :by_commit_sha, ->(shas) { where(commit_sha: shas) }
def self.safe_create!(attributes)
create_with(attributes)
.safe_find_or_create_by!(commit_sha: attributes[:commit_sha])
end
# Find commits that are lacking a signature in the database at present
def self.unsigned_commit_shas(commit_shas)
return [] if commit_shas.empty?
signed = by_commit_sha(commit_shas).pluck(:commit_sha)
commit_shas - signed
end
def commit
project.commit(commit_sha)
end
def x509_commit
return unless commit
Gitlab::X509::Commit.new(commit)
end
end
# frozen_string_literal: true
class X509Issuer < ApplicationRecord
has_many :x509_certificates, inverse_of: 'x509_issuer'
# rfc 5280 - 4.2.1.1 Authority Key Identifier
validates :subject_key_identifier, presence: true, format: { with: /\A(\h{2}:){19}\h{2}\z/ }
# rfc 5280 - 4.1.2.4 Issuer
validates :subject, presence: true
# rfc 5280 - 4.2.1.14 CRL Distribution Points
# cRLDistributionPoints extension using URI:http
validates :crl_url, presence: true, public_url: true
def self.safe_create!(attributes)
create_with(attributes)
.safe_find_or_create_by!(subject_key_identifier: attributes[:subject_key_identifier])
end
end
Loading
Loading
@@ -6,7 +6,7 @@ module Git
execute_branch_hooks
 
super.tap do
enqueue_update_gpg_signatures
enqueue_update_signatures
end
end
 
Loading
Loading
@@ -103,14 +103,22 @@ module Git
end
end
 
def enqueue_update_gpg_signatures
unsigned = GpgSignature.unsigned_commit_shas(limited_commits.map(&:sha))
def unsigned_x509_shas(commits)
X509CommitSignature.unsigned_commit_shas(commits.map(&:sha))
end
def unsigned_gpg_shas(commits)
GpgSignature.unsigned_commit_shas(commits.map(&:sha))
end
def enqueue_update_signatures
unsigned = unsigned_x509_shas(commits) & unsigned_gpg_shas(commits)
return if unsigned.empty?
 
signable = Gitlab::Git::Commit.shas_with_signatures(project.repository, unsigned)
return if signable.empty?
 
CreateGpgSignatureWorker.perform_async(signable, project.id)
CreateCommitSignatureWorker.perform_async(signable, project.id)
end
 
# It's not sufficient to just check for a blank SHA as it's possible for the
Loading
Loading
- if signature
= render partial: "projects/commit/#{signature.verification_status}_signature_badge", locals: { signature: signature }
- uri = "projects/commit/#{"x509/" if signature.instance_of?(X509CommitSignature)}"
= render partial: "#{uri}#{signature.verification_status}_signature_badge", locals: { signature: signature }
Loading
Loading
@@ -17,12 +17,18 @@
- content = capture do
- if show_user
.clearfix
= render partial: 'projects/commit/signature_badge_user', locals: { signature: signature }
- uri_signature_badge_user = "projects/commit/#{"x509/" if signature.instance_of?(X509CommitSignature)}signature_badge_user"
= render partial: "#{uri_signature_badge_user}", locals: { signature: signature }
 
= _('GPG Key ID:')
%span.monospace= signature.gpg_key_primary_keyid
- if signature.instance_of?(X509CommitSignature)
= render partial: "projects/commit/x509/certificate_details", locals: { signature: signature }
 
= link_to(_('Learn more about signing commits'), help_page_path('user/project/repository/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link')
= link_to(_('Learn more about x509 signed commits'), help_page_path('user/project/repository/x509_signed_commits/index.md'), class: 'gpg-popover-help-link')
- else
= _('GPG Key ID:')
%span.monospace= signature.gpg_key_primary_keyid
= link_to(_('Learn more about signing commits'), help_page_path('user/project/repository/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link')
 
%button{ tabindex: 0, class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'top', title: title, content: content } }
= label
.gpg-popover-certificate-details
%strong= _('Certificate Subject')
%ul
- signature.x509_certificate.subject.split(",").each do |i|
- if i.start_with?("CN", "O")
%li= i
%li= _('Subject Key Identifier:')
%li.unstyled= signature.x509_certificate.subject_key_identifier.gsub(":", " ")
.gpg-popover-certificate-details
%strong= _('Certificate Issuer')
%ul
- signature.x509_certificate.x509_issuer.subject.split(",").each do |i|
- if i.start_with?("CN", "OU", "O")
%li= i
%li= _('Subject Key Identifier:')
%li.unstyled= signature.x509_certificate.x509_issuer.subject_key_identifier.gsub(":", " ")
- user = signature.commit.committer
- user_email = signature.x509_certificate.email
- if user
= link_to user_path(user), class: 'gpg-popover-user-link' do
%div
= user_avatar_without_link(user: user, size: 32)
%div
%strong= user.name
%div= user.to_reference
- else
= mail_to user_email do
%div
= user_avatar_without_link(user_email: user_email, size: 32)
%div
%strong= user_email
- title = capture do
= _('This commit was signed with an <strong>unverified</strong> signature.').html_safe
- locals = { signature: signature, title: title, label: _('Unverified'), css_class: 'invalid', icon: 'status_notfound_borderless', show_user: true }
= render partial: 'projects/commit/signature_badge', locals: locals
- title = capture do
= _('This commit was signed with a <strong>verified</strong> signature and the committer email is verified to belong to the same user.').html_safe
- locals = { signature: signature, title: title, label: _('Verified'), css_class: 'valid', icon: 'status_success_borderless', show_user: true }
= render partial: 'projects/commit/signature_badge', locals: locals
Loading
Loading
@@ -699,14 +699,14 @@
:latency_sensitive: true
:resource_boundary: :unknown
:weight: 2
- :name: create_evidence
:feature_category: :release_governance
- :name: create_commit_signature
:feature_category: :source_code_management
:has_external_dependencies:
:latency_sensitive:
:resource_boundary: :unknown
:weight: 2
- :name: create_gpg_signature
:feature_category: :source_code_management
- :name: create_evidence
:feature_category: :release_governance
:has_external_dependencies:
:latency_sensitive:
:resource_boundary: :unknown
Loading
Loading
# frozen_string_literal: true
 
class CreateGpgSignatureWorker
class CreateCommitSignatureWorker
include ApplicationWorker
 
feature_category :source_code_management
Loading
Loading
@@ -23,7 +23,12 @@ class CreateGpgSignatureWorker
 
# This calculates and caches the signature in the database
commits.each do |commit|
Gitlab::Gpg::Commit.new(commit).signature
case commit.signature_type
when :PGP
Gitlab::Gpg::Commit.new(commit).signature
when :X509
Gitlab::X509::Commit.new(commit).signature
end
rescue => e
Rails.logger.error("Failed to create signature for commit #{commit.id}. Error: #{e.message}") # rubocop:disable Gitlab/RailsLogger
end
Loading
Loading
---
title: Extend logs retention to period from 15 to 30 days
merge_request: 24466
author:
type: changed
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment