vault-rails 0.3.2 → 0.7.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.
@@ -42,12 +42,22 @@ describe Vault::Rails do
42
42
 
43
43
  it "allows attributes to be unset" do
44
44
  person = Person.create!(ssn: "123-45-6789")
45
- person.update_attributes!(ssn: nil)
45
+ person.update!(ssn: nil)
46
46
  person.reload
47
47
 
48
48
  expect(person.ssn).to be(nil)
49
49
  end
50
50
 
51
+ it "allows dirty attributes to be unset" do
52
+ person = Person.create!(ssn: "123-45-6789")
53
+ person.ssn = nil
54
+ expect(person.ssn).to be_nil
55
+
56
+ person2 = Person.create!(ssn: "123-45-6789")
57
+ person2.assign_attributes(ssn: nil)
58
+ expect(person2.ssn).to be_nil
59
+ end
60
+
51
61
  it "allows saving without validations" do
52
62
  person = Person.new(ssn: "123-456-7890")
53
63
  person.save(validate: false)
@@ -57,7 +67,7 @@ describe Vault::Rails do
57
67
  it "allows attributes to be unset after reload" do
58
68
  person = Person.create!(ssn: "123-45-6789")
59
69
  person.reload
60
- person.update_attributes!(ssn: nil)
70
+ person.update!(ssn: nil)
61
71
  person.reload
62
72
 
63
73
  expect(person.ssn).to be(nil)
@@ -65,10 +75,20 @@ describe Vault::Rails do
65
75
 
66
76
  it "allows attributes to be blank" do
67
77
  person = Person.create!(ssn: "123-45-6789")
68
- person.update_attributes!(ssn: "")
78
+ person.update!(ssn: "")
69
79
  person.reload
70
80
 
71
81
  expect(person.ssn).to eq("")
82
+ expect(person.ssn_encrypted).to eq("")
83
+ end
84
+
85
+ it "allows attributes to be null" do
86
+ person = Person.create!(ssn: "123-45-6789")
87
+ person.update!(ssn: nil)
88
+ person.reload
89
+
90
+ expect(person.ssn).to eq(nil)
91
+ expect(person.ssn_encrypted).to eq(nil)
72
92
  end
73
93
 
74
94
  it "reloads instance variables on reload" do
@@ -87,6 +107,18 @@ describe Vault::Rails do
87
107
  person.name = "Cinderella"
88
108
  person.save!
89
109
  end
110
+
111
+ it "does not register a Vault attribute as necessarily being backed by a column" do
112
+ expect(Person.attribute_names).to include("ssn")
113
+ expect(Person.column_names).not_to include("ssn")
114
+ end
115
+
116
+ it "does not reload encrypted attributes on destroy" do
117
+ person = Person.create!(ssn: "123-45-6789")
118
+
119
+ expect(Vault::Rails).to_not receive(:decrypt)
120
+ person.destroy
121
+ end
90
122
  end
91
123
 
92
124
  context "lazy decrypt" do
@@ -130,16 +162,33 @@ describe Vault::Rails do
130
162
  expect(person.ssn_changed?).to be(true)
131
163
  expect(person.ssn_change).to eq(["123-45-6789", "111-11-1111"])
132
164
  expect(person.ssn_was).to eq("123-45-6789")
165
+
166
+ person.assign_attributes(ssn: "222-22-2222")
167
+
168
+ expect(person.ssn_changed?).to be(true)
169
+ expect(person.ssn_change).to eq(["123-45-6789", "222-22-2222"])
170
+ expect(person.ssn_was).to eq("123-45-6789")
133
171
  end
134
172
 
135
173
  it "allows attributes to be unset" do
136
174
  person = LazyPerson.create!(ssn: "123-45-6789")
137
- person.update_attributes!(ssn: nil)
175
+ person.update!(ssn: nil)
138
176
  person.reload
139
177
 
140
178
  expect(person.ssn).to be(nil)
141
179
  end
142
180
 
181
+ it "allows dirty attributes to be unset" do
182
+ person = LazyPerson.create!(ssn: "123-45-6789")
183
+ person.ssn = nil
184
+ expect(person.ssn).to be_nil
185
+
186
+ person2 = LazyPerson.create!(ssn: "123-45-6789")
187
+ person2.assign_attributes(ssn: nil)
188
+ expect(person2.ssn).to be_nil
189
+ end
190
+
191
+
143
192
  it "allows saving without validations" do
144
193
  person = LazyPerson.new(ssn: "123-456-7890")
145
194
  expect(person.save(validate: false)).to be(true)
@@ -149,7 +198,7 @@ describe Vault::Rails do
149
198
  it "allows attributes to be unset after reload" do
150
199
  person = LazyPerson.create!(ssn: "123-45-6789")
151
200
  person.reload
152
- person.update_attributes!(ssn: nil)
201
+ person.update!(ssn: nil)
153
202
  person.reload
154
203
 
155
204
  expect(person.ssn).to be(nil)
@@ -157,7 +206,7 @@ describe Vault::Rails do
157
206
 
158
207
  it "allows attributes to be blank" do
159
208
  person = LazyPerson.create!(ssn: "123-45-6789")
160
- person.update_attributes!(ssn: "")
209
+ person.update!(ssn: "")
161
210
  person.reload
162
211
 
163
212
  expect(person.ssn).to eq("")
@@ -180,6 +229,145 @@ describe Vault::Rails do
180
229
  person.name = "Cinderella"
181
230
  person.save!
182
231
  end
232
+
233
+ it "allows attributes to be accessed after a destroy" do
234
+ person = LazyPerson.create!(ssn: "123-45-6789")
235
+
236
+ person.destroy
237
+ expect { person.ssn }.not_to raise_error
238
+ end
239
+ end
240
+
241
+ context "lazy single decrypt" do
242
+ before(:all) do
243
+ Vault::Rails.logical.write("transit/keys/dummy_people_ssn")
244
+ end
245
+
246
+ it "encrypts attributes" do
247
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
248
+ expect(person.ssn_encrypted.length).to eq(61)
249
+ expect(person.ssn_encrypted).to start_with("vault:v1:")
250
+ expect(person.ssn_encrypted.encoding).to eq(Encoding::UTF_8)
251
+ end
252
+
253
+ it "decrypts attributes" do
254
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
255
+ person.reload
256
+
257
+ expect(person.ssn).to eq("123-45-6789")
258
+ expect(person.ssn.encoding).to eq(Encoding::UTF_8)
259
+ end
260
+
261
+ it "does not decrypt on initialization" do
262
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
263
+ person.reload
264
+
265
+ p2 = LazySinglePerson.find(person.id)
266
+
267
+ expect(p2.instance_variable_get("@ssn")).to eq(nil)
268
+ expect(p2.ssn).to eq("123-45-6789")
269
+ end
270
+
271
+ it "does not decrypt all attributes on single read" do
272
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
273
+ person.update!(credit_card: "abcd-efgh-hijk-lmno")
274
+ expect(person.credit_card).to eq("abcd-efgh-hijk-lmno")
275
+
276
+ person.reload
277
+
278
+ p2 = LazySinglePerson.find(person.id)
279
+
280
+ expect(p2.instance_variable_get("@ssn")).to eq(nil)
281
+ expect(p2.ssn).to eq("123-45-6789")
282
+ expect(p2.instance_variable_get("@credit_card")).to eq(nil)
283
+ expect(p2.credit_card).to eq("abcd-efgh-hijk-lmno")
284
+ end
285
+
286
+ it "does not decrypt all attributes on single write" do
287
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
288
+ person.update!(credit_card: "abcd-efgh-hijk-lmno")
289
+ expect(person.credit_card).to eq("abcd-efgh-hijk-lmno")
290
+
291
+ person.reload
292
+
293
+ p2 = LazySinglePerson.find(person.id)
294
+
295
+ expect(p2.instance_variable_get("@ssn")).to eq(nil)
296
+ expect(p2.ssn).to eq("123-45-6789")
297
+ person.ssn = "111-11-1111"
298
+ expect(p2.instance_variable_get("@credit_card")).to eq(nil)
299
+ expect(p2.credit_card).to eq("abcd-efgh-hijk-lmno")
300
+ end
301
+
302
+ it "tracks dirty attributes" do
303
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
304
+
305
+ expect(person.ssn_changed?).to be(false)
306
+ expect(person.ssn_change).to be(nil)
307
+ expect(person.ssn_was).to eq("123-45-6789")
308
+
309
+ person.ssn = "111-11-1111"
310
+
311
+ expect(person.ssn_changed?).to be(true)
312
+ expect(person.ssn_change).to eq(["123-45-6789", "111-11-1111"])
313
+ expect(person.ssn_was).to eq("123-45-6789")
314
+ end
315
+
316
+ it "allows attributes to be unset" do
317
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
318
+ person.update!(ssn: nil)
319
+ person.reload
320
+
321
+ expect(person.ssn).to be(nil)
322
+ end
323
+
324
+ it "allows saving without validations" do
325
+ person = LazySinglePerson.new(ssn: "123-456-7890")
326
+ expect(person.save(validate: false)).to be(true)
327
+ expect(person.ssn_encrypted).to match("vault:")
328
+ end
329
+
330
+ it "allows attributes to be unset after reload" do
331
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
332
+ person.reload
333
+ person.update!(ssn: nil)
334
+ person.reload
335
+
336
+ expect(person.ssn).to be(nil)
337
+ end
338
+
339
+ it "allows attributes to be blank" do
340
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
341
+ person.update!(ssn: "")
342
+ person.reload
343
+
344
+ expect(person.ssn).to eq("")
345
+ end
346
+
347
+ it "reloads instance variables on reload" do
348
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
349
+ expect(person.instance_variable_get(:@ssn)).to eq("123-45-6789")
350
+
351
+ person.ssn = "111-11-1111"
352
+ person.reload
353
+
354
+ expect(person.ssn).to eq("123-45-6789")
355
+ end
356
+
357
+ it "does not try to encrypt unchanged attributes" do
358
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
359
+
360
+ expect(Vault::Rails).to_not receive(:encrypt)
361
+ person.name = "Cinderella"
362
+ person.save!
363
+ end
364
+
365
+ it "allows attributes to be accessed after a destroy" do
366
+ person = LazyPerson.create!(ssn: "123-45-6789")
367
+
368
+ person.destroy
369
+ expect { person.ssn }.not_to raise_error
370
+ end
183
371
  end
184
372
 
185
373
  context "with custom options" do
@@ -218,7 +406,7 @@ describe Vault::Rails do
218
406
 
219
407
  it "allows attributes to be unset" do
220
408
  person = Person.create!(credit_card: "1234567890111213")
221
- person.update_attributes!(credit_card: nil)
409
+ person.update!(credit_card: nil)
222
410
  person.reload
223
411
 
224
412
  expect(person.credit_card).to be(nil)
@@ -226,7 +414,7 @@ describe Vault::Rails do
226
414
 
227
415
  it "allows attributes to be blank" do
228
416
  person = Person.create!(credit_card: "1234567890111213")
229
- person.update_attributes!(credit_card: "")
417
+ person.update!(credit_card: "")
230
418
  person.reload
231
419
 
232
420
  expect(person.credit_card).to eq("")
@@ -269,7 +457,7 @@ describe Vault::Rails do
269
457
 
270
458
  it "allows attributes to be unset" do
271
459
  person = Person.create!(non_ascii: "dás ümlaut")
272
- person.update_attributes!(non_ascii: nil)
460
+ person.update!(non_ascii: nil)
273
461
  person.reload
274
462
 
275
463
  expect(person.non_ascii).to be(nil)
@@ -277,26 +465,80 @@ describe Vault::Rails do
277
465
 
278
466
  it "allows attributes to be blank" do
279
467
  person = Person.create!(non_ascii: "dás ümlaut")
280
- person.update_attributes!(non_ascii: "")
468
+ person.update!(non_ascii: "")
281
469
  person.reload
282
470
 
283
471
  expect(person.non_ascii).to eq("")
284
472
  end
285
473
  end
286
474
 
475
+ context "with a default" do
476
+ %i[new create].each do |creation_method|
477
+ context "on #{creation_method}" do
478
+ context "without an initial attribute" do
479
+ it "sets the default" do
480
+ person = Person.public_send(creation_method)
481
+ expect(person.default).to eq("abc123")
482
+ person.save!
483
+ person.reload
484
+ expect(person.default).to eq("abc123")
485
+ end
486
+ end
487
+
488
+ context "with an initial attribute" do
489
+ it "does not set the default" do
490
+ person = Person.public_send(creation_method, default: "another")
491
+ expect(person.default).to eq("another")
492
+ person.save!
493
+ person.reload
494
+ expect(person.default).to eq("another")
495
+ end
496
+ end
497
+ end
498
+ end
499
+ end
500
+
501
+ context "with a default and serializer" do
502
+ %i[new create].each do |creation_method|
503
+ context "on #{creation_method}" do
504
+ context "without an initial attribute" do
505
+ it "sets the default" do
506
+ person = Person.public_send(creation_method)
507
+ expect(person.default_with_serializer).to eq({})
508
+ person.save!
509
+ person.reload
510
+ expect(person.default_with_serializer).to eq({})
511
+ end
512
+ end
513
+
514
+ context "with an initial attribute" do
515
+ it "does not set the default" do
516
+ person = Person.public_send(
517
+ creation_method,
518
+ default_with_serializer: { "foo" => "bar" }
519
+ )
520
+
521
+ expect(person.default_with_serializer).to eq({ "foo" => "bar" })
522
+ person.save!
523
+ person.reload
524
+ expect(person.default_with_serializer).to eq({ "foo" => "bar" })
525
+ end
526
+ end
527
+ end
528
+ end
529
+ end
530
+
287
531
  context "with the :json serializer" do
288
532
  before(:all) do
289
533
  Vault::Rails.logical.write("transit/keys/dummy_people_details")
290
534
  end
291
535
 
292
- it "has a default value for unpersisted records" do
536
+ it "does not default to a hash" do
293
537
  person = Person.new
294
- expect(person.details).to eq({})
295
- end
296
-
297
- it "has a default value for persisted records" do
298
- person = Person.create!
299
- expect(person.details).to eq({})
538
+ expect(person.details).to eq(nil)
539
+ person.save!
540
+ person.reload
541
+ expect(person.details).to eq(nil)
300
542
  end
301
543
 
302
544
  it "tracks dirty attributes" do
@@ -356,6 +598,129 @@ describe Vault::Rails do
356
598
  end
357
599
  end
358
600
 
601
+ context "with context" do
602
+ it "encodes and decodes with a string context" do
603
+ person = Person.create!(context_string: "foobar")
604
+ person.reload
605
+
606
+ raw = Vault::Rails.decrypt(
607
+ "transit", "dummy_people_context_string",
608
+ person.context_string_encrypted, context: "production")
609
+
610
+ expect(raw).to eq("foobar")
611
+
612
+ expect(person.context_string).to eq("foobar")
613
+
614
+ # Decrypting without the correct context fails
615
+ expect {
616
+ Vault::Rails.decrypt(
617
+ "transit", "dummy_people_context_string",
618
+ person.context_string_encrypted, context: "wrongcontext")
619
+ }.to raise_error(Vault::HTTPClientError, /invalid ciphertext/)
620
+
621
+ # Decrypting without a context fails
622
+ expect {
623
+ Vault::Rails.decrypt(
624
+ "transit", "dummy_people_context_string",
625
+ person.context_string_encrypted)
626
+ }.to raise_error(Vault::HTTPClientError, /context/)
627
+ end
628
+
629
+ it "encodes and decodes with a symbol context" do
630
+ person = Person.create!(context_symbol: "foobar")
631
+ person.reload
632
+
633
+ raw = Vault::Rails.decrypt(
634
+ "transit", "dummy_people_context_symbol",
635
+ person.context_symbol_encrypted, context: person.encryption_context)
636
+
637
+ expect(raw).to eq("foobar")
638
+
639
+ expect(person.context_symbol).to eq("foobar")
640
+
641
+ # Decrypting without the correct context fails
642
+ expect {
643
+ Vault::Rails.decrypt(
644
+ "transit", "dummy_people_context_symbol",
645
+ person.context_symbol_encrypted, context: "wrongcontext")
646
+ }.to raise_error(Vault::HTTPClientError, /invalid ciphertext/)
647
+
648
+ # Decrypting without a context fails
649
+ expect {
650
+ Vault::Rails.decrypt(
651
+ "transit", "dummy_people_context_symbol",
652
+ person.context_symbol_encrypted)
653
+ }.to raise_error(Vault::HTTPClientError, /context/)
654
+ end
655
+
656
+ it "encodes and decodes with a proc context" do
657
+ person = Person.create!(context_proc: "foobar")
658
+ person.reload
659
+
660
+ raw = Vault::Rails.decrypt(
661
+ "transit", "dummy_people_context_proc",
662
+ person.context_proc_encrypted, context: person.encryption_context)
663
+
664
+ expect(raw).to eq("foobar")
665
+
666
+ expect(person.context_proc).to eq("foobar")
667
+
668
+ # Decrypting without the correct context fails
669
+ expect {
670
+ Vault::Rails.decrypt(
671
+ "transit", "dummy_people_context_proc",
672
+ person.context_proc_encrypted, context: "wrongcontext")
673
+ }.to raise_error(Vault::HTTPClientError, /invalid ciphertext/)
674
+
675
+ # Decrypting without a context fails
676
+ expect {
677
+ Vault::Rails.decrypt(
678
+ "transit", "dummy_people_context_proc",
679
+ person.context_proc_encrypted)
680
+ }.to raise_error(Vault::HTTPClientError, /context/)
681
+ end
682
+ end
683
+
684
+ context 'with transform_secret', ent_vault: ">= 1.4" do
685
+ before(:all) do
686
+ Vault::Rails.sys.mount("transform", :transform)
687
+ Vault::Rails.client.transform.create_transformation(
688
+ "social_sec",
689
+ template: "builtin/socialsecuritynumber",
690
+ tweak_source: "internal",
691
+ type: "fpe",
692
+ allowed_roles: [Vault::Rails.application]
693
+ )
694
+ Vault::Rails.client.transform.create_role(Vault::Rails.application, transformations: ["social_sec"])
695
+ Vault::Rails.client.transform.create_role("foobar_role", transformations: ["social_sec"])
696
+ end
697
+
698
+ it "encrypts the attribute using the given transformation" do
699
+ person = Person.create!(transform_ssn: "123-45-6789")
700
+ expect(person[:transform_ssn_encrypted]).not_to eq("123-45-6789")
701
+ expect(person[:transform_ssn_encrypted]).to match(/\d{3}-\d{2}-\d{4}/)
702
+ expect(person.transform_ssn).to eq("123-45-6789")
703
+ end
704
+
705
+ it "raises an error if the format is incorrect" do
706
+ expect{ Person.create!(transform_ssn: "1234-5678-90") }.to(
707
+ raise_error(Vault::HTTPClientError, /unable to find matching expression/)
708
+ )
709
+ end
710
+
711
+ it "raises an error if the transformation does not exist" do
712
+ expect{ Person.create!(bad_transform: "nope") }.to(
713
+ raise_error(Vault::HTTPClientError, /unable to find transformation/)
714
+ )
715
+ end
716
+
717
+ it "raises an error if the provided role doesn't have the ability to use the transformation" do
718
+ expect{ Person.create!(bad_role_transform: "123-45-6789") }.to(
719
+ raise_error(Vault::HTTPClientError, /is not an allowed role for the transformation/)
720
+ )
721
+ end
722
+ end
723
+
359
724
  context 'with errors' do
360
725
  it 'raises the appropriate exception' do
361
726
  expect {
@@ -363,4 +728,19 @@ describe Vault::Rails do
363
728
  }.to raise_error(Vault::HTTPClientError)
364
729
  end
365
730
  end
731
+
732
+ context "without a server" do
733
+ it "encrypts attributes with a dev prefix" do
734
+ allow(Vault::Rails).to receive(:enabled?).and_return(false)
735
+ person = Person.create!(credit_card: "1234567890111213")
736
+ expect(person.cc_encrypted).to start_with(Vault::Rails::DEV_PREFIX)
737
+ end
738
+
739
+ it "decrypts attributes" do
740
+ allow(Vault::Rails).to receive(:enabled?).and_return(false)
741
+ person = Person.create!(credit_card: "1234567890111213")
742
+ person.reload
743
+ expect(person.credit_card).to eq("1234567890111213")
744
+ end
745
+ end
366
746
  end