From 1385478346704d03ab9d3a9bf8ae3812cea0b6b5 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 2 Jun 2023 21:59:19 +0000 Subject: Add latest changes from gitlab-org/security/gitlab@16-0-stable-ee --- app/assets/javascripts/single_file_diff.js | 4 +- app/controllers/abuse_reports_controller.rb | 9 +--- app/helpers/merge_requests_helper.rb | 4 +- app/models/concerns/ci/artifactable.rb | 4 ++ app/models/concerns/exportable.rb | 69 ++++++++++++++++++++++------- app/models/concerns/issuable.rb | 5 +++ app/models/issue.rb | 1 - app/models/label.rb | 15 +++++++ app/models/project_team.rb | 6 ++- app/models/user.rb | 4 +- 10 files changed, 92 insertions(+), 29 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js index bab167bb7e4..11896a75798 100644 --- a/app/assets/javascripts/single_file_diff.js +++ b/app/assets/javascripts/single_file_diff.js @@ -24,7 +24,9 @@ export default class SingleFileDiff { this.content = $('.diff-content', this.file); this.$chevronRightIcon = $('.diff-toggle-caret .chevron-right', this.file); this.$chevronDownIcon = $('.diff-toggle-caret .chevron-down', this.file); - this.diffForPath = this.content.find('[data-diff-for-path]').data('diffForPath'); + this.diffForPath = this.content + .find('div:not(.note-text)[data-diff-for-path]') + .data('diffForPath'); this.isOpen = !this.diffForPath; if (this.diffForPath) { this.collapsedContent = this.content; diff --git a/app/controllers/abuse_reports_controller.rb b/app/controllers/abuse_reports_controller.rb index edeac57bc42..5a4f80fcb32 100644 --- a/app/controllers/abuse_reports_controller.rb +++ b/app/controllers/abuse_reports_controller.rb @@ -1,17 +1,10 @@ # frozen_string_literal: true class AbuseReportsController < ApplicationController - before_action :set_user, only: [:new, :add_category] + before_action :set_user, only: [:add_category] feature_category :insider_threat - def new - @abuse_report = AbuseReport.new( - user_id: @user.id, - reported_from_url: params.fetch(:ref_url, '') - ) - end - def add_category @abuse_report = AbuseReport.new( user_id: @user.id, diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 15901e13c1a..af1c85532c3 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -247,13 +247,13 @@ module MergeRequestsHelper end branch = if merge_request.for_fork? - _('%{fork_icon} %{source_project_path}:%{source_branch}').html_safe % { fork_icon: fork_icon.html_safe, source_project_path: merge_request.source_project_path.html_safe, source_branch: merge_request.source_branch.html_safe } + html_escape(_('%{fork_icon} %{source_project_path}:%{source_branch}')) % { fork_icon: fork_icon.html_safe, source_project_path: merge_request.source_project_path, source_branch: merge_request.source_branch } else merge_request.source_branch end branch_title = if merge_request.for_fork? - _('%{source_project_path}:%{source_branch}').html_safe % { source_project_path: merge_request.source_project_path.html_safe, source_branch: merge_request.source_branch.html_safe } + html_escape(_('%{source_project_path}:%{source_branch}')) % { source_project_path: merge_request.source_project_path, source_branch: merge_request.source_branch } else merge_request.source_branch end diff --git a/app/models/concerns/ci/artifactable.rb b/app/models/concerns/ci/artifactable.rb index 3fdbd6a8789..974f8213a29 100644 --- a/app/models/concerns/ci/artifactable.rb +++ b/app/models/concerns/ci/artifactable.rb @@ -9,6 +9,7 @@ module Ci STORE_COLUMN = :file_store NotSupportedAdapterError = Class.new(StandardError) + FILE_FORMAT_ADAPTERS = { # While zip is a streamable file format, performing streaming # reads requires that each entry in the zip has certain headers @@ -41,6 +42,9 @@ module Ci raise NotSupportedAdapterError, 'This file format requires a dedicated adapter' end + ::Gitlab::Ci::Artifacts::DecompressedArtifactSizeValidator + .new(file: file, file_format: file_format.to_sym).validate! + log_artifacts_filesize(file.model) file.open do |stream| diff --git a/app/models/concerns/exportable.rb b/app/models/concerns/exportable.rb index 066a44912be..c305d272a14 100644 --- a/app/models/concerns/exportable.rb +++ b/app/models/concerns/exportable.rb @@ -3,19 +3,6 @@ module Exportable extend ActiveSupport::Concern - def readable_records(association, current_user: nil) - association_records = try(association) - return unless association_records.present? - - if has_many_association?(association) - DeclarativePolicy.user_scope do - association_records.select { |record| readable_record?(record, current_user) } - end - else - readable_record?(association_records, current_user) ? association_records : nil - end - end - def exportable_association?(association, current_user: nil) return false unless respond_to?(association) return true if has_many_association?(association) @@ -30,8 +17,17 @@ module Exportable exportable_restricted_associations & keys end - def has_many_association?(association_name) - self.class.reflect_on_association(association_name)&.macro == :has_many + def to_authorized_json(keys_to_authorize, current_user, options) + modified_options = filtered_associations_opts(options, keys_to_authorize) + record_hash = as_json(modified_options).with_indifferent_access + + keys_to_authorize.each do |key| + next unless record_hash.key?(key) + + record_hash[key] = authorized_association_records(key, current_user, options) + end + + record_hash.to_json end private @@ -47,4 +43,47 @@ module Exportable record.readable_by?(user) end end + + def has_many_association?(association_name) + self.class.reflect_on_association(association_name)&.macro == :has_many + end + + def readable_records(association, current_user: nil) + association_records = try(association) + return unless association_records.present? + + if has_many_association?(association) + DeclarativePolicy.user_scope do + association_records.select { |record| readable_record?(record, current_user) } + end + else + readable_record?(association_records, current_user) ? association_records : nil + end + end + + def authorized_association_records(key, current_user, options) + records = readable_records(key, current_user: current_user) + empty_assoc = has_many_association?(key) ? [] : nil + return empty_assoc unless records.present? + + assoc_opts = association_options(key, options)&.dig(key) + records.as_json(assoc_opts) + end + + def filtered_associations_opts(options, associations) + options_copy = options.deep_dup + + associations.each do |key| + assoc_opts = association_options(key, options_copy) + next unless assoc_opts + + assoc_opts[key] = { only: [:id] } + end + + options_copy + end + + def association_options(key, options) + options[:include].find { |assoc| assoc.key?(key) } + end end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index b1ec6b8ba32..8926e805d8d 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -27,6 +27,7 @@ module Issuable include ClosedAtFilterable include VersionedDescription include SortableTitle + include Exportable TITLE_LENGTH_MAX = 255 TITLE_HTML_LENGTH_MAX = 800 @@ -230,6 +231,10 @@ module Issuable issuable_severity&.severity || IssuableSeverity::DEFAULT end + def exportable_restricted_associations + super + [:notes] + end + private def validate_description_length? diff --git a/app/models/issue.rb b/app/models/issue.rb index b7125617034..f214bc0f1af 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -25,7 +25,6 @@ class Issue < ApplicationRecord include FromUnion include EachBatch include PgFullTextSearchable - include Exportable extend ::Gitlab::Utils::Override diff --git a/app/models/label.rb b/app/models/label.rb index 32b399ac461..0831ba40536 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -14,6 +14,7 @@ class Label < ApplicationRecord cache_markdown_field :description, pipeline: :single_line DEFAULT_COLOR = ::Gitlab::Color.of('#6699cc') + DESCRIPTION_LENGTH_MAX = 512.kilobytes attribute :color, ::Gitlab::Database::Type::Color.new, default: DEFAULT_COLOR @@ -32,6 +33,10 @@ class Label < ApplicationRecord validates :title, uniqueness: { scope: [:group_id, :project_id] } validates :title, length: { maximum: 255 } + # we validate the description against DESCRIPTION_LENGTH_MAX only for labels being created and on updates if + # the description changes to avoid breaking the existing labels which may have their descriptions longer + validates :description, bytesize: { maximum: -> { DESCRIPTION_LENGTH_MAX } }, if: :validate_description_length? + default_scope { order(title: :asc) } # rubocop:disable Cop/DefaultScope scope :templates, -> { where(template: true, type: [Label.name, nil]) } @@ -282,6 +287,16 @@ class Label < ApplicationRecord private + def validate_description_length? + return false unless description_changed? + + previous_description = changes['description'].first + # previous_description will be nil for new records + return true if previous_description.blank? + + previous_description.bytesize <= DESCRIPTION_LENGTH_MAX || description.bytesize > previous_description.bytesize + end + def issues_count(user, params = {}) params.merge!(subject_foreign_key => subject.id, label_name: title, scope: 'all') IssuesFinder.new(user, params.with_indifferent_access).execute.count diff --git a/app/models/project_team.rb b/app/models/project_team.rb index dd200aec807..ca1064997af 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -117,12 +117,14 @@ class ProjectTeam owners.include?(user) end - def import(source_project, current_user = nil) + def import(source_project, current_user) target_project = project source_members = source_project.project_members.to_a target_user_ids = target_project.project_members.pluck_user_ids + importer_access_level = max_member_access(current_user.id) + source_members.reject! do |member| # Skip if user already present in team !member.invite? && target_user_ids.include?(member.user_id) @@ -132,6 +134,8 @@ class ProjectTeam new_member = member.dup new_member.id = nil new_member.source = target_project + # So that a maintainer cannot import a member with owner access + new_member.access_level = [new_member.access_level, importer_access_level].min new_member.created_by = current_user new_member end diff --git a/app/models/user.rb b/app/models/user.rb index dc70ff2e232..50da6f9e491 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1549,7 +1549,9 @@ class User < ApplicationRecord # rubocop: enable CodeReuse/ServiceClass def primary_email_verified? - confirmed? && !temp_oauth_email? + return false unless confirmed? && !temp_oauth_email? + + !email_changed? || new_record? end def accept_pending_invitations! -- cgit v1.2.3