summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/api/helpers/projects_helpers.rb5
-rw-r--r--lib/api/projects.rb4
-rw-r--r--lib/api/users.rb8
-rw-r--r--lib/banzai/filter/ascii_doc_sanitization_filter.rb33
-rw-r--r--lib/banzai/filter/reference_redactor_filter.rb (renamed from lib/banzai/filter/redactor_filter.rb)4
-rw-r--r--lib/banzai/object_renderer.rb2
-rw-r--r--lib/banzai/pipeline/post_process_pipeline.rb2
-rw-r--r--lib/banzai/reference_redactor.rb (renamed from lib/banzai/redactor.rb)2
-rw-r--r--lib/banzai/renderer.rb2
-rw-r--r--lib/gitlab/background_migration/fix_pages_access_level.rb128
-rw-r--r--lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml2
-rw-r--r--lib/gitlab/git/repository.rb22
-rw-r--r--lib/gitlab/graphql/representation/submodule_tree_entry.rb34
-rw-r--r--lib/gitlab/submodule_links.rb26
-rw-r--r--lib/gitlab/zoom_link_extractor.rb21
-rw-r--r--lib/tasks/gitlab/features.rake14
17 files changed, 285 insertions, 25 deletions
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 0a9515f1dd2..494da770279 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -294,7 +294,6 @@ module API
expose :statistics, using: 'API::Entities::ProjectStatistics', if: -> (project, options) {
options[:statistics] && Ability.allowed?(options[:current_user], :read_statistics, project)
}
- expose :external_authorization_classification_label
expose :auto_devops_enabled?, as: :auto_devops_enabled
expose :auto_devops_deploy_strategy do |project, options|
project.auto_devops.nil? ? 'continuous' : project.auto_devops.deploy_strategy
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index 0e21a7a66fd..833e3b9ebaf 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -42,7 +42,6 @@ module API
optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line'
optional :merge_method, type: String, values: %w(ff rebase_merge merge), desc: 'The merge method used when merging merge requests'
optional :initialize_with_readme, type: Boolean, desc: "Initialize a project with a README.md"
- optional :external_authorization_classification_label, type: String, desc: 'The classification label for the project'
optional :ci_default_git_depth, type: Integer, desc: 'Default number of revisions for shallow cloning'
optional :auto_devops_enabled, type: Boolean, desc: 'Flag indication if Auto DevOps is enabled'
optional :auto_devops_deploy_strategy, type: String, values: %w(continuous manual timed_incremental), desc: 'Auto Deploy strategy'
@@ -94,7 +93,6 @@ module API
:visibility,
:wiki_access_level,
:avatar,
- :external_authorization_classification_label,
# TODO: remove in API v5, replaced by *_access_level
:issues_enabled,
@@ -105,6 +103,9 @@ module API
:snippets_enabled
]
end
+
+ def filter_attributes_using_license!(attrs)
+ end
end
end
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index a7d62014509..0923d31f5ff 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -145,6 +145,7 @@ module API
post do
attrs = declared_params(include_missing: false)
attrs = translate_params_for_compatibility(attrs)
+ filter_attributes_using_license!(attrs)
project = ::Projects::CreateService.new(current_user, attrs).execute
if project.saved?
@@ -179,6 +180,7 @@ module API
attrs = declared_params(include_missing: false)
attrs = translate_params_for_compatibility(attrs)
+ filter_attributes_using_license!(attrs)
project = ::Projects::CreateService.new(user, attrs).execute
if project.saved?
@@ -292,7 +294,7 @@ module API
authorize! :change_visibility_level, user_project if attrs[:visibility].present?
attrs = translate_params_for_compatibility(attrs)
-
+ filter_attributes_using_license!(attrs)
verify_update_project_attrs!(user_project, attrs)
result = ::Projects::UpdateService.new(user_project, current_user, attrs).execute
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 30a278fdff1..a4ac5b629b8 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -148,7 +148,7 @@ module API
end
desc 'Create a user. Available only for admins.' do
- success Entities::UserPublic
+ success Entities::UserWithAdmin
end
params do
requires :email, type: String, desc: 'The email of the user'
@@ -168,7 +168,7 @@ module API
user = ::Users::CreateService.new(current_user, params).execute(skip_authorization: true)
if user.persisted?
- present user, with: Entities::UserPublic, current_user: current_user
+ present user, with: Entities::UserWithAdmin, current_user: current_user
else
conflict!('Email has already been taken') if User
.by_any_email(user.email.downcase)
@@ -183,7 +183,7 @@ module API
end
desc 'Update a user. Available only for admins.' do
- success Entities::UserPublic
+ success Entities::UserWithAdmin
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
@@ -215,7 +215,7 @@ module API
result = ::Users::UpdateService.new(current_user, user_params.merge(user: user)).execute
if result[:status] == :success
- present user, with: Entities::UserPublic, current_user: current_user
+ present user, with: Entities::UserWithAdmin, current_user: current_user
else
render_validation_error!(user)
end
diff --git a/lib/banzai/filter/ascii_doc_sanitization_filter.rb b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
index d8d63075752..9105e86ad04 100644
--- a/lib/banzai/filter/ascii_doc_sanitization_filter.rb
+++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
@@ -8,12 +8,18 @@ module Banzai
class AsciiDocSanitizationFilter < Banzai::Filter::BaseSanitizationFilter
# Section anchor link pattern
SECTION_LINK_REF_PATTERN = /\A#{Gitlab::Asciidoc::DEFAULT_ADOC_ATTRS['idprefix']}(:?[[:alnum:]]|-|_)+\z/.freeze
+ SECTION_HEADINGS = %w(h2 h3 h4 h5 h6).freeze
+
+ # Footnote link patterns
+ FOOTNOTE_LINK_ID_PATTERNS = {
+ a: /\A_footnoteref_\d+\z/,
+ div: /\A_footnotedef_\d+\z/
+ }.freeze
# Classes used by Asciidoctor to style components
ADMONITION_CLASSES = %w(fa icon-note icon-tip icon-warning icon-caution icon-important).freeze
CALLOUT_CLASSES = ['conum'].freeze
CHECKLIST_CLASSES = %w(fa fa-check-square-o fa-square-o).freeze
-
LIST_CLASSES = %w(checklist none no-bullet unnumbered unstyled).freeze
ELEMENT_CLASSES_WHITELIST = {
@@ -26,8 +32,6 @@ module Banzai
a: ['anchor'].freeze
}.freeze
- ALLOWED_HEADERS = %w(h2 h3 h4 h5 h6).freeze
-
def customize_whitelist(whitelist)
# Allow marks
whitelist[:elements].push('mark')
@@ -44,20 +48,39 @@ module Banzai
whitelist[:transformers].push(self.class.remove_element_classes)
# Allow `id` in heading elements for section anchors
- ALLOWED_HEADERS.each do |header|
+ SECTION_HEADINGS.each do |header|
whitelist[:attributes][header] = %w(id)
end
whitelist[:transformers].push(self.class.remove_non_heading_ids)
+ # Allow `id` in footnote elements
+ FOOTNOTE_LINK_ID_PATTERNS.keys.each do |element|
+ whitelist[:attributes][element.to_s].push('id')
+ end
+ whitelist[:transformers].push(self.class.remove_non_footnote_ids)
+
whitelist
end
class << self
+ def remove_non_footnote_ids
+ lambda do |env|
+ node = env[:node]
+
+ return unless (pattern = FOOTNOTE_LINK_ID_PATTERNS[node.name.to_sym])
+ return unless node.has_attribute?('id')
+
+ return if node['id'] =~ pattern
+
+ node.remove_attribute('id')
+ end
+ end
+
def remove_non_heading_ids
lambda do |env|
node = env[:node]
- return unless ALLOWED_HEADERS.any?(node.name)
+ return unless SECTION_HEADINGS.any?(node.name)
return unless node.has_attribute?('id')
return if node['id'] =~ SECTION_LINK_REF_PATTERN
diff --git a/lib/banzai/filter/redactor_filter.rb b/lib/banzai/filter/reference_redactor_filter.rb
index 1f091f594f8..485d3fd5fc7 100644
--- a/lib/banzai/filter/redactor_filter.rb
+++ b/lib/banzai/filter/reference_redactor_filter.rb
@@ -7,12 +7,12 @@ module Banzai
#
# Expected to be run in its own post-processing pipeline.
#
- class RedactorFilter < HTML::Pipeline::Filter
+ class ReferenceRedactorFilter < HTML::Pipeline::Filter
def call
unless context[:skip_redaction]
context = RenderContext.new(project, current_user)
- Redactor.new(context).redact([doc])
+ ReferenceRedactor.new(context).redact([doc])
end
doc
diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb
index 75661ffa233..d6d29f4bfab 100644
--- a/lib/banzai/object_renderer.rb
+++ b/lib/banzai/object_renderer.rb
@@ -72,7 +72,7 @@ module Banzai
#
# Returns an Array containing the redacted documents.
def redact_documents(documents)
- redactor = Redactor.new(context)
+ redactor = ReferenceRedactor.new(context)
redactor.redact(documents)
end
diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb
index 5c199453638..54af26b41be 100644
--- a/lib/banzai/pipeline/post_process_pipeline.rb
+++ b/lib/banzai/pipeline/post_process_pipeline.rb
@@ -12,7 +12,7 @@ module Banzai
def self.internal_link_filters
[
- Filter::RedactorFilter,
+ Filter::ReferenceRedactorFilter,
Filter::InlineMetricsRedactorFilter,
Filter::RelativeLinkFilter,
Filter::IssuableStateFilter,
diff --git a/lib/banzai/redactor.rb b/lib/banzai/reference_redactor.rb
index c2da7fec7cc..eb5c35da375 100644
--- a/lib/banzai/redactor.rb
+++ b/lib/banzai/reference_redactor.rb
@@ -3,7 +3,7 @@
module Banzai
# Class for removing Markdown references a certain user is not allowed to
# view.
- class Redactor
+ class ReferenceRedactor
attr_reader :context
# context - An instance of `Banzai::RenderContext`.
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
index 81f32ef5bcf..3cb9ec21e8f 100644
--- a/lib/banzai/renderer.rb
+++ b/lib/banzai/renderer.rb
@@ -134,7 +134,7 @@ module Banzai
#
# This method is used to perform state-dependent changes to a String of
# HTML, such as removing references that the current user doesn't have
- # permission to make (`RedactorFilter`).
+ # permission to make (`ReferenceRedactorFilter`).
#
# html - String to process
# context - Hash of options to customize output
diff --git a/lib/gitlab/background_migration/fix_pages_access_level.rb b/lib/gitlab/background_migration/fix_pages_access_level.rb
new file mode 100644
index 00000000000..0d49f3dd8c5
--- /dev/null
+++ b/lib/gitlab/background_migration/fix_pages_access_level.rb
@@ -0,0 +1,128 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # corrects stored pages access level on db depending on project visibility
+ class FixPagesAccessLevel
+ # Copy routable here to avoid relying on application logic
+ module Routable
+ def build_full_path
+ if parent && path
+ parent.build_full_path + '/' + path
+ else
+ path
+ end
+ end
+ end
+
+ # Namespace
+ class Namespace < ApplicationRecord
+ self.table_name = 'namespaces'
+ self.inheritance_column = :_type_disabled
+
+ include Routable
+
+ belongs_to :parent, class_name: "Namespace"
+ end
+
+ # Project
+ class Project < ActiveRecord::Base
+ self.table_name = 'projects'
+ self.inheritance_column = :_type_disabled
+
+ include Routable
+
+ belongs_to :namespace
+ alias_method :parent, :namespace
+ alias_attribute :parent_id, :namespace_id
+
+ PRIVATE = 0
+ INTERNAL = 10
+ PUBLIC = 20
+
+ def pages_deployed?
+ Dir.exist?(public_pages_path)
+ end
+
+ def public_pages_path
+ File.join(pages_path, 'public')
+ end
+
+ def pages_path
+ # TODO: when we migrate Pages to work with new storage types, change here to use disk_path
+ File.join(Settings.pages.path, build_full_path)
+ end
+ end
+
+ # ProjectFeature
+ class ProjectFeature < ActiveRecord::Base
+ include ::EachBatch
+
+ self.table_name = 'project_features'
+
+ belongs_to :project
+
+ PRIVATE = 10
+ ENABLED = 20
+ PUBLIC = 30
+ end
+
+ def perform(start_id, stop_id)
+ fix_public_access_level(start_id, stop_id)
+
+ make_internal_projects_public(start_id, stop_id)
+
+ fix_private_access_level(start_id, stop_id)
+ end
+
+ private
+
+ def access_control_is_enabled
+ @access_control_is_enabled = Gitlab.config.pages.access_control
+ end
+
+ # Public projects are allowed to have only enabled pages_access_level
+ # which is equivalent to public
+ def fix_public_access_level(start_id, stop_id)
+ project_features(start_id, stop_id, ProjectFeature::PUBLIC, Project::PUBLIC).each_batch do |features|
+ features.update_all(pages_access_level: ProjectFeature::ENABLED)
+ end
+ end
+
+ # If access control is disabled and project has pages deployed
+ # project will become unavailable when access control will become enabled
+ # we make these projects public to avoid negative surprise to user
+ def make_internal_projects_public(start_id, stop_id)
+ return if access_control_is_enabled
+
+ project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::INTERNAL).find_each do |project_feature|
+ next unless project_feature.project.pages_deployed?
+
+ project_feature.update(pages_access_level: ProjectFeature::PUBLIC)
+ end
+ end
+
+ # Private projects are not allowed to have enabled access level, only `private` and `public`
+ # If access control is enabled, these projects currently behave as if the have `private` pages_access_level
+ # if access control is disabled, these projects currently behave as if the have `public` pages_access_level
+ # so we preserve this behaviour for projects with pages already deployed
+ # for project without pages we always set `private` access_level
+ def fix_private_access_level(start_id, stop_id)
+ project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::PRIVATE).find_each do |project_feature|
+ if access_control_is_enabled
+ project_feature.update!(pages_access_level: ProjectFeature::PRIVATE)
+ else
+ fixed_access_level = project_feature.project.pages_deployed? ? ProjectFeature::PUBLIC : ProjectFeature::PRIVATE
+ project_feature.update!(pages_access_level: fixed_access_level)
+ end
+ end
+ end
+
+ def project_features(start_id, stop_id, pages_access_level, project_visibility_level)
+ ProjectFeature.where(id: start_id..stop_id).joins(:project)
+ .where(pages_access_level: pages_access_level)
+ .where(projects: { visibility_level: project_visibility_level })
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
index f176771775e..89eccce69f6 100644
--- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
@@ -41,6 +41,8 @@ dependency_scanning:
DS_PULL_ANALYZER_IMAGE_TIMEOUT \
DS_RUN_ANALYZER_TIMEOUT \
DS_PYTHON_VERSION \
+ PIP_INDEX_URL \
+ PIP_EXTRA_INDEX_URL \
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index b7b7578cef9..a7d9ba51277 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -464,6 +464,18 @@ module Gitlab
end
end
+ # Returns path to url mappings for submodules
+ #
+ # Ex.
+ # @repository.submodule_urls_for('master')
+ # # => { 'rack' => 'git@localhost:rack.git' }
+ #
+ def submodule_urls_for(ref)
+ wrapped_gitaly_errors do
+ gitaly_submodule_urls_for(ref)
+ end
+ end
+
# Return total commits count accessible from passed ref
def commit_count(ref)
wrapped_gitaly_errors do
@@ -1059,12 +1071,16 @@ module Gitlab
return unless commit_object && commit_object.type == :COMMIT
+ urls = gitaly_submodule_urls_for(ref)
+ urls && urls[path]
+ end
+
+ def gitaly_submodule_urls_for(ref)
gitmodules = gitaly_commit_client.tree_entry(ref, '.gitmodules', Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE)
return unless gitmodules
- found_module = GitmodulesParser.new(gitmodules.data).parse[path]
-
- found_module && found_module['url']
+ submodules = GitmodulesParser.new(gitmodules.data).parse
+ submodules.transform_values { |submodule| submodule['url'] }
end
# Returns true if the given ref name exists
diff --git a/lib/gitlab/graphql/representation/submodule_tree_entry.rb b/lib/gitlab/graphql/representation/submodule_tree_entry.rb
new file mode 100644
index 00000000000..65716dff75d
--- /dev/null
+++ b/lib/gitlab/graphql/representation/submodule_tree_entry.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module Representation
+ class SubmoduleTreeEntry < SimpleDelegator
+ class << self
+ def decorate(submodules, tree)
+ repository = tree.repository
+ submodule_links = Gitlab::SubmoduleLinks.new(repository)
+
+ submodules.map do |submodule|
+ self.new(submodule, submodule_links.for(submodule, tree.sha))
+ end
+ end
+ end
+
+ def initialize(submodule, submodule_links)
+ @submodule_links = submodule_links
+
+ super(submodule)
+ end
+
+ def web_url
+ @submodule_links.first
+ end
+
+ def tree_url
+ @submodule_links.last
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/submodule_links.rb b/lib/gitlab/submodule_links.rb
new file mode 100644
index 00000000000..a6c0369d864
--- /dev/null
+++ b/lib/gitlab/submodule_links.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class SubmoduleLinks
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(repository)
+ @repository = repository
+ end
+
+ def for(submodule, sha)
+ submodule_url = submodule_url_for(sha)[submodule.path]
+ SubmoduleHelper.submodule_links_for_url(submodule.id, submodule_url, repository)
+ end
+
+ private
+
+ attr_reader :repository
+
+ def submodule_url_for(sha)
+ strong_memoize(:"submodule_links_for_#{sha}") do
+ repository.submodule_urls_for(sha)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/zoom_link_extractor.rb b/lib/gitlab/zoom_link_extractor.rb
new file mode 100644
index 00000000000..d9994898a08
--- /dev/null
+++ b/lib/gitlab/zoom_link_extractor.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# Detect links matching the following formats:
+# Zoom Start links: https://zoom.us/s/<meeting-id>
+# Zoom Join links: https://zoom.us/j/<meeting-id>
+# Personal Zoom links: https://zoom.us/my/<meeting-id>
+# Vanity Zoom links: https://gitlab.zoom.us/j/<meeting-id> (also /s and /my)
+
+module Gitlab
+ class ZoomLinkExtractor
+ ZOOM_REGEXP = %r{https://(?:[\w-]+\.)?zoom\.us/(?:s|j|my)/\S+}.freeze
+
+ def initialize(text)
+ @text = text.to_s
+ end
+
+ def links
+ @text.scan(ZOOM_REGEXP)
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/features.rake b/lib/tasks/gitlab/features.rake
index d88bcca0819..9cf568c07fe 100644
--- a/lib/tasks/gitlab/features.rake
+++ b/lib/tasks/gitlab/features.rake
@@ -10,14 +10,22 @@ namespace :gitlab do
set_rugged_feature_flags(false)
puts 'All Rugged feature flags were disabled.'
end
+
+ task unset_rugged: :environment do
+ set_rugged_feature_flags(nil)
+ puts 'All Rugged feature flags were unset.'
+ end
end
def set_rugged_feature_flags(status)
Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS.each do |flag|
- if status
- Feature.enable(flag)
- else
+ case status
+ when nil
Feature.get(flag).remove
+ when true
+ Feature.enable(flag)
+ when false
+ Feature.disable(flag)
end
end
end