chef-encrypted-attributes 0.3.0 → 0.4.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +8 -0
  5. data/CHANGELOG.md +40 -4
  6. data/CONTRIBUTING.md +7 -6
  7. data/KNIFE.md +151 -0
  8. data/README.md +70 -192
  9. data/Rakefile +27 -14
  10. data/TESTING.md +18 -7
  11. data/TODO.md +2 -5
  12. data/lib/chef-encrypted-attributes.rb +7 -1
  13. data/lib/chef/encrypted_attribute.rb +282 -121
  14. data/lib/chef/encrypted_attribute/api.rb +521 -0
  15. data/lib/chef/encrypted_attribute/assertions.rb +16 -6
  16. data/lib/chef/encrypted_attribute/cache_lru.rb +54 -13
  17. data/lib/chef/encrypted_attribute/config.rb +198 -89
  18. data/lib/chef/encrypted_attribute/encrypted_mash.rb +127 -33
  19. data/lib/chef/encrypted_attribute/encrypted_mash/version0.rb +236 -48
  20. data/lib/chef/encrypted_attribute/encrypted_mash/version1.rb +249 -36
  21. data/lib/chef/encrypted_attribute/encrypted_mash/version2.rb +133 -19
  22. data/lib/chef/encrypted_attribute/exceptions.rb +19 -3
  23. data/lib/chef/encrypted_attribute/local_node.rb +15 -4
  24. data/lib/chef/encrypted_attribute/remote_clients.rb +33 -17
  25. data/lib/chef/encrypted_attribute/remote_node.rb +84 -29
  26. data/lib/chef/encrypted_attribute/remote_nodes.rb +62 -11
  27. data/lib/chef/encrypted_attribute/remote_users.rb +58 -19
  28. data/lib/chef/encrypted_attribute/search_helper.rb +214 -74
  29. data/lib/chef/encrypted_attribute/version.rb +3 -1
  30. data/lib/chef/encrypted_attributes.rb +20 -0
  31. data/lib/chef/knife/core/config.rb +4 -1
  32. data/lib/chef/knife/core/encrypted_attribute_base.rb +179 -0
  33. data/lib/chef/knife/core/encrypted_attribute_depends.rb +43 -0
  34. data/lib/chef/knife/core/encrypted_attribute_editor_options.rb +125 -61
  35. data/lib/chef/knife/encrypted_attribute_create.rb +51 -31
  36. data/lib/chef/knife/encrypted_attribute_delete.rb +32 -40
  37. data/lib/chef/knife/encrypted_attribute_edit.rb +51 -32
  38. data/lib/chef/knife/encrypted_attribute_show.rb +30 -55
  39. data/lib/chef/knife/encrypted_attribute_update.rb +43 -28
  40. data/spec/benchmark_helper.rb +2 -1
  41. data/spec/integration_helper.rb +1 -0
  42. data/spec/spec_helper.rb +21 -7
  43. metadata +75 -36
  44. metadata.gz.sig +1 -1
  45. data/API.md +0 -174
  46. data/INTERNAL.md +0 -166
@@ -0,0 +1,43 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Xabier de Zuazo (<xabier@onddo.com>)
4
+ # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/knife'
21
+
22
+ class Chef
23
+ class Knife
24
+ module Core
25
+ # Loads knife encrypted attribute dependencies.
26
+ module EncryptedAttributeDepends
27
+ # Reopens EncryptedAttributeDepends class to define knife dependencies.
28
+ #
29
+ # Includes the required gems to work with encrypted attributes.
30
+ #
31
+ # @param includer [Class] includer class.
32
+ def self.included(includer)
33
+ includer.class_eval do
34
+ deps do
35
+ require 'chef/encrypted_attribute'
36
+ require 'chef/json_compat'
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -21,88 +22,151 @@ require 'chef/knife/core/config'
21
22
  class Chef
22
23
  class Knife
23
24
  module Core
24
-
25
+ # Reads knife encrypted attribute edit commands arguments
25
26
  module EncryptedAttributeEditorOptions
27
+ # Reopens EncryptedAttributeEditorOptions class to define knife
28
+ # argument options.
29
+ #
30
+ # @param includer [Class] includer class.
26
31
  def self.included(includer)
27
32
  includer.class_eval do
28
33
 
29
- deps do
30
- require 'chef/encrypted_attribute'
31
- require 'chef/json_compat'
34
+ # Helper method to set the encrypted attributes configuration.
35
+ def self.encrypted_attributes_option_set(key, value)
36
+ Chef::Config[:knife][:encrypted_attributes][key] = value
37
+ end
38
+
39
+ # Helper method to add a value to an encrypted configuration array
40
+ # option.
41
+ def self.encrypted_attributes_option_push(key, value)
42
+ unless Chef::Config[:knife][:encrypted_attributes][key]
43
+ .is_a?(Array)
44
+ Chef::Config[:knife][:encrypted_attributes][key] = []
45
+ end
46
+ Chef::Config[:knife][:encrypted_attributes][key] << value
32
47
  end
33
48
 
34
49
  option :encrypted_attribute_version,
35
- :long => '--encrypted-attribute-version VERSION',
36
- :description => 'Encrypted Attribute protocol version to use',
37
- :proc => lambda { |i| Chef::Config[:knife][:encrypted_attributes][:version] = i }
50
+ long: '--encrypted-attribute-version VERSION',
51
+ description: 'Encrypted Attribute protocol version to use',
52
+ proc: ->(i) { encrypted_attributes_option_set(:version, i) }
38
53
 
39
54
  option :encrypted_attribute_partial_search,
40
- :short => '-P',
41
- :long => '--disable-partial-search',
42
- :description => 'Disable partial search',
43
- :boolean => true,
44
- :proc => lambda { |i| Chef::Config[:knife][:encrypted_attributes][:partial_search] = false }
55
+ short: '-P',
56
+ long: '--disable-partial-search',
57
+ description: 'Disable partial search',
58
+ boolean: true,
59
+ proc:
60
+ (lambda do |_i|
61
+ encrypted_attributes_option_set(:partial_search, false)
62
+ end)
45
63
 
46
64
  option :encrypted_attribute_client_search,
47
- :short => '-C CLIENT_SEARCH_QUERY',
48
- :long => '--client-search CLIENT_SEARCH_QUERY',
49
- :description => 'Client search query. Can be specified multiple times',
50
- :proc => lambda { |i|
51
- Chef::Config[:knife][:encrypted_attributes][:client_search] = [] unless Chef::Config[:knife][:encrypted_attributes][:client_search].kind_of?(Array)
52
- Chef::Config[:knife][:encrypted_attributes][:client_search] << i
53
- }
65
+ short: '-C CLIENT_SEARCH_QUERY',
66
+ long: '--client-search CLIENT_SEARCH_QUERY',
67
+ description:
68
+ 'Client search query. Can be specified multiple times',
69
+ proc:
70
+ (lambda do |i|
71
+ encrypted_attributes_option_push(:client_search, i)
72
+ end)
54
73
 
55
74
  option :encrypted_attribute_node_search,
56
- :short => '-N NODE_SEARCH_QUERY',
57
- :long => '--node-search NODE_SEARCH_QUERY',
58
- :description => 'Node search query. Can be specified multiple times',
59
- :proc => lambda { |i|
60
- Chef::Config[:knife][:encrypted_attributes][:node_search] = [] unless Chef::Config[:knife][:encrypted_attributes][:node_search].kind_of?(Array)
61
- Chef::Config[:knife][:encrypted_attributes][:node_search] << i
62
- }
75
+ short: '-N NODE_SEARCH_QUERY',
76
+ long: '--node-search NODE_SEARCH_QUERY',
77
+ description:
78
+ 'Node search query. Can be specified multiple times',
79
+ proc:
80
+ ->(i) { encrypted_attributes_option_push(:node_search, i) }
63
81
 
64
82
  option :encrypted_attribute_users,
65
- :short => '-U USER',
66
- :long => '--encrypted-attribute-user USER',
67
- :description => 'User name to allow access to. Can be specified multiple times',
68
- :proc => lambda { |i|
69
- Chef::Config[:knife][:encrypted_attributes][:users] = [] unless Chef::Config[:knife][:encrypted_attributes][:users].kind_of?(Array)
70
- Chef::Config[:knife][:encrypted_attributes][:users] << i
71
- }
83
+ short: '-U USER',
84
+ long: '--encrypted-attribute-user USER',
85
+ description:
86
+ 'User name to allow access to. Can be specified multiple '\
87
+ 'times',
88
+ proc: ->(i) { encrypted_attributes_option_push(:users, i) }
72
89
 
73
- # TODO option :keys
90
+ # TODO: option :keys
91
+ end # includer.class_eval
92
+ end # self.included(includer)
74
93
 
75
- # Modified Chef::Knife::UI#edit_data method with plain text format support
76
- def edit_data(data=nil, format='plain')
77
- output = case format
78
- when 'JSON', 'json'
79
- data.nil? ? {} : Chef::JSONCompat.to_json_pretty(data, {:quirks_mode => true})
80
- else
81
- data.nil? ? '' : data
82
- end
94
+ # Converts a string data to a Ruby value.
95
+ #
96
+ # @param data [String] data to convert.
97
+ # @param format [String] `'plain'` or `'json'`.
98
+ # @return [String, Mixed] Ruby value.
99
+ def edit_data_string_to_obj(data, format)
100
+ case format
101
+ when 'JSON', 'json'
102
+ if data.nil?
103
+ {}
104
+ else
105
+ Chef::JSONCompat.to_json_pretty(data, quirks_mode: true)
106
+ end
107
+ else
108
+ data.nil? ? '' : data
109
+ end
110
+ end
83
111
 
84
- if !config[:disable_editing]
85
- Tempfile.open([ 'knife-edit-', '.json' ]) do |tf|
86
- tf.sync = true
87
- tf.puts output
88
- tf.close
89
- raise 'Please set EDITOR environment variable' unless system("#{config[:editor]} #{tf.path}")
112
+ # Converts Ruby values to string.
113
+ #
114
+ # @param data [Mixed] Ruby value to convert.
115
+ # @param format [String] `'plain'` or `'json'`.
116
+ # @return [String] value encoded as string.
117
+ def edit_data_obj_to_string(data, format)
118
+ case format
119
+ when 'JSON', 'json'
120
+ FFI_Yajl::Parser.parse(data)
121
+ else
122
+ data
123
+ end
124
+ end
90
125
 
91
- output = IO.read(tf.path)
92
- tf.unlink # not needed, but recommended
93
- end
94
- end
126
+ # Runs system editor.
127
+ #
128
+ # @param path [String] path file to edit.
129
+ # @return void
130
+ # @raise [RuntimeError] if the editing command fails.
131
+ def edit_data_run_editor_command(path)
132
+ return if system("#{config[:editor]} #{path}")
133
+ fail 'Please set EDITOR environment variable'
134
+ end
95
135
 
96
- case format
97
- when 'JSON', 'json'
98
- Yajl::Parser.parse(output)
99
- else
100
- output
101
- end
102
- end # def edit_data
136
+ # Edits a data using the system editor.
137
+ #
138
+ # Creates a temporal file to edit the data value.
139
+ #
140
+ # @param data [String] data to edit.
141
+ # @return [String] the data after the editing.
142
+ # @raise [RuntimeError] if the editing command fails.
143
+ def edit_data_run_editor(data)
144
+ return if config[:disable_editing]
145
+ result = nil
146
+ Tempfile.open(%w(knife-edit- .json)) do |tf|
147
+ tf.sync = true
148
+ tf.puts(data)
149
+ tf.close
150
+ edit_data_run_editor_command(tf.path)
151
+ result = IO.read(tf.path)
152
+ end
153
+ result
154
+ end
103
155
 
104
- end # includer.class_eval
105
- end # self.included(includer)
156
+ # Edits data using an editor.
157
+ #
158
+ # Modified `Chef::Knife::UI#edit_data` method with plain text format
159
+ # support
160
+ #
161
+ # @param data [String] default data value to edit.
162
+ # @param format [String] `'plain'` or `'json'`.
163
+ # @return [String] resulting data value after edition.
164
+ # @raise [RuntimeError] if the editing command fails.
165
+ def edit_data(data = nil, format = 'plain')
166
+ output = edit_data_string_to_obj(data, format)
167
+ output = edit_data_run_editor(output)
168
+ edit_data_obj_to_string(output, format)
169
+ end # def edit_data
106
170
  end # EncryptedAttributeEditorOptions
107
171
  end # Core
108
172
  end # Knife
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -16,52 +17,71 @@
16
17
  # limitations under the License.
17
18
  #
18
19
 
19
- require 'chef/knife/encrypted_attribute_show'
20
+ require 'chef/knife/core/encrypted_attribute_base'
21
+ require 'chef/knife/core/encrypted_attribute_depends'
20
22
  require 'chef/knife/core/encrypted_attribute_editor_options'
21
23
 
22
24
  class Chef
23
25
  class Knife
24
- class EncryptedAttributeCreate < EncryptedAttributeShow
25
-
26
+ # knife encrypted attribute create command.
27
+ #
28
+ # ```
29
+ # $ knife encrypted attribute create NODE ATTRIBUTE (options)
30
+ # ```
31
+ class EncryptedAttributeCreate < Core::EncryptedAttributeBase
32
+ include Knife::Core::EncryptedAttributeDepends
26
33
  include Knife::Core::EncryptedAttributeEditorOptions
27
34
 
28
35
  option :input_format,
29
- :short => '-i FORMAT',
30
- :long => '--input-format FORMAT',
31
- :description => 'Input (EDITOR) format, supported formats are "plain" (default) and "json"'
36
+ short: '-i FORMAT',
37
+ long: '--input-format FORMAT',
38
+ description:
39
+ 'Input (EDITOR) format, supported formats are "plain" '\
40
+ '(default) and "json"'
32
41
 
33
42
  banner 'knife encrypted attribute create NODE ATTRIBUTE (options)'
34
43
 
35
- def run
36
- node_name = @name_args[0]
37
- attr_path = @name_args[1]
38
-
39
- if node_name.nil?
40
- show_usage
41
- ui.fatal('You must specify a node name')
42
- exit 1
43
- end
44
-
45
- if attr_path.nil?
46
- show_usage
47
- ui.fatal('You must specify an encrypted attribute name')
48
- exit 1
49
- end
50
-
51
- attr_ary = attribute_path_to_ary(attr_path)
52
-
44
+ # (see EncryptedAttributeBase#assert_valid_args)
45
+ # @raise [ArgumentError] if the attribute path format is wrong.
46
+ def assert_valid_args
53
47
  # check if the encrypted attribute already exists
54
- if Chef::EncryptedAttribute.exist_on_node?(node_name, attr_ary)
55
- ui.fatal('Encrypted attribute already exists')
56
- exit 1
57
- end
48
+ assert_attribute_does_not_exist(@node_name, @attr_ary)
49
+ end
50
+
51
+ # Runs knife command.
52
+ #
53
+ # @raise [RuntimeError] if the editing command fails.
54
+ # @raise [ArgumentError] if the attribute path format or the user list is
55
+ # wrong.
56
+ # @raise [UnacceptableEncryptedAttributeFormat] if encrypted attribute
57
+ # format is wrong or does not exist.
58
+ # @raise [UnsupportedEncryptedAttributeFormat] if encrypted attribute
59
+ # format is not supported or unknown.
60
+ # @raise [EncryptionFailure] if there are encryption errors.
61
+ # @raise [MessageAuthenticationFailure] if HMAC calculation error.
62
+ # @raise [InvalidPublicKey] if it is not a valid RSA public key.
63
+ # @raise [InvalidKey] if the RSA key format is wrong.
64
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
65
+ # the keys from the Chef Server.
66
+ # @raise [ClientNotFound] if client does not exist.
67
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
68
+ # @raise [RequirementsFailure] if the specified encrypted attribute
69
+ # version cannot be used.
70
+ # @raise [SearchFailure] if there is a Chef search error.
71
+ # @raise [SearchFatalError] if the Chef search response is wrong.
72
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
73
+ # @return void
74
+ def run
75
+ parse_args
58
76
 
59
77
  # create encrypted attribute
60
78
  output = edit_data(nil, config[:input_format])
61
- enc_attr = Chef::EncryptedAttribute.new(Chef::Config[:knife][:encrypted_attributes])
62
- enc_attr.create_on_node(node_name, attr_ary, output)
79
+ enc_attr =
80
+ Chef::EncryptedAttribute.new(
81
+ Chef::Config[:knife][:encrypted_attributes]
82
+ )
83
+ enc_attr.create_on_node(@node_name, @attr_ary, output)
63
84
  end
64
-
65
85
  end
66
86
  end
67
87
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -16,56 +17,47 @@
16
17
  # limitations under the License.
17
18
  #
18
19
 
19
- require 'chef/knife'
20
- require 'chef/knife/encrypted_attribute_show'
20
+ require 'chef/knife/core/encrypted_attribute_base'
21
+ require 'chef/knife/core/encrypted_attribute_depends'
21
22
  require 'chef/encrypted_attribute/remote_node'
22
23
 
23
24
  class Chef
24
25
  class Knife
25
- class EncryptedAttributeDelete < EncryptedAttributeShow
26
-
27
- deps do
28
- require 'chef/encrypted_attribute'
29
- require 'chef/json_compat'
30
- end
26
+ # knife encrypted attribute delete command.
27
+ #
28
+ # ```
29
+ # $ knife encrypted attribute delete NODE ATTRIBUTE (options)
30
+ # ```
31
+ class EncryptedAttributeDelete < Core::EncryptedAttributeBase
32
+ include Knife::Core::EncryptedAttributeDepends
31
33
 
32
34
  banner 'knife encrypted attribute delete NODE ATTRIBUTE (options)'
33
35
 
34
36
  option :force,
35
- :short => '-f',
36
- :long => '--force',
37
- :description => 'Force the attribute deletion even if you cannot read it',
38
- :boolean => true
39
-
37
+ short: '-f',
38
+ long: '--force',
39
+ description:
40
+ 'Force the attribute deletion even if you cannot read it',
41
+ boolean: true
42
+
43
+ # Runs knife command.
44
+ #
45
+ # @return void
46
+ # @raise [ArgumentError] if the attribute path format is wrong.
47
+ # @raise [SearchFailure] if there is a Chef search error.
48
+ # @raise [SearchFatalError] if the Chef search response is wrong.
49
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
40
50
  def run
41
- node_name = @name_args[0]
42
- attr_path = @name_args[1]
43
-
44
- if node_name.nil?
45
- show_usage
46
- ui.fatal('You must specify a node name')
47
- exit 1
48
- end
49
-
50
- if attr_path.nil?
51
- show_usage
52
- ui.fatal('You must specify an encrypted attribute name')
53
- exit 1
54
- end
55
-
56
- attr_ary = attribute_path_to_ary(attr_path)
57
- if Chef::EncryptedAttribute.exist_on_node?(node_name, attr_ary)
58
- # TODO move this to lib/EncryptedAttribute
59
- unless config[:force] # try to read the attribute
60
- Chef::EncryptedAttribute.load_from_node(node_name, attr_ary)
61
- end
62
- remote_node = Chef::EncryptedAttribute::RemoteNode.new(node_name)
63
- if remote_node.delete_attribute(attr_ary)
64
- ui.info('Encrypted attribute deleted.')
65
- end
66
- end
51
+ parse_args
52
+
53
+ return unless
54
+ Chef::EncryptedAttribute.exist_on_node?(@node_name, @attr_ary)
55
+ # TODO: move this to lib/EncryptedAttribute
56
+ assert_attribute_readable(@node_name, @attr_ary) unless config[:force]
57
+ remote_node = Chef::EncryptedAttribute::RemoteNode.new(@node_name)
58
+ return unless remote_node.delete_attribute(@attr_ary)
59
+ ui.info('Encrypted attribute deleted.')
67
60
  end
68
-
69
61
  end
70
62
  end
71
63
  end