Skip to content

Commit 13bbf47

Browse files
authored
Check build permissions when restarting build/job via API (#1167)
1 parent 8b20437 commit 13bbf47

File tree

2 files changed

+101
-1
lines changed

2 files changed

+101
-1
lines changed

lib/travis/api/enqueue/services/restart_model.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,15 @@ def target
7878
private
7979

8080
def permission?
81-
current_user && current_user.permission?(required_role, repository_id: target.repository_id) && !abusive?
81+
current_user && current_user.permission?(required_role, repository_id: target.repository_id) && !abusive? && build_permission?
82+
end
83+
84+
def build_permission?
85+
# nil value is considered true
86+
return false if repository.permissions.find_by(user_id: current_user.id).build == false
87+
return false if repository.owner_type == 'Organization' && repository.owner.memberships.find_by(user_id: current_user.id)&.build_permission == false
88+
89+
true
8290
end
8391

8492
def abusive?
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
describe Travis::Enqueue::Services::RestartModel do
2+
let(:owner) { FactoryBot.create(:user) }
3+
let(:repository) { FactoryBot.create(:repository, owner: owner) }
4+
let(:job) { FactoryBot.create(:job, repository: repository, state: 'canceled') }
5+
let(:user) { FactoryBot.create(:user) }
6+
7+
let(:service) { Travis::Enqueue::Services::RestartModel.new(user, { job_id: job.id }) }
8+
9+
before do
10+
Travis.config.billing.url = 'http://localhost:9292/'
11+
Travis.config.billing.auth_key = 'secret'
12+
13+
stub_request(:post, /http:\/\/localhost:9292\/(users|organizations)\/(.+)\/authorize_build/).to_return(
14+
body: MultiJson.dump(allowed: true, rejection_code: nil)
15+
)
16+
end
17+
18+
after do
19+
Travis.config.billing.url = nil
20+
Travis.config.billing.auth_key = nil
21+
end
22+
23+
describe 'push' do
24+
let(:payload) { { id: job.id, user_id: user.id } }
25+
26+
subject { service.push('job:restart', payload) }
27+
28+
shared_examples 'restarts the job' do
29+
it do
30+
expect(subject.value).to eq({ id: job.id, user_id: user.id })
31+
expect(subject.error).to eq(nil)
32+
end
33+
end
34+
35+
shared_examples 'does not restart the job' do
36+
it do
37+
expect(subject.value).to eq(nil)
38+
expect(subject.error).to eq('restart failed')
39+
end
40+
end
41+
42+
context 'build permissions' do
43+
context 'when owner is a user' do
44+
context 'on repo level' do
45+
context 'when value is nil' do
46+
before { repository.permissions.create(user: user, build: nil) }
47+
48+
include_examples 'restarts the job'
49+
end
50+
51+
context 'when value is true' do
52+
before { repository.permissions.create(user: user, build: true) }
53+
54+
include_examples 'restarts the job'
55+
end
56+
57+
context 'when value is false' do
58+
before { repository.permissions.create(user: user, build: false) }
59+
60+
include_examples 'does not restart the job'
61+
end
62+
end
63+
end
64+
65+
context 'when owner is an organization' do
66+
let(:owner) { FactoryBot.create(:org) }
67+
68+
before { repository.permissions.create(user: user, build: true) }
69+
70+
context 'on organization level' do
71+
context 'when value is nil' do
72+
before { owner.memberships.create(user: user, build_permission: nil) }
73+
74+
include_examples 'restarts the job'
75+
end
76+
77+
context 'when value is true' do
78+
before { owner.memberships.create(user: user, build_permission: true) }
79+
80+
include_examples 'restarts the job'
81+
end
82+
83+
context 'when value is false' do
84+
before { owner.memberships.create(user: user, build_permission: false) }
85+
86+
include_examples 'does not restart the job'
87+
end
88+
end
89+
end
90+
end
91+
end
92+
end

0 commit comments

Comments
 (0)