Commit 43645436 authored by GitLab Release Tools Bot's avatar GitLab Release Tools Bot

Merge remote-tracking branch 'dev/14-10-stable-ee' into 14-10-stable-ee

parents d118e6c4 94a44086
......@@ -2,6 +2,18 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 14.10.4 (2022-06-01)
### Security (7 changes)
- [Fix IP restrictions not applying to deploy tokens](gitlab-org/security/gitlab@8866d00e50f1d2857d54130239851f21404d7432) ([merge request](gitlab-org/security/gitlab!2471))
- [Trigger token should respect group IP restrictions](gitlab-org/security/gitlab@8534ca1be10f115dad2e0c1a4e167673049e401a) ([merge request](gitlab-org/security/gitlab!2478))
- [Fix content injection in Jira issue title](gitlab-org/security/gitlab@b8f82ec8d7ddf30c656642bff12de8fc8b5930a2) ([merge request](gitlab-org/security/gitlab!2464))
- [Subgroup member can list members of parent group](gitlab-org/security/gitlab@b59c49fa7b681a93bbe4bc69b20e72930a8b9d8d) ([merge request](gitlab-org/security/gitlab!2480))
- [Do not allow project member import when membership is locked](gitlab-org/security/gitlab@baed30570206b5ed9973ad8bfac5462721745a5d) ([merge request](gitlab-org/security/gitlab!2447))
- [Disable changing user attributes when updating SCIM provisioned user](gitlab-org/security/gitlab@ae4eb58668513f38c0daf1dc3b977c6b22a9a476) ([merge request](gitlab-org/security/gitlab!2454))
- [Allow only job owner to run interactive terminal](gitlab-org/security/gitlab@b0819e77b5a65d4412b42f27a513c02cc056a2b8) ([merge request](gitlab-org/security/gitlab!2433))
## 14.10.3 (2022-05-20)
### Added (1 change)
14.10.3
\ No newline at end of file
14.10.4
\ No newline at end of file
14.10.3-ee
\ No newline at end of file
14.10.4-ee
\ No newline at end of file
......@@ -67,6 +67,12 @@ class Groups::ApplicationController < ApplicationController
end
end
def authorize_read_group_member!
unless can?(current_user, :read_group_member, group)
render_403
end
end
def build_canonical_path(group)
params[:group_id] = group.to_param
......
......@@ -14,6 +14,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
# Authorize
before_action :authorize_admin_group_member!, except: admin_not_required_endpoints
before_action :authorize_read_group_member!, only: :index
skip_before_action :check_two_factor_requirement, only: :leave
skip_cross_project_access_check :index, :update, :destroy, :request_access,
......
......@@ -84,7 +84,7 @@ module Ci
enable :update_commit_status
end
rule { can?(:update_build) & terminal }.enable :create_build_terminal
rule { can?(:update_build) & terminal & owner_of_job }.enable :create_build_terminal
rule { can?(:update_build) }.enable :play_job
......
......@@ -22,6 +22,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
condition(:share_with_group_locked, scope: :subject) { @subject.share_with_group_lock? }
condition(:parent_share_with_group_locked, scope: :subject) { @subject.parent&.share_with_group_lock? }
condition(:can_change_parent_share_with_group_lock) { can?(:change_share_with_group_lock, @subject.parent) }
condition(:can_read_group_member) { can_read_group_member? }
desc "User is a project bot"
condition(:project_bot) { user.project_bot? && access_level >= GroupMember::GUEST }
......@@ -127,6 +128,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
rule { ~public_group & ~has_access }.prevent :read_counts
rule { ~can_read_group_member }.policy do
prevent :read_group_member
end
rule { ~can?(:read_group) }.policy do
prevent :read_design_activity
end
......@@ -308,6 +313,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
true
end
def can_read_group_member?
!(@subject.private? && access_level == GroupMember::NO_ACCESS)
end
def resource_access_token_creation_allowed?
resource_access_token_feature_available? && group.root_ancestor.namespace_settings.resource_access_token_creation_allowed?
end
......
......@@ -748,6 +748,10 @@ class ProjectPolicy < BasePolicy
prevent :register_project_runners
end
rule { can?(:admin_project_member) }.policy do
enable :import_project_members_from_another_project
end
private
def user_is_user?
......
......@@ -26,6 +26,7 @@ module Ci
def create_pipeline_from_trigger(trigger)
# this check is to not leak the presence of the project if user cannot read it
return unless trigger.project == project
return unless can?(trigger.owner, :read_project, project)
response = Ci::CreatePipelineService
.new(project, trigger.owner, ref: params[:ref], variables_attributes: variables)
......
......@@ -29,7 +29,7 @@ module Members
def import_project_team
return false unless target_project.present? && source_project.present? && current_user.present?
return false unless can?(current_user, :read_project_member, source_project)
return false unless can?(current_user, :admin_project_member, target_project)
return false unless can?(current_user, :import_project_members_from_another_project, target_project)
target_project.team.import(source_project, current_user)
end
......
......@@ -171,12 +171,12 @@ Returns a `201` status code if successful.
Fields that can be updated are:
| SCIM/IdP field | GitLab field |
|:---------------------------------|:---------------------------------------|
|:---------------------------------|:-----------------------------------------------------------------------------|
| `id/externalId` | `extern_uid` |
| `name.formatted` | `name` |
| `emails\[type eq "work"\].value` | `email` |
| `name.formatted` | `name` ([Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/363058)) |
| `emails\[type eq "work"\].value` | `email` ([Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/363058)) |
| `active` | Identity removal if `active` = `false` |
| `userName` | `username` |
| `userName` | `username` ([Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/363058)) |
```plaintext
PATCH /api/scim/v2/groups/:group_path/Users/:id
......
......@@ -93,6 +93,9 @@ For more information, view the [permissions table](../../permissions.md#group-me
## Subgroup membership
NOTE:
There is a bug that causes some pages in the parent group to be accessible by subgroup members. For more details, see [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/340421).
When you add a member to a group, that member is also added to all subgroups. The user's permissions are inherited from
the group's parent.
......
......@@ -433,6 +433,13 @@ module EE
super
end
override :can_read_group_member?
def can_read_group_member?
return true if user&.can_read_all_resources?
super
end
def ldap_lock_bypassable?
return false unless ::Feature.enabled?(:ldap_settings_unlock_groups_by_owners)
return false unless ::Gitlab::CurrentSettings.allow_group_owners_to_manage_ldap?
......
......@@ -145,6 +145,15 @@ module EE
::Gitlab::IncidentManagement.escalation_policies_available?(@subject)
end
with_scope :subject
condition(:membership_locked_via_parent_group) do
@subject.group && (@subject.group.membership_lock? || ::Gitlab::CurrentSettings.lock_memberships_to_ldap?)
end
rule { membership_locked_via_parent_group }.policy do
prevent :import_project_members_from_another_project
end
rule { visual_review_bot }.policy do
prevent :read_note
enable :create_note
......
......@@ -13,6 +13,10 @@ module Integrations
jira_issue.summary
end
expose :title_html do |jira_issue|
html_escape jira_issue.summary
end
expose :created_at do |jira_issue|
jira_issue.created.to_datetime.utc
end
......
......@@ -75,13 +75,10 @@ module API
elsif parsed_hash[:extern_uid]
identity.update(parsed_hash.slice(:extern_uid))
else
scim_conflict!(message: 'Email has already been taken') if email_taken?(parsed_hash[:email], identity)
result = ::Users::UpdateService.new(identity.user,
parsed_hash.except(:extern_uid, :active)
.merge(user: identity.user)).execute
result[:status] == :success
# With 15.0, we no longer allow modifying user attributes.
# However, we mark the operation as successful to avoid breaking
# existing automations
true
end
end
......@@ -91,12 +88,6 @@ module API
false
end
def email_taken?(email, identity)
return unless email
User.by_any_email(email.downcase).where.not(id: identity.user.id).exists?
end
def find_user_identity(group, extern_uid)
return unless group.saml_provider
......
......@@ -25,6 +25,23 @@ module EE
super
end
override :check_project_accessibility!
def check_project_accessibility!
super
# Deploy keys and tokens are unique in that we don't check
# against the project policy, where IP restrictions normally are
# checked. The existence of a project's associated key or
# token is enough to authenticate read access. To ensure deploy keys
# and tokens honor the IP allow list, we need to force a check here. We
# don't want to do this for all Git access because GitLab admin users
# aren't subject to this IP restriction, but deploy keys and tokens don't
# necessarily have an associated user.
return unless deploy_key? || deploy_token?
raise ::Gitlab::GitAccess::NotFoundError, not_found_message if ip_restricted?
end
def group?
# Strict nil check, to avoid any surprises with Object#present?
# which can delegate to #empty?
......@@ -46,6 +63,10 @@ module EE
private
def ip_restricted?
!::Gitlab::IpRestriction::Enforcer.new(project.group).allows_current_ip? if project.group
end
override :check_custom_action
def check_custom_action
geo_custom_action || super
......
......@@ -79,6 +79,43 @@ RSpec.describe 'Jira issues list', :js do
end
end
context 'when title or description contains HTML characters' do
let(:html) { '<script>foobar</script>' }
let(:escaped_html) { ERB::Util.html_escape(html) }
let(:issue) { build_issue(1).deep_merge(fields: { summary: html }) }
before do
stub_licensed_features(jira_issues_integration: true)
end
it 'escapes the HTML on issues#index' do
stub_issues([issue])
visit project_integrations_jira_issues_path(project)
expect(page).to have_text(html)
expect(page).not_to have_css('script', text: 'foobar')
expect(page.source).to include(escaped_html)
end
it 'escapes the HTML on issues#show' do
issue.deep_merge!(
fields: { comment: { comments: [] } },
renderedFields: { description: html },
duedate: Time.zone.now.to_s
)
stub_request(:get, /\A#{public_url}/)
.to_return(headers: { 'Content-Type' => 'application/json' }, body: issue.to_json)
visit project_integrations_jira_issue_path(project, 1)
expect(page).to have_text(html)
expect(page).not_to have_css('script', text: 'foobar')
expect(page.source).to include(escaped_html)
end
end
private
def all_pages
......
......@@ -30,6 +30,180 @@ RSpec.describe Gitlab::GitAccess do
end
end
describe '#check_project_accessibility!' do
let_it_be_with_reload(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:deploy_key) { create(:deploy_key, user: user) }
let_it_be(:admin) { create(:admin) }
let(:deploy_token) { create(:deploy_token, projects: [project]) }
let(:start_sha) { '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' }
let(:end_sha) { '570e7b2abdd848b95f2f578043fc23bd6f6fd24d' }
let(:changes) { "#{start_sha} #{end_sha} refs/heads/master" }
let(:push_error_message) { Gitlab::GitAccess::ERROR_MESSAGES[:upload] }
before(:all) do
project.add_developer(user)
deploy_key.deploy_keys_projects.create!(project: project, can_push: true)
end
context 'with ip restriction' do
before do
allow(Gitlab::IpAddressState).to receive(:current).and_return('192.168.0.2')
stub_licensed_features(group_ip_restriction: true)
end
context 'group with restriction' do
before do
create(:ip_restriction, group: group, range: range)
end
context 'address is within the range' do
let(:range) { '192.168.0.0/24' }
context 'when actor is a DeployKey with access to project' do
let(:actor) { deploy_key }
it 'allows pull, push access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.not_to raise_error
end
end
end
context 'when actor is DeployToken with access to project' do
let(:actor) { deploy_token }
it 'allows pull access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.to raise_forbidden(push_error_message)
end
end
end
context 'when actor is user with access to project' do
let(:actor) { user }
it 'allows push, pull access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.not_to raise_error
end
end
end
context 'when actor is instance admin', :enable_admin_mode do
let(:actor) { admin }
it 'allows push, pull access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.not_to raise_error
end
end
end
end
context 'address is outside the range' do
let(:range) { '10.0.0.0/8' }
context 'when actor is a DeployKey with access to project' do
let(:actor) { deploy_key }
it 'blocks pull, push with "not found"' do
aggregate_failures do
expect { pull_changes }.to raise_not_found
expect { push_changes }.to raise_not_found
end
end
end
context 'when actor is DeployToken with access to project' do
let(:actor) { deploy_token }
it 'blocks pull, push with "not found"' do
aggregate_failures do
expect { pull_changes }.to raise_not_found
expect { push_changes }.to raise_not_found
end
end
end
context 'when actor is user with access to project' do
let(:actor) { user }
it 'blocks pull, push with "not found"' do
aggregate_failures do
expect { pull_changes }.to raise_not_found
expect { push_changes }.to raise_not_found
end
end
end
context 'when actor is instance admin', :enable_admin_mode do
let(:actor) { admin }
it 'allows push, pull access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.not_to raise_error
end
end
end
end
end
context 'group without restriction' do
context 'when actor is a DeployKey with access to project' do
let(:actor) { deploy_key }
it 'allows pull, push access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.not_to raise_error
end
end
end
context 'when actor is DeployToken with access to project' do
let(:actor) { deploy_token }
it 'allows pull access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.to raise_forbidden(push_error_message)
end
end
end
context 'when actor is user with access to project' do
let(:actor) { user }
it 'allows push, pull access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.not_to raise_error
end
end
end
context 'when actor is instance admin', :enable_admin_mode do
let(:actor) { admin }
it 'allows push, pull access' do
aggregate_failures do
expect { pull_changes }.not_to raise_error
expect { push_changes }.not_to raise_error
end
end
end
end
end
end
context "when in a read-only GitLab instance" do
before do
create(:protected_branch, name: 'feature', project: project)
......@@ -1094,4 +1268,8 @@ RSpec.describe Gitlab::GitAccess do
def raise_forbidden(message)
raise_error(Gitlab::GitAccess::ForbiddenError, message)
end
def raise_not_found
raise_error(Gitlab::GitAccess::NotFoundError, Gitlab::GitAccess::ERROR_MESSAGES[:project_not_found])
end
end
......@@ -2052,4 +2052,34 @@ RSpec.describe ProjectPolicy do
expect_disallowed(*owner_permissions)
end
end
context 'importing members from another project' do
let(:current_user) { owner }
context 'for a personal project' do
it { is_expected.to be_allowed(:import_project_members_from_another_project) }
end
context 'for a project in a group' do
let(:project) { create(:project, group: create(:group)) }
context 'when the project has locked their membership' do
context 'via the parent group' do
before do
project.group.update!(membership_lock: true)
end
it { is_expected.to be_disallowed(:import_project_members_from_another_project) }
end
context 'via LDAP' do
before do
stub_application_setting(lock_memberships_to_ldap: true)
end
it { is_expected.to be_disallowed(:import_project_members_from_another_project) }
end
end
end
end
end
......@@ -1433,4 +1433,46 @@ RSpec.describe API::Projects do
end
end
end
describe 'POST /projects/:id/import_project_members/:project_id' do
let_it_be(:project) { create(:project) }
let_it_be(:target_project) { create(:project, group: create(:group)) }
before_all do
project.add_maintainer(another_user)
target_project.add_maintainer(another_user)
end
context 'when the target project has locked their membership' do
context 'via the parent group' do
before do
target_project.group.update!(membership_lock: true)
end
it 'returns 403' do
expect do
post api("/projects/#{target_project.id}/import_project_members/#{project.id}", another_user)
end.not_to change { target_project.members.count }
expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(json_response['message']).to eq('Import failed')
end
end
context 'via LDAP' do
before do
stub_application_setting(lock_memberships_to_ldap: true)
end
it 'returns 403' do
expect do
post api("/projects/#{target_project.id}/import_project_members/#{project.id}", another_user)
end.not_to change { target_project.members.count }
expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(json_response['message']).to eq('Import failed')
end
end
end
end
end
......@@ -371,7 +371,6 @@ RSpec.describe API::Scim do
it 'does not call reprovision service when identity is already active' do
expect(::EE::Gitlab::Scim::ReprovisionService).not_to receive(:new)
expect(::Users::UpdateService).to receive(:new).and_call_original
call_patch_api(params)
end
......@@ -394,6 +393,7 @@ RSpec.describe API::Scim do
end
end
context 'user attributes' do
context 'name' do
before do
params = { Operations: [{ 'op': 'Replace', 'path': 'name.formatted', 'value': 'new_name' }] }.to_query
......@@ -405,8 +405,8 @@ RSpec.describe API::Scim do
expect(response).to have_gitlab_http_status(:no_content)
end
it 'updates the name' do
expect(user.reload.name).to eq('new_name')
it 'does not update the name' do
expect(user.reload.name).not_to eq('new_name')
end
it 'responds with an empty response' do
......@@ -415,15 +415,14 @@ RSpec.describe API::Scim do
end
context 'email' do
context 'non existent email' do
before do
params = { Operations: [{ 'op': 'Replace', 'path': 'emails[type eq "work"].value', 'value': 'new@mail.com' }] }.to_query
call_patch_api(params)
end
it 'updates the email' do
expect(user.reload.unconfirmed_email).to eq('new@mail.com')
it 'does not update the email' do
expect(user.reload.unconfirmed_email).not_to eq('new@mail.com')
end
it 'responds with 204' do
......@@ -431,21 +430,23 @@ RSpec.describe API::Scim do
end
end
context 'existent email' do
context 'userName' do
before do
create(:user, email: 'new@mail.com')
params = { Operations: [{ 'op': 'Replace', 'path': 'emails[type eq "work"].value', 'value': 'new@mail.com' }] }.to_query
params = { Operations: [{ 'op': 'Replace', 'path': 'userName', 'value': 'new_username' }] }.to_query
call_patch_api(params)
end
it 'does not update a duplicated email' do
expect(user.reload.unconfirmed_email).not_to eq('new@mail.com')
it 'responds with 204' do
expect(response).to have_gitlab_http_status(:no_content)
end
it 'does not update the username' do
expect(user.reload.username).not_to eq('new_username')
end
it 'responds with 209' do
expect(response).to have_gitlab_http_status(:conflict)
it 'responds with an empty response' do
expect(response.body).to eq('')
end
end
end
......
......@@ -26,7 +26,7 @@ RSpec.describe Integrations::JiraSerializers::IssueEntity do
let(:jira_issue) do
double(
summary: 'Title',
summary: 'Title with <h1>HTML</h1>',
created: '2020-06-25T15:39:30.000+0000',
updated: '2020-06-26T15:38:32.000+0000',
resolutiondate: '2020-06-27T13:23:51.000+0000',
......@@ -46,7 +46,8 @@ RSpec.describe Integrations::JiraSerializers::IssueEntity do
it 'returns the Jira issues attributes' do
expect(subject).to include(
project_id: project.id,
title: 'Title',
title: 'Title with <h1>HTML</h1>',
title_html: 'Title with &lt;h1&gt;HTML&lt;/h1&gt;',
created_at: '2020-06-25T15:39:30.000+0000'.to_datetime.utc,
updated_at: '2020-06-26T15:38:32.000+0000'.to_datetime.utc,
closed_at: '2020-06-27T13:23:51.000+0000'.to_datetime.utc,
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::PipelineTriggerService do
let_it_be(:project) { create(:project, :repository) }
before do
stub_ci_pipeline_to_return_yaml_file
end
describe '#execute' do
let_it_be(:user) { create(:user) }
let(:result) { described_class.new(project, user, params).execute }
before do
project.add_developer(user)
end
shared_examples 'with ip restriction' do
let_it_be_with_reload(:group) { create(:group, :public) }
let_it_be_with_reload(:project) { create(:project, :repository, group: group) }
before do
allow(Gitlab::IpAddressState).to receive(:current).and_return('192.168.0.2')
stub_licensed_features(group_ip_restriction: true)
end
context 'group with restriction' do
before do
create(:ip_restriction, group: group, range: range)
end
context 'address is within the range' do
let(:range) { '192.168.0.0/24' }
it 'triggers a pipeline' do
expect { result }.to change { Ci::Pipeline.count }.by(1)
end
end
context 'address is outside the range' do
let(:range) { '10.0.0.0/8' }
it 'does nothing' do
expect { result }.not_to change { Ci::Pipeline.count }
end
end
end
context 'group without restriction' do
it 'triggers a pipeline' do
expect { result }.to change { Ci::Pipeline.count }.by(1)
end
end
end
context 'with a trigger token' do
let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
let(:trigger) { create(:ci_trigger, project: project, owner: user) }
include_examples 'with ip restriction'
end
context 'with a job token' do
let!(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:job) { create(:ci_build, :running, pipeline: pipeline, user: user) }
let(:params) { { token: job.token, ref: 'master', variables: nil } }
include_examples 'with ip restriction'
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Members::ImportProjectTeamService do
describe '#execute' do
let_it_be(:source_project) { create(:project) }
let_it_be(:target_project) { create(:project, group: create(:group)) }
let_it_be(:user) { create(:user) }
let(:source_project_id) { source_project.id }
let(:target_project_id) { target_project.id }
subject { described_class.new(user, { id: target_project_id, project_id: source_project_id }) }
before_all do
source_project.add_guest(user)
target_project.add_maintainer(user)
end
context 'when the project team import fails' do
context 'when the target project has locked their membership' do
context 'via the parent group' do
before do
target_project.group.update!(membership_lock: true)
end
it 'returns false' do
expect(subject.execute).to be(false)
end
end
context 'via LDAP' do
before do
stub_application_setting(lock_memberships_to_ldap: true)
end
it 'returns false' do
expect(subject.execute).to be(false)
end
end
end
end
end
end
......@@ -15,6 +15,10 @@ module API
public_send("find_#{source_type}!", id) # rubocop:disable GitlabSecurity/PublicSend
end
def authorize_read_source_member!(source_type, source)
authorize! :"read_#{source_type}_member", source
end
def authorize_admin_source!(source_type, source)
authorize! :"admin_#{source_type}", source
end
......
......@@ -30,6 +30,8 @@ module API
get ":id/members" do
source = find_source(source_type, params[:id])
authorize_read_source_member!(source_type, source)
members = paginate(retrieve_members(source, params: params))
present_members members
......@@ -49,6 +51,8 @@ module API
get ":id/members/all" do
source = find_source(source_type, params[:id])
authorize_read_source_member!(source_type, source)
members = paginate(retrieve_members(source, params: params, deep: true))
present_members members
......@@ -64,6 +68,8 @@ module API
get ":id/members/:user_id" do
source = find_source(source_type, params[:id])
authorize_read_source_member!(source_type, source)
members = source_members(source)
member = members.find_by!(user_id: params[:user_id])
......@@ -81,6 +87,8 @@ module API
get ":id/members/all/:user_id" do
source = find_source(source_type, params[:id])
authorize_read_source_member!(source_type, source)
members = find_all_members(source)
member = members.find_by!(user_id: params[:user_id])
......
......@@ -183,7 +183,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
context 'with web terminal' do
let(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }
let(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline, user: user) }
it 'exposes the terminal path' do
expect(response).to have_gitlab_http_status(:ok)
......@@ -1284,7 +1284,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
context 'when job exists' do
context 'and it has a terminal' do
let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }
let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline, user: user) }
it 'has a job' do
get_terminal(id: job.id)
......@@ -1295,7 +1295,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
context 'and does not have a terminal' do
let!(:job) { create(:ci_build, :running, pipeline: pipeline) }
let!(:job) { create(:ci_build, :running, pipeline: pipeline, user: user) }
it 'returns not_found' do
get_terminal(id: job.id)
......@@ -1324,7 +1324,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
describe 'GET #terminal_websocket_authorize' do
let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }
let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline, user: user) }
before do
project.add_developer(user)
......
......@@ -97,7 +97,7 @@ RSpec.describe 'Private Group access' do
it { is_expected.to be_allowed_for(:developer).of(group) }
it { is_expected.to be_allowed_for(:reporter).of(group) }
it { is_expected.to be_allowed_for(:guest).of(group) }
it { is_expected.to be_allowed_for(project_guest) }
it { is_expected.to be_denied_for(project_guest) }
it { is_expected.to be_denied_for(:user) }
it { is_expected.to be_denied_for(:external) }
it { is_expected.to be_denied_for(:visitor) }
......
......@@ -405,4 +405,52 @@ RSpec.describe Ci::BuildPolicy do
end
end
end
describe 'ability :create_build_terminal' do
let(:project) { create(:project, :private) }
subject { described_class.new(user, build) }
context 'when user can update_build' do
before do
project.add_maintainer(user)
end
context 'when job has terminal' do
before do
allow(build).to receive(:has_terminal?).and_return(true)
end
context 'when current user is the job owner' do
before do
build.update!(user: user)
end
it { expect_allowed(:create_build_terminal) }
end
context 'when current user is not the job owner' do
it { expect_disallowed(:create_build_terminal) }
end
end
context 'when job does not have terminal' do
before do
allow(build).to receive(:has_terminal?).and_return(false)
build.update!(user: user)
end
it { expect_disallowed(:create_build_terminal) }
end
end
context 'when user cannot update build' do
before do
project.add_guest(user)
allow(build).to receive(:has_terminal?).and_return(true)
end
it { expect_disallowed(:create_build_terminal) }
end
end
end
......@@ -396,6 +396,36 @@ RSpec.describe ProjectPolicy do
end
end
context 'importing members from another project' do
%w(maintainer owner).each do |role|
context "with #{role}" do
let(:current_user) { send(role) }
it { is_expected.to be_allowed(:import_project_members_from_another_project) }
end
end
%w(guest reporter developer anonymous).each do |role|
context "with #{role}" do
let(:current_user) { send(role) }
it { is_expected.to be_disallowed(:import_project_members_from_another_project) }
end
end
context 'with an admin' do
let(:current_user) { admin }
context 'when admin mode is enabled', :enable_admin_mode do
it { expect_allowed(:import_project_members_from_another_project) }
end
context 'when admin mode is disabled' do
it { expect_disallowed(:import_project_members_from_another_project) }
end
end
end
context 'reading usage quotas' do
%w(maintainer owner).each do |role|
context "with #{role}" do
......
......@@ -184,6 +184,21 @@ RSpec.describe API::Members do
expect(json_response).to be_an Array
expect(json_response.map { |u| u['id'] }).to match_array [maintainer.id, developer.id, nested_user.id]
end
context 'with a subgroup' do
let(:group) { create(:group, :private)}
let(:subgroup) { create(:group, :private, parent: group)}
let(:project) { create(:project, group: subgroup) }
before do
subgroup.add_developer(developer)
end
it 'subgroup member cannot get parent group members list' do
get api("/groups/#{group.id}/members/all", developer)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
shared_examples 'GET /:source_type/:id/members/(all/):user_id' do |source_type, all|
......
......@@ -56,6 +56,15 @@ RSpec.describe Ci::PipelineTriggerService do
end
end
context 'when trigger owner does not have a permission to read a project' do
let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
let(:trigger) { create(:ci_trigger, project: project, owner: create(:user)) }
it 'does nothing' do
expect { result }.not_to change { Ci::Pipeline.count }
end
end
context 'when params have an existing trigger token' do
context 'when params have an existing ref' do
let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
......
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