vault-rails 0.1.2 → 0.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.
@@ -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