slosilo 1.0.0 → 2.2.1
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.
- checksums.yaml +5 -5
- data/.dockerignore +2 -0
- data/.gitleaks.toml +221 -0
- data/CHANGELOG.md +11 -0
- data/CONTRIBUTING.md +16 -0
- data/Jenkinsfile +55 -0
- data/LICENSE +2 -2
- data/README.md +125 -8
- data/lib/slosilo.rb +1 -0
- data/lib/slosilo/adapters/sequel_adapter.rb +1 -1
- data/lib/slosilo/attr_encrypted.rb +29 -6
- data/lib/slosilo/errors.rb +3 -0
- data/lib/slosilo/jwt.rb +122 -0
- data/lib/slosilo/key.rb +86 -3
- data/lib/slosilo/keystore.rb +13 -2
- data/lib/slosilo/symmetric.rb +30 -9
- data/lib/slosilo/version.rb +1 -1
- data/publish-rubygem.sh +11 -0
- data/slosilo.gemspec +11 -3
- data/spec/encrypted_attributes_spec.rb +114 -0
- data/spec/file_adapter_spec.rb +10 -10
- data/spec/jwt_spec.rb +102 -0
- data/spec/key_spec.rb +120 -41
- data/spec/keystore_spec.rb +2 -2
- data/spec/random_spec.rb +12 -2
- data/spec/sequel_adapter_spec.rb +26 -30
- data/spec/slosilo_spec.rb +47 -15
- data/spec/spec_helper.rb +2 -20
- data/spec/symmetric_spec.rb +44 -22
- data/test.sh +25 -0
- metadata +36 -11
data/spec/keystore_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe Slosilo::Keystore do
|
|
7
7
|
describe '#put' do
|
8
8
|
it "handles Slosilo::Keys" do
|
9
9
|
subject.put(:test, key)
|
10
|
-
adapter['test'].to_der.
|
10
|
+
expect(adapter['test'].to_der).to eq(rsa.to_der)
|
11
11
|
end
|
12
12
|
|
13
13
|
it "refuses to store a key with a nil id" do
|
@@ -19,7 +19,7 @@ describe Slosilo::Keystore do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it "passes the Slosilo key to the adapter" do
|
22
|
-
adapter.
|
22
|
+
expect(adapter).to receive(:put_key).with "test", key
|
23
23
|
subject.put :test, key
|
24
24
|
end
|
25
25
|
end
|
data/spec/random_spec.rb
CHANGED
@@ -4,6 +4,16 @@ describe Slosilo::Random do
|
|
4
4
|
subject { Slosilo::Random }
|
5
5
|
let(:other_salt) { Slosilo::Random::salt }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
describe '#salt' do
|
8
|
+
subject { super().salt }
|
9
|
+
describe '#length' do
|
10
|
+
subject { super().length }
|
11
|
+
it { is_expected.to eq(32) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#salt' do
|
16
|
+
subject { super().salt }
|
17
|
+
it { is_expected.not_to eq(other_salt) }
|
18
|
+
end
|
9
19
|
end
|
data/spec/sequel_adapter_spec.rb
CHANGED
@@ -8,21 +8,21 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
8
8
|
include_context "with example key"
|
9
9
|
|
10
10
|
let(:model) { double "model" }
|
11
|
-
before { subject.
|
11
|
+
before { allow(subject).to receive_messages create_model: model }
|
12
12
|
|
13
13
|
describe "#get_key" do
|
14
14
|
context "when given key does not exist" do
|
15
|
-
before { model.
|
15
|
+
before { allow(model).to receive_messages :[] => nil }
|
16
16
|
it "returns nil" do
|
17
|
-
subject.get_key(:whatever).
|
17
|
+
expect(subject.get_key(:whatever)).not_to be
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
context "when it exists" do
|
22
22
|
let(:id) { "id" }
|
23
|
-
before { model.
|
23
|
+
before { allow(model).to receive(:[]).with(id).and_return (double "key entry", id: id, key: rsa.to_der) }
|
24
24
|
it "returns it" do
|
25
|
-
subject.get_key(id).
|
25
|
+
expect(subject.get_key(id)).to eq(key)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -30,14 +30,14 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
30
30
|
describe "#put_key" do
|
31
31
|
let(:id) { "id" }
|
32
32
|
it "creates the key" do
|
33
|
-
model.
|
34
|
-
model.
|
33
|
+
expect(model).to receive(:create).with id: id, key: key.to_der
|
34
|
+
allow(model).to receive_messages columns: [:id, :key]
|
35
35
|
subject.put_key id, key
|
36
36
|
end
|
37
37
|
|
38
38
|
it "adds the fingerprint if feasible" do
|
39
|
-
model.
|
40
|
-
model.
|
39
|
+
expect(model).to receive(:create).with id: id, key: key.to_der, fingerprint: key.fingerprint
|
40
|
+
allow(model).to receive_messages columns: [:id, :key, :fingerprint]
|
41
41
|
subject.put_key id, key
|
42
42
|
end
|
43
43
|
end
|
@@ -46,25 +46,21 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
46
46
|
describe "#each" do
|
47
47
|
let(:one) { double("one", id: :one, key: :onek) }
|
48
48
|
let(:two) { double("two", id: :two, key: :twok) }
|
49
|
-
before { model.
|
49
|
+
before { allow(model).to receive(:each).and_yield(one).and_yield(two) }
|
50
50
|
|
51
51
|
it "iterates over each key" do
|
52
52
|
results = []
|
53
|
-
Slosilo::Key.
|
53
|
+
allow(Slosilo::Key).to receive(:new) {|x|x}
|
54
54
|
adapter.each { |id,k| results << { id => k } }
|
55
|
-
results.
|
55
|
+
expect(results).to eq([ { one: :onek}, {two: :twok } ])
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
shared_context "database" do
|
60
60
|
let(:db) { Sequel.sqlite }
|
61
61
|
before do
|
62
|
-
subject.
|
63
|
-
|
64
|
-
Sequel::Model.cache_anonymous_models = false
|
65
|
-
rescue NoMethodError # sequel 4.0 moved the method
|
66
|
-
Sequel.cache_anonymous_models = false
|
67
|
-
end
|
62
|
+
allow(subject).to receive(:create_model).and_call_original
|
63
|
+
Sequel::Model.cache_anonymous_models = false
|
68
64
|
Sequel::Model.db = db
|
69
65
|
end
|
70
66
|
end
|
@@ -91,24 +87,24 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
91
87
|
before { subject.migrate! }
|
92
88
|
|
93
89
|
it "supports look up by id" do
|
94
|
-
subject.get_key("test").
|
90
|
+
expect(subject.get_key("test")).to eq(key)
|
95
91
|
end
|
96
92
|
|
97
93
|
it "supports look up by fingerprint, without a warning" do
|
98
|
-
$stderr.grab do
|
99
|
-
subject.get_by_fingerprint(key.fingerprint).
|
100
|
-
end.
|
94
|
+
expect($stderr.grab do
|
95
|
+
expect(subject.get_by_fingerprint(key.fingerprint)).to eq([key, 'test'])
|
96
|
+
end).to be_empty
|
101
97
|
end
|
102
98
|
end
|
103
99
|
|
104
100
|
it "supports look up by id" do
|
105
|
-
subject.get_key("test").
|
101
|
+
expect(subject.get_key("test")).to eq(key)
|
106
102
|
end
|
107
103
|
|
108
104
|
it "supports look up by fingerprint, but issues a warning" do
|
109
|
-
$stderr.grab do
|
110
|
-
subject.get_by_fingerprint(key.fingerprint).
|
111
|
-
end.
|
105
|
+
expect($stderr.grab do
|
106
|
+
expect(subject.get_by_fingerprint(key.fingerprint)).to eq([key, 'test'])
|
107
|
+
end).not_to be_empty
|
112
108
|
end
|
113
109
|
end
|
114
110
|
|
@@ -129,11 +125,11 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
129
125
|
end
|
130
126
|
|
131
127
|
it "supports look up by id" do
|
132
|
-
subject.get_key("test").
|
128
|
+
expect(subject.get_key("test")).to eq(key)
|
133
129
|
end
|
134
130
|
|
135
131
|
it "supports look up by fingerprint" do
|
136
|
-
subject.get_by_fingerprint(key.fingerprint).
|
132
|
+
expect(subject.get_by_fingerprint(key.fingerprint)).to eq([key, 'test'])
|
137
133
|
end
|
138
134
|
end
|
139
135
|
|
@@ -141,7 +137,7 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
141
137
|
include_context "encryption key"
|
142
138
|
include_context "current schema"
|
143
139
|
|
144
|
-
it {
|
140
|
+
it { is_expected.to be_secure }
|
145
141
|
|
146
142
|
it "saves the keys in encrypted form" do
|
147
143
|
subject.put_key 'test', key
|
@@ -158,7 +154,7 @@ describe Slosilo::Adapters::SequelAdapter do
|
|
158
154
|
|
159
155
|
include_context "current schema"
|
160
156
|
|
161
|
-
it {
|
157
|
+
it { is_expected.not_to be_secure }
|
162
158
|
|
163
159
|
it "refuses to store a private key" do
|
164
160
|
expect { subject.put_key 'test', key }.to raise_error(Slosilo::Error::InsecureKeyStorage)
|
data/spec/slosilo_spec.rb
CHANGED
@@ -7,32 +7,32 @@ describe Slosilo do
|
|
7
7
|
|
8
8
|
describe '[]' do
|
9
9
|
it "returns a Slosilo::Key" do
|
10
|
-
Slosilo[:test].
|
10
|
+
expect(Slosilo[:test]).to be_instance_of Slosilo::Key
|
11
11
|
end
|
12
12
|
|
13
13
|
it "allows looking up by fingerprint" do
|
14
|
-
Slosilo[fingerprint: key_fingerprint].
|
14
|
+
expect(Slosilo[fingerprint: key_fingerprint]).to eq(key)
|
15
15
|
end
|
16
16
|
|
17
17
|
context "when the requested key does not exist" do
|
18
18
|
it "returns nil instead of creating a new key" do
|
19
|
-
Slosilo[:aether].
|
19
|
+
expect(Slosilo[:aether]).not_to be
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
describe '.sign' do
|
25
25
|
let(:own_key) { double "own key" }
|
26
|
-
before { Slosilo.
|
26
|
+
before { allow(Slosilo).to receive(:[]).with(:own).and_return own_key }
|
27
27
|
let (:argument) { double "thing to sign" }
|
28
28
|
it "fetches the own key and signs using that" do
|
29
|
-
own_key.
|
29
|
+
expect(own_key).to receive(:sign).with(argument)
|
30
30
|
Slosilo.sign argument
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
describe '.token_valid?' do
|
35
|
-
before { adapter['test'].
|
35
|
+
before { allow(adapter['test']).to receive_messages token_valid?: false }
|
36
36
|
let(:key2) { double "key 2", token_valid?: false }
|
37
37
|
let(:key3) { double "key 3", token_valid?: false }
|
38
38
|
before do
|
@@ -44,19 +44,19 @@ describe Slosilo do
|
|
44
44
|
subject { Slosilo.token_valid? token }
|
45
45
|
|
46
46
|
context "when no key validates the token" do
|
47
|
-
before { Slosilo::Key.
|
48
|
-
it {
|
47
|
+
before { allow(Slosilo::Key).to receive_messages new: (double "key", token_valid?: false) }
|
48
|
+
it { is_expected.to be_falsey }
|
49
49
|
end
|
50
50
|
|
51
51
|
context "when a key validates the token" do
|
52
52
|
let(:valid_key) { double token_valid?: true }
|
53
53
|
let(:invalid_key) { double token_valid?: true }
|
54
54
|
before do
|
55
|
-
Slosilo::Key.
|
55
|
+
allow(Slosilo::Key).to receive_messages new: invalid_key
|
56
56
|
adapter[:key2] = valid_key
|
57
57
|
end
|
58
58
|
|
59
|
-
it {
|
59
|
+
it { is_expected.to be_truthy }
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -66,18 +66,18 @@ describe Slosilo do
|
|
66
66
|
let(:token) {{ 'data' => 'foo', 'key' => key.fingerprint, 'signature' => 'XXX' }}
|
67
67
|
|
68
68
|
context "and the signature is valid" do
|
69
|
-
before { key.
|
69
|
+
before { allow(key).to receive(:token_valid?).with(token).and_return true }
|
70
70
|
|
71
71
|
it "returns the key id" do
|
72
|
-
subject.token_signer(token).
|
72
|
+
expect(subject.token_signer(token)).to eq('test')
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
context "and the signature is invalid" do
|
77
|
-
before { key.
|
77
|
+
before { allow(key).to receive(:token_valid?).with(token).and_return false }
|
78
78
|
|
79
79
|
it "returns nil" do
|
80
|
-
subject.token_signer(token).
|
80
|
+
expect(subject.token_signer(token)).not_to be
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
@@ -85,7 +85,39 @@ describe Slosilo do
|
|
85
85
|
context "when token doesn't match a key" do
|
86
86
|
let(:token) {{ 'data' => 'foo', 'key' => "footprint", 'signature' => 'XXX' }}
|
87
87
|
it "returns nil" do
|
88
|
-
subject.token_signer(token).
|
88
|
+
expect(subject.token_signer(token)).not_to be
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with JWT token" do
|
93
|
+
before do
|
94
|
+
expect(key).to receive(:validate_jwt) do |jwt|
|
95
|
+
expect(jwt.header).to eq 'kid' => key.fingerprint
|
96
|
+
expect(jwt.claims).to eq({})
|
97
|
+
expect(jwt.signature).to eq 'sig'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "accepts pre-parsed JSON serialization" do
|
102
|
+
expect(Slosilo.token_signer(
|
103
|
+
'protected' => 'eyJraWQiOiIxMDdiZGI4NTAxYzQxOWZhZDJmZGIyMGI0NjdkNGQwYTYyYTE2YTk4YzM1ZjJkYTBlYjNiMWZmOTI5Nzk1YWQ5In0=',
|
104
|
+
'payload' => 'e30=',
|
105
|
+
'signature' => 'c2ln'
|
106
|
+
)).to eq 'test'
|
107
|
+
end
|
108
|
+
|
109
|
+
it "accepts pre-parsed JWT token" do
|
110
|
+
expect(Slosilo.token_signer(Slosilo::JWT(
|
111
|
+
'protected' => 'eyJraWQiOiIxMDdiZGI4NTAxYzQxOWZhZDJmZGIyMGI0NjdkNGQwYTYyYTE2YTk4YzM1ZjJkYTBlYjNiMWZmOTI5Nzk1YWQ5In0=',
|
112
|
+
'payload' => 'e30=',
|
113
|
+
'signature' => 'c2ln'
|
114
|
+
))).to eq 'test'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "accepts compact serialization" do
|
118
|
+
expect(Slosilo.token_signer(
|
119
|
+
'eyJraWQiOiIxMDdiZGI4NTAxYzQxOWZhZDJmZGIyMGI0NjdkNGQwYTYyYTE2YTk4YzM1ZjJkYTBlYjNiMWZmOTI5Nzk1YWQ5In0=.e30=.c2ln'
|
120
|
+
)).to eq 'test'
|
89
121
|
end
|
90
122
|
end
|
91
123
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
require "simplecov"
|
2
2
|
SimpleCov.start
|
3
3
|
|
4
|
-
RSpec.configure do |c|
|
5
|
-
c.treat_symbols_as_metadata_keys_with_true_values = true
|
6
|
-
end
|
7
|
-
|
8
4
|
require 'slosilo'
|
9
5
|
|
10
6
|
shared_context "with mock adapter" do
|
@@ -45,7 +41,7 @@ Dg1ikwi8GUF4HPZe9DyhXgDhg19wM/qcpjX8bSypsUWHWP+FanhjdWU=
|
|
45
41
|
-----END RSA PRIVATE KEY-----
|
46
42
|
""" }
|
47
43
|
let (:key) { Slosilo::Key.new rsa.to_der }
|
48
|
-
let (:key_fingerprint) { "
|
44
|
+
let (:key_fingerprint) { "107bdb8501c419fad2fdb20b467d4d0a62a16a98c35f2da0eb3b1ff929795ad9" }
|
49
45
|
|
50
46
|
let (:another_rsa) do
|
51
47
|
OpenSSL::PKey::RSA.new """
|
@@ -80,20 +76,6 @@ ooQ2FuL0K6ukQfHPjuMswqi41lmVH8gIVqVC+QnImUCrGxH9WXWy
|
|
80
76
|
end
|
81
77
|
|
82
78
|
def self.mock_own_key
|
83
|
-
before { Slosilo.
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class RackEnvironmentInputMatcher
|
88
|
-
def initialize expected
|
89
|
-
@expected = expected
|
79
|
+
before { allow(Slosilo).to receive(:[]).with(:own).and_return key }
|
90
80
|
end
|
91
|
-
|
92
|
-
def == env
|
93
|
-
env['rack.input'].read.should == @expected
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def rack_environment_with_input expected
|
98
|
-
RackEnvironmentInputMatcher.new expected
|
99
81
|
end
|
data/spec/symmetric_spec.rb
CHANGED
@@ -3,49 +3,71 @@ require 'spec_helper'
|
|
3
3
|
describe Slosilo::Symmetric do
|
4
4
|
# TODO transform it to class methods only?
|
5
5
|
let(:plaintext) { "quick brown fox jumped over the lazy dog" }
|
6
|
+
let(:auth_data) { "some record id" }
|
6
7
|
let(:key) { "^\xBAIv\xDB1\x0Fi\x04\x11\xFD\x14\xA7\xCD\xDFf\x93\xFE\x93}\v\x01\x11\x98\x14\xE0;\xC1\xE2 v\xA5".force_encoding("ASCII-8BIT") }
|
7
|
-
let(:iv) { "\
|
8
|
-
let(:ciphertext) { "\
|
8
|
+
let(:iv) { "\xD9\xABn\x01b\xFA\xBD\xC2\xE5\xEA\x01\xAC".force_encoding("ASCII-8BIT") }
|
9
|
+
let(:ciphertext) { "G^W1\x9C\xD4\xCC\x87\xD3\xFF\x86[\x0E3\xC0\xC8^\xD9\xABn\x01b\xFA\xBD\xC2\xE5\xEA\x01\xAC\x9E\xB9:\xF7\xD4ebeq\xDC \xC0sG\xA4\xAE,\xB8A|\x97\xBC\xFD\x85\xE1\xB93\x95>\xBD\n\x05\xFB\x15\x1F\x06#3M9".force_encoding('ASCII-8BIT') }
|
10
|
+
|
9
11
|
describe '#encrypt' do
|
10
|
-
it "encrypts with AES-256-
|
11
|
-
subject.
|
12
|
-
subject.encrypt(plaintext, key: key).
|
12
|
+
it "encrypts with AES-256-GCM" do
|
13
|
+
allow(subject).to receive_messages random_iv: iv
|
14
|
+
expect(subject.encrypt(plaintext, key: key, aad: auth_data)).to eq(ciphertext)
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
16
18
|
describe '#decrypt' do
|
17
|
-
it "decrypts with AES-256-
|
18
|
-
subject.decrypt(ciphertext, key: key).
|
19
|
+
it "decrypts with AES-256-GCM" do
|
20
|
+
expect(subject.decrypt(ciphertext, key: key, aad: auth_data)).to eq(plaintext)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
context "when the ciphertext has been messed with" do
|
25
|
+
let(:ciphertext) { "pwnd!" } # maybe we should do something more realistic like add some padding?
|
26
|
+
it "raises an exception" do
|
27
|
+
expect{ subject.decrypt(ciphertext, key: key, aad: auth_data)}.to raise_exception /Invalid version/
|
28
|
+
end
|
29
|
+
context "by adding a trailing 0" do
|
30
|
+
let(:new_ciphertext){ ciphertext + '\0' }
|
31
|
+
it "raises an exception" do
|
32
|
+
expect{ subject.decrypt(new_ciphertext, key: key, aad: auth_data) }.to raise_exception /Invalid version/
|
33
|
+
end
|
34
|
+
end
|
19
35
|
end
|
20
|
-
|
21
|
-
context "when
|
22
|
-
let(:
|
23
|
-
let(:
|
24
|
-
|
25
|
-
|
36
|
+
|
37
|
+
context "when no auth_data is given" do
|
38
|
+
let(:auth_data){""}
|
39
|
+
let(:ciphertext){ "Gm\xDAT\xE8I\x9F\xB7\xDC\xBB\x84\xD3Q#\x1F\xF4\x8C\aV\x93\x8F_\xC7\xBC87\xC9U\xF1\xAF\x8A\xD62\x1C5H\x86\x17\x19=B~Y*\xBC\x9D\eJeTx\x1F\x02l\t\t\xD3e\xA4\x11\x13y*\x95\x9F\xCD\xC4@\x9C"}
|
40
|
+
|
41
|
+
it "decrypts the message" do
|
42
|
+
expect(subject.decrypt(ciphertext, key: key, aad: auth_data)).to eq(plaintext)
|
43
|
+
end
|
44
|
+
|
45
|
+
context "and the ciphertext has been messed with" do
|
46
|
+
it "raises an exception" do
|
47
|
+
expect{ subject.decrypt(ciphertext + "\0\0\0", key: key, aad: auth_data)}.to raise_exception OpenSSL::Cipher::CipherError
|
48
|
+
end
|
26
49
|
end
|
27
50
|
end
|
28
51
|
|
29
|
-
context "when the
|
30
|
-
let(:
|
31
|
-
|
32
|
-
|
33
|
-
subject.decrypt(ciphertext, key: key).should == "zGptmL3vd4obi1vqSiWHt/Ias2k+6qDtuq9vdow8jNA="
|
52
|
+
context "when the auth data doesn't match" do
|
53
|
+
let(:auth_data){ "asdf" }
|
54
|
+
it "raises an exception" do
|
55
|
+
expect{ subject.decrypt(ciphertext, key: key, aad: auth_data)}.to raise_exception OpenSSL::Cipher::CipherError
|
34
56
|
end
|
35
57
|
end
|
36
58
|
end
|
37
59
|
|
38
60
|
describe '#random_iv' do
|
39
61
|
it "generates a random iv" do
|
40
|
-
OpenSSL::Cipher.
|
41
|
-
subject.random_iv.
|
62
|
+
expect_any_instance_of(OpenSSL::Cipher).to receive(:random_iv).and_return :iv
|
63
|
+
expect(subject.random_iv).to eq(:iv)
|
42
64
|
end
|
43
65
|
end
|
44
66
|
|
45
67
|
describe '#random_key' do
|
46
68
|
it "generates a random key" do
|
47
|
-
OpenSSL::Cipher.
|
48
|
-
subject.random_key.
|
69
|
+
expect_any_instance_of(OpenSSL::Cipher).to receive(:random_key).and_return :key
|
70
|
+
expect(subject.random_key).to eq(:key)
|
49
71
|
end
|
50
72
|
end
|
51
73
|
end
|
data/test.sh
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/bin/bash -xe
|
2
|
+
|
3
|
+
iid=slosilo-test-$(date +%s)
|
4
|
+
|
5
|
+
docker build -t $iid -f - . << EOF
|
6
|
+
FROM ruby
|
7
|
+
WORKDIR /app
|
8
|
+
COPY Gemfile slosilo.gemspec ./
|
9
|
+
RUN bundle
|
10
|
+
COPY . ./
|
11
|
+
RUN bundle
|
12
|
+
EOF
|
13
|
+
|
14
|
+
cidfile=$(mktemp -u)
|
15
|
+
docker run --cidfile $cidfile -v /app/spec/reports $iid bundle exec rake jenkins || :
|
16
|
+
|
17
|
+
cid=$(cat $cidfile)
|
18
|
+
|
19
|
+
docker cp $cid:/app/spec/reports spec/
|
20
|
+
docker rm $cid
|
21
|
+
|
22
|
+
# untag, will use cache next time if available but no junk will be left
|
23
|
+
docker rmi $iid
|
24
|
+
|
25
|
+
rm $cidfile
|