Skip to content

Commit 85d564b

Browse files
AndriiMyskovitalie
authored and
vitalie
committed
PRD Securely signed releases (#282)
1 parent 4238c34 commit 85d564b

File tree

7 files changed

+105
-1
lines changed

7 files changed

+105
-1
lines changed

lib/travis/scheduler/record.rb

+2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
require 'travis/scheduler/record/branch'
44
require 'travis/scheduler/record/build'
55
require 'travis/scheduler/record/commit'
6+
require 'travis/scheduler/record/custom_key'
67
require 'travis/scheduler/record/installation'
78
require 'travis/scheduler/record/job'
89
require 'travis/scheduler/record/log'
10+
require 'travis/scheduler/record/membership'
911
require 'travis/scheduler/record/organization'
1012
require 'travis/scheduler/record/permission'
1113
require 'travis/scheduler/record/pull_request'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
require 'travis/support/encrypted_column'
2+
require 'travis/support/secure_config'
3+
4+
class CustomKey < ActiveRecord::Base
5+
serialize :private_key, Travis::EncryptedColumn.new
6+
belongs_to :owner, polymorphic: true
7+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class Membership < ActiveRecord::Base
2+
belongs_to :user
3+
belongs_to :organization
4+
end

lib/travis/scheduler/serialize/worker.rb

+34-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def data
1919
vm_size: job.vm_size,
2020
queue: job.queue,
2121
config: job.decrypted_config,
22-
env_vars: job.env_vars,
22+
env_vars: env_vars_with_custom_keys,
2323
job: job_data,
2424
host: Travis::Scheduler.config.host,
2525
source: build_data,
@@ -238,6 +238,39 @@ def allowed_repositories
238238
def travis_vcs_proxy?
239239
repo.vcs_type == 'TravisproxyRepository'
240240
end
241+
242+
def env_vars_with_custom_keys
243+
job.env_vars + custom_keys
244+
end
245+
246+
def custom_keys
247+
return [] if job.decrypted_config[:keys].blank?
248+
249+
if job.source.event_type == 'pull_request' && job.source.request.pull_request.head_repo_slug != job.source.request.pull_request.base_repo_slug
250+
base_repo_owner_name, base_repo_name = job.source.request.pull_request.base_repo_slug.to_s.split('/')
251+
return [] unless base_repo_owner_name && base_repo_name
252+
253+
254+
base_repo = ::Repository.find_by(owner_name: base_repo_owner_name, name: base_repo_name)
255+
return [] unless base_repo && base_repo.settings.share_ssh_keys_with_forks?
256+
257+
end
258+
259+
job.decrypted_config[:keys].map do |key|
260+
custom_key = CustomKey.where(name: key, owner_id: build.sender_id, owner_type: 'User').first
261+
if custom_key.nil?
262+
org_ids = Membership.where(user_id: build.sender_id).map(&:organization_id)
263+
if !base_repo.nil? && base_repo.owner_type == 'Organization'
264+
org_ids.reject! { |id| id != base_repo.owner_id }
265+
elsif repo.owner_type == 'Organization'
266+
org_ids.reject! { |id| id != repo.owner_id }
267+
end
268+
269+
custom_key = CustomKey.where(name: key, owner_id: org_ids, owner_type: 'Organization').first unless org_ids.empty?
270+
end
271+
custom_key.nil? ? nil : { name: "TRAVIS_#{key}", value: Base64.strict_encode64(custom_key.private_key), public: false, branch: nil }
272+
end.compact
273+
end
241274
end
242275
end
243276
end

lib/travis/scheduler/serialize/worker/repo.rb

+8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ def travis_vcs_proxy?
5656
vcs_type == 'TravisproxyRepository'
5757
end
5858

59+
def owner_type
60+
repo.owner_type
61+
end
62+
63+
def owner_id
64+
repo.owner_id
65+
end
66+
5967
private
6068

6169
# If the repo does not have a custom timeout, look to the repo's

spec/support/factories.rb

+9
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,14 @@ def public=(value)
8787
author_name 'Sven Fuchs'
8888
author_email '[email protected]'
8989
end
90+
91+
factory :membership do
92+
association :organization
93+
association :user
94+
end
95+
96+
factory :custom_key, :class => 'CustomKey' do
97+
name 'key'
98+
end
9099
end
91100

spec/travis/scheduler/serialize/worker_spec.rb

+41
Original file line numberDiff line numberDiff line change
@@ -449,4 +449,45 @@ def encrypted(value)
449449
it { expect(data[:keep_netrc]).to be false }
450450
end
451451
end
452+
453+
context 'custom_keys' do
454+
let!(:organization1) {FactoryGirl.create(:org, login: "org1", id: 1)}
455+
let!(:organization2) {FactoryGirl.create(:org, login: "org2", id: 2)}
456+
let!(:repo) { FactoryGirl.create(:repo, default_branch: 'main') }
457+
let!(:membership1) {FactoryGirl.create(:membership, user: repo.owner, organization: organization1) }
458+
let!(:membership2) {FactoryGirl.create(:membership, user: repo.owner, organization: organization2) }
459+
let!(:custom_key1) {FactoryGirl.create(:custom_key, name: 'key1', owner_id: organization1.id, owner_type: 'Organization', private_key: 'abc')}
460+
let!(:custom_key2) {FactoryGirl.create(:custom_key, name: 'key1', owner_id: organization2.id, owner_type: 'Organization', private_key: 'def')}
461+
462+
describe 'when two organization have the same key name' do
463+
before {
464+
build.update(sender_id: repo.owner.id)
465+
job.update(config: {:keys => ['key1']})
466+
repo.update_attributes(owner: organization2, owner_name: 'org2')
467+
}
468+
469+
it { expect(data[:env_vars]).to include({:name=>"TRAVIS_key1", :value=>"ZGVm", :public=>false, :branch=>nil})}
470+
end
471+
472+
describe 'when user has no access to organization' do
473+
let!(:organization3) {FactoryGirl.create(:org, login: "org3", id: 3)}
474+
let!(:custom_key3) {FactoryGirl.create(:custom_key, name: 'key1', owner_id: organization3.id, owner_type: 'Organization', private_key: 'ghi')}
475+
let(:raw_settings) do
476+
{
477+
env_vars: nil,
478+
timeout_hard_limit: 180,
479+
timeout_log_silence: 20,
480+
share_ssh_keys_with_forks: false
481+
}
482+
end
483+
484+
before {
485+
build.update(sender_id: repo.owner.id)
486+
job.update(config: {:keys => ['key1']})
487+
repo.update_attributes(owner: organization3, owner_name: 'org3')
488+
}
489+
490+
it { expect(data[:env_vars]).to eq([])}
491+
end
492+
end
452493
end

0 commit comments

Comments
 (0)