kensa 1.2.0rc7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -1
- data/Gemfile +5 -4
- data/Gemfile.lock +21 -27
- data/README.md +1 -1
- data/Rakefile +18 -10
- data/bin/kensa +10 -30
- data/kensa.gemspec +27 -20
- data/lib/heroku/kensa.rb +7 -9
- data/lib/heroku/kensa/check.rb +499 -0
- data/lib/heroku/kensa/client.rb +67 -89
- data/lib/heroku/kensa/git.rb +39 -0
- data/lib/heroku/kensa/manifest.rb +41 -8
- data/lib/heroku/kensa/screen.rb +37 -0
- data/lib/heroku/kensa/sso.rb +22 -22
- data/lib/heroku/kensa/version.rb +1 -2
- data/test/all_check_test.rb +25 -0
- data/test/create_test.rb +40 -6
- data/test/deprovision_check_test.rb +39 -0
- data/test/helper.rb +74 -11
- data/test/init_test.rb +54 -0
- data/test/manifest_check_test.rb +94 -0
- data/test/manifest_test.rb +37 -33
- data/test/plan_change_check_test.rb +31 -0
- data/test/provision_check_test.rb +51 -0
- data/test/provision_response_check_test.rb +81 -0
- data/test/resources/runner.rb +1 -0
- data/test/resources/server.rb +227 -0
- data/test/sso_check_test.rb +58 -0
- data/test/sso_test.rb +113 -53
- metadata +97 -91
- data/test.rb +0 -1
- data/test/deprovision_test.rb +0 -30
- data/test/lib/dependencies.rb +0 -12
- data/test/lib/formatter.rb +0 -84
- data/test/lib/http.rb +0 -60
- data/test/lib/response.rb +0 -12
- data/test/manifest_generation_test.rb +0 -32
- data/test/plan_change_test.rb +0 -30
- data/test/provision_test.rb +0 -84
- data/test/resources/provider_server.rb +0 -81
- data/test/resources/views/index.haml +0 -6
- data/test/sso_launch_test.rb +0 -130
data/test.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
puts ARGV
|
data/test/deprovision_test.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
$:.unshift(File.expand_path("../..",__FILE__))
|
2
|
-
require 'test/lib/dependencies'
|
3
|
-
class DeprovisionTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
def setup
|
6
|
-
super
|
7
|
-
@params = {}
|
8
|
-
end
|
9
|
-
|
10
|
-
def deprovision(auth = nil)
|
11
|
-
delete "/heroku/resources/123", auth
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_working_deprovision_call
|
15
|
-
response = deprovision
|
16
|
-
assert_equal 200, response.code, "Expects a 200 - OK response/status code when successfully deprovisioned."
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_detects_missing_auth
|
20
|
-
response = deprovision(auth = false)
|
21
|
-
assert_equal 401, response.code, "Provisioning request should require authentication."
|
22
|
-
|
23
|
-
response = deprovision(auth = [manifest["id"]+"a", manifest["api"]["password"]])
|
24
|
-
assert_equal 401, response.code, "Provisioning request appears to allow any username, should require '#{manifest["id"]}'."
|
25
|
-
|
26
|
-
response = deprovision(auth = [manifest["id"], manifest["api"]["password"]+"a"])
|
27
|
-
assert_equal 401, response.code, "Provisioning request appears to allow any password, should require '#{manifest["api"]["password"]}'."
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
data/test/lib/dependencies.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'artifice'
|
3
|
-
require 'rest-client'
|
4
|
-
require 'yajl'
|
5
|
-
require 'lib/heroku/kensa/manifest'
|
6
|
-
%w{response http formatter}.each do |lib|
|
7
|
-
require "test/lib/#{lib}"
|
8
|
-
end
|
9
|
-
|
10
|
-
class Test::Unit::TestCase
|
11
|
-
include Heroku::Kensa::HTTPTest
|
12
|
-
end
|
data/test/lib/formatter.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'test/unit/ui/console/testrunner'
|
3
|
-
|
4
|
-
def format_kensa_test_name(name)
|
5
|
-
name.sub(/\Atest_/,"").match(/\A([^\(]*)/)[1].gsub("_", " ")
|
6
|
-
end
|
7
|
-
|
8
|
-
module Test
|
9
|
-
module Unit
|
10
|
-
class TestCase
|
11
|
-
alias_method :add_error_with_connection_exception, :add_error
|
12
|
-
alias_method :add_failure_with_connection_exception, :add_failure
|
13
|
-
|
14
|
-
private
|
15
|
-
def add_error(exception)
|
16
|
-
if exception.is_a? Heroku::Kensa::UserError
|
17
|
-
@test_passed = false
|
18
|
-
@_result.add_failure(Failure.new(name, filter_backtrace(caller()), exception.message))
|
19
|
-
else
|
20
|
-
add_error_with_connection_exception(exception)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class Failure
|
26
|
-
def long_display
|
27
|
-
name = format_kensa_test_name(@test_name)
|
28
|
-
"#{name} - FAILED: #@message"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class Error
|
33
|
-
def long_display
|
34
|
-
backtrace = filter_backtrace(@exception.backtrace).join("\n ")
|
35
|
-
name = format_kensa_test_name(@test_name)
|
36
|
-
"#{@exception.class.name} in #{name}:\n#{message}\n #{backtrace}"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
module UI
|
41
|
-
module Console
|
42
|
-
class TestRunner
|
43
|
-
|
44
|
-
alias_method :test_started_old, :test_started
|
45
|
-
|
46
|
-
def add_fault(fault)
|
47
|
-
@faults << fault
|
48
|
-
@already_outputted = true
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_started(name)
|
52
|
-
if name =~ /\((.*)::([^\)]*)/
|
53
|
-
ctx, should = [$1, $2]
|
54
|
-
end
|
55
|
-
unless ctx.nil? or should.nil?
|
56
|
-
if ctx != @ctx
|
57
|
-
nl
|
58
|
-
output("#{ctx}:")
|
59
|
-
end
|
60
|
-
@ctx = ctx
|
61
|
-
@current_test_text = " ==> #{should}"
|
62
|
-
else
|
63
|
-
test_started_old(name)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_finished(name)
|
68
|
-
@current_test_text = name.sub(/\Atest_/,"").match(/\A([^\(]*)/)[1].gsub("_", " ")
|
69
|
-
if fault = @faults.find {|f| f.test_name == name}
|
70
|
-
fault_type = fault.is_a?(Test::Unit::Failure) ? "FAILED" : "ERROR!"
|
71
|
-
# NOTE -- Concatenation because "\e[0m]" does funky stuff.
|
72
|
-
output("[\e[0;31m#{fault_type}\e[0m" + "] #{@current_test_text}.")
|
73
|
-
else
|
74
|
-
output("[ \e[0;32mOK\e[0m ] #{@current_test_text}.")
|
75
|
-
end
|
76
|
-
@already_outputted = false
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
data/test/lib/http.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
module Heroku::Kensa::HTTPTest
|
2
|
-
def make_token(id, salt, timestamp)
|
3
|
-
Digest::SHA1.hexdigest([id, salt, timestamp].join(':'))
|
4
|
-
end
|
5
|
-
|
6
|
-
def provider_request(meth, path, params = {}, auth_credentials = nil)
|
7
|
-
if auth_credentials.nil?
|
8
|
-
auth_credentials = [manifest["id"], manifest["api"]["password"]]
|
9
|
-
end
|
10
|
-
if path =~ /http/
|
11
|
-
uri = URI.parse(path)
|
12
|
-
else
|
13
|
-
uri = URI.parse(base_url)
|
14
|
-
uri.path = path
|
15
|
-
end
|
16
|
-
if auth_credentials
|
17
|
-
uri.userinfo = auth_credentials
|
18
|
-
end
|
19
|
-
opts = meth == :get ? { :params => params } : params
|
20
|
-
response = RestClient.send(meth, "#{uri.to_s}", opts)
|
21
|
-
Response.new(response.code, response.body, response.cookies)
|
22
|
-
rescue Errno::ECONNREFUSED
|
23
|
-
raise UserError.new("Unable to connect to your API.")
|
24
|
-
rescue RestClient::Forbidden
|
25
|
-
Response.new(403)
|
26
|
-
rescue RestClient::Unauthorized
|
27
|
-
Response.new(401)
|
28
|
-
rescue RestClient::InternalServerError
|
29
|
-
raise UserError.new("HTTP 500 Internal Server Error")
|
30
|
-
end
|
31
|
-
|
32
|
-
def get(path, params = {})
|
33
|
-
provider_request(:get, path, params, auth = false)
|
34
|
-
end
|
35
|
-
|
36
|
-
def delete(path, auth_credentials = nil)
|
37
|
-
provider_request(:delete, path, params = nil, auth_credentials)
|
38
|
-
end
|
39
|
-
|
40
|
-
def post(path, params = {}, auth_credentials = nil)
|
41
|
-
provider_request(:post, path, params, auth_credentials)
|
42
|
-
end
|
43
|
-
|
44
|
-
def put(path, params = {}, auth_credentials = nil)
|
45
|
-
provider_request(:put, path, params, auth_credentials)
|
46
|
-
end
|
47
|
-
|
48
|
-
def manifest
|
49
|
-
return @manifest if @manifest
|
50
|
-
@manifest ||= $manifest || Heroku::Kensa::Manifest.new.skeleton
|
51
|
-
end
|
52
|
-
|
53
|
-
def base_url
|
54
|
-
if manifest["api"]["test"].is_a?(Hash)
|
55
|
-
manifest["api"]["test"]["base_url"].chomp("/")
|
56
|
-
else
|
57
|
-
manifest["api"]["test"].chomp("/")
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/test/lib/response.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
Response = Struct.new(:code, :body, :cookies) do
|
2
|
-
def json_body
|
3
|
-
Yajl::Parser.parse(self.body)
|
4
|
-
rescue Yajl::ParseError
|
5
|
-
if !self.body || self.body.empty?
|
6
|
-
raise Heroku::Kensa::UserError.new("response body empty")
|
7
|
-
else
|
8
|
-
raise Heroku::Kensa::UserError.new("Could not parse json: #{self.body}")
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
@@ -1,32 +0,0 @@
|
|
1
|
-
$:.unshift(File.expand_path("../..",__FILE__))
|
2
|
-
require 'test/helper'
|
3
|
-
class ManifestGenerationTest < Test::Unit::TestCase
|
4
|
-
include Heroku::Kensa
|
5
|
-
|
6
|
-
def setup
|
7
|
-
super
|
8
|
-
@manifest = Manifest.new
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_generates_a_new_sso_salt_every_time
|
12
|
-
assert @manifest.skeleton['api']['sso_salt'] != Manifest.new.skeleton['api']['sso_salt']
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_generates_a_new_password_every_time
|
16
|
-
assert @manifest.skeleton['api']['password'] != Manifest.new.skeleton['api']['password']
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class ManifestGenerationWithoutSSOTest < Test::Unit::TestCase
|
21
|
-
include Heroku::Kensa
|
22
|
-
|
23
|
-
def setup
|
24
|
-
super
|
25
|
-
options = { :sso => false }
|
26
|
-
@manifest = Manifest.new 'test.txt', options
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_exclude_sso_salt
|
30
|
-
assert_nil @manifest.skeleton['api']['sso_salt']
|
31
|
-
end
|
32
|
-
end
|
data/test/plan_change_test.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
$:.unshift(File.expand_path("../..",__FILE__))
|
2
|
-
require 'test/lib/dependencies'
|
3
|
-
class PlanChangeTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
def setup
|
6
|
-
super
|
7
|
-
@params = { :plan => "new_plan" }
|
8
|
-
end
|
9
|
-
|
10
|
-
def plan_change(auth = nil, params = @params)
|
11
|
-
response = put "/heroku/resources/123", params, auth
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_working_plan_change_call
|
15
|
-
response = plan_change
|
16
|
-
assert_equal 200, response.code, "Expected a 200 response code on successful plan change."
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_detects_missing_auth
|
20
|
-
response = plan_change(auth = false)
|
21
|
-
assert_equal 401, response.code, "Provisioning request should require authentication."
|
22
|
-
|
23
|
-
response = plan_change(auth = [manifest["id"]+"a", manifest["api"]["password"]])
|
24
|
-
assert_equal 401, response.code, "Provisioning request appears to allow any username, should require '#{manifest["id"]}'."
|
25
|
-
|
26
|
-
response = plan_change(auth = [manifest["id"], manifest["api"]["password"]+"a"])
|
27
|
-
assert_equal 401, response.code, "Provisioning request appears to allow any password, should require '#{manifest["api"]["password"]}'."
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
data/test/provision_test.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
$:.unshift(File.expand_path("../..",__FILE__))
|
2
|
-
require 'test/lib/dependencies'
|
3
|
-
class ProvisionTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
def setup
|
6
|
-
super
|
7
|
-
@params = {}
|
8
|
-
end
|
9
|
-
|
10
|
-
def provision(auth = nil, params = @params)
|
11
|
-
post "/heroku/resources", params, auth
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_working_provision_call
|
15
|
-
response = provision
|
16
|
-
assert_equal 201, response.code, "Expects a 201 - Created response/status code when successfully provisioned."
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_allows_the_definition_of_a_custom_provisioning_endpoint
|
20
|
-
#Artifice.activate_with(KensaServer.new)
|
21
|
-
#@data['api']['test'] = {
|
22
|
-
# "base_url" => "https://example.org/providers/provision",
|
23
|
-
# "sso_url" => "https://example.org/sso"
|
24
|
-
#}
|
25
|
-
#assert_valid
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_expects_a_valid_json_response
|
29
|
-
response = provision
|
30
|
-
assert response.json_body, "Expects a valid JSON object as response body."
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_detects_missing_id
|
34
|
-
response = provision
|
35
|
-
assert response.json_body["id"], "Expects JSON response to contain the Provider's unique ID for this app."
|
36
|
-
assert response.json_body["id"].to_s.strip != "", "Expects JSON response to contain the Provider's unique ID for this app."
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_provides_app_config
|
40
|
-
response = provision
|
41
|
-
assert response.json_body["config"].is_a?(Hash), "Expects JSON response to contain a hash of config variables."
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_all_config_values_are_strings
|
45
|
-
response = provision
|
46
|
-
response.json_body["config"].each do |k,v|
|
47
|
-
assert k.is_a?(String), "Expect all config names to be strings ('#{k}' is not)."
|
48
|
-
assert v.is_a?(String), "Expect all config values to be strings ('#{v}' is not)."
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_all_config_vars_are_defined_in_the_manifest
|
53
|
-
response = provision
|
54
|
-
response.json_body["config"].each do |k,v|
|
55
|
-
assert manifest["api"]["config_vars"].include?(k), "Only config vars defined in the manfiest can be set ('#{k}' is not)."
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_all_config_url_values_are_valid
|
60
|
-
response = provision
|
61
|
-
response.json_body["config"].each do |k,v|
|
62
|
-
next unless k =~ /_URL\z/
|
63
|
-
begin
|
64
|
-
uri = URI.parse(v)
|
65
|
-
assert uri.host, "#{v} is not a valid URI - missing host"
|
66
|
-
assert uri.scheme, "#{v} is not a valid URI - missing scheme"
|
67
|
-
rescue URI::InvalidURIError
|
68
|
-
assert false, "#{v} is not a valud URI"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def test_detects_missing_auth
|
74
|
-
response = provision(auth = false)
|
75
|
-
assert_equal 401, response.code, "Provisioning request should require authentication."
|
76
|
-
|
77
|
-
response = provision(auth = [manifest["id"]+"a", manifest["api"]["password"]])
|
78
|
-
assert_equal 401, response.code, "Provisioning request appears to allow any username, should require '#{manifest["id"]}'."
|
79
|
-
|
80
|
-
response = provision(auth = [manifest["id"], manifest["api"]["password"]+"a"])
|
81
|
-
assert_equal 401, response.code, "Provisioning request appears to allow any password, should require '#{manifest["api"]["password"]}'."
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'sinatra'
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
class ProviderServer < Sinatra::Base
|
5
|
-
set :views, File.dirname(__FILE__) + "/views"
|
6
|
-
|
7
|
-
def initialize(manifest = nil)
|
8
|
-
@manifest = manifest
|
9
|
-
super
|
10
|
-
end
|
11
|
-
|
12
|
-
helpers do
|
13
|
-
def unauthorized!(status=403)
|
14
|
-
halt status, "Not authorized\n"
|
15
|
-
end
|
16
|
-
|
17
|
-
def check_timestamp!
|
18
|
-
unauthorized! if params[:timestamp].to_i < (Time.now-60*2).to_i
|
19
|
-
end
|
20
|
-
|
21
|
-
def check_token!
|
22
|
-
salt = @manifest && @manifest['api']["sso_salt"]
|
23
|
-
token = Digest::SHA1.hexdigest([params[:id], salt, params[:timestamp]].join(':'))
|
24
|
-
unauthorized! if params[:token] != token
|
25
|
-
end
|
26
|
-
|
27
|
-
def authenticate!
|
28
|
-
unless auth_heroku?
|
29
|
-
response['WWW-Authenticate'] = %(Basic realm="Kensa Test Server")
|
30
|
-
unauthorized!(401)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def auth_heroku?
|
35
|
-
auth = Rack::Auth::Basic::Request.new(request.env)
|
36
|
-
return false unless auth.provided? && auth.basic? && auth.credentials
|
37
|
-
if @manifest
|
38
|
-
auth.credentials == [@manifest["id"], @manifest["api"]["password"]]
|
39
|
-
else
|
40
|
-
auth.credentials == ['myaddon', 'secret']
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
delete '/heroku/resources/:id' do
|
46
|
-
authenticate!
|
47
|
-
status 200
|
48
|
-
end
|
49
|
-
|
50
|
-
put '/heroku/resources/:id' do
|
51
|
-
authenticate!
|
52
|
-
status 200
|
53
|
-
end
|
54
|
-
|
55
|
-
post '/heroku/resources' do
|
56
|
-
authenticate!
|
57
|
-
status 201
|
58
|
-
{ "id" => 52343.to_s,
|
59
|
-
"config" => {
|
60
|
-
"MYADDON_USER" => "1",
|
61
|
-
"MYADDON_URL" => "http://host.example.org/"
|
62
|
-
}
|
63
|
-
}.to_json
|
64
|
-
end
|
65
|
-
|
66
|
-
get '/heroku/resources/:id' do
|
67
|
-
check_timestamp!
|
68
|
-
check_token!
|
69
|
-
response.set_cookie('heroku-nav-data', params['nav-data'])
|
70
|
-
session[:heroku] = true
|
71
|
-
haml :index
|
72
|
-
end
|
73
|
-
|
74
|
-
post '/sso/login' do
|
75
|
-
check_timestamp!
|
76
|
-
check_token!
|
77
|
-
response.set_cookie('heroku-nav-data', params['nav-data'])
|
78
|
-
session[:heroku] = true
|
79
|
-
haml :index
|
80
|
-
end
|
81
|
-
end
|