Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
188f99dcc3
commit
2bfa43cf3a
|
@ -206,13 +206,6 @@ Layout/HashAlignment:
|
|||
- 'app/uploaders/file_uploader.rb'
|
||||
- 'app/workers/emails_on_push_worker.rb'
|
||||
- 'app/workers/x509_issuer_crl_check_worker.rb'
|
||||
- 'config/initializers/1_settings.rb'
|
||||
- 'config/initializers/default_url_options.rb'
|
||||
- 'config/initializers/rest-client-hostname_override.rb'
|
||||
- 'config/routes/profile.rb'
|
||||
- 'config/routes/project.rb'
|
||||
- 'config/routes/unmatched_project.rb'
|
||||
- 'config/routes/uploads.rb'
|
||||
- 'db/migrate/20210601080039_group_protected_environments_add_index_and_constraint.rb'
|
||||
- 'db/migrate/20210804150320_create_base_work_item_types.rb'
|
||||
- 'db/migrate/20210831203408_upsert_base_work_item_types.rb'
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
---
|
||||
# Cop supports --auto-correct.
|
||||
Performance/ConstantRegexp:
|
||||
Exclude:
|
||||
- 'app/models/commit.rb'
|
||||
- 'app/models/commit_range.rb'
|
||||
- 'app/models/custom_emoji.rb'
|
||||
- 'app/models/gpg_key.rb'
|
||||
- 'app/models/merge_request.rb'
|
||||
- 'app/models/packages/package.rb'
|
||||
- 'app/models/project.rb'
|
||||
- 'app/models/wiki.rb'
|
||||
- 'ee/app/models/ee/epic.rb'
|
||||
- 'lib/banzai/filter/custom_emoji_filter.rb'
|
||||
- 'lib/gitlab/cleanup/project_uploads.rb'
|
||||
- 'lib/gitlab/database/reindexing/reindex_concurrently.rb'
|
||||
- 'lib/gitlab/dependency_linker/base_linker.rb'
|
||||
- 'lib/gitlab/dependency_linker/composer_json_linker.rb'
|
||||
- 'lib/gitlab/dependency_linker/godeps_json_linker.rb'
|
||||
- 'lib/gitlab/dependency_linker/podspec_linker.rb'
|
||||
- 'lib/gitlab/git.rb'
|
||||
- 'lib/gitlab/job_waiter.rb'
|
||||
- 'lib/gitlab/metrics/dashboard/url.rb'
|
||||
- 'lib/gitlab/path_regex.rb'
|
||||
- 'lib/gitlab/regex.rb'
|
||||
- 'scripts/perf/query_limiting_report.rb'
|
||||
- 'scripts/validate_migration_schema'
|
||||
- 'spec/features/users/email_verification_on_login_spec.rb'
|
||||
- 'spec/models/concerns/token_authenticatable_spec.rb'
|
||||
- 'spec/services/notes/copy_service_spec.rb'
|
|
@ -16,12 +16,9 @@ import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.
|
|||
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
VISIBILITY_TYPE_ICON,
|
||||
GROUP_VISIBILITY_TYPE,
|
||||
ITEM_TYPE,
|
||||
VISIBILITY_PRIVATE,
|
||||
} from '../constants';
|
||||
import { VISIBILITY_LEVELS_ENUM } from '~/visibility_level/constants';
|
||||
import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE, ITEM_TYPE } from '../constants';
|
||||
|
||||
import eventHub from '../event_hub';
|
||||
|
||||
import itemActions from './item_actions.vue';
|
||||
|
@ -114,8 +111,8 @@ export default {
|
|||
shouldShowVisibilityWarning() {
|
||||
return (
|
||||
this.action === 'shared' &&
|
||||
this.currentGroupVisibility === VISIBILITY_PRIVATE &&
|
||||
this.group.visibility !== VISIBILITY_PRIVATE
|
||||
VISIBILITY_LEVELS_ENUM[this.group.visibility] >
|
||||
VISIBILITY_LEVELS_ENUM[this.currentGroupVisibility]
|
||||
);
|
||||
},
|
||||
},
|
||||
|
@ -142,7 +139,7 @@ export default {
|
|||
shareProjectsWithGroupsHelpPagePath: helpPagePath(
|
||||
'user/project/members/share_project_with_groups',
|
||||
{
|
||||
anchor: 'share-a-public-project-with-private-group',
|
||||
anchor: 'sharing-projects-with-groups-of-a-higher-restrictive-visibility-level',
|
||||
},
|
||||
),
|
||||
safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
import {
|
||||
VISIBILITY_LEVEL_PRIVATE,
|
||||
VISIBILITY_LEVEL_INTERNAL,
|
||||
VISIBILITY_LEVEL_PUBLIC,
|
||||
} from '~/visibility_level/constants';
|
||||
|
||||
export const MAX_CHILDREN_COUNT = 20;
|
||||
|
||||
|
@ -28,32 +33,30 @@ export const ITEM_TYPE = {
|
|||
GROUP: 'group',
|
||||
};
|
||||
|
||||
export const VISIBILITY_PUBLIC = 'public';
|
||||
export const VISIBILITY_INTERNAL = 'internal';
|
||||
export const VISIBILITY_PRIVATE = 'private';
|
||||
|
||||
export const GROUP_VISIBILITY_TYPE = {
|
||||
[VISIBILITY_PUBLIC]: __(
|
||||
[VISIBILITY_LEVEL_PUBLIC]: __(
|
||||
'Public - The group and any public projects can be viewed without any authentication.',
|
||||
),
|
||||
[VISIBILITY_INTERNAL]: __(
|
||||
[VISIBILITY_LEVEL_INTERNAL]: __(
|
||||
'Internal - The group and any internal projects can be viewed by any logged in user except external users.',
|
||||
),
|
||||
[VISIBILITY_PRIVATE]: __('Private - The group and its projects can only be viewed by members.'),
|
||||
[VISIBILITY_LEVEL_PRIVATE]: __(
|
||||
'Private - The group and its projects can only be viewed by members.',
|
||||
),
|
||||
};
|
||||
|
||||
export const PROJECT_VISIBILITY_TYPE = {
|
||||
[VISIBILITY_PUBLIC]: __('Public - The project can be accessed without any authentication.'),
|
||||
[VISIBILITY_INTERNAL]: __(
|
||||
[VISIBILITY_LEVEL_PUBLIC]: __('Public - The project can be accessed without any authentication.'),
|
||||
[VISIBILITY_LEVEL_INTERNAL]: __(
|
||||
'Internal - The project can be accessed by any logged in user except external users.',
|
||||
),
|
||||
[VISIBILITY_PRIVATE]: __(
|
||||
[VISIBILITY_LEVEL_PRIVATE]: __(
|
||||
'Private - Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.',
|
||||
),
|
||||
};
|
||||
|
||||
export const VISIBILITY_TYPE_ICON = {
|
||||
[VISIBILITY_PUBLIC]: 'earth',
|
||||
[VISIBILITY_INTERNAL]: 'shield',
|
||||
[VISIBILITY_PRIVATE]: 'lock',
|
||||
[VISIBILITY_LEVEL_PUBLIC]: 'earth',
|
||||
[VISIBILITY_LEVEL_INTERNAL]: 'shield',
|
||||
[VISIBILITY_LEVEL_PRIVATE]: 'lock',
|
||||
};
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
export const VISIBILITY_LEVEL_PRIVATE = 'private';
|
||||
export const VISIBILITY_LEVEL_INTERNAL = 'internal';
|
||||
export const VISIBILITY_LEVEL_PUBLIC = 'public';
|
||||
|
||||
// Matches `lib/gitlab/visibility_level.rb`
|
||||
export const VISIBILITY_LEVELS_ENUM = {
|
||||
[VISIBILITY_LEVEL_PRIVATE]: 0,
|
||||
[VISIBILITY_LEVEL_INTERNAL]: 10,
|
||||
[VISIBILITY_LEVEL_PUBLIC]: 20,
|
||||
};
|
|
@ -190,7 +190,7 @@ class Commit
|
|||
|
||||
def self.link_reference_pattern
|
||||
@link_reference_pattern ||=
|
||||
super("commit", /(?<commit>#{COMMIT_SHA_PATTERN})?(\.(?<extension>#{LINK_EXTENSION_PATTERN}))?/)
|
||||
super("commit", /(?<commit>#{COMMIT_SHA_PATTERN})?(\.(?<extension>#{LINK_EXTENSION_PATTERN}))?/o)
|
||||
end
|
||||
|
||||
def to_reference(from = nil, full: false)
|
||||
|
|
|
@ -50,7 +50,7 @@ class CommitRange
|
|||
end
|
||||
|
||||
def self.link_reference_pattern
|
||||
@link_reference_pattern ||= super("compare", /(?<commit_range>#{PATTERN})/)
|
||||
@link_reference_pattern ||= super("compare", /(?<commit_range>#{PATTERN})/o)
|
||||
end
|
||||
|
||||
# Initialize a CommitRange
|
||||
|
@ -64,7 +64,7 @@ class CommitRange
|
|||
|
||||
range_string = range_string.strip
|
||||
|
||||
unless range_string =~ /\A#{PATTERN}\z/
|
||||
unless range_string =~ /\A#{PATTERN}\z/o
|
||||
raise ArgumentError, "invalid CommitRange string format: #{range_string}"
|
||||
end
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class CustomEmoji < ApplicationRecord
|
|||
presence: true,
|
||||
length: { maximum: 36 },
|
||||
|
||||
format: { with: /\A#{NAME_REGEXP}\z/ }
|
||||
format: { with: /\A#{NAME_REGEXP}\z/o }
|
||||
|
||||
scope :by_name, -> (names) { where(name: names) }
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class GpgKey < ApplicationRecord
|
|||
presence: true,
|
||||
uniqueness: true,
|
||||
format: {
|
||||
with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX})(?!#{KEY_SUFFIX}).)+#{KEY_SUFFIX}\Z/m,
|
||||
with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX})(?!#{KEY_SUFFIX}).)+#{KEY_SUFFIX}\Z/mo,
|
||||
message: "is invalid. A valid public GPG key begins with '#{KEY_PREFIX}' and ends with '#{KEY_SUFFIX}'"
|
||||
}
|
||||
|
||||
|
|
|
@ -1500,7 +1500,7 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
|
||||
def self.merge_train_ref?(ref)
|
||||
%r{\Arefs/#{Repository::REF_MERGE_REQUEST}/\d+/train\z}.match?(ref)
|
||||
%r{\Arefs/#{Repository::REF_MERGE_REQUEST}/\d+/train\z}o.match?(ref)
|
||||
end
|
||||
|
||||
def in_locked_state
|
||||
|
|
|
@ -327,7 +327,7 @@ class Packages::Package < ApplicationRecord
|
|||
def normalized_pypi_name
|
||||
return name unless pypi?
|
||||
|
||||
name.gsub(/#{Gitlab::Regex::Packages::PYPI_NORMALIZED_NAME_REGEX_STRING}/, '-').downcase
|
||||
name.gsub(/#{Gitlab::Regex::Packages::PYPI_NORMALIZED_NAME_REGEX_STRING}/o, '-').downcase
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -814,7 +814,7 @@ class Project < ApplicationRecord
|
|||
(?<!#{Gitlab::PathRegex::PATH_START_CHAR})
|
||||
((?<namespace>#{Gitlab::PathRegex::FULL_NAMESPACE_FORMAT_REGEX})\/)?
|
||||
(?<project>#{Gitlab::PathRegex::PROJECT_PATH_FORMAT_REGEX})
|
||||
}x
|
||||
}xo
|
||||
end
|
||||
|
||||
def reference_postfix
|
||||
|
|
|
@ -335,7 +335,7 @@ class Wiki
|
|||
end
|
||||
|
||||
def wiki_base_path
|
||||
web_url(only_path: true).sub(%r{/#{Wiki::HOMEPAGE}\z}, '')
|
||||
web_url(only_path: true).sub(%r{/#{Wiki::HOMEPAGE}\z}o, '')
|
||||
end
|
||||
|
||||
# Callbacks for synchronous processing after wiki changes.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -136,9 +136,9 @@ if github_settings
|
|||
OmniAuth::Strategies::GitHub.default_options[:client_options]
|
||||
else
|
||||
{
|
||||
"site" => File.join(github_settings["url"], "api/v3"),
|
||||
"site" => File.join(github_settings["url"], "api/v3"),
|
||||
"authorize_url" => File.join(github_settings["url"], "login/oauth/authorize"),
|
||||
"token_url" => File.join(github_settings["url"], "login/oauth/access_token")
|
||||
"token_url" => File.join(github_settings["url"], "login/oauth/access_token")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
default_url_options = {
|
||||
host: Gitlab.config.gitlab.host,
|
||||
protocol: Gitlab.config.gitlab.protocol,
|
||||
host: Gitlab.config.gitlab.host,
|
||||
protocol: Gitlab.config.gitlab.protocol,
|
||||
script_name: Gitlab.config.gitlab.relative_url_root
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ module RestClient
|
|||
def transmit(uri, req, payload, &block)
|
||||
begin
|
||||
ip, hostname_override = Gitlab::UrlBlocker.validate!(uri, allow_local_network: allow_settings_local_requests?,
|
||||
allow_localhost: allow_settings_local_requests?,
|
||||
dns_rebind_protection: dns_rebind_protection?)
|
||||
allow_localhost: allow_settings_local_requests?,
|
||||
dns_rebind_protection: dns_rebind_protection?)
|
||||
|
||||
self.hostname_override = hostname_override
|
||||
rescue Gitlab::UrlBlocker::BlockedUrlError => e
|
||||
|
|
|
@ -23,10 +23,10 @@ resource :profile, only: [:show, :update] do
|
|||
|
||||
resource :notifications, only: [:show, :update] do
|
||||
scope(path: 'groups/*id',
|
||||
id: Gitlab::PathRegex.full_namespace_route_regex,
|
||||
as: :group,
|
||||
controller: :groups,
|
||||
constraints: { format: /(html|json)/ }) do
|
||||
id: Gitlab::PathRegex.full_namespace_route_regex,
|
||||
as: :group,
|
||||
controller: :groups,
|
||||
constraints: { format: /(html|json)/ }) do
|
||||
patch '/', action: :update
|
||||
put '/', action: :update
|
||||
end
|
||||
|
|
|
@ -29,7 +29,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
# "Route Globbing" syntax (/*page) so that the route helpers do not encode
|
||||
# the slash character.
|
||||
get 'metrics(/:dashboard_path)(/*page)', constraints: { dashboard_path: /.+\.yml/, page: 'panel/new' },
|
||||
to: 'metrics_dashboard#show', as: :metrics_dashboard, format: false
|
||||
to: 'metrics_dashboard#show', as: :metrics_dashboard, format: false
|
||||
|
||||
namespace :metrics, module: :metrics do
|
||||
namespace :dashboards do
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
scope(path: '*namespace_id',
|
||||
as: :namespace,
|
||||
namespace_id: Gitlab::PathRegex.full_namespace_route_regex) do
|
||||
as: :namespace,
|
||||
namespace_id: Gitlab::PathRegex.full_namespace_route_regex) do
|
||||
scope(path: ':project_id',
|
||||
constraints: { project_id: Gitlab::PathRegex.project_route_regex },
|
||||
as: :project) do
|
||||
constraints: { project_id: Gitlab::PathRegex.project_route_regex },
|
||||
as: :project) do
|
||||
post '*all', to: 'application#route_not_found'
|
||||
put '*all', to: 'application#route_not_found'
|
||||
patch '*all', to: 'application#route_not_found'
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
scope path: :uploads do
|
||||
# Note attachments and User/Group/Project/Topic avatars
|
||||
get "-/system/:model/:mounted_as/:id/:filename",
|
||||
to: "uploads#show",
|
||||
constraints: { model: %r{note|user|group|project|projects\/topic}, mounted_as: /avatar|attachment/, filename: %r{[^/]+} }
|
||||
to: "uploads#show",
|
||||
constraints: { model: %r{note|user|group|project|projects\/topic}, mounted_as: /avatar|attachment/, filename: %r{[^/]+} }
|
||||
|
||||
# show uploads for models, snippets (notes) available for now
|
||||
get '-/system/:model/:id/:secret/:filename',
|
||||
|
@ -18,8 +18,8 @@ scope path: :uploads do
|
|||
|
||||
# Appearance
|
||||
get "-/system/:model/:mounted_as/:id/:filename",
|
||||
to: "uploads#show",
|
||||
constraints: { model: /appearance/, mounted_as: /logo|header_logo|favicon/, filename: /.+/ },
|
||||
to: "uploads#show",
|
||||
constraints: { model: /appearance/, mounted_as: /logo|header_logo|favicon/, filename: /.+/ },
|
||||
as: 'appearance_upload'
|
||||
|
||||
# Project markdown uploads
|
||||
|
@ -27,7 +27,7 @@ scope path: :uploads do
|
|||
# https://gitlab.com/gitlab-org/gitlab/issues/196396
|
||||
get ":namespace_id/:project_id/:secret/:filename",
|
||||
to: redirect("%{namespace_id}/%{project_id}/uploads/%{secret}/%{filename}"),
|
||||
constraints: { namespace_id: /[a-zA-Z.0-9_\-]+/, project_id: /[a-zA-Z.0-9_\-]+/, filename: %r{[^/]+} }, format: false, defaults: { format: nil }
|
||||
constraints: { namespace_id: /[a-zA-Z.0-9_\-]+/, project_id: /[a-zA-Z.0-9_\-]+/, filename: %r{[^/]+} }, format: false, defaults: { format: nil }
|
||||
|
||||
# create uploads for models, snippets (notes) available for now
|
||||
post ':model',
|
||||
|
@ -41,12 +41,12 @@ scope path: :uploads do
|
|||
|
||||
# Alert Metric Images
|
||||
get "-/system/:model/:mounted_as/:id/:filename",
|
||||
to: "uploads#show",
|
||||
constraints: { model: /alert_management_metric_image/, mounted_as: /file/, filename: %r{[^/]+} },
|
||||
to: "uploads#show",
|
||||
constraints: { model: /alert_management_metric_image/, mounted_as: /file/, filename: %r{[^/]+} },
|
||||
as: 'alert_metric_image_upload'
|
||||
end
|
||||
|
||||
# Redirect old note attachments path to new uploads path.
|
||||
get "files/note/:id/:filename",
|
||||
to: redirect("uploads/note/attachment/%{id}/%{filename}"),
|
||||
constraints: { filename: %r{[^/]+} }
|
||||
to: redirect("uploads/note/attachment/%{id}/%{filename}"),
|
||||
constraints: { filename: %r{[^/]+} }
|
||||
|
|
|
@ -52,7 +52,7 @@ After sharing 'Project Acme' with 'Engineering':
|
|||
When you share a project, be aware of the following restrictions and outcomes:
|
||||
|
||||
- [Maximum access level](#maximum-access-level)
|
||||
- [Sharing a public project with a private group](#share-a-public-project-with-private-group)
|
||||
- [Sharing projects with groups of a higher restrictive visibility level](#sharing-projects-with-groups-of-a-higher-restrictive-visibility-level)
|
||||
- [Sharing project with group lock](#share-project-with-group-lock)
|
||||
|
||||
## Maximum access level
|
||||
|
@ -67,13 +67,19 @@ in. That means you can only share down the hierarchy. For example, `group/subgro
|
|||
- Can not be shared with `group`.
|
||||
- Can be shared with `group/subgroup02` or `group/subgroup01/subgroup03`.
|
||||
|
||||
## Share a public project with private group
|
||||
## Sharing projects with groups of a higher restrictive visibility level
|
||||
|
||||
When you share a public project with a private group, be aware of the following outcomes:
|
||||
There are several outcomes you must be aware of when you share a project with a group that has a more restrictive [visibility level](../../public_access.md#project-and-group-visibility) than the project. For example, when you:
|
||||
|
||||
- The name of the group is no longer private and is visible to all users in the project members page.
|
||||
- Owners of the project have access to members of the private group when they mention them in issues or merge requests.
|
||||
- Project members who are direct or indirect members of the private group can see private group members listed in addition to members of the project.
|
||||
- Share a public project with a private group.
|
||||
- Share a public project with an internal group.
|
||||
- Share an internal project with a private group.
|
||||
|
||||
The following outcomes occur:
|
||||
|
||||
- The group name is visible to all users that can view the project members page.
|
||||
- Owners of the project have access to members of the group when they mention them in issues or merge requests.
|
||||
- Project members who are direct or indirect members of the group can see group members listed in addition to members of the project.
|
||||
|
||||
## Share project with group lock
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ module Banzai
|
|||
@emoji_pattern ||=
|
||||
/(?<=[^[:alnum:]:]|\n|^)
|
||||
:(#{CustomEmoji::NAME_REGEXP}):
|
||||
(?=[^[:alnum:]:]|$)/x
|
||||
(?=[^[:alnum:]:]|$)/xo
|
||||
end
|
||||
|
||||
def custom_emoji_name_element_filter(text)
|
||||
|
@ -58,7 +58,7 @@ module Banzai
|
|||
end
|
||||
|
||||
def custom_emoji_candidates
|
||||
doc.to_html.scan(/:(#{CustomEmoji::NAME_REGEXP}):/).flatten
|
||||
doc.to_html.scan(/:(#{CustomEmoji::NAME_REGEXP}):/o).flatten
|
||||
end
|
||||
|
||||
def all_custom_emoji
|
||||
|
|
|
@ -16,7 +16,7 @@ module Gitlab
|
|||
def parse!
|
||||
@data = Gitlab::Json.parse(json_data)
|
||||
|
||||
return unless supported_spec_version?
|
||||
return unless valid?
|
||||
|
||||
parse_components
|
||||
rescue JSON::ParserError => e
|
||||
|
@ -27,6 +27,14 @@ module Gitlab
|
|||
|
||||
attr_reader :json_data, :report, :data
|
||||
|
||||
def schema_validator
|
||||
@schema_validator ||= Validators::CyclonedxSchemaValidator.new(data)
|
||||
end
|
||||
|
||||
def valid?
|
||||
valid_schema? && supported_spec_version?
|
||||
end
|
||||
|
||||
def supported_spec_version?
|
||||
return true if SUPPORTED_SPEC_VERSIONS.include?(data['specVersion'])
|
||||
|
||||
|
@ -38,6 +46,14 @@ module Gitlab
|
|||
false
|
||||
end
|
||||
|
||||
def valid_schema?
|
||||
return true if schema_validator.valid?
|
||||
|
||||
schema_validator.errors.each { |error| report.add_error(error) }
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def parse_components
|
||||
data['components']&.each do |component|
|
||||
next unless supported_component_type?(component['type'])
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Parsers
|
||||
module Sbom
|
||||
module Validators
|
||||
class CyclonedxSchemaValidator
|
||||
SCHEMA_PATH = Rails.root.join('app', 'validators', 'json_schemas', 'cyclonedx_report.json').freeze
|
||||
|
||||
def initialize(report_data)
|
||||
@report_data = report_data
|
||||
end
|
||||
|
||||
def valid?
|
||||
errors.empty?
|
||||
end
|
||||
|
||||
def errors
|
||||
@errors ||= pretty_errors
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def raw_errors
|
||||
JSONSchemer.schema(SCHEMA_PATH).validate(@report_data)
|
||||
end
|
||||
|
||||
def pretty_errors
|
||||
raw_errors.map { |error| JSONSchemer::Errors.pretty(error) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -56,7 +56,7 @@ module Gitlab
|
|||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def move_to_lost_and_found(path, dry_run)
|
||||
new_path = path.sub(/\A#{ProjectUploadFileFinder::ABSOLUTE_UPLOAD_DIR}/, LOST_AND_FOUND)
|
||||
new_path = path.sub(/\A#{ProjectUploadFileFinder::ABSOLUTE_UPLOAD_DIR}/o, LOST_AND_FOUND)
|
||||
|
||||
move(path, new_path, 'move to lost and found', dry_run)
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ module Gitlab
|
|||
|
||||
def perform
|
||||
raise ReindexError, 'indexes serving an exclusion constraint are currently not supported' if index.exclusion?
|
||||
raise ReindexError, 'index is a left-over temporary index from a previous reindexing run' if index.name =~ /#{TEMPORARY_INDEX_PATTERN}/
|
||||
raise ReindexError, 'index is a left-over temporary index from a previous reindexing run' if index.name =~ /#{TEMPORARY_INDEX_PATTERN}/o
|
||||
|
||||
# Expression indexes require additional statistics in `pg_statistic`:
|
||||
# select * from pg_statistic where starelid = (select oid from pg_class where relname = 'some_index');
|
||||
|
@ -81,10 +81,10 @@ module Gitlab
|
|||
# Example lingering index name: some_index_ccnew1
|
||||
|
||||
# Example prefix: 'some_index'
|
||||
prefix = lingering_index.name.gsub(/#{TEMPORARY_INDEX_PATTERN}/, '')
|
||||
prefix = lingering_index.name.gsub(/#{TEMPORARY_INDEX_PATTERN}/o, '')
|
||||
|
||||
# Example suffix: '_ccnew1'
|
||||
suffix = lingering_index.name.match(/#{TEMPORARY_INDEX_PATTERN}/)[0]
|
||||
suffix = lingering_index.name.match(/#{TEMPORARY_INDEX_PATTERN}/o)[0]
|
||||
|
||||
# Only remove if the lingering index name could have been chosen
|
||||
# as a result of a REINDEX operation (considering that PostgreSQL
|
||||
|
|
|
@ -34,9 +34,9 @@ module Gitlab
|
|||
return if external_ref =~ GIT_INVALID_URL_REGEX
|
||||
|
||||
case external_ref
|
||||
when /\A#{URL_REGEX}\z/
|
||||
when /\A#{URL_REGEX}\z/o
|
||||
external_ref
|
||||
when /\A#{REPO_REGEX}\z/
|
||||
when /\A#{REPO_REGEX}\z/o
|
||||
github_url(external_ref)
|
||||
else
|
||||
package_url(name)
|
||||
|
|
|
@ -13,7 +13,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def package_url(name)
|
||||
"https://packagist.org/packages/#{name}" if name =~ /\A#{REPO_REGEX}\z/
|
||||
"https://packagist.org/packages/#{name}" if name =~ /\A#{REPO_REGEX}\z/o
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,10 +12,10 @@ module Gitlab
|
|||
def link_dependencies
|
||||
link_json('ImportPath') do |path|
|
||||
case path
|
||||
when %r{\A(?<repo>github\.com/#{REPO_REGEX})/(?<path>.+)\z}
|
||||
when %r{\A(?<repo>github\.com/#{REPO_REGEX})/(?<path>.+)\z}o
|
||||
"https://#{$~[:repo]}/tree/master/#{$~[:path]}"
|
||||
when %r{\A(?<repo>gitlab\.com/#{NESTED_REPO_REGEX})\.git/(?<path>.+)\z},
|
||||
%r{\A(?<repo>gitlab\.com/#{REPO_REGEX})/(?<path>.+)\z}
|
||||
when %r{\A(?<repo>gitlab\.com/#{NESTED_REPO_REGEX})\.git/(?<path>.+)\z}o,
|
||||
%r{\A(?<repo>gitlab\.com/#{REPO_REGEX})/(?<path>.+)\z}o
|
||||
|
||||
"https://#{$~[:repo]}/-/tree/master/#{$~[:path]}"
|
||||
when /\Agolang\.org/
|
||||
|
|
|
@ -14,10 +14,10 @@ module Gitlab
|
|||
def link_dependencies
|
||||
link_method_call('homepage', URL_REGEX, &:itself)
|
||||
|
||||
link_regex(/(git:|:git\s*=>)\s*['"](?<name>#{URL_REGEX})['"]/, &:itself)
|
||||
link_regex(/(git:|:git\s*=>)\s*['"](?<name>#{URL_REGEX})['"]/o, &:itself)
|
||||
|
||||
link_method_call('license', &method(:license_url))
|
||||
link_regex(/license\s*=\s*\{\s*(type:|:type\s*=>)\s*#{STRING_REGEX}/, &method(:license_url))
|
||||
link_regex(/license\s*=\s*\{\s*(type:|:type\s*=>)\s*#{STRING_REGEX}/o, &method(:license_url))
|
||||
|
||||
link_method_call('dependency', &method(:package_url))
|
||||
end
|
||||
|
|
|
@ -47,11 +47,11 @@ module Gitlab
|
|||
end
|
||||
|
||||
def tag_ref?(ref)
|
||||
ref =~ /^#{TAG_REF_PREFIX}.+/
|
||||
ref =~ /^#{TAG_REF_PREFIX}.+/o
|
||||
end
|
||||
|
||||
def branch_ref?(ref)
|
||||
ref =~ /^#{BRANCH_REF_PREFIX}.+/
|
||||
ref =~ /^#{BRANCH_REF_PREFIX}.+/o
|
||||
end
|
||||
|
||||
def blank_ref?(ref)
|
||||
|
|
|
@ -35,7 +35,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def self.key?(key)
|
||||
key.is_a?(String) && key =~ /\A#{KEY_PREFIX}:\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/
|
||||
key.is_a?(String) && key =~ /\A#{KEY_PREFIX}:\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/o
|
||||
end
|
||||
|
||||
attr_reader :key, :finished, :worker_label
|
||||
|
|
|
@ -42,7 +42,7 @@ module Gitlab
|
|||
#{DASH_PATTERN}?
|
||||
/grafana
|
||||
/metrics_dashboard
|
||||
}x
|
||||
}xo
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -64,7 +64,7 @@ module Gitlab
|
|||
/(?<cluster_id>\d+)
|
||||
/?
|
||||
( (/metrics) | ( /metrics_dashboard\.json ) )?
|
||||
}x
|
||||
}xo
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -82,7 +82,7 @@ module Gitlab
|
|||
/alerts
|
||||
/(?<alert>\d+)
|
||||
/metrics_dashboard(\.json)?
|
||||
}x
|
||||
}xo
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -112,7 +112,7 @@ module Gitlab
|
|||
/environments
|
||||
/(?<environment>\d+)
|
||||
/(metrics_dashboard|metrics)
|
||||
}x
|
||||
}xo
|
||||
end
|
||||
|
||||
def non_environment_metrics_regex
|
||||
|
@ -125,7 +125,7 @@ module Gitlab
|
|||
environment=(?<environment>\d+)
|
||||
.*
|
||||
)
|
||||
}x
|
||||
}xo
|
||||
end
|
||||
|
||||
def regex_for_project_metrics(path_suffix_pattern)
|
||||
|
|
|
@ -204,7 +204,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def namespace_format_regex
|
||||
@namespace_format_regex ||= /\A#{NAMESPACE_FORMAT_REGEX}\z/.freeze
|
||||
@namespace_format_regex ||= /\A#{NAMESPACE_FORMAT_REGEX}\z/o.freeze
|
||||
end
|
||||
|
||||
def namespace_format_message
|
||||
|
@ -213,7 +213,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def project_path_format_regex
|
||||
@project_path_format_regex ||= /\A#{PROJECT_PATH_FORMAT_REGEX}\z/.freeze
|
||||
@project_path_format_regex ||= /\A#{PROJECT_PATH_FORMAT_REGEX}\z/o.freeze
|
||||
end
|
||||
|
||||
def project_path_format_message
|
||||
|
|
|
@ -70,7 +70,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def npm_package_name_regex
|
||||
@npm_package_name_regex ||= %r{\A(?:@(#{Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX})/)?[-+\.\_a-zA-Z0-9]+\z}
|
||||
@npm_package_name_regex ||= %r{\A(?:@(#{Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX})/)?[-+\.\_a-zA-Z0-9]+\z}o
|
||||
end
|
||||
|
||||
def nuget_package_name_regex
|
||||
|
@ -128,15 +128,15 @@ module Gitlab
|
|||
def debian_architecture_regex
|
||||
# See official parser: https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/arch.c?id=9e0c88ec09475f4d1addde9cdba1ad7849720356#n43
|
||||
# But we limit to lower case
|
||||
@debian_architecture_regex ||= %r{\A#{::Packages::Debian::ARCHITECTURE_REGEX}\z}.freeze
|
||||
@debian_architecture_regex ||= %r{\A#{::Packages::Debian::ARCHITECTURE_REGEX}\z}o.freeze
|
||||
end
|
||||
|
||||
def debian_distribution_regex
|
||||
@debian_distribution_regex ||= %r{\A#{::Packages::Debian::DISTRIBUTION_REGEX}\z}i.freeze
|
||||
@debian_distribution_regex ||= %r{\A#{::Packages::Debian::DISTRIBUTION_REGEX}\z}io.freeze
|
||||
end
|
||||
|
||||
def debian_component_regex
|
||||
@debian_component_regex ||= %r{\A#{::Packages::Debian::COMPONENT_REGEX}\z}.freeze
|
||||
@debian_component_regex ||= %r{\A#{::Packages::Debian::COMPONENT_REGEX}\z}o.freeze
|
||||
end
|
||||
|
||||
def helm_channel_regex
|
||||
|
|
|
@ -11497,6 +11497,9 @@ msgstr ""
|
|||
msgid "CycleAnalyticsStage|should be under a group"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|%{selectedLabelsCount} selected (%{maxLabels} max)"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|'%{name}' is collecting the data. This can take a few minutes."
|
||||
msgstr ""
|
||||
|
||||
|
@ -11521,6 +11524,9 @@ msgstr ""
|
|||
msgid "CycleAnalytics|Date"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|Display chart filters"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|If you have recently upgraded to GitLab Premium, it can take up to 30 minutes for data to collect and display."
|
||||
msgstr ""
|
||||
|
||||
|
@ -11530,11 +11536,20 @@ msgstr ""
|
|||
msgid "CycleAnalytics|Number of tasks"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|Only %{maxLabels} labels can be selected at this time"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|Project selected"
|
||||
msgid_plural "CycleAnalytics|%d projects selected"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "CycleAnalytics|Select labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|Show"
|
||||
msgstr ""
|
||||
|
||||
msgid "CycleAnalytics|Stage time: %{title}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -36286,9 +36301,6 @@ msgstr ""
|
|||
msgid "Showing version #%{versionNumber}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Shows issues and 1 label for group '%{group_name}' from Nov 1, 2019 to Dec 31, 2019"
|
||||
msgstr ""
|
||||
|
||||
msgid "Shows issues for group '%{group_name}' from Nov 1, 2019 to Dec 31, 2019"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -108,3 +108,5 @@ module QA
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
QA::Flow::Purchase.prepend_mod_with('Flow::Purchase', namespace: QA)
|
||||
|
|
|
@ -9,7 +9,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
let(:target_group) do
|
||||
let!(:target_group) do
|
||||
Resource::Group.fabricate_via_api! do |group|
|
||||
group.path = "target-group-for-transfer_#{SecureRandom.hex(8)}"
|
||||
end
|
||||
|
@ -19,48 +19,39 @@ module QA
|
|||
Resource::Project.fabricate_via_api! do |project|
|
||||
project.group = source_group
|
||||
project.name = 'transfer-project'
|
||||
project.initialize_with_readme = true
|
||||
end
|
||||
end
|
||||
|
||||
let(:edited_readme_content) { 'Here is the edited content.' }
|
||||
let(:readme_content) { 'Here is the edited content.' }
|
||||
|
||||
before do
|
||||
Resource::Repository::Commit.fabricate_via_api! do |commit|
|
||||
commit.project = project
|
||||
commit.add_files([
|
||||
{ file_path: 'README.md', content: readme_content }
|
||||
])
|
||||
end
|
||||
|
||||
Flow::Login.sign_in
|
||||
|
||||
project.visit!
|
||||
|
||||
Page::Project::Show.perform do |project|
|
||||
project.click_file('README.md')
|
||||
end
|
||||
|
||||
Page::File::Show.perform(&:click_edit)
|
||||
|
||||
Page::File::Edit.perform do |file|
|
||||
file.remove_content
|
||||
file.add_content(edited_readme_content)
|
||||
file.commit_changes
|
||||
end
|
||||
end
|
||||
|
||||
it 'user transfers a project between groups',
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347878' do
|
||||
# Retry is needed here as the target group is not avaliable for transfer right away.
|
||||
QA::Support::Retrier.retry_on_exception(reload_page: page) do
|
||||
Page::File::Show.perform(&:go_to_general_settings)
|
||||
Page::File::Show.perform(&:go_to_general_settings)
|
||||
|
||||
Page::Project::Settings::Main.perform(&:expand_advanced_settings)
|
||||
Page::Project::Settings::Main.perform(&:expand_advanced_settings)
|
||||
|
||||
Page::Project::Settings::Advanced.perform do |advanced|
|
||||
advanced.transfer_project!(project.name, target_group.full_path)
|
||||
end
|
||||
Page::Project::Settings::Advanced.perform do |advanced|
|
||||
advanced.transfer_project!(project.name, target_group.full_path)
|
||||
end
|
||||
|
||||
Page::Project::Settings::Main.perform(&:click_project)
|
||||
|
||||
Page::Project::Show.perform do |project|
|
||||
expect(project).to have_breadcrumb(target_group.path)
|
||||
expect(project).to have_readme_content(edited_readme_content)
|
||||
expect(project).to have_readme_content(readme_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -124,7 +124,7 @@ class QueryLimitingReport
|
|||
|
||||
file_lines.each_index do |index|
|
||||
line = file_lines[index]
|
||||
if line =~ /#{CODE_LINES_SEARCH_STRING}/
|
||||
if line =~ /#{CODE_LINES_SEARCH_STRING}/o
|
||||
issue_iid = line.slice(%r{issues/(\d+)\D}, 1)
|
||||
line_number = index + 1
|
||||
code_line = {
|
||||
|
|
|
@ -87,7 +87,7 @@ class MigrationSchemaValidator
|
|||
|
||||
def find_migration_version(filename)
|
||||
file_basename = File.basename(filename)
|
||||
version_match = /\A(?<version>\d{#{VERSION_DIGITS}})_/.match(file_basename)
|
||||
version_match = /\A(?<version>\d{#{VERSION_DIGITS}})_/o.match(file_basename)
|
||||
|
||||
die "#{filename} has an invalid migration version" if version_match.nil?
|
||||
|
||||
|
|
|
@ -97,28 +97,43 @@ RSpec.describe 'Group show page' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when a public project is shared with a private group' do
|
||||
let_it_be(:private_group) { create(:group, :private) }
|
||||
context 'visibility warning popover' do
|
||||
let_it_be(:public_project) { create(:project, :public) }
|
||||
let_it_be(:project_group_link) { create(:project_group_link, group: private_group, project: public_project) }
|
||||
|
||||
before do
|
||||
private_group.add_owner(user)
|
||||
sign_in(user)
|
||||
shared_examples 'it shows warning popover' do
|
||||
it 'shows warning popover', :js do
|
||||
group_to_share_with.add_owner(user)
|
||||
sign_in(user)
|
||||
visit group_path(group_to_share_with)
|
||||
|
||||
click_link _('Shared projects')
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within("[data-testid=\"group-overview-item-#{public_project.id}\"]") do
|
||||
click_button _('Less restrictive visibility')
|
||||
end
|
||||
|
||||
expect(page).to have_content _('Project visibility level is less restrictive than the group settings.')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows warning popover', :js do
|
||||
visit group_path(private_group)
|
||||
|
||||
click_link _('Shared projects')
|
||||
|
||||
wait_for_requests
|
||||
|
||||
page.within("[data-testid=\"group-overview-item-#{public_project.id}\"]") do
|
||||
click_button _('Less restrictive visibility')
|
||||
context 'when a public project is shared with a private group' do
|
||||
let_it_be(:group_to_share_with) { create(:group, :private) }
|
||||
let_it_be(:project_group_link) do
|
||||
create(:project_group_link, group: group_to_share_with, project: public_project)
|
||||
end
|
||||
|
||||
expect(page).to have_content _('Project visibility level is less restrictive than the group settings.')
|
||||
include_examples 'it shows warning popover'
|
||||
end
|
||||
|
||||
context 'when a public project is shared with an internal group' do
|
||||
let_it_be(:group_to_share_with) { create(:group, :internal) }
|
||||
let_it_be(:project_group_link) do
|
||||
create(:project_group_link, group: group_to_share_with, project: public_project)
|
||||
end
|
||||
|
||||
include_examples 'it shows warning popover'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -335,7 +335,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
|
|||
mail = find_email_for(user)
|
||||
expect(mail.to).to match_array([user.email])
|
||||
expect(mail.subject).to eq('Verify your identity')
|
||||
code = mail.body.parts.first.to_s[/\d{#{VerifiesWithEmail::TOKEN_LENGTH}}/]
|
||||
code = mail.body.parts.first.to_s[/\d{#{VerifiesWithEmail::TOKEN_LENGTH}}/o]
|
||||
reset_delivered_emails!
|
||||
code
|
||||
end
|
||||
|
|
|
@ -6,19 +6,20 @@ import ItemActions from '~/groups/components/item_actions.vue';
|
|||
import eventHub from '~/groups/event_hub';
|
||||
import { getGroupItemMicrodata } from '~/groups/store/utils';
|
||||
import * as urlUtilities from '~/lib/utils/url_utility';
|
||||
import { ITEM_TYPE } from '~/groups/constants';
|
||||
import {
|
||||
ITEM_TYPE,
|
||||
VISIBILITY_INTERNAL,
|
||||
VISIBILITY_PRIVATE,
|
||||
VISIBILITY_PUBLIC,
|
||||
} from '~/groups/constants';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
VISIBILITY_LEVEL_PRIVATE,
|
||||
VISIBILITY_LEVEL_INTERNAL,
|
||||
VISIBILITY_LEVEL_PUBLIC,
|
||||
} from '~/visibility_level/constants';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import { mockParentGroupItem, mockChildren } from '../mock_data';
|
||||
|
||||
const createComponent = (
|
||||
propsData = { group: mockParentGroupItem, parentGroup: mockChildren[0] },
|
||||
provide = {
|
||||
currentGroupVisibility: VISIBILITY_PRIVATE,
|
||||
currentGroupVisibility: VISIBILITY_LEVEL_PRIVATE,
|
||||
},
|
||||
) => {
|
||||
return mountExtended(GroupItem, {
|
||||
|
@ -289,7 +290,7 @@ describe('GroupItemComponent', () => {
|
|||
});
|
||||
|
||||
describe('visibility warning popover', () => {
|
||||
const findPopover = () => wrapper.findComponent(GlPopover);
|
||||
const findPopover = () => extendedWrapper(wrapper.findComponent(GlPopover));
|
||||
|
||||
const itDoesNotRenderVisibilityWarningPopover = () => {
|
||||
it('does not render visibility warning popover', () => {
|
||||
|
@ -319,13 +320,16 @@ describe('GroupItemComponent', () => {
|
|||
|
||||
describe('when showing projects', () => {
|
||||
describe.each`
|
||||
itemVisibility | currentGroupVisibility | isPopoverShown
|
||||
${VISIBILITY_PRIVATE} | ${VISIBILITY_PUBLIC} | ${false}
|
||||
${VISIBILITY_INTERNAL} | ${VISIBILITY_PUBLIC} | ${false}
|
||||
${VISIBILITY_PUBLIC} | ${VISIBILITY_PUBLIC} | ${false}
|
||||
${VISIBILITY_PRIVATE} | ${VISIBILITY_PRIVATE} | ${false}
|
||||
${VISIBILITY_INTERNAL} | ${VISIBILITY_PRIVATE} | ${true}
|
||||
${VISIBILITY_PUBLIC} | ${VISIBILITY_PRIVATE} | ${true}
|
||||
itemVisibility | currentGroupVisibility | isPopoverShown
|
||||
${VISIBILITY_LEVEL_PRIVATE} | ${VISIBILITY_LEVEL_PUBLIC} | ${false}
|
||||
${VISIBILITY_LEVEL_INTERNAL} | ${VISIBILITY_LEVEL_PUBLIC} | ${false}
|
||||
${VISIBILITY_LEVEL_PUBLIC} | ${VISIBILITY_LEVEL_PUBLIC} | ${false}
|
||||
${VISIBILITY_LEVEL_PRIVATE} | ${VISIBILITY_LEVEL_PRIVATE} | ${false}
|
||||
${VISIBILITY_LEVEL_INTERNAL} | ${VISIBILITY_LEVEL_PRIVATE} | ${true}
|
||||
${VISIBILITY_LEVEL_PUBLIC} | ${VISIBILITY_LEVEL_PRIVATE} | ${true}
|
||||
${VISIBILITY_LEVEL_PRIVATE} | ${VISIBILITY_LEVEL_INTERNAL} | ${false}
|
||||
${VISIBILITY_LEVEL_INTERNAL} | ${VISIBILITY_LEVEL_INTERNAL} | ${false}
|
||||
${VISIBILITY_LEVEL_PUBLIC} | ${VISIBILITY_LEVEL_INTERNAL} | ${true}
|
||||
`(
|
||||
'when item visibility is $itemVisibility and parent group visibility is $currentGroupVisibility',
|
||||
({ itemVisibility, currentGroupVisibility, isPopoverShown }) => {
|
||||
|
@ -347,8 +351,17 @@ describe('GroupItemComponent', () => {
|
|||
});
|
||||
|
||||
if (isPopoverShown) {
|
||||
it('renders visibility warning popover', () => {
|
||||
expect(findPopover().exists()).toBe(true);
|
||||
it('renders visibility warning popover with `Learn more` link', () => {
|
||||
const popover = findPopover();
|
||||
|
||||
expect(popover.exists()).toBe(true);
|
||||
expect(
|
||||
popover.findByRole('link', { name: GroupItem.i18n.learnMore }).attributes('href'),
|
||||
).toBe(
|
||||
helpPagePath('user/project/members/share_project_with_groups', {
|
||||
anchor: 'sharing-projects-with-groups-of-a-higher-restrictive-visibility-level',
|
||||
}),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
itDoesNotRenderVisibilityWarningPopover();
|
||||
|
@ -361,7 +374,7 @@ describe('GroupItemComponent', () => {
|
|||
wrapper = createComponent({
|
||||
group: {
|
||||
...mockParentGroupItem,
|
||||
visibility: VISIBILITY_PUBLIC,
|
||||
visibility: VISIBILITY_LEVEL_PUBLIC,
|
||||
type: ITEM_TYPE.PROJECT,
|
||||
},
|
||||
parentGroup: mockChildren[0],
|
||||
|
|
|
@ -6,7 +6,7 @@ import GroupItemComponent from '~/groups/components/group_item.vue';
|
|||
import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
|
||||
import GroupsComponent from '~/groups/components/groups.vue';
|
||||
import eventHub from '~/groups/event_hub';
|
||||
import { VISIBILITY_PRIVATE } from '~/groups/constants';
|
||||
import { VISIBILITY_LEVEL_PRIVATE } from '~/visibility_level/constants';
|
||||
import { mockGroups, mockPageInfo } from '../mock_data';
|
||||
|
||||
describe('GroupsComponent', () => {
|
||||
|
@ -26,7 +26,7 @@ describe('GroupsComponent', () => {
|
|||
...propsData,
|
||||
},
|
||||
provide: {
|
||||
currentGroupVisibility: VISIBILITY_PRIVATE,
|
||||
currentGroupVisibility: VISIBILITY_LEVEL_PRIVATE,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -4,7 +4,10 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx do
|
||||
let(:report) { instance_double('Gitlab::Ci::Reports::Sbom::Report') }
|
||||
let(:report_data) { base_report_data }
|
||||
let(:raw_report_data) { report_data.to_json }
|
||||
let(:report_valid?) { true }
|
||||
let(:validator_errors) { [] }
|
||||
|
||||
let(:base_report_data) do
|
||||
{
|
||||
|
@ -16,6 +19,13 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx do
|
|||
|
||||
subject(:parse!) { described_class.new(raw_report_data, report).parse! }
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Gitlab::Ci::Parsers::Sbom::Validators::CyclonedxSchemaValidator) do |validator|
|
||||
allow(validator).to receive(:valid?).and_return(report_valid?)
|
||||
allow(validator).to receive(:errors).and_return(validator_errors)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when report JSON is invalid' do
|
||||
let(:raw_report_data) { '{ ' }
|
||||
|
||||
|
@ -36,9 +46,19 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when cyclonedx report has no components' do
|
||||
let(:report_data) { base_report_data }
|
||||
context 'when report does not conform to the CycloneDX schema' do
|
||||
let(:report_valid?) { false }
|
||||
let(:validator_errors) { %w[error1 error2] }
|
||||
|
||||
it 'reports all errors returned by the validator' do
|
||||
expect(report).to receive(:add_error).with("error1")
|
||||
expect(report).to receive(:add_error).with("error2")
|
||||
|
||||
parse!
|
||||
end
|
||||
end
|
||||
|
||||
context 'when cyclonedx report has no components' do
|
||||
it 'skips component processing' do
|
||||
expect(report).not_to receive(:add_component)
|
||||
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Gitlab::Ci::Parsers::Sbom::Validators::CyclonedxSchemaValidator do
|
||||
# Reports should be valid or invalid according to the specification at
|
||||
# https://cyclonedx.org/docs/1.4/json/
|
||||
|
||||
subject(:validator) { described_class.new(report_data) }
|
||||
|
||||
let_it_be(:required_attributes) do
|
||||
{
|
||||
"bomFormat" => "CycloneDX",
|
||||
"specVersion" => "1.4",
|
||||
"version" => 1
|
||||
}
|
||||
end
|
||||
|
||||
context "with minimally valid report" do
|
||||
let_it_be(:report_data) { required_attributes }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
|
||||
context "when report has components" do
|
||||
let(:report_data) { required_attributes.merge({ "components" => components }) }
|
||||
|
||||
context "with minimally valid components" do
|
||||
let(:components) do
|
||||
[
|
||||
{
|
||||
"type" => "library",
|
||||
"name" => "activesupport"
|
||||
},
|
||||
{
|
||||
"type" => "library",
|
||||
"name" => "byebug"
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
|
||||
context "when components have versions" do
|
||||
let(:components) do
|
||||
[
|
||||
{
|
||||
"type" => "library",
|
||||
"name" => "activesupport",
|
||||
"version" => "5.1.4"
|
||||
},
|
||||
{
|
||||
"type" => "library",
|
||||
"name" => "byebug",
|
||||
"version" => "10.0.0"
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
|
||||
context "when components are not valid" do
|
||||
let(:components) do
|
||||
[
|
||||
{ "type" => "foo" },
|
||||
{ "name" => "activesupport" }
|
||||
]
|
||||
end
|
||||
|
||||
it { is_expected.not_to be_valid }
|
||||
|
||||
it "outputs errors for each validation failure" do
|
||||
expect(validator.errors).to match_array([
|
||||
"property '/components/0' is missing required keys: name",
|
||||
"property '/components/0/type' is not one of: [\"application\", \"framework\"," \
|
||||
" \"library\", \"container\", \"operating-system\", \"device\", \"firmware\", \"file\"]",
|
||||
"property '/components/1' is missing required keys: type"
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when report has metadata" do
|
||||
let(:metadata) do
|
||||
{
|
||||
"timestamp" => "2022-02-23T08:02:39Z",
|
||||
"tools" => [{ "vendor" => "GitLab", "name" => "Gemnasium", "version" => "2.34.0" }],
|
||||
"authors" => [{ "name" => "GitLab", "email" => "support@gitlab.com" }]
|
||||
}
|
||||
end
|
||||
|
||||
let(:report_data) { required_attributes.merge({ "metadata" => metadata }) }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
|
||||
context "when metadata has properties" do
|
||||
before do
|
||||
metadata.merge!({ "properties" => properties })
|
||||
end
|
||||
|
||||
context "when properties are valid" do
|
||||
let(:properties) do
|
||||
[
|
||||
{ "name" => "gitlab:dependency_scanning:input_file", "value" => "Gemfile.lock" },
|
||||
{ "name" => "gitlab:dependency_scanning:package_manager", "value" => "bundler" }
|
||||
]
|
||||
end
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
|
||||
context "when properties are invalid" do
|
||||
let(:properties) do
|
||||
[
|
||||
{ "name" => ["gitlab:meta:schema_version"], "value" => 1 }
|
||||
]
|
||||
end
|
||||
|
||||
it { is_expected.not_to be_valid }
|
||||
|
||||
it "outputs errors for each validation failure" do
|
||||
expect(validator.errors).to match_array([
|
||||
"property '/metadata/properties/0/name' is not of type: string",
|
||||
"property '/metadata/properties/0/value' is not of type: string"
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'fast_spec_helper'
|
||||
require 'test_prof/recipes/rspec/let_it_be'
|
||||
require 'graphql'
|
||||
require_relative '../../../../app/graphql/types/base_scalar'
|
||||
require_relative '../../../../app/graphql/types/global_id_type'
|
||||
require_relative '../../../support/helpers/global_id_deprecation_helpers'
|
||||
|
||||
TestProf::BeforeAll.adapter = Class.new do
|
||||
def begin_transaction; end
|
||||
|
||||
def rollback_transaction; end
|
||||
end.new
|
||||
|
||||
RSpec.describe Gitlab::GlobalId::Deprecations do
|
||||
include GlobalIDDeprecationHelpers
|
||||
|
||||
let_it_be(:deprecation_1) do
|
||||
let(:deprecation_1) do
|
||||
described_class::NameDeprecation.new(old_name: 'Foo::Model', new_name: 'Bar', milestone: '9.0')
|
||||
end
|
||||
|
||||
let_it_be(:deprecation_2) do
|
||||
let(:deprecation_2) do
|
||||
described_class::NameDeprecation.new(old_name: 'Baz', new_name: 'Qux::Model', milestone: '10.0')
|
||||
end
|
||||
|
||||
|
|
|
@ -442,7 +442,7 @@ RSpec.shared_examples 'prefixed token rotation' do
|
|||
|
||||
context 'token is not set' do
|
||||
it 'generates a new token' do
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/)
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/o)
|
||||
expect(instance).not_to be_persisted
|
||||
end
|
||||
end
|
||||
|
@ -453,7 +453,7 @@ RSpec.shared_examples 'prefixed token rotation' do
|
|||
end
|
||||
|
||||
it 'generates a new token' do
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/)
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/o)
|
||||
expect(instance).not_to be_persisted
|
||||
end
|
||||
end
|
||||
|
@ -475,7 +475,7 @@ RSpec.shared_examples 'prefixed token rotation' do
|
|||
|
||||
context 'token is not set' do
|
||||
it 'generates a new token' do
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/)
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/o)
|
||||
expect(instance).to be_persisted
|
||||
end
|
||||
end
|
||||
|
@ -486,7 +486,7 @@ RSpec.shared_examples 'prefixed token rotation' do
|
|||
end
|
||||
|
||||
it 'generates a new token' do
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/)
|
||||
expect(subject).to match(/^#{RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX}/o)
|
||||
expect(instance).to be_persisted
|
||||
end
|
||||
end
|
||||
|
|
|
@ -146,8 +146,8 @@ RSpec.describe Notes::CopyService do
|
|||
new_note = to_noteable.notes.first
|
||||
|
||||
aggregate_failures do
|
||||
expect(note.note).to match(/Simple text with image: #{FileUploader::MARKDOWN_PATTERN}/)
|
||||
expect(new_note.note).to match(/Simple text with image: #{FileUploader::MARKDOWN_PATTERN}/)
|
||||
expect(note.note).to match(/Simple text with image: #{FileUploader::MARKDOWN_PATTERN}/o)
|
||||
expect(new_note.note).to match(/Simple text with image: #{FileUploader::MARKDOWN_PATTERN}/o)
|
||||
expect(note.note).not_to eq(new_note.note)
|
||||
expect(note.note_html).not_to eq(new_note.note_html)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue