veil 0.3.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6101318787572fead55a5c0c06c46227f840114d
4
- data.tar.gz: af7f78cc9004e614ba49757eda9cba8996646f8d
2
+ SHA256:
3
+ metadata.gz: 3af8aaa1c4ac8737e148057359becae4bc29fcd2e4ba93a5e783f3ea840097e0
4
+ data.tar.gz: e9de20099a2d0a0288bdbd75f831471d83473ea284dd662b2fc9393bce370432
5
5
  SHA512:
6
- metadata.gz: 5f50e2f7e67dce633ec09ca5918e37949ed0e073499ac0878050ad40ed598f5a455ed01e635d8fb0bb13238e785b5204ec1ae4d9770bb73bd5067baf8c19c68c
7
- data.tar.gz: 241a21af2f050f4c193b6389a9f69673b1f913f24755cb54f7750ad83366cf363dc301278057faf9ed181489ffaa4c698a65684e197f8a1bcd9964470361c9a5
6
+ metadata.gz: 4c9f9d837b56c7c1bd19283a8442761ef66ce108a09427ac9a42162c21a44465f26fddeb50480c2c44c9dd7d15890d77574116af854f99ea001d870615e2b013
7
+ data.tar.gz: cce7ba9c026d5ccce2cdaff51974919a7d8d85d8e97fa97e8f6f8a28c2ce2097798250728e1f94b71506711ce5aeb54cafdcdaf5ceefbd064d28bdcb3e7fc806
@@ -1,10 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'veil'
4
+ require 'json'
4
5
  require 'optparse'
5
6
 
6
7
  options = {
7
- secrets_file: "/etc/opscode/private-chef-secrets.json"
8
+ secrets_file: "/etc/opscode/private-chef-secrets.json",
9
+ pack: false,
10
+ use_file: false,
11
+ debug: false,
12
+ secrets: [],
13
+ optional_secrets: []
8
14
  }
9
15
 
10
16
  OptionParser.new do |opts|
@@ -14,8 +20,20 @@ OptionParser.new do |opts|
14
20
  options[:debug] = d
15
21
  end
16
22
 
17
- opts.on("-s SECRETS_SPEC", "--secrets SECRETS_SPEC", "A comma seperated list of secrets to put in the environment") do |spec|
18
- options[:secrets] = spec.split(",")
23
+ opts.on("--pack", "Pass secrets in a single CHEF_SECRETS_DATA environment variable") do |p|
24
+ options[:pack] = p
25
+ end
26
+
27
+ opts.on("--use-file", "Pass secrets via a unlinked file available at the FD specified in CHEF_SECRETS_FD") do |fd|
28
+ options[:use_file] = fd
29
+ end
30
+
31
+ opts.on("-s SECRET_SPEC", "--secret SECRET_SPEC", "Secret to put in the environment") do |spec|
32
+ options[:secrets] << spec
33
+ end
34
+
35
+ opts.on("-o SECRET_SPEC", "--optional-secret SECRET_SPEC", "Optional secrets to put in the environment (if it exists)") do |spec|
36
+ options[:optional_secrets] << spec
19
37
  end
20
38
 
21
39
  opts.on("-f SECRETS_FILE", "--secrets-file SECRETS_FILE", "Location of veil-managed secrets file. Default: /etc/opscode/private-chef-secrets.json") do |file|
@@ -23,25 +41,64 @@ OptionParser.new do |opts|
23
41
  end
24
42
  end.parse!
25
43
 
26
- def env_name_from_secret_spec(secret)
44
+ def from_secret_spec(secret, start = {})
27
45
  parts = secret.split("=")
28
- case parts.length
29
- when 1
30
- ["CHEF_SECRET_#{parts[0].upcase}", parts[0]]
31
- when 2
32
- [parts[0].upcase, parts[1]]
46
+ env_name, secret_name = case parts.length
47
+ when 1
48
+ ["CHEF_SECRET_#{parts[0].upcase}", parts[0]]
49
+ when 2
50
+ [parts[0].upcase, parts[1]]
51
+ else
52
+ raise "Bad secret spec: #{secret}"
53
+ end
54
+
55
+ start.merge({ args: secret_name.split("."),
56
+ env_name: env_name,
57
+ name: secret_name })
58
+ end
59
+
60
+ veil = Veil::CredentialCollection::ChefSecretsFile.from_file(options[:secrets_file])
61
+ packed_data = Hash.new()
62
+
63
+ secrets = options[:secrets].map { |spec| from_secret_spec(spec) }
64
+ secrets += options[:optional_secrets].map { |spec| from_secret_spec(spec, { optional: true }) }
65
+
66
+ secrets.each do |secret|
67
+ veil_args = secret[:args]
68
+
69
+ begin
70
+ secret_value = veil.get(*veil_args)
71
+ rescue
72
+ raise unless secret[:optional]
73
+ next
74
+ end
75
+
76
+ if options[:pack] || options[:use_file]
77
+ STDERR.puts "Packing data using #{veil_args.inspect} and #{secret_value}" if options[:debug]
78
+ if veil_args.length == 2
79
+ packed_data[veil_args[0]] ||= {}
80
+ packed_data[veil_args[0]][veil_args[1]] = secret_value
81
+ elsif veil_args.length == 1
82
+ packed_data[veil_args[0]] = secret_value
83
+ elsif !secret[:optional]
84
+ raise "Invalid secrets name: #{secret[:name]}"
85
+ end
33
86
  else
34
- raise "Bad secret spec: #{secret}"
87
+ STDERR.puts "Setting #{secret[:env_name]}=#{secret_value}" if options[:debug]
88
+ ENV[secret[:env_name]] = secret_value
35
89
  end
36
90
  end
37
91
 
38
- veil = Veil::CredentialCollection::ChefSecretsFile.from_file(options[:secrets_file])
39
- Array(options[:secrets]).each do |secret|
40
- env_name, secret_name = env_name_from_secret_spec(secret)
41
- veil_args = secret_name.split(".")
42
- secret_value = veil.get(*veil_args)
43
- STDERR.puts "Setting #{env_name}=#{secret_value}" if options[:debug]
44
- ENV[env_name] = secret_value
92
+ if options[:pack] && !options[:use_file]
93
+ ENV['CHEF_SECRETS_DATA'] = packed_data.to_json
94
+ end
95
+
96
+ if options[:use_file]
97
+ rd, wd = IO.pipe
98
+ wd.puts packed_data.to_json
99
+ wd.close
100
+ rd.close_on_exec = false
101
+ ENV['CHEF_SECRETS_FD'] = rd.to_i.to_s
45
102
  end
46
103
 
47
- exec(*ARGV)
104
+ exec(*ARGV, close_others: false)
@@ -1,5 +1,7 @@
1
1
  require "veil/credential_collection/base"
2
+ require "veil/credential_collection/chef_secrets_fd"
2
3
  require "veil/credential_collection/chef_secrets_file"
4
+ require "veil/credential_collection/chef_secrets_env"
3
5
 
4
6
  module Veil
5
7
  class CredentialCollection
@@ -8,6 +10,10 @@ module Veil
8
10
  klass = case opts[:provider]
9
11
  when 'chef-secrets-file'
10
12
  ChefSecretsFile
13
+ when 'chef-secrets-env'
14
+ ChefSecretsEnv
15
+ when 'chef-secrets-fd'
16
+ ChefSecretsFd
11
17
  else
12
18
  raise UnknownProvider, "Unknown provider: #{opts[:provider]}"
13
19
  end
@@ -176,6 +176,39 @@ module Veil
176
176
  end
177
177
  end
178
178
 
179
+ def credentials_as_hash
180
+ hash = Hash.new
181
+
182
+ credentials.each do |cred_or_group_name, cred_or_group_attrs|
183
+ if cred_or_group_attrs.is_a?(Hash)
184
+ cred_or_group_attrs.each do |name, cred|
185
+ hash[cred_or_group_name] ||= Hash.new
186
+ hash[cred_or_group_name][name] = cred.to_hash
187
+ end
188
+ else
189
+ hash[cred_or_group_name] = cred_or_group_attrs.to_hash
190
+ end
191
+ end
192
+
193
+ hash
194
+ end
195
+
196
+ def credentials_for_export
197
+ hash = Hash.new
198
+
199
+ credentials.each do |namespace, cred_or_creds|
200
+ if cred_or_creds.is_a?(Veil::Credential)
201
+ hash[namespace] = cred_or_creds.value
202
+ else
203
+ hash[namespace] = {}
204
+ cred_or_creds.each { |name, cred| hash[namespace][name] = cred.value }
205
+ end
206
+ end
207
+
208
+ hash
209
+ end
210
+ alias_method :legacy_credentials_hash, :credentials_for_export
211
+
179
212
  private
180
213
 
181
214
  def add_from_params(params)
@@ -222,21 +255,17 @@ module Veil
222
255
  expanded
223
256
  end
224
257
 
225
- def credentials_as_hash
226
- hash = Hash.new
227
-
228
- credentials.each do |cred_or_group_name, cred_or_group_attrs|
229
- if cred_or_group_attrs.is_a?(Hash)
230
- cred_or_group_attrs.each do |name, cred|
231
- hash[cred_or_group_name] ||= Hash.new
232
- hash[cred_or_group_name][name] = cred.to_hash
233
- end
234
- else
235
- hash[cred_or_group_name] = cred_or_group_attrs.to_hash
258
+ def import_credentials_hash(hash)
259
+ hash.each do |namespace, creds_hash|
260
+ credentials[namespace.to_s] ||= Hash.new
261
+ creds_hash.each do |cred, value|
262
+ credentials[namespace.to_s][cred.to_s] = Veil::Credential.new(
263
+ name: cred.to_s,
264
+ value: value,
265
+ length: value.length
266
+ )
236
267
  end
237
268
  end
238
-
239
- hash
240
269
  end
241
270
  end
242
271
  end
@@ -0,0 +1,43 @@
1
+ require "veil/credential_collection/base"
2
+ require "json"
3
+
4
+ module Veil
5
+ class CredentialCollection
6
+ class ChefSecretsEnv < Base
7
+
8
+ # Create a new ChefSecretsEnv
9
+ #
10
+ # @param [Hash] opts
11
+ # a hash of options to pass to the constructor
12
+ def initialize(opts = {})
13
+ var_name = opts[:var_name] || 'CHEF_SECRETS_DATA'
14
+
15
+ @credentials = {}
16
+ import_credentials_hash(inflate_secrets_from_environment(var_name))
17
+ end
18
+
19
+ # Unsupported methods
20
+ def rotate
21
+ raise NotImplementedError
22
+ end
23
+ alias_method :rotate_credentials, :rotate
24
+ alias_method :save, :rotate
25
+
26
+ def inflate_secrets_from_environment(var_name)
27
+ value = ENV[var_name]
28
+ unless value
29
+ msg = "Env var #{var_name} has not been set. This should by done by "\
30
+ "launching this application via veil-env-wrapper."
31
+ raise InvalidCredentialCollectionEnv.new(msg)
32
+ end
33
+
34
+ begin
35
+ JSON.parse(value)
36
+ rescue JSON::ParserError => e
37
+ msg = "Env var #{var_name} could not be parsed: #{e.message}"
38
+ raise InvalidCredentialCollectionEnv.new(msg)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ require "veil/exceptions"
2
+ require "veil/credential_collection/base"
3
+ require "json"
4
+
5
+ module Veil
6
+ class CredentialCollection
7
+ class ChefSecretsFd < Base
8
+
9
+ # Create a new ChefSecretsFd
10
+ #
11
+ # @param [Hash] opts
12
+ # ignored
13
+ def initialize(opts = {})
14
+ @credentials = {}
15
+ import_credentials_hash(inflate_secrets_from_fd)
16
+ end
17
+
18
+ # Unsupported methods
19
+ def rotate
20
+ raise NotImplementedError
21
+ end
22
+ alias_method :rotate_credentials, :rotate
23
+ alias_method :save, :rotate
24
+
25
+ def inflate_secrets_from_fd
26
+ if ENV['CHEF_SECRETS_FD'].nil?
27
+ raise InvalidCredentialCollectionFd.new("CHEF_SECRETS_FD not found in environment")
28
+ end
29
+
30
+ fd = ENV['CHEF_SECRETS_FD'].to_i
31
+ value = nil
32
+
33
+ begin
34
+ file = IO.new(fd, "r")
35
+ value = file.gets
36
+ rescue StandardError => e
37
+ msg = "A problem occured trying to read passed file descriptor: #{e}"
38
+ raise InvalidCredentialCollectionFd.new(msg)
39
+ ensure
40
+ file.close if file
41
+ end
42
+
43
+ if !value
44
+ msg = "File at CHEF_SECRETS_FD (#{fd}) did not contain any data!"
45
+ raise InvalidCredentialCollectionFd.new(msg)
46
+ end
47
+
48
+ begin
49
+ JSON.parse(value)
50
+ rescue JSON::ParserError => e
51
+ msg = "Chef secrets data could not be parsed: #{e.message}"
52
+ raise InvalidCredentialCollectionFd.new(msg)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -48,7 +48,7 @@ module Veil
48
48
  opts[:version] = CURRENT_VERSION
49
49
  super(opts)
50
50
 
51
- import_legacy_credentials(hash) if import_existing && legacy
51
+ import_credentials_hash(hash) if import_existing && legacy
52
52
  end
53
53
 
54
54
  # Set the secrets file path
@@ -64,6 +64,12 @@ module Veil
64
64
  FileUtils.mkdir_p(File.dirname(path))
65
65
 
66
66
  f = Tempfile.new("veil") # defaults to mode 0600
67
+
68
+ if existing
69
+ @user ||= existing.uid
70
+ @group ||= existing.gid
71
+ end
72
+
67
73
  FileUtils.chown(user, group, f.path) if user
68
74
  f.puts(JSON.pretty_generate(secrets_hash))
69
75
  f.flush
@@ -78,33 +84,10 @@ module Veil
78
84
  { "veil" => to_h }
79
85
  end
80
86
 
81
- def credentials_for_export
82
- hash = Hash.new
83
-
84
- credentials.each do |namespace, cred_or_creds|
85
- if cred_or_creds.is_a?(Veil::Credential)
86
- hash[namespace] = cred_or_creds.value
87
- else
88
- hash[namespace] = {}
89
- cred_or_creds.each { |name, cred| hash[namespace][name] = cred.value }
90
- end
91
- end
92
-
93
- hash
94
- end
95
- alias_method :legacy_credentials_hash, :credentials_for_export
96
-
97
- def import_legacy_credentials(hash)
98
- hash.each do |namespace, creds_hash|
99
- credentials[namespace.to_s] ||= Hash.new
100
- creds_hash.each do |cred, value|
101
- credentials[namespace.to_s][cred.to_s] = Veil::Credential.new(
102
- name: cred.to_s,
103
- value: value,
104
- length: value.length
105
- )
106
- end
107
- end
87
+ def existing
88
+ @existing ||= File.stat(path)
89
+ rescue Errno::ENOENT
90
+ nil
108
91
  end
109
92
  end
110
93
  end
@@ -3,7 +3,10 @@ module Veil
3
3
  class InvalidSecret < StandardError; end
4
4
  class InvalidParameter < StandardError; end
5
5
  class InvalidHasher < StandardError; end
6
- class InvalidCredentialCollectionFile < StandardError; end
6
+ class InvalidCredentialCollection < StandardError; end
7
+ class InvalidCredentialCollectionFile < InvalidCredentialCollection; end
8
+ class InvalidCredentialCollectionEnv < InvalidCredentialCollection; end
9
+ class InvalidCredentialCollectionFd < InvalidCredentialCollection; end
7
10
  class MissingParameter < StandardError; end
8
11
  class NotImplmented < StandardError; end
9
12
  class InvalidCredentialHash < StandardError; end
@@ -1,3 +1,3 @@
1
1
  module Veil
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -2,17 +2,17 @@ require "spec_helper"
2
2
  require "openssl"
3
3
 
4
4
  describe Veil::Cipher::V2 do
5
- let(:iv64) { Base64.strict_encode64("mondaytuesdaywednesday") }
6
- let(:key64) { Base64.strict_encode64("thursdayfridaysaturdaysundaymonday") }
7
- let(:ciphertext64) { "yhHR8ZVUfzRv+4dvcUFlitdmCS3ybi2dGLofzEF1Ibw=" }
5
+ let(:iv64) { Base64.strict_encode64("mondaytue16bytes") }
6
+ let(:key64) { Base64.strict_encode64("thursdayfridaysaturdaysun32bytes") }
7
+ let(:ciphertext64) { "qS6SRmgOgSta2jSdD60sJmu83cRgy4DUJ2nKZwStrqs=" }
8
8
  let(:plainhash) { { "chef-server": "test-value" } }
9
9
 
10
10
  describe "#new" do
11
11
  it "accepts passed key and iv base64-encoded data" do
12
12
  cipher = described_class.new(iv: iv64, key: key64)
13
13
 
14
- expect(cipher.iv).to eq("mondaytuesdaywednesday")
15
- expect(cipher.key).to eq("thursdayfridaysaturdaysundaymonday")
14
+ expect(cipher.iv).to eq("mondaytue16bytes")
15
+ expect(cipher.key).to eq("thursdayfridaysaturdaysun32bytes")
16
16
  end
17
17
 
18
18
  it "generates key and iv data if none was passed" do
@@ -36,8 +36,8 @@ describe Veil::Cipher::V2 do
36
36
  describe "#to_hash" do
37
37
  it "base64-encodes iv and key" do
38
38
  expected = {
39
- iv: "bW9uZGF5dHVlc2RheXdlZG5lc2RheQ==",
40
- key: "dGh1cnNkYXlmcmlkYXlzYXR1cmRheXN1bmRheW1vbmRheQ==",
39
+ iv: "bW9uZGF5dHVlMTZieXRlcw==",
40
+ key: "dGh1cnNkYXlmcmlkYXlzYXR1cmRheXN1bjMyYnl0ZXM=",
41
41
  type: "Veil::Cipher::V2"
42
42
  }
43
43
  expect(described_class.new(iv: iv64, key: key64).to_hash).to eq(expected)
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe Veil::CredentialCollection::ChefSecretsEnv do
4
+ describe "#new" do
5
+ context "env variable is set" do
6
+ let(:var_name) { "CHEF_SECRETS_DATA" }
7
+
8
+ before(:each) do
9
+ ENV[var_name] = '{ "secret_service": { "secret_name": "secret_value" } }'
10
+ end
11
+
12
+ it 'reads the secret from the env var CHEF_SECRETS_DATA' do
13
+ expect(subject.get("secret_service", "secret_name")).to eq("secret_value")
14
+ end
15
+
16
+ context "env variable name is passed" do
17
+ let(:var_name) { "CHEF_SECRETS_DATA_2" }
18
+ let(:subject) { described_class.new(var_name: var_name) }
19
+
20
+ it 'reads the secret from the passed env var name' do
21
+ expect(subject.get("secret_service", "secret_name")).to eq("secret_value")
22
+ end
23
+ end
24
+
25
+ context "env var content cannot be parsed" do
26
+ before(:each) do
27
+ ENV[var_name] = '{ "secre '
28
+ end
29
+
30
+ it "re-raises the JSON parse error" do
31
+ expect{ subject.get("secret_service", "secret_name") }.to raise_error(Veil::InvalidCredentialCollectionEnv)
32
+ end
33
+ end
34
+ end
35
+
36
+ context "env variable is not set" do
37
+ let(:var_name) { "CHEF_SECRETS_DATA" }
38
+
39
+ before(:each) do
40
+ ENV.delete(var_name)
41
+ end
42
+
43
+ it 'raises an exception' do
44
+ expect{ described_class.new }.to raise_error(Veil::InvalidCredentialCollectionEnv)
45
+ end
46
+ end
47
+
48
+ context "unsupported methods" do
49
+ let(:var_name) { "CHEF_SECRETS_DATA" }
50
+
51
+ before(:each) do
52
+ ENV[var_name] = '{}'
53
+ end
54
+
55
+ it 'does not support #rotate' do
56
+ expect{ subject.rotate }.to raise_error(NotImplementedError)
57
+ end
58
+
59
+ it 'does not support #save' do
60
+ expect{ subject.save }.to raise_error(NotImplementedError)
61
+ end
62
+
63
+ it 'does not support #rotate_hasher' do
64
+ expect{ subject.rotate_hasher }.to raise_error(NotImplementedError)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Veil::CredentialCollection::ChefSecretsFd do
4
+ describe "#new" do
5
+ let(:content) { '{ "secret_service": { "secret_name": "secret_value" } }' }
6
+ let(:content_file) {
7
+ rd, wr = IO.pipe
8
+ wr.puts content
9
+ wr.close
10
+ rd
11
+ }
12
+
13
+ context "env variable is set" do
14
+ before(:each) do
15
+ ENV['CHEF_SECRETS_FD'] = content_file.to_i.to_s
16
+ end
17
+
18
+ it 'reads the secret from the passed file descriptor' do
19
+ expect(subject.get("secret_service", "secret_name")).to eq("secret_value")
20
+ end
21
+
22
+ # TODO(ssd) 2017-03-22: We wanted a test for closing the FD, but
23
+ # didn't want to fight with ruby today.
24
+
25
+ context "env var content cannot be parsed" do
26
+ let(:content) { '{ "secre ' }
27
+
28
+ it "re-raises the JSON parse error" do
29
+ expect{ subject.get("secret_service", "secret_name") }.to raise_error(Veil::InvalidCredentialCollectionFd)
30
+ end
31
+ end
32
+ end
33
+
34
+ context "CHEF_SECRETS_FD is not set" do
35
+ before(:each) do
36
+ ENV.delete('CHEF_SECRETS_FD')
37
+ end
38
+
39
+ it 'raises an exception' do
40
+ expect{ described_class.new }.to raise_error(Veil::InvalidCredentialCollectionFd)
41
+ end
42
+ end
43
+
44
+ context "unsupported methods" do
45
+ let(:content) { '{}' }
46
+
47
+ before(:each) do
48
+ ENV['CHEF_SECRETS_FD'] = content_file.to_i.to_s
49
+ end
50
+
51
+ it 'does not support #rotate' do
52
+ expect{ subject.rotate }.to raise_error(NotImplementedError)
53
+ end
54
+
55
+ it 'does not support #save' do
56
+ expect{ subject.save }.to raise_error(NotImplementedError)
57
+ end
58
+
59
+ it 'does not support #rotate_hasher' do
60
+ expect{ subject.rotate_hasher }.to raise_error(NotImplementedError)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -97,43 +97,97 @@ describe Veil::CredentialCollection::ChefSecretsFile do
97
97
  s
98
98
  end
99
99
 
100
- context "when the user is set" do
101
- it "gives the file proper permissions" do
102
- expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
103
- expect(FileUtils).to receive(:chown).with(user, user, "/tmp/unguessable")
104
- expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
105
-
106
- creds = described_class.new(path: file.path,
107
- user: user)
108
- creds.add("redis_lb", "password")
109
- creds.save
100
+ context "when the target file does not exist" do
101
+
102
+ let(:secrets_file) { double(File) }
103
+ before(:each) do
104
+ allow(File).to receive(:stat).with(file.path).and_raise(Errno::ENOENT)
105
+ end
106
+
107
+ context "when the user is not set" do
108
+ it "does not change any permissions" do
109
+ expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
110
+ expect(FileUtils).not_to receive(:chown)
111
+ expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
112
+
113
+ creds = described_class.new(path: file.path)
114
+ creds.add("redis_lb", "password")
115
+ creds.save
116
+ end
117
+ end
118
+
119
+ context "when the user is set" do
120
+ it "gives the file proper permissions" do
121
+ expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
122
+ expect(FileUtils).to receive(:chown).with(user, user, "/tmp/unguessable")
123
+ expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
124
+
125
+ creds = described_class.new(path: file.path,
126
+ user: user)
127
+ creds.add("redis_lb", "password")
128
+ creds.save
129
+ end
110
130
  end
111
131
  end
112
132
 
113
- context "when user and group are set" do
114
- it "gives the file proper permissions" do
115
- expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
116
- expect(FileUtils).to receive(:chown).with(user, group, "/tmp/unguessable")
117
- expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
118
-
119
- creds = described_class.new(path: file.path,
120
- user: user,
121
- group: group)
122
- creds.add("redis_lb", "password")
123
- creds.save
133
+ context "when the target file exists" do
134
+
135
+ let(:secrets_file) { double(File) }
136
+ let(:secrets_file_stat) { double(File, uid: 100, gid: 1000) }
137
+ before(:each) do
138
+ allow(File).to receive(:stat).with(file.path).and_return(secrets_file_stat)
124
139
  end
125
140
 
126
- it "gives the file proper permission even when called from_file" do
127
- file.puts("{}"); file.rewind
128
- expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
129
- expect(FileUtils).to receive(:chown).with(user, group, "/tmp/unguessable")
130
- expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
131
-
132
- creds = described_class.from_file(file.path,
133
- user: user,
134
- group: group)
135
- creds.add("redis_lb", "password")
136
- creds.save
141
+ context "when the user is not set" do
142
+ it "keeps the existing file permissions" do
143
+ expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
144
+ expect(FileUtils).to receive(:chown).with(100, 1000, "/tmp/unguessable")
145
+ expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
146
+
147
+ creds = described_class.new(path: file.path)
148
+ creds.add("redis_lb", "password")
149
+ creds.save
150
+ end
151
+ end
152
+
153
+ context "when the user is set" do
154
+ it "gives the file proper permissions" do
155
+ expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
156
+ expect(FileUtils).to receive(:chown).with(user, user, "/tmp/unguessable")
157
+ expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
158
+
159
+ creds = described_class.new(path: file.path,
160
+ user: user)
161
+ creds.add("redis_lb", "password")
162
+ creds.save
163
+ end
164
+ end
165
+
166
+ context "when user and group are set" do
167
+ it "gives the file proper permissions" do
168
+ expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
169
+ expect(FileUtils).to receive(:chown).with(user, group, "/tmp/unguessable")
170
+ expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
171
+
172
+ creds = described_class.new(path: file.path,
173
+ user: user,
174
+ group: group)
175
+ creds.add("redis_lb", "password")
176
+ creds.save
177
+ end
178
+
179
+ it "gives the file proper permission even when called from_file" do
180
+ file.puts("{}"); file.rewind
181
+ expect(Tempfile).to receive(:new).with("veil").and_return(tmpfile)
182
+ expect(FileUtils).to receive(:chown).with(user, group, "/tmp/unguessable")
183
+ expect(FileUtils).to receive(:mv).with("/tmp/unguessable", file.path)
184
+
185
+ creds = described_class.from_file(file.path,
186
+ user: user,
187
+ group: group)
188
+ creds.add("redis_lb", "password")
189
+ creds.save
190
+ end
137
191
  end
138
192
  end
139
193
  end
@@ -11,6 +11,15 @@ describe Veil::CredentialCollection do
11
11
  end
12
12
  end
13
13
 
14
+ context 'passing provider "chef-secrets-env"' do
15
+ let(:opts) { { provider: 'chef-secrets-env' } }
16
+
17
+ it 'instantiates ChefSecretsFile with all options' do
18
+ expect(Veil::CredentialCollection::ChefSecretsEnv).to receive(:new).with(opts)
19
+ described_class.from_config(opts)
20
+ end
21
+ end
22
+
14
23
  context 'passing anything else as provider' do
15
24
  let(:opts) { { provider: 'vault' } }
16
25
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: veil
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-15 00:00:00.000000000 Z
11
+ date: 2020-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bcrypt
@@ -84,8 +84,6 @@ description: Veil is a Ruby Gem for generating secure secrets from a shared secr
84
84
  email:
85
85
  - partnereng@chef.io
86
86
  executables:
87
- - console
88
- - setup
89
87
  - veil-dump-secrets
90
88
  - veil-env-helper
91
89
  - veil-ingest-secret
@@ -105,6 +103,8 @@ files:
105
103
  - lib/veil/credential.rb
106
104
  - lib/veil/credential_collection.rb
107
105
  - lib/veil/credential_collection/base.rb
106
+ - lib/veil/credential_collection/chef_secrets_env.rb
107
+ - lib/veil/credential_collection/chef_secrets_fd.rb
108
108
  - lib/veil/credential_collection/chef_secrets_file.rb
109
109
  - lib/veil/exceptions.rb
110
110
  - lib/veil/hasher.rb
@@ -117,6 +117,8 @@ files:
117
117
  - spec/cipher/v2_spec.rb
118
118
  - spec/cipher_spec.rb
119
119
  - spec/credential_collection/base_spec.rb
120
+ - spec/credential_collection/chef_secrets_env_spec.rb
121
+ - spec/credential_collection/chef_secrets_fd_spec.rb
120
122
  - spec/credential_collection/chef_secrets_file_spec.rb
121
123
  - spec/credential_collection_spec.rb
122
124
  - spec/credential_spec.rb
@@ -127,7 +129,7 @@ files:
127
129
  - spec/spec_helper.rb
128
130
  - spec/utils_spec.rb
129
131
  - spec/veil_spec.rb
130
- homepage: https://github.com/chef/chef-server/
132
+ homepage: https://github.com/chef/chef_secrets/
131
133
  licenses:
132
134
  - Apache-2.0
133
135
  metadata: {}
@@ -146,8 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
148
  - !ruby/object:Gem::Version
147
149
  version: '0'
148
150
  requirements: []
149
- rubyforge_project:
150
- rubygems_version: 2.4.5.2
151
+ rubygems_version: 3.0.3
151
152
  signing_key:
152
153
  specification_version: 4
153
154
  summary: Veil is a Ruby Gem for generating secure secrets from a shared secret
@@ -156,6 +157,8 @@ test_files:
156
157
  - spec/cipher/v2_spec.rb
157
158
  - spec/cipher_spec.rb
158
159
  - spec/credential_collection/base_spec.rb
160
+ - spec/credential_collection/chef_secrets_env_spec.rb
161
+ - spec/credential_collection/chef_secrets_fd_spec.rb
159
162
  - spec/credential_collection/chef_secrets_file_spec.rb
160
163
  - spec/credential_collection_spec.rb
161
164
  - spec/credential_spec.rb