conjur-cli 4.23.0 → 4.24.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf3b61260f8129d53e15aaca659af65769bdd729
4
- data.tar.gz: b40c45ae844b63e70d1975b2fc2934806562a8b3
3
+ metadata.gz: f4a996c0914a820ab371451e111785dc061c89a7
4
+ data.tar.gz: 3469ca2580a5df324247818f181515e530d4bc03
5
5
  SHA512:
6
- metadata.gz: 0105965b5726d5449fe576a034f7b4f90627d0277d44d9f7c5f95744052fe9a012a037d28ca70f1ba1deef793a5aa0c71bcf9546e221769348aaca60faf37a29
7
- data.tar.gz: d0b1bd9f7f6b094bc846439914d4fbcb852b6b3d6a20a195dd24bc7f2bc6e69b781c4494d3def7d51d188620aabf7432d668fd6c1bd5c51bcdf9ad16d1df8fbb
6
+ metadata.gz: c73f490d57c0dbd9cfc0c69aab11d6832442be416c29cc4b147d048669ca7c0914bdeda8ed6f82f8bde7d171ca955680b201af0685f879ba85334de850e0438b
7
+ data.tar.gz: b4a2f624525b425cfbfbb69eb03f2b04fd84cbe02772f47ac4dbe14371860aa764dfaa69151e8cc0a021108388ed7c491420cdd16a6944bf539b673c13f03dee
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Unreleased
2
2
 
3
+ # 4.24.0
4
+
5
+ * Interactive mode for variable creation
6
+
3
7
  # 4.23.0
4
8
 
5
9
  * Don't check if netrc is world-readable on Windows, since the answer is not reliable
@@ -18,7 +18,6 @@
18
18
  # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
19
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
20
 
21
-
22
21
  class Conjur::Command::Variables < Conjur::Command
23
22
  desc "Manage variables"
24
23
  command :variable do |var|
@@ -26,10 +25,10 @@ class Conjur::Command::Variables < Conjur::Command
26
25
  var.arg_name "id [value]"
27
26
  var.command :create do |c|
28
27
  c.arg_name "mime_type"
29
- c.flag [:m, :"mime-type"], default_value: "text/plain"
28
+ c.flag [:m, :"mime-type"], default_value: 'text/plain'
30
29
 
31
30
  c.arg_name "kind"
32
- c.flag [:k, :"kind"], default_value: "secret"
31
+ c.flag [:k, :"kind"], default_value: 'secret'
33
32
 
34
33
  c.arg_name "value"
35
34
  c.desc "Initial value, which may also be specified as the second command argument after the variable id"
@@ -37,26 +36,54 @@ class Conjur::Command::Variables < Conjur::Command
37
36
 
38
37
  acting_as_option(c)
39
38
 
40
- c.action do |global_options,options,args|
41
- id = args.shift
42
- unless id
43
- ActiveSupport::Deprecation.warn "id argument will be required in future releases"
44
- end
39
+ c.arg_name 'interactive'
40
+ c.desc 'Create variable interactively'
41
+ c.switch [:i, :'interactive']
42
+
43
+ c.action do |global_options,options, args|
44
+ @default_mime_type = c.flags[:m].default_value
45
+ @default_kind = c.flags[:k].default_value
46
+
47
+ id = args.shift unless args.empty?
48
+
45
49
  value = args.shift unless args.empty?
46
50
 
47
- raise "Received extra arguments '#{args.join(' ')}'" unless args.empty?
48
51
  raise "Received conflicting value arguments" if value && options[:value]
49
-
50
- options[:id] = id if id
51
- options[:value] ||= value if value
52
52
 
53
+ groupid = options[:'ownerid']
53
54
  mime_type = options.delete(:m)
54
55
  kind = options.delete(:k)
55
-
56
+ value ||= options.delete(:v)
57
+
58
+ options.delete(:'interactive')
56
59
  options.delete(:"mime-type")
57
60
  options.delete(:"kind")
61
+ options.delete(:'value')
62
+
63
+ annotations = {}
64
+
65
+ # If the user asked for interactive mode, or he didn't specify
66
+ # both an id and a value, prompt for any missing options.
67
+ if options.delete(:i) || !(id && value)
68
+ id ||= prompt_for_id
58
69
 
70
+ groupid ||= prompt_for_group
71
+
72
+ kind = prompt_for_kind if !kind || kind == @default_kind
73
+
74
+ mime_type = prompt_for_mime_type if !mime_type || mime_type == @default_mime_type
75
+
76
+ annotations = prompt_for_annotations
77
+
78
+ value ||= prompt_for_value
79
+ end
80
+
81
+ options[:id] = id
82
+ options[:value] = value
83
+ options[:'ownerid'] = groupid if groupid
84
+
59
85
  var = api.create_variable(mime_type, kind, options)
86
+ api.resource(var).annotations.merge!(annotations) if annotations && !annotations.empty?
60
87
  display(var, options)
61
88
  end
62
89
  end
@@ -124,4 +151,56 @@ class Conjur::Command::Variables < Conjur::Command
124
151
  end
125
152
 
126
153
  end
154
+
155
+ def self.prompt_for_id
156
+ highline.ask('Enter the id: ')
157
+ end
158
+
159
+ def self.prompt_for_group
160
+ highline.ask('Enter the group: ', ->(name) { @group && @group.roleid } ) do |q|
161
+ q.validate = ->(name) do
162
+ name.empty? || (@group = api.group(name)).exists?
163
+ end
164
+ q.responses[:not_valid] = "Group '<%= @answer %>' doesn't exist, or you don't have permission to use it"
165
+ end
166
+ end
167
+
168
+ def self.prompt_for_kind
169
+ highline.ask('Enter the kind: ') {|q| q.default = @default_kind }
170
+ end
171
+
172
+ def self.prompt_for_mime_type
173
+ highline.ask('Enter the MIME type: ') {|q| q.default = @default_mime_type }
174
+ end
175
+
176
+ def self.prompt_for_annotations
177
+ highline.say('Add annotations (press enter to finish):')
178
+ {}.tap do |annotations|
179
+ until (name = highline.ask('annotation name: ')).empty?
180
+ annotations[name] = read_till_eof('annotation value (^D to finish):')
181
+ end
182
+ end
183
+ end
184
+
185
+ def self.prompt_for_value
186
+ read_till_eof('Enter the value (^D on its own line to finish):')
187
+ end
188
+
189
+ def self.highline
190
+ require 'highline'
191
+ @highline ||= HighLine.new($stdin,$stderr)
192
+ end
193
+
194
+ def self.read_till_eof(prompt = nil)
195
+ highline.say(prompt) if prompt
196
+ [].tap do |lines|
197
+ loop do
198
+ begin
199
+ lines << highline.ask('')
200
+ rescue EOFError
201
+ break
202
+ end
203
+ end
204
+ end.join("\n")
205
+ end
127
206
  end
@@ -19,6 +19,6 @@
19
19
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
20
  #
21
21
  module Conjur
22
- VERSION = "4.23.0"
22
+ VERSION = "4.24.0"
23
23
  ::Version=VERSION
24
24
  end
@@ -1,72 +1,157 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Conjur::Command::Variables, logged_in: true do
4
- let(:collection_url) { "https://core.example.com/variables" }
5
- let(:base_payload) { { mime_type: 'text/json', kind: 'password' } }
4
+ let(:host) { 'https://core.example.com' }
5
+ let(:collection_url) { "#{host}/variables" }
6
+ let(:mime_type) { 'text/plain' }
7
+ let(:kind) { 'secret' }
8
+ let(:base_payload) do
9
+ { id: id, value: value, mime_type: mime_type, kind: kind }.tap do |t|
10
+ group && t.merge(ownerid: group)
11
+ end
12
+ end
6
13
  let(:id) { 'the-id' }
7
14
  let(:variable) { post_response(id) }
8
-
9
- describe_command "variable:create -m text/json -k password" do
10
- let(:id) { 'assigned-id' }
11
- it "lets the server assign the id" do
12
- expect(RestClient::Request).to receive(:execute).with({
13
- method: :post,
14
- url: collection_url,
15
- headers: {},
16
- payload: base_payload
17
- }.merge(cert_store_options)).and_return(variable)
18
-
19
- expect { invoke }.to write({ id: 'assigned-id' }).to(:stdout)
15
+ let (:group) { nil }
16
+ let (:annotation) { {} }
17
+ let (:value) { 'the-value' }
18
+ let (:full_payload) { base_payload }
19
+
20
+ context 'when there are command-line errors' do
21
+ describe_command "variable:create -v the-value-1 the-id the-value-2" do
22
+ it "complains about conflicting values" do
23
+ expect { invoke }.to raise_error("Received conflicting value arguments")
24
+ end
20
25
  end
21
26
  end
22
27
 
23
- describe_command "variable:create -m text/json -k password the-id" do
24
- it "propagates the user-assigned id" do
25
- expect(RestClient::Request).to receive(:execute).with({
26
- method: :post,
27
- url: collection_url,
28
- headers: {},
29
- payload: base_payload.merge({ id: 'the-id' })
30
- }.merge(cert_store_options)).and_return(variable)
28
+ context 'when there are no command-line errors' do
29
+
30
+ before do
31
+ allow(Conjur::Command::Variables).to receive(:prompt_for_id) { id }
32
+ allow(Conjur::Command::Variables).to receive(:prompt_for_group) { group }
33
+ allow(Conjur::Command::Variables).to receive(:prompt_for_kind) { kind }
34
+ allow(Conjur::Command::Variables).to receive(:prompt_for_mime_type) { mime_type }
35
+ allow(Conjur::Command::Variables).to receive(:prompt_for_annotations) { annotation }
36
+ allow(Conjur::Command::Variables).to receive(:prompt_for_value) { value }
31
37
 
32
- expect { invoke }.to write({ id: 'the-id' }).to(:stdout)
38
+ expect(RestClient::Request).to receive(:execute).with({
39
+ method: :post,
40
+ url: collection_url,
41
+ headers: {},
42
+ payload: full_payload
43
+ }.merge(cert_store_options)).and_return(variable)
33
44
  end
34
- end
35
-
36
- describe_command "variable:create -m text/json -k password the-id the-value" do
37
- it "propagates the user-assigned id and value" do
38
- expect(RestClient::Request).to receive(:execute).with({
39
- method: :post,
40
- url: collection_url,
41
- headers: {},
42
- payload: base_payload.merge({ id: 'the-id', value: 'the-value' })
43
- }.merge(cert_store_options)).and_return(variable)
44
-
45
- expect { invoke }.to write({ id: 'the-id' }).to(:stdout)
45
+
46
+ describe_command "variable:create the-different-id" do
47
+ let (:id) { 'the-different-id' }
48
+ it "propagates the user-assigned id" do
49
+ expect { invoke }.to write({ id: 'the-different-id' }).to(:stdout)
50
+ end
46
51
  end
47
- end
48
-
49
- describe_command "variable:create -v the-value-1 the-id the-value-2" do
50
- it "complains about conflicting values" do
51
- expect { invoke }.to raise_error("Received conflicting value arguments")
52
+
53
+ describe_command "variable:create the-id the-different-value" do
54
+ let (:value) { 'the-different-value' }
55
+ it "propagates the user-assigned id" do
56
+ expect { invoke }.to write({ id: 'the-id' }).to(:stdout)
57
+ end
52
58
  end
53
- end
54
-
55
- describe_command "variable:create the-id -v the-value" do
56
- it "complains about extra arguments" do
57
- expect { invoke }.to raise_error("Received extra arguments 'the-value'")
59
+
60
+ describe_command "variable:create -m application/json" do
61
+ let (:mime_type) { 'application/json' }
62
+ it "propagates the user-assigned MIME type" do
63
+ expect { invoke }.to write({ id: 'the-id' }).to(:stdout)
64
+ end
58
65
  end
59
- end
66
+
67
+ describe_command "variable:create -k password" do
68
+ let (:kind) { 'password' }
69
+ it "propagates the user-assigned kind" do
70
+ expect { invoke }.to write({ id: 'the-id' }).to(:stdout)
71
+ end
72
+ end
73
+
74
+ describe "in interactive mode" do
75
+ after do
76
+ expect { invoke }.to write({ id: 'the-id' }).to(:stdout)
77
+ end
78
+
79
+ subject { Conjur::Command::Variables }
80
+
81
+ context "when -i is omitted" do
82
+ describe_command 'variable:create' do
83
+ it { is_expected.to receive(:prompt_for_id) }
84
+ it { is_expected.to receive(:prompt_for_group) }
85
+ it { is_expected.to receive(:prompt_for_kind) }
86
+ it { is_expected.to receive(:prompt_for_mime_type) }
87
+ it { is_expected.to receive(:prompt_for_annotations) }
88
+ it { is_expected.to receive(:prompt_for_value) }
89
+ end
90
+
91
+ describe_command 'variable:create the-id' do
92
+ it { is_expected.not_to receive(:prompt_for_id) }
93
+ end
94
+
95
+ describe_command 'variable:create the-id the-value' do
96
+ it { is_expected.not_to receive(:prompt_for_value) }
97
+ end
98
+
99
+ describe_command 'variable:create -m application/json' do
100
+ let (:mime_type) { 'application/json' }
101
+ it { is_expected.not_to receive(:prompt_for_mime_type) }
102
+ end
103
+
104
+ describe_command 'variable:create -k password' do
105
+ let (:kind) { 'password' }
106
+ it { is_expected.not_to receive(:prompt_for_kind) }
107
+ end
108
+
109
+ describe_command 'variable:create -v the-value' do
110
+ it { is_expected.not_to receive(:prompt_for_value) }
111
+ end
60
112
 
61
- describe_command "variable:create" do
62
- it "provides default values for optional parameters mime_type and kind" do
63
- expect(RestClient::Request).to receive(:execute).with({
64
- method: :post,
65
- url: collection_url,
66
- headers: {},
67
- payload: { mime_type: 'text/plain', kind: 'secret'}
68
- }.merge(cert_store_options)).and_return(variable)
69
- expect { invoke }.to write # invoke_silently
113
+ describe_command 'variable:create --as-group the-group' do
114
+ before do
115
+ allow(RestClient::Request).to receive(:execute).with({
116
+ method: :head,
117
+ url: 'https://authz.example.com/the-account/roles/group/the-group',
118
+ headers: {}
119
+ }.merge(cert_store_options)).and_return(OpenStruct.new(headers: {}, body: '{}'))
120
+ end
121
+
122
+ let (:full_payload) { base_payload.merge(ownerid: 'the-account:group:the-group') }
123
+
124
+ it { is_expected.not_to receive(:prompt_for_group) }
125
+ end
126
+
127
+ describe_command 'variable:create --as-role the-account:group:the-group' do
128
+ before do
129
+ allow(RestClient::Request).to receive(:execute).with({
130
+ method: :head,
131
+ url: 'https://authz.example.com/the-account/roles/group/the-group',
132
+ headers: {}
133
+ }.merge(cert_store_options)).and_return(OpenStruct.new(headers: {}, body: '{}'))
134
+ end
135
+
136
+ let (:full_payload) { base_payload.merge(ownerid: 'the-account:group:the-group') }
137
+
138
+ it { is_expected.not_to receive(:prompt_for_group) }
139
+ end
140
+
141
+ end
142
+
143
+ context "when -i is provided" do
144
+ describe_command 'variable:create -i the-id the-value' do
145
+ it { is_expected.not_to receive(:prompt_for_id) }
146
+ it { is_expected.not_to receive(:prompt_for_value) }
147
+ it { is_expected.to receive(:prompt_for_group) }
148
+ it { is_expected.to receive(:prompt_for_mime_type) }
149
+ it { is_expected.to receive(:prompt_for_kind) }
150
+ it { is_expected.to receive(:prompt_for_annotations) }
151
+ end
152
+ end
153
+
70
154
  end
155
+
71
156
  end
72
157
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conjur-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.23.0
4
+ version: 4.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafal Rzepecki
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-05-04 00:00:00.000000000 Z
12
+ date: 2015-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport