vault-rails 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,41 +1,265 @@
1
+ # encoding: utf-8
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe Vault::Rails do
6
+ before(:all) do
7
+ Vault::Rails.sys.mount("transit", :transit)
8
+ end
9
+
4
10
  context "with default options" do
5
11
  before(:all) do
6
- Vault.sys.mount("transit", :transit)
7
- Vault.logical.write("transit/keys/dummy_people_ssn")
12
+ Vault::Rails.logical.write("transit/keys/dummy_people_ssn")
8
13
  end
9
14
 
10
15
  it "encrypts attributes" do
11
16
  person = Person.create!(ssn: "123-45-6789")
12
17
  expect(person.ssn_encrypted).to be
18
+ expect(person.ssn_encrypted.encoding).to eq(Encoding::UTF_8)
13
19
  end
14
20
 
15
21
  it "decrypts attributes" do
16
22
  person = Person.create!(ssn: "123-45-6789")
17
- person = Person.find(person.id)
23
+ person.reload
18
24
 
19
25
  expect(person.ssn).to eq("123-45-6789")
26
+ expect(person.ssn.encoding).to eq(Encoding::UTF_8)
27
+ end
28
+
29
+ it "tracks dirty attributes" do
30
+ person = Person.create!(ssn: "123-45-6789")
31
+
32
+ expect(person.ssn_changed?).to be(false)
33
+ expect(person.ssn_change).to be(nil)
34
+ expect(person.ssn_was).to eq("123-45-6789")
35
+
36
+ person.ssn = "111-11-1111"
37
+
38
+ expect(person.ssn_changed?).to be(true)
39
+ expect(person.ssn_change).to eq(["123-45-6789", "111-11-1111"])
40
+ expect(person.ssn_was).to eq("123-45-6789")
41
+ end
42
+
43
+ it "allows attributes to be unset" do
44
+ person = Person.create!(ssn: "123-45-6789")
45
+ person.update_attributes!(ssn: nil)
46
+ person.reload
47
+
48
+ expect(person.ssn).to be(nil)
49
+ end
50
+
51
+ it "allows saving without validations" do
52
+ person = Person.new(ssn: "123-456-7890")
53
+ person.save(validate: false)
54
+ expect(person.ssn_encrypted).to match("vault:")
55
+ end
56
+
57
+ it "allows attributes to be unset after reload" do
58
+ person = Person.create!(ssn: "123-45-6789")
59
+ person.reload
60
+ person.update_attributes!(ssn: nil)
61
+ person.reload
62
+
63
+ expect(person.ssn).to be(nil)
64
+ end
65
+
66
+ it "allows attributes to be blank" do
67
+ person = Person.create!(ssn: "123-45-6789")
68
+ person.update_attributes!(ssn: "")
69
+ person.reload
70
+
71
+ expect(person.ssn).to eq("")
72
+ end
73
+
74
+ it "reloads instance variables on reload" do
75
+ person = Person.create!(ssn: "123-45-6789")
76
+ expect(person.instance_variable_get(:@ssn)).to eq("123-45-6789")
77
+
78
+ person.ssn = "111-11-1111"
79
+ person.reload
80
+ expect(person.instance_variable_get(:@ssn)).to eq("123-45-6789")
81
+ end
82
+
83
+ it "does not try to encrypt unchanged attributes" do
84
+ person = Person.create!(ssn: "123-45-6789")
85
+
86
+ expect(Vault::Rails).to_not receive(:encrypt)
87
+ person.name = "Cinderella"
88
+ person.save!
20
89
  end
21
90
  end
22
91
 
23
92
  context "with custom options" do
24
93
  before(:all) do
25
- Vault.sys.mount("credit-secrets", :transit)
26
- Vault.logical.write("credit-secrets/keys/people_credit_cards")
94
+ Vault::Rails.sys.mount("credit-secrets", :transit)
95
+ Vault::Rails.logical.write("credit-secrets/keys/people_credit_cards")
27
96
  end
28
97
 
29
98
  it "encrypts attributes" do
30
99
  person = Person.create!(credit_card: "1234567890111213")
31
100
  expect(person.cc_encrypted).to be
101
+ expect(person.cc_encrypted.encoding).to eq(Encoding::UTF_8)
32
102
  end
33
103
 
34
104
  it "decrypts attributes" do
35
105
  person = Person.create!(credit_card: "1234567890111213")
36
- person = Person.find(person.id)
106
+ person.reload
37
107
 
38
108
  expect(person.credit_card).to eq("1234567890111213")
109
+ expect(person.credit_card.encoding).to eq(Encoding::UTF_8)
110
+ end
111
+
112
+ it "tracks dirty attributes" do
113
+ person = Person.create!(credit_card: "1234567890111213")
114
+
115
+ expect(person.credit_card_changed?).to be(false)
116
+ expect(person.credit_card_change).to eq(nil)
117
+ expect(person.credit_card_was).to eq("1234567890111213")
118
+
119
+ person.credit_card = "123456789010"
120
+
121
+ expect(person.credit_card_changed?).to be(true)
122
+ expect(person.credit_card_change).to eq(["1234567890111213", "123456789010"])
123
+ expect(person.credit_card_was).to eq("1234567890111213")
124
+ end
125
+
126
+ it "allows attributes to be unset" do
127
+ person = Person.create!(credit_card: "1234567890111213")
128
+ person.update_attributes!(credit_card: nil)
129
+ person.reload
130
+
131
+ expect(person.credit_card).to be(nil)
132
+ end
133
+
134
+ it "allows attributes to be blank" do
135
+ person = Person.create!(credit_card: "1234567890111213")
136
+ person.update_attributes!(credit_card: "")
137
+ person.reload
138
+
139
+ expect(person.credit_card).to eq("")
140
+ end
141
+ end
142
+
143
+ context "with non-ASCII characters" do
144
+ before(:all) do
145
+ Vault::Rails.sys.mount("non-ascii", :transit)
146
+ Vault::Rails.logical.write("non-ascii/keys/people_non_ascii")
147
+ end
148
+
149
+ it "encrypts attributes" do
150
+ person = Person.create!(non_ascii: "dás ümlaut")
151
+ expect(person.non_ascii_encrypted).to be
152
+ expect(person.non_ascii_encrypted.encoding).to eq(Encoding::UTF_8)
153
+ end
154
+
155
+ it "decrypts attributes" do
156
+ person = Person.create!(non_ascii: "dás ümlaut")
157
+ person.reload
158
+
159
+ expect(person.non_ascii).to eq("dás ümlaut")
160
+ expect(person.non_ascii.encoding).to eq(Encoding::UTF_8)
161
+ end
162
+
163
+ it "tracks dirty attributes" do
164
+ person = Person.create!(non_ascii: "dás ümlaut")
165
+
166
+ expect(person.non_ascii_changed?).to be(false)
167
+ expect(person.non_ascii_change).to eq(nil)
168
+ expect(person.non_ascii_was).to eq("dás ümlaut")
169
+
170
+ person.non_ascii = "él ñiñô"
171
+
172
+ expect(person.non_ascii_changed?).to be(true)
173
+ expect(person.non_ascii_change).to eq(["dás ümlaut", "él ñiñô"])
174
+ expect(person.non_ascii_was).to eq("dás ümlaut")
175
+ end
176
+
177
+ it "allows attributes to be unset" do
178
+ person = Person.create!(non_ascii: "dás ümlaut")
179
+ person.update_attributes!(non_ascii: nil)
180
+ person.reload
181
+
182
+ expect(person.non_ascii).to be(nil)
183
+ end
184
+
185
+ it "allows attributes to be blank" do
186
+ person = Person.create!(non_ascii: "dás ümlaut")
187
+ person.update_attributes!(non_ascii: "")
188
+ person.reload
189
+
190
+ expect(person.non_ascii).to eq("")
191
+ end
192
+ end
193
+
194
+ context "with the :json serializer" do
195
+ before(:all) do
196
+ Vault::Rails.logical.write("transit/keys/dummy_people_details")
197
+ end
198
+
199
+ it "has a default value for unpersisted records" do
200
+ person = Person.new
201
+ expect(person.details).to eq({})
202
+ end
203
+
204
+ it "has a default value for persisted records" do
205
+ person = Person.create!
206
+ expect(person.details).to eq({})
207
+ end
208
+
209
+ it "tracks dirty attributes" do
210
+ person = Person.create!(details: { "foo" => "bar" })
211
+
212
+ expect(person.details_changed?).to be(false)
213
+ expect(person.details_change).to be(nil)
214
+ expect(person.details_was).to eq({ "foo" => "bar" })
215
+
216
+ person.details = { "zip" => "zap" }
217
+
218
+ expect(person.details_changed?).to be(true)
219
+ expect(person.details_change).to eq([{ "foo" => "bar" }, { "zip" => "zap" }])
220
+ expect(person.details_was).to eq({ "foo" => "bar" })
221
+ end
222
+
223
+ it "encodes and decodes attributes" do
224
+ person = Person.create!(details: { "foo" => "bar", "zip" => 1 })
225
+ person.reload
226
+
227
+ raw = Vault::Rails.decrypt("transit", "dummy_people_details", person.details_encrypted)
228
+ expect(raw).to eq("{\"foo\":\"bar\",\"zip\":1}")
229
+
230
+ expect(person.details).to eq("foo" => "bar", "zip" => 1)
231
+ end
232
+ end
233
+
234
+ context "with a custom serializer" do
235
+ before(:all) do
236
+ Vault::Rails.logical.write("transit/keys/dummy_people_business_card")
237
+ end
238
+
239
+ it "encodes and decodes attributes" do
240
+ person = Person.create!(business_card: "data")
241
+ person.reload
242
+
243
+ raw = Vault::Rails.decrypt("transit", "dummy_people_business_card", person.business_card_encrypted)
244
+ expect(raw).to eq("01100100011000010111010001100001")
245
+
246
+ expect(person.business_card).to eq("data")
247
+ end
248
+ end
249
+
250
+ context "with custom encode/decode proc" do
251
+ before(:all) do
252
+ Vault::Rails.logical.write("transit/keys/dummy_people_favorite_color")
253
+ end
254
+
255
+ it "encodes and decodes attributes" do
256
+ person = Person.create!(favorite_color: "blue")
257
+ person.reload
258
+
259
+ raw = Vault::Rails.decrypt("transit", "dummy_people_favorite_color", person.favorite_color_encrypted)
260
+ expect(raw).to eq("xxxbluexxx")
261
+
262
+ expect(person.favorite_color).to eq("blue")
39
263
  end
40
264
  end
41
265
  end
@@ -7,6 +7,9 @@ module RSpec
7
7
  class VaultServer
8
8
  include Singleton
9
9
 
10
+ TOKEN_PATH = File.expand_path("~/.vault-token").freeze
11
+ TOKEN_PATH_BKUP = "#{TOKEN_PATH}.bak".freeze
12
+
10
13
  def self.method_missing(m, *args, &block)
11
14
  self.instance.public_send(m, *args, &block)
12
15
  end
@@ -14,6 +17,15 @@ module RSpec
14
17
  attr_reader :token
15
18
 
16
19
  def initialize
20
+ # If there is already a vault-token, we need to move it so we do not
21
+ # clobber!
22
+ if File.exist?(TOKEN_PATH)
23
+ FileUtils.mv(TOKEN_PATH, TOKEN_PATH_BKUP)
24
+ at_exit do
25
+ FileUtils.mv(TOKEN_PATH_BKUP, TOKEN_PATH)
26
+ end
27
+ end
28
+
17
29
  io = Tempfile.new("vault-server")
18
30
  pid = Process.spawn({}, "vault server -dev", out: io.to_i, err: io.to_i)
19
31
 
@@ -26,19 +38,7 @@ module RSpec
26
38
  end
27
39
 
28
40
  wait_for_ready do
29
- output = ""
30
-
31
- while
32
- io.rewind
33
- output = io.read
34
- break if !output.empty?
35
- end
36
-
37
- if output.match(/Root Token: (.+)/)
38
- @token = $1.strip
39
- else
40
- raise "Vault did not return a token!"
41
- end
41
+ @token = File.read(TOKEN_PATH)
42
42
  end
43
43
  end
44
44
 
@@ -48,14 +48,7 @@ module RSpec
48
48
 
49
49
  def wait_for_ready(&block)
50
50
  Timeout.timeout(5) do
51
- while
52
- begin
53
- open(address)
54
- rescue SocketError, Errno::ECONNREFUSED, EOFError
55
- rescue OpenURI::HTTPError => e
56
- break if e.message =~ /404/
57
- end
58
-
51
+ while !File.exist?(TOKEN_PATH)
59
52
  sleep(0.25)
60
53
  end
61
54
  end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe Vault::EncryptedModel do
4
+ let(:klass) do
5
+ Class.new(ActiveRecord::Base) do
6
+ include Vault::EncryptedModel
7
+ end
8
+ end
9
+
10
+ describe ".vault_attribute" do
11
+ it "raises an exception if a serializer and :encode is given" do
12
+ expect {
13
+ klass.vault_attribute(:foo, serializer: :json, encode: ->(r) { r })
14
+ }.to raise_error(Vault::Rails::ValidationFailedError)
15
+ end
16
+
17
+ it "raises an exception if a serializer and :decode is given" do
18
+ expect {
19
+ klass.vault_attribute(:foo, serializer: :json, decode: ->(r) { r })
20
+ }.to raise_error(Vault::Rails::ValidationFailedError)
21
+ end
22
+
23
+ it "defines a getter" do
24
+ klass.vault_attribute(:foo)
25
+ expect(klass.instance_methods).to include(:foo)
26
+ end
27
+
28
+ it "defines a setter" do
29
+ klass.vault_attribute(:foo)
30
+ expect(klass.instance_methods).to include(:foo=)
31
+ end
32
+
33
+ it "defines a checker" do
34
+ klass.vault_attribute(:foo)
35
+ expect(klass.instance_methods).to include(:foo?)
36
+ end
37
+
38
+ it "defines dirty attribute methods" do
39
+ klass.vault_attribute(:foo)
40
+ expect(klass.instance_methods).to include(:foo_change)
41
+ expect(klass.instance_methods).to include(:foo_changed?)
42
+ expect(klass.instance_methods).to include(:foo_was)
43
+ end
44
+ end
45
+ end
@@ -1,28 +1,23 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Vault do
4
- describe ".application" do
5
- it "returns the application" do
6
- Vault.instance_variable_set(:@application, "dummy")
7
- expect(Vault.application).to eq("dummy")
3
+ describe Vault::Rails do
4
+ describe ".serializer_for" do
5
+ it "accepts a string" do
6
+ serializer = Vault::Rails.serializer_for("json")
7
+ expect(serializer).to be(Vault::Rails::JSONSerializer)
8
8
  end
9
9
 
10
- it "raises an error if unset" do
11
- Vault.instance_variable_set(:@application, nil)
12
- expect { Vault.application }.to raise_error
10
+ it "accepts a symbol" do
11
+ serializer = Vault::Rails.serializer_for(:json)
12
+ expect(serializer).to be(Vault::Rails::JSONSerializer)
13
13
  end
14
- end
15
-
16
- describe ".application=" do
17
- it "sets the value" do
18
- Vault.application = "dummy"
19
- expect(Vault.instance_variable_get(:@application)).to eq("dummy")
20
- end
21
- end
22
14
 
23
- describe "Rails" do
24
- it "is defined" do
25
- expect { Vault.const_get(:Rails) }.to_not raise_error
15
+ it "raises an exception when there is no serializer for the key" do
16
+ expect {
17
+ Vault::Rails.serializer_for(:not_a_serializer)
18
+ }.to raise_error(Vault::Rails::UnknownSerializerError) { |e|
19
+ expect(e.message).to match("Unknown Vault serializer `:not_a_serializer'")
20
+ }
26
21
  end
27
22
  end
28
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vault-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seth Vargo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-14 00:00:00.000000000 Z
11
+ date: 2016-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -30,28 +30,42 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.1'
33
+ version: '0.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.1'
40
+ version: '0.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1.9'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1.9'
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -106,7 +120,9 @@ files:
106
120
  - Rakefile
107
121
  - lib/vault/encrypted_model.rb
108
122
  - lib/vault/rails.rb
109
- - lib/vault/rails/testing.rb
123
+ - lib/vault/rails/configurable.rb
124
+ - lib/vault/rails/errors.rb
125
+ - lib/vault/rails/serializer.rb
110
126
  - lib/vault/rails/version.rb
111
127
  - spec/dummy/Rakefile
112
128
  - spec/dummy/app/models/person.rb
@@ -136,6 +152,7 @@ files:
136
152
  - spec/dummy/db/migrate/20150428220101_create_people.rb
137
153
  - spec/dummy/db/schema.rb
138
154
  - spec/dummy/db/test.sqlite3
155
+ - spec/dummy/lib/binary_serializer.rb
139
156
  - spec/dummy/log/development.log
140
157
  - spec/dummy/log/test.log
141
158
  - spec/dummy/public/404.html
@@ -145,6 +162,7 @@ files:
145
162
  - spec/integration/rails_spec.rb
146
163
  - spec/spec_helper.rb
147
164
  - spec/support/vault_server.rb
165
+ - spec/unit/encrypted_model_spec.rb
148
166
  - spec/unit/rails_spec.rb
149
167
  homepage: https://github.com/hashicorp/vault-rails
150
168
  licenses:
@@ -198,6 +216,7 @@ test_files:
198
216
  - spec/dummy/db/migrate/20150428220101_create_people.rb
199
217
  - spec/dummy/db/schema.rb
200
218
  - spec/dummy/db/test.sqlite3
219
+ - spec/dummy/lib/binary_serializer.rb
201
220
  - spec/dummy/log/development.log
202
221
  - spec/dummy/log/test.log
203
222
  - spec/dummy/public/404.html
@@ -208,4 +227,5 @@ test_files:
208
227
  - spec/integration/rails_spec.rb
209
228
  - spec/spec_helper.rb
210
229
  - spec/support/vault_server.rb
230
+ - spec/unit/encrypted_model_spec.rb
211
231
  - spec/unit/rails_spec.rb