kensa 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/server.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'sinatra'
2
+ require 'yajl'
3
+ require 'restclient'
4
+
5
+ post "/heroku/resources" do
6
+ resp = { :id => 123, :config => { "FOO" => "bar" } }
7
+ #resp = { :id => 123 }
8
+ Yajl::Encoder.encode(resp)
9
+ end
10
+
11
+ delete "/heroku/resources/:id" do
12
+ "ok"
13
+ end
data/set-env.sh ADDED
@@ -0,0 +1,4 @@
1
+ PATH=$(pwd)/bin:$PATH
2
+ RUBYOPT=rubygems
3
+ RUBYLIB=$(pwd)/lib:$RUBYLIB
4
+ export PATH RUBYOPT RUBYLIB
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class DeprovisionCheckTest < Test::Unit::TestCase
4
+ include Heroku::Sensei
5
+
6
+ setup do
7
+ @data = Manifest.skeleton.merge :id => 123
8
+ @responses = [
9
+ [200, ""],
10
+ [401, ""],
11
+ ]
12
+ end
13
+
14
+ def check ; DeprovisionCheck ; end
15
+
16
+ test "valid on 200" do
17
+ assert_valid do |check|
18
+ stub :delete, check, @responses
19
+ end
20
+ end
21
+
22
+ test "status other than 200" do
23
+ @responses[0] = [500, ""]
24
+ assert_invalid do |check|
25
+ stub :delete, check, @responses
26
+ end
27
+ end
28
+
29
+ test "runs auth check" do
30
+ @responses[1] = [200, ""]
31
+ assert_invalid do |check|
32
+ stub :delete, check, @responses
33
+ end
34
+ end
35
+
36
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'heroku/kensa'
2
+ require 'contest'
3
+
4
+ class Test::Unit::TestCase
5
+
6
+ def assert_valid(data=@data, &blk)
7
+ check = create_check(data, &blk)
8
+ assert check.call
9
+ end
10
+
11
+ def assert_invalid(data=@data, &blk)
12
+ check = create_check(data, &blk)
13
+ assert !check.call
14
+ end
15
+
16
+ def create_check(data, &blk)
17
+ check = self.check.new(data)
18
+ blk.call(check) if blk
19
+ check
20
+ end
21
+
22
+ module Headerize
23
+ attr_accessor :headers
24
+ end
25
+
26
+ def to_json(data, headers={})
27
+ body = Yajl::Encoder.encode(data)
28
+ add_headers(body, headers)
29
+ end
30
+
31
+ def add_headers(o, headers={})
32
+ o.extend Headerize
33
+ o.headers = {}
34
+ o.headers["Content-Type"] ||= "application/json"
35
+ o.headers.merge!(headers)
36
+ o
37
+ end
38
+
39
+ def stub(meth, o, returns)
40
+ o.instance_eval { @returns = Array(returns) }
41
+ eval <<-EVAL
42
+ def o.#{meth}(*args)
43
+ @returns.shift || fail("Nothing else to return from stub'ed method")
44
+ end
45
+ EVAL
46
+ end
47
+
48
+ end
@@ -0,0 +1,142 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class ManifestCheckTest < Test::Unit::TestCase
4
+ include Heroku::Sensei
5
+
6
+ def check ; ManifestCheck ; end
7
+
8
+ setup do
9
+ @data = Manifest.skeleton
10
+ @data["plans"] << {
11
+ "id" => "advanced",
12
+ "name" => "Advanced",
13
+ "price" => "100",
14
+ "price_unit" => "month"
15
+ }
16
+ end
17
+
18
+ test "is valid if no errors" do
19
+ assert_valid
20
+ end
21
+
22
+ test "has an id" do
23
+ @data.delete("id")
24
+ assert_invalid
25
+ end
26
+
27
+ test "has a name" do
28
+ @data.delete("name")
29
+ assert_invalid
30
+ end
31
+
32
+ test "api key exists" do
33
+ @data.delete("api")
34
+ assert_invalid
35
+ end
36
+
37
+ test "api is a Hash" do
38
+ @data["api"] = ""
39
+ assert_invalid
40
+ end
41
+
42
+ test "api has a username" do
43
+ @data["api"].delete("username")
44
+ assert_invalid
45
+ end
46
+
47
+ test "api has a password" do
48
+ @data["api"].delete("password")
49
+ assert_invalid
50
+ end
51
+
52
+ test "api contains test" do
53
+ @data["api"].delete("test")
54
+ assert_invalid
55
+ end
56
+
57
+ test "api contains production" do
58
+ @data["api"].delete("production")
59
+ assert_invalid
60
+ end
61
+
62
+ test "api contains production of https" do
63
+ @data["api"]["production"] = "http://foo.com"
64
+ assert_invalid
65
+ end
66
+
67
+ test "api contains config_vars array" do
68
+ @data["api"]["config_vars"] = "test"
69
+ assert_invalid
70
+ end
71
+
72
+ test "api contains at least one config var" do
73
+ @data["api"]["config_vars"].clear
74
+ assert_invalid
75
+ end
76
+
77
+ test "all config vars are in upper case" do
78
+ @data["api"]["config_vars"] << 'MYADDON_invalid_var'
79
+ assert_invalid
80
+ end
81
+
82
+ test "assert config var prefixes match addon id" do
83
+ @data["api"]["config_vars"] << 'MONGO_URL'
84
+ assert_invalid
85
+ end
86
+
87
+ test "plans key must exist" do
88
+ @data.delete("plans")
89
+ assert_invalid
90
+ end
91
+
92
+ test "plans key must be an Array" do
93
+ @data["plans"] = ""
94
+ assert_invalid
95
+ end
96
+
97
+ test "has at least one plan" do
98
+ @data["plans"] = []
99
+ assert_invalid
100
+ end
101
+
102
+ test "all plans are a hash" do
103
+ @data["plans"][0] = ""
104
+ assert_invalid
105
+ end
106
+
107
+ test "all plans have an id" do
108
+ @data["plans"].first.delete("id")
109
+ assert_invalid
110
+ end
111
+
112
+ test "all plans have an unique id" do
113
+ @data["plans"].first["id"] = @data["plans"].last["id"]
114
+ assert_invalid
115
+ end
116
+
117
+ test "all plans have a name" do
118
+ @data["plans"].first.delete("name")
119
+ assert_invalid
120
+ end
121
+
122
+ test "all plans have a unique name" do
123
+ @data["plans"].first["name"] = @data["plans"].last["name"]
124
+ assert_invalid
125
+ end
126
+
127
+ test "plans have a price" do
128
+ @data["plans"].first.delete("price")
129
+ assert_invalid
130
+ end
131
+
132
+ test "plans have an integer price" do
133
+ @data["plans"].first["price"] = "fiddy cent"
134
+ assert_invalid
135
+ end
136
+
137
+ test "plans have a valid price_unit" do
138
+ @data["plans"].first["price_unit"] = "first ov da munth"
139
+ assert_invalid
140
+ end
141
+
142
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class ProvisionCheckTest < Test::Unit::TestCase
4
+ include Heroku::Sensei
5
+
6
+ setup do
7
+ @data = Manifest.skeleton
8
+ @responses = [
9
+ [200, to_json({ :id => 456 })],
10
+ [401, "Unauthorized"]
11
+ ]
12
+ end
13
+
14
+ def check ; ProvisionCheck ; end
15
+
16
+ test "valid on 200 for the regular check, and 401 for the auth check" do
17
+ assert_valid do |check|
18
+ stub :post, check, @responses
19
+ end
20
+ end
21
+
22
+ test "invalid JSON" do
23
+ @responses[0] = [200, "---"]
24
+ assert_invalid do |check|
25
+ stub :post, check, @responses
26
+ end
27
+ end
28
+
29
+ test "status other than 200" do
30
+ @responses[0] = [500, to_json({ :id => 456 })]
31
+ assert_invalid do |check|
32
+ stub :post, check, @responses
33
+ end
34
+ end
35
+
36
+ test "runs provision response check" do
37
+ @responses[0] = [200, to_json({ :noid => 456 })]
38
+ assert_invalid do |check|
39
+ stub :post, check, @responses
40
+ end
41
+ end
42
+
43
+ test "runs auth check" do
44
+ @responses[1] = [200, to_json({ :id => 456 })]
45
+ assert_invalid do |check|
46
+ stub :post, check, @responses
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class ProvisionResponseCheckTest < Test::Unit::TestCase
4
+ include Heroku::Sensei
5
+
6
+ def check ; ProvisionResponseCheck ; end
7
+
8
+ setup do
9
+ @response = { "id" => "123" }
10
+ @data = Manifest.skeleton.merge(:provision_response => @response)
11
+ @data['api']['config_vars'] << "MYADDON_CONFIG"
12
+ end
13
+
14
+ test "is valid if no errors" do
15
+ assert_valid
16
+ end
17
+
18
+ test "has an id" do
19
+ @response.delete("id")
20
+ assert_invalid
21
+ end
22
+
23
+ describe "when config is present" do
24
+
25
+ test "is a hash" do
26
+ @response["config"] = ""
27
+ assert_invalid
28
+ end
29
+
30
+ test "each key is previously set in the manifest" do
31
+ @response["config"] = { "MYSQL_URL" => "http://..." }
32
+ assert_invalid
33
+ end
34
+
35
+ test "each value is a string" do
36
+ @response["config"] = { "MYADDON_URL" => {} }
37
+ assert_invalid
38
+ end
39
+
40
+ test "asserts _URL vars are valid URIs" do
41
+ @response["config"] = { "MYADDON_URL" => "abc:" }
42
+ assert_invalid
43
+ end
44
+
45
+ test "asserts _URL vars have a host" do
46
+ @response["config"] = { "MYADDON_URL" => "path" }
47
+ assert_invalid
48
+ end
49
+
50
+ test "asserts _URL vars have a scheme" do
51
+ @response["config"] = { "MYADDON_URL" => "//host/path" }
52
+ assert_invalid
53
+ end
54
+
55
+ test "doesn't run URI test against other vars" do
56
+ @response["config"] = { "MYADDON_CONFIG" => "abc:" }
57
+ assert_valid
58
+ end
59
+
60
+ test "doesn't allow localhost URIs on production" do
61
+ @data[:env] = 'production'
62
+ @response["config"] = { "MYADDON_URL" => "http://localhost/abc" }
63
+ assert_invalid
64
+ end
65
+
66
+ test "is valid otherwise" do
67
+ @response["config"] = { "MYADDON_URL" => "http://localhost/abc" }
68
+ assert_valid
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+
4
+ enable :sessions
5
+
6
+ helpers do
7
+ def unauthorized!(status=403)
8
+ throw(:halt, [status, "Not authorized\n"])
9
+ end
10
+
11
+ def make_token
12
+ Digest::SHA1.hexdigest([params[:id], 'SSO_SALT', params[:timestamp]].join(':'))
13
+ end
14
+
15
+ def login
16
+ session[:logged_in] = true
17
+ redirect '/'
18
+ end
19
+ end
20
+
21
+ get '/working/heroku/resources/:id' do
22
+ unauthorized! unless params[:id] && params[:token]
23
+ unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
24
+ unauthorized! unless params[:token] == make_token
25
+ login
26
+ end
27
+
28
+ get '/notoken/heroku/resources/:id' do
29
+ unauthorized! unless params[:id] && params[:token]
30
+ unauthorized! unless params[:timestamp].to_i > (Time.now-60*2).to_i
31
+ login
32
+ end
33
+
34
+ get '/notimestamp/heroku/resources/:id' do
35
+ unauthorized! unless params[:id] && params[:token]
36
+ unauthorized! unless params[:token] == make_token
37
+ login
38
+ end
39
+
40
+ get '/' do
41
+ unauthorized! unless session[:logged_in]
42
+ "OK"
43
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + "/helper"
2
+
3
+ class SsoCheckTest < Test::Unit::TestCase
4
+ include Heroku::Sensei
5
+
6
+ setup do
7
+ @data = Manifest.skeleton.merge :id => 123
8
+ @data['api']['sso_salt'] = 'SSO_SALT'
9
+ end
10
+
11
+ def check ; SsoCheck ; end
12
+
13
+ test "working sso request" do
14
+ @data['api']['test'] += "working"
15
+ assert_valid
16
+ end
17
+
18
+ test "rejects bad token" do
19
+ @data['api']['test'] += "notoken"
20
+ assert_invalid
21
+ end
22
+
23
+ test "rejects old timestamp" do
24
+ @data['api']['test'] += "notimestamp"
25
+ assert_invalid
26
+ end
27
+
28
+ end