Merge branch 'master' into jc-v3-env-vars

This commit is contained in:
Renée Hendricksen 2016-07-05 11:44:28 -04:00
commit ac7e610510
10 changed files with 49 additions and 23 deletions

View File

@ -22,7 +22,7 @@ gem 'sentry-raven'
gem 'yard-sinatra', github: 'rkh/yard-sinatra' gem 'yard-sinatra', github: 'rkh/yard-sinatra'
gem 'rack-contrib' gem 'rack-contrib'
gem 'rack-cache', github: 'rtomayko/rack-cache' gem 'rack-cache', github: 'rtomayko/rack-cache'
gem 'rack-attack' gem 'rack-attack', '5.0.0.beta1'
gem 'gh' gem 'gh'
gem 'bunny', '~> 0.8.0' gem 'bunny', '~> 0.8.0'
gem 'dalli' gem 'dalli'
@ -33,6 +33,7 @@ gem 'micro_migrations'
gem 'simplecov' gem 'simplecov'
gem 'skylight', '~> 0.6.0.beta.1' gem 'skylight', '~> 0.6.0.beta.1'
gem 'stackprof' gem 'stackprof'
gem 'netaddr'
gem 'jemalloc' gem 'jemalloc'
gem 'customerio' gem 'customerio'

View File

@ -260,6 +260,7 @@ GEM
multipart-post (2.0.0) multipart-post (2.0.0)
net-http-persistent (2.9.4) net-http-persistent (2.9.4)
net-http-pipeline (1.0.1) net-http-pipeline (1.0.1)
netaddr (1.5.1)
os (0.9.6) os (0.9.6)
pg (0.18.4) pg (0.18.4)
proxies (0.2.1) proxies (0.2.1)
@ -273,7 +274,7 @@ GEM
pusher-signature (~> 0.1.8) pusher-signature (~> 0.1.8)
pusher-signature (0.1.8) pusher-signature (0.1.8)
rack (1.4.7) rack (1.4.7)
rack-attack (4.4.1) rack-attack (5.0.0.beta1)
rack rack
rack-contrib (1.4.0) rack-contrib (1.4.0)
git-version-bump (~> 0.15) git-version-bump (~> 0.15)
@ -397,8 +398,9 @@ DEPENDENCIES
micro_migrations micro_migrations
mocha (~> 0.12) mocha (~> 0.12)
mustermann! mustermann!
netaddr
pry pry
rack-attack rack-attack (= 5.0.0.beta1)
rack-cache! rack-cache!
rack-contrib rack-contrib
rake (~> 0.9.2) rake (~> 0.9.2)

View File

@ -132,7 +132,7 @@ module Travis::Api
use Travis::Api::App::Middleware::UserAgentTracker use Travis::Api::App::Middleware::UserAgentTracker
# make sure this is below ScopeCheck so we have the token # make sure this is below ScopeCheck so we have the token
use Rack::Attack if Endpoint.production? use Rack::Attack if Endpoint.production? and not Travis.config.enterprise
# if this is a v3 API request, ignore everything after # if this is a v3 API request, ignore everything after
use Travis::API::V3::OptIn use Travis::API::V3::OptIn

View File

@ -114,7 +114,7 @@ class Travis::Api::App
# access token and user payload to the parent window via postMessage. # access token and user payload to the parent window via postMessage.
# #
# However, the endpoint to send the payload to has to be explicitely # However, the endpoint to send the payload to has to be explicitely
# whitelisted in production, as this is endpoint is only meant to be used # safelisted in production, as this is endpoint is only meant to be used
# with the official Travis CI client at the moment. # with the official Travis CI client at the moment.
# #
# Example usage: # Example usage:
@ -408,7 +408,7 @@ __END__
@@ invalid_target @@ invalid_target
<script> <script>
console.log('refusing to send a token to <%= target_origin.inspect %>, not whitelisted!'); console.log('refusing to send a token to <%= target_origin.inspect %>, not safelisted!');
</script> </script>
@@ common @@ common

View File

@ -1,4 +1,5 @@
require 'rack/attack' require 'rack/attack'
require 'netaddr'
class Rack::Attack class Rack::Attack
class Request class Request
@ -31,29 +32,38 @@ class Rack::Attack
"/auth/post_message/iframe" "/auth/post_message/iframe"
] ]
whitelist('safelist build status images') do |request| GITHUB_CIDR = NetAddr::CIDR.create('192.30.252.0/22')
safelist('safelist build status images') do |request|
/\.(png|svg)$/.match(request.path) /\.(png|svg)$/.match(request.path)
end end
# https://help.github.com/articles/what-ip-addresses-does-github-use-that-i-should-safelist/
safelist('safelist anything coming from github') do |request|
request.ip && GITHUB_CIDR.contains?(request.ip)
end
#### ####
# Whitelisted IP addresses # Whitelisted IP addresses
whitelist('whitelist client requesting from redis') do |request| safelist('safelist client requesting from redis') do |request|
Travis.redis.sismember(:api_whitelisted_ips, request.ip) # TODO: deprecate :api_whitelisted_ips in favour of api_safelisted_ips
Travis.redis.sismember(:api_whitelisted_ips, request.ip) || Travis.redis.sismember(:api_safelisted_ips, request.ip)
end end
#### ####
# Ban based on: IP address # Ban based on: IP address
# Ban time: indefinite # Ban time: indefinite
# Ban after: manually banned # Ban after: manually banned
blacklist('block client requesting from redis') do |request| blocklist('block client requesting from redis') do |request|
Travis.redis.sismember(:api_blacklisted_ips, request.ip) # TODO: deprecate :api_blacklisted_ips in favour of api_blocklisted_ips
Travis.redis.sismember(:api_blacklisted_ips, request.ip) || Travis.redis.sismember(:api_blocklisted_ips, request.ip)
end end
#### ####
# Ban based on: IP address or access token # Ban based on: IP address or access token
# Ban time: 5 hours # Ban time: 5 hours
# Ban after: 10 POST requests within five minutes to /auth/github # Ban after: 10 POST requests within five minutes to /auth/github
blacklist('hammering /auth/github') do |request| blocklist('hammering /auth/github') do |request|
Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 2, findtime: 5.minutes, bantime: bantime(5.hours)) do Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 2, findtime: 5.minutes, bantime: bantime(5.hours)) do
request.post? and request.path == '/auth/github' request.post? and request.path == '/auth/github'
end end
@ -63,7 +73,7 @@ class Rack::Attack
# Ban based on: IP address or access token # Ban based on: IP address or access token
# Ban time: 1 hour # Ban time: 1 hour
# Ban after: 10 POST requests within 30 seconds # Ban after: 10 POST requests within 30 seconds
blacklist('spamming with POST requests') do |request| blocklist('spamming with POST requests') do |request|
Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 10, findtime: 30.seconds, bantime: bantime(1.hour)) do Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 10, findtime: 30.seconds, bantime: bantime(1.hour)) do
request.post? and not POST_SAFELIST.include? request.path request.post? and not POST_SAFELIST.include? request.path
end end

View File

@ -29,7 +29,7 @@ module Travis::API::V3
result = service.run result = service.run
metrics.tick(:service) metrics.tick(:service)
env_params.each_key { |key| result.ignored_param(key, reason: "not whitelisted".freeze) unless filtered.include?(key) } env_params.each_key { |key| result.ignored_param(key, reason: "not safelisted".freeze) unless filtered.include?(key) }
response = render(result, env_params, env) response = render(result, env_params, env)
metrics.tick(:renderer) metrics.tick(:renderer)

View File

@ -6,18 +6,31 @@ describe Rack::Attack do
} }
it 'should be safelisted' do it 'should be safelisted' do
expect(Rack::Attack.whitelisted?(request)).to be_truthy expect(Rack::Attack.safelisted?(request)).to be_truthy
end end
end end
describe 'non-image API request' do describe 'request from GitHub ip' do
let(:request) {
env = Rack::MockRequest.env_for("https://api-test.travis-ci.org/repos/rails/rails/branches", {
'REMOTE_ADDR' => '192.30.252.42',
})
Rack::Attack::Request.new(env)
}
it 'should be safelisted' do
expect(Rack::Attack.safelisted?(request)).to be_truthy
end
end
describe 'non-safelisted request' do
let(:request) { let(:request) {
env = Rack::MockRequest.env_for("https://api-test.travis-ci.org/repos/rails/rails/branches") env = Rack::MockRequest.env_for("https://api-test.travis-ci.org/repos/rails/rails/branches")
Rack::Attack::Request.new(env) Rack::Attack::Request.new(env)
} }
it 'should not be safelisted' do it 'should not be safelisted' do
expect(Rack::Attack.whitelisted?(request)).to be_falsy expect(Rack::Attack.safelisted?(request)).to be_falsy
end end
end end
end end

View File

@ -167,7 +167,7 @@ describe Travis::API::V3::Services::Owner::Find, set_app: true do
"avatar_url" => nil, "avatar_url" => nil,
"@warnings" => [{ "@warnings" => [{
"@type" => "warning", "@type" => "warning",
"message" => "query parameter organization.id not whitelisted, ignored", "message" => "query parameter organization.id not safelisted, ignored",
"warning_type" => "ignored_parameter", "warning_type" => "ignored_parameter",
"parameter" => "organization.id"}] "parameter" => "organization.id"}]
}} }}
@ -254,7 +254,7 @@ describe Travis::API::V3::Services::Owner::Find, set_app: true do
"synced_at" => nil, "synced_at" => nil,
"@warnings" => [{ "@warnings" => [{
"@type" => "warning", "@type" => "warning",
"message" => "query parameter user.id not whitelisted, ignored", "message" => "query parameter user.id not safelisted, ignored",
"warning_type" => "ignored_parameter", "warning_type" => "ignored_parameter",
"parameter" => "user.id"}] "parameter" => "user.id"}]
}} }}

View File

@ -129,7 +129,7 @@ describe Job do
} }
end end
it 'removes addons items which are not whitelisted' do it 'removes addons items which are not safelisted' do
job = Job.new(repository: repo) job = Job.new(repository: repo)
config = { rvm: '1.8.7', config = { rvm: '1.8.7',
addons: { sauce_connect: true, firefox: '22.0' }, addons: { sauce_connect: true, firefox: '22.0' },
@ -328,7 +328,7 @@ describe Job do
} }
end end
it 'removes addons items which are not whitelisted' do it 'removes addons items which are not safelisted' do
config = { rvm: '1.8.7', config = { rvm: '1.8.7',
addons: { addons: {
sauce_connect: { sauce_connect: {

View File

@ -14,7 +14,7 @@ class Job < Travis::Model
require 'travis/model/job/test' require 'travis/model/job/test'
require 'travis/model/env_helpers' require 'travis/model/env_helpers'
WHITELISTED_ADDONS = %w( SAFELISTED_ADDONS = %w(
apt apt
apt_packages apt_packages
apt_sources apt_sources
@ -167,7 +167,7 @@ class Job < Travis::Model
def delete_addons(config) def delete_addons(config)
if config[:addons].is_a?(Hash) if config[:addons].is_a?(Hash)
config[:addons].keep_if { |key, _| WHITELISTED_ADDONS.include? key.to_s } config[:addons].keep_if { |key, _| SAFELISTED_ADDONS.include? key.to_s }
else else
config.delete(:addons) config.delete(:addons)
end end