Commit 69db8c79 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 4913f421 01cae961
32b44d3c44af62f55c1049743149c103dfd58fb7
d950585cb9763c6014ae2c9b7c4f4923d90c9f81
......@@ -4,8 +4,9 @@
%fieldset
%h5= _('Permissions')
.form-group
= render 'shared/allow_request_access', form: f
- unless ::Feature.enabled?(:saas_user_caps)
.form-group
= render 'shared/allow_request_access', form: f
- if @group.root?
.form-group.gl-mb-3
......@@ -43,5 +44,6 @@
= render_if_exists 'groups/settings/prevent_forking', f: f, group: @group
= render 'groups/settings/two_factor_auth', f: f, group: @group
= render_if_exists 'groups/personal_access_token_expiration_policy', f: f, group: @group
= render_if_exists 'groups/settings/membership', f: f
= render_if_exists 'groups/member_lock_setting', f: f, group: @group
= f.submit _('Save changes'), class: 'btn gl-button btn-confirm gl-mt-3 js-dirty-submit', data: { qa_selector: 'save_permissions_changes_button' }
......@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332963
milestone: '14.0'
type: development
group: group::pipeline authoring
default_enabled: false
default_enabled: true
......@@ -4472,7 +4472,6 @@ Input type: `VulnerabilityCreateInput`
| <a id="mutationvulnerabilitycreateproject"></a>`project` | [`ProjectID!`](#projectid) | ID of the project to attach the vulnerability to. |
| <a id="mutationvulnerabilitycreateresolvedat"></a>`resolvedAt` | [`Time`](#time) | Timestamp of when the vulnerability state changed to resolved (defaults to creation time if status is `resolved`). |
| <a id="mutationvulnerabilitycreatescannername"></a>`scannerName` | [`String!`](#string) | Name of the security scanner used to discover the vulnerability. |
| <a id="mutationvulnerabilitycreatescannertype"></a>`scannerType` | [`SecurityScannerType!`](#securityscannertype) | Type of the security scanner used to discover the vulnerability. |
| <a id="mutationvulnerabilitycreateseverity"></a>`severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability (defaults to `unknown`). |
| <a id="mutationvulnerabilitycreatesolution"></a>`solution` | [`String`](#string) | How to fix this vulnerability. |
| <a id="mutationvulnerabilitycreatestate"></a>`state` | [`VulnerabilityState`](#vulnerabilitystate) | State of the vulnerability (defaults to `detected`). |
......
......@@ -81,7 +81,9 @@ export default {
},
error: createPolicyFetchError,
skip() {
return this.isLoadingEnvironments || !this.shouldShowNetworkPolicies;
return (
!this.hasEnvironment || this.isLoadingEnvironments || !this.shouldShowNetworkPolicies
);
},
},
scanExecutionPolicies: {
......
......@@ -19,10 +19,6 @@ module Mutations
required: true,
description: 'Description of the vulnerability.'
argument :scanner_type, Types::SecurityScannerTypeEnum,
required: true,
description: 'Type of the security scanner used to discover the vulnerability.'
argument :scanner_name, GraphQL::Types::String,
required: true,
description: 'Name of the security scanner used to discover the vulnerability.'
......@@ -118,8 +114,7 @@ module Mutations
])
scanner_params = {
name: params.fetch(:scanner_name),
type: params.fetch(:scanner_type)
name: params.fetch(:scanner_name)
}
{
......
- return unless ::Feature.enabled?(:saas_user_caps)
%h5= _('Membership')
.form-group{ data: { testid: 'membership-form-group' } }
= render 'shared/allow_request_access', form: f
......@@ -3,7 +3,7 @@
module EE
module Gitlab
module Checks
module BaseSingleChecker
module BaseChecker
extend ActiveSupport::Concern
include ::Gitlab::Utils::StrongMemoize
......
......@@ -3,12 +3,12 @@
module EE
module Gitlab
module Checks
module SingleChangeAccess
module ChangesAccess
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
override :ref_level_checks
def ref_level_checks
override :bulk_access_checks!
def bulk_access_checks!
super
PushRuleCheck.new(self).validate!
......
......@@ -3,7 +3,7 @@
module EE
module Gitlab
module Checks
class PushRuleCheck < ::Gitlab::Checks::BaseSingleChecker
class PushRuleCheck < ::Gitlab::Checks::BaseBulkChecker
def validate!
return unless push_rule
......@@ -19,17 +19,23 @@ module EE
# @return [Nil] returns nil unless an error is raised
# @raise [Gitlab::GitAccess::ForbiddenError] if check fails
def check_tag_or_branch!
if tag_name
PushRules::TagCheck.new(change_access).validate!
else
PushRules::BranchCheck.new(change_access).validate!
changes_access.single_change_accesses.each do |single_change_access|
if single_change_access.tag_name
PushRules::TagCheck.new(single_change_access).validate!
else
PushRules::BranchCheck.new(single_change_access).validate!
end
end
nil
end
# @return [Nil] returns nil unless an error is raised
# @raise [Gitlab::GitAccess::ForbiddenError] if check fails
def check_file_size!
PushRules::FileSizeCheck.new(change_access).validate!
PushRules::FileSizeCheck.new(changes_access).validate!
nil
end
# Run the checks one after the other.
......
......@@ -4,7 +4,7 @@ module EE
module Gitlab
module Checks
module PushRules
class FileSizeCheck < ::Gitlab::Checks::BaseSingleChecker
class FileSizeCheck < ::Gitlab::Checks::BaseBulkChecker
LOG_MESSAGE = "Checking if any files are larger than the allowed size..."
def validate!
......@@ -12,14 +12,21 @@ module EE
logger.log_timed(LOG_MESSAGE) do
max_file_size = push_rule.max_file_size
blobs = project.repository.new_blobs(newrev, dynamic_timeout: logger.time_left)
large_blob = blobs.find do |blob|
::Gitlab::Utils.bytes_to_megabytes(blob.size) > max_file_size
end
changes_access.changes.each do |change|
newrev = change[:newrev]
next if newrev.blank? || ::Gitlab::Git.blank_ref?(newrev)
blobs = project.repository.new_blobs(newrev, dynamic_timeout: logger.time_left)
large_blob = blobs.find do |blob|
::Gitlab::Utils.bytes_to_megabytes(blob.size) > max_file_size
end
if large_blob
raise ::Gitlab::GitAccess::ForbiddenError, %Q{File "#{large_blob.path}" is larger than the allowed size of #{max_file_size} MB}
if large_blob
raise ::Gitlab::GitAccess::ForbiddenError, %Q{File "#{large_blob.path}" is larger than the allowed size of #{max_file_size} MB}
end
end
end
end
......
......@@ -32,9 +32,10 @@ const environments = [
global_id: 'gid://gitlab/Environment/3',
},
];
const networkPoliciesSpy = networkPolicies(mockNetworkPoliciesResponse);
const scanExecutionPoliciesSpy = scanExecutionPolicies(mockScanExecutionPoliciesResponse);
const defaultRequestHandlers = {
networkPolicies: networkPolicies(mockNetworkPoliciesResponse),
networkPolicies: networkPoliciesSpy,
scanExecutionPolicies: scanExecutionPoliciesSpy,
};
const pendingHandler = jest.fn(() => new Promise(() => {}));
......@@ -45,13 +46,19 @@ describe('PoliciesList component', () => {
let requestHandlers;
const factory = (mountFn = mountExtended) => (options = {}) => {
const { state = {}, handlers, ...wrapperOptions } = options;
store = createStore();
const { state, handlers, ...wrapperOptions } = options;
Object.assign(store.state.networkPolicies, {
...state,
store.replaceState({
...store.state,
threatMonitoring: {
...store.state.threatMonitoring,
environments,
currentEnvironmentId: environments[0].id,
...state.threatMonitoring,
},
});
store.state.threatMonitoring.environments = environments;
store.state.threatMonitoring.currentEnvironmentId = environments[0].id;
requestHandlers = {
...defaultRequestHandlers,
...handlers,
......@@ -260,8 +267,7 @@ describe('PoliciesList component', () => {
describe('with allEnvironments enabled', () => {
beforeEach(() => {
mountWrapper();
wrapper.vm.$store.state.threatMonitoring.allEnvironments = true;
mountWrapper({ state: { threatMonitoring: { allEnvironments: true } } });
});
it('renders environments column', () => {
......@@ -312,7 +318,26 @@ describe('PoliciesList component', () => {
});
});
describe('given no environement', () => {
describe('given loading environment', () => {
beforeEach(() => {
mountWrapper({
propsData: {
hasEnvironment: true,
},
state: {
threatMonitoring: {
isLoadingEnvironments: true,
},
},
});
});
it('does not make a request for network policies', () => {
expect(networkPoliciesSpy).not.toHaveBeenCalled();
});
});
describe('given no environments', () => {
beforeEach(() => {
mountWrapper({
propsData: {
......@@ -321,8 +346,12 @@ describe('PoliciesList component', () => {
});
});
it('does not make a request for network policies', () => {
expect(networkPoliciesSpy).not.toHaveBeenCalled();
});
it('does not render default network policies', () => {
expect(findPolicyStatusCells()).toHaveLength(3);
expect(findPolicyStatusCells()).toHaveLength(1);
});
});
});
......@@ -32,7 +32,6 @@ RSpec.describe Mutations::Vulnerabilities::Create do
project: project_gid,
title: "Test vulnerability",
description: "Test vulnerability created via GraphQL",
scanner_type: "dast",
scanner_name: "My custom DAST scanner",
identifiers: [identifier_attributes],
state: "detected",
......@@ -74,7 +73,6 @@ RSpec.describe Mutations::Vulnerabilities::Create do
project: project_gid,
title: "Test vulnerability",
description: "Test vulnerability created via GraphQL",
scanner_type: "dast",
scanner_name: "My custom DAST scanner",
identifiers: [identifier_attributes],
state: "detected",
......@@ -122,7 +120,6 @@ RSpec.describe Mutations::Vulnerabilities::Create do
project: project_gid,
title: "Test vulnerability",
description: "Test vulnerability created via GraphQL",
scanner_type: "dast",
scanner_name: "My custom DAST scanner",
identifiers: [identifier_attributes],
state: state,
......
......@@ -3,9 +3,16 @@
require 'spec_helper'
RSpec.describe EE::Gitlab::Checks::PushRuleCheck do
include_context 'push rules checks context'
include_context 'changes access checks context'
let(:push_rule) { create(:push_rule, :commit_message) }
let(:project) { create(:project, :public, :repository, push_rule: push_rule) }
before do
allow(project.repository).to receive(:new_commits).and_return(
project.repository.commits_between('be93687618e4b132087f430a4d8fc3a609c9b77c', '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51')
)
end
shared_examples "push checks" do
before do
......@@ -28,8 +35,11 @@ RSpec.describe EE::Gitlab::Checks::PushRuleCheck do
end
context 'when tag name exists' do
before do
allow(change_access).to receive(:tag_name).and_return(true)
let(:changes) do
[
# Update of a tag.
{ oldrev: oldrev, newrev: newrev, ref: 'refs/tags/name' }
]
end
it 'validates tags push rules' do
......@@ -43,8 +53,11 @@ RSpec.describe EE::Gitlab::Checks::PushRuleCheck do
end
context 'when tag name does not exists' do
before do
allow(change_access).to receive(:tag_name).and_return(false)
let(:changes) do
[
# Update of a branch.
{ oldrev: oldrev, newrev: newrev, ref: 'refs/heads/name' }
]
end
it 'validates branches push rules' do
......@@ -56,6 +69,24 @@ RSpec.describe EE::Gitlab::Checks::PushRuleCheck do
subject.validate!
end
end
context 'when tag and branch exist' do
let(:changes) do
[
{ oldrev: oldrev, newrev: newrev, ref: 'refs/heads/name' },
{ oldrev: oldrev, newrev: newrev, ref: 'refs/tags/name' }
]
end
it 'validates tag and branch push rules' do
expect_any_instance_of(EE::Gitlab::Checks::PushRules::TagCheck)
.to receive(:validate!)
expect_any_instance_of(EE::Gitlab::Checks::PushRules::BranchCheck)
.to receive(:validate!)
subject.validate!
end
end
end
describe '#validate!' do
......
......@@ -5,6 +5,29 @@ require 'spec_helper'
RSpec.describe EE::Gitlab::Checks::PushRules::FileSizeCheck do
include_context 'push rules checks context'
let(:changes) do
[
# Update of existing branch
{ oldrev: oldrev, newrev: newrev, ref: ref },
# Creation of new branch
{ newrev: newrev, ref: 'refs/heads/something' },
# Deletion of branch
{ oldrev: oldrev, ref: 'refs/heads/deleteme' }
]
end
let(:changes_access) do
Gitlab::Checks::ChangesAccess.new(
changes,
project: project,
user_access: user_access,
protocol: protocol,
logger: logger
)
end
subject { described_class.new(changes_access) }
describe '#validate!' do
let(:push_rule) { create(:push_rule, max_file_size: 1) }
# SHA of the 2-mb-file branch
......
......@@ -2,13 +2,28 @@
require 'spec_helper'
RSpec.describe Gitlab::Checks::SingleChangeAccess do
RSpec.describe Gitlab::Checks::ChangesAccess do
describe '#validate!' do
include_context 'push rules checks context'
let(:push_rule) { create(:push_rule, deny_delete_tag: true) }
let(:changes) do
[
{ oldrev: oldrev, newrev: newrev, ref: ref }
]
end
let(:changes_access) do
Gitlab::Checks::ChangesAccess.new(
changes,
project: project,
user_access: user_access,
protocol: protocol,
logger: logger
)
end
subject { change_access }
subject { changes_access }
it_behaves_like 'check ignored when push rule unlicensed'
......
......@@ -13,18 +13,13 @@ module API
post '/lint' do
unauthorized! if (Gitlab::CurrentSettings.signup_disabled? || Gitlab::CurrentSettings.signup_limited?) && current_user.nil?
result = Gitlab::Ci::YamlProcessor.new(params[:content], user: current_user).execute
result = Gitlab::Ci::Lint.new(project: nil, current_user: current_user)
.validate(params[:content], dry_run: false)
status 200
response = if result.errors.empty?
{ status: 'valid', errors: [], warnings: result.warnings }
else
{ status: 'invalid', errors: result.errors, warnings: result.warnings }
end
response.tap do |response|
response[:merged_yaml] = result.merged_yaml if params[:include_merged_yaml]
Entities::Ci::Lint::Result.represent(result, current_user: current_user).serializable_hash.tap do |presented_result|
presented_result[:status] = presented_result[:valid] ? 'valid' : 'invalid'
presented_result.delete(:merged_yaml) unless params[:include_merged_yaml]
end
end
end
......
......@@ -30,5 +30,3 @@ module Gitlab
end
end
end
Gitlab::Checks::BaseSingleChecker.prepend_mod_with('Gitlab::Checks::BaseSingleChecker')
......@@ -76,23 +76,33 @@ module Gitlab
result
end
def single_change_accesses
@single_changes_accesses ||=
changes.map do |change|
commits =
if change[:newrev].blank? || Gitlab::Git.blank_ref?(change[:newrev])
[]
else
Gitlab::Lazy.new { commits_for(change[:newrev]) }
end
Checks::SingleChangeAccess.new(
change,
user_access: user_access,
project: project,
protocol: protocol,
logger: logger,
commits: commits
)
end
end
protected
def single_access_checks!
# Iterate over all changes to find if user allowed all of them to be applied
changes.each do |change|
commits = Gitlab::Lazy.new { commits_for(change[:newrev]) }
# If user does not have access to make at least one change, cancel all
# push by allowing the exception to bubble up
Checks::SingleChangeAccess.new(
change,
user_access: user_access,
project: project,
protocol: protocol,
logger: logger,
commits: commits
).validate!
single_change_accesses.each do |single_change_access|
single_change_access.validate!
end
end
......@@ -102,3 +112,5 @@ module Gitlab
end
end
end
Gitlab::Checks::ChangesAccess.prepend_mod_with('Gitlab::Checks::ChangesAccess')
......@@ -21,7 +21,7 @@ module Gitlab
def initialize(project:, current_user:, sha: nil)
@project = project
@current_user = current_user
@sha = sha || project.repository.commit&.sha
@sha = sha || project&.repository&.commit&.sha
end
def validate(content, dry_run: false)
......
......@@ -20811,6 +20811,9 @@ msgstr ""
msgid "Members of a group may only view projects they have permission to access"
msgstr ""
msgid "Membership"
msgstr ""
msgid "Members|%{time} by %{user}"
msgstr ""
......
......@@ -174,6 +174,101 @@ RSpec.describe Gitlab::Checks::ChangesAccess do
end
end
describe '#single_change_accesses' do
let(:commits_for) { {} }
let(:expected_accesses) { [] }
shared_examples '#single_change_access' do
before do
commits_for.each do |id, commits|
expect(subject)
.to receive(:commits_for)
.with(id)
.and_return(commits)
end
end
it 'returns an array of SingleChangeAccess' do
# Commits are wrapped in a Gitlab::Lazy and thus need to be resolved
# first such that we can directly compare types.
actual_accesses = subject.single_change_accesses
.each { |access| access.instance_variable_set(:@commits, access.commits.to_a) }
expect(actual_accesses).to match_array(expected_accesses)
end
end
context 'with no changes' do
let(:changes) { [] }
it_behaves_like '#single_change_access'
end
context 'with a single change and no new commits' do
let(:commits_for) { { 'new' => [] } }
let(:changes) do
[
{ oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch' }
]
end
let(:expected_accesses) do
[
have_attributes(oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch', commits: [])
]
end
it_behaves_like '#single_change_access'
end
context 'with a single change and new commits' do
let(:commits_for) { { 'new' => [create_commit('new', [])] } }
let(:changes) do
[
{ oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch' }
]
end
let(:expected_accesses) do
[
have_attributes(oldrev: 'old', newrev: 'new', ref: 'refs/heads/branch', commits: [create_commit('new', [])])
]
end
it_behaves_like '#single_change_access'
end
context 'with multiple changes' do
let(:commits_for) do
{
'a' => [create_commit('a', [])],
'c' => [create_commit('c', [])],
'd' => []
}
end
let(:changes) do
[
{ newrev: 'a', ref: 'refs/heads/a' },
{ oldrev: 'b', ref: 'refs/heads/b' },
{ oldrev: 'a', newrev: 'c', ref: 'refs/heads/c' },
{ newrev: 'd', ref: 'refs/heads/d' }
]
end
let(:expected_accesses) do
[
have_attributes(newrev: 'a', ref: 'refs/heads/a', commits: [create_commit('a', [])]),
have_attributes(oldrev: 'b', ref: 'refs/heads/b', commits: []),
have_attributes(oldrev: 'a', newrev: 'c', ref: 'refs/heads/c', commits: [create_commit('c', [])]),
have_attributes(newrev: 'd', ref: 'refs/heads/d', commits: [])
]
end
it_behaves_like '#single_change_access'
end
end
def create_commit(id, parent_ids)
Gitlab::Git::Commit.new(project.repository, {
id: id,
......
......@@ -113,7 +113,6 @@ RSpec.describe API::Lint do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['status']).to eq('valid')
expect(json_response['warnings']).not_to be_empty
expect(json_response['status']).to eq('valid')
expect(json_response['errors']).to eq([])
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment