conjur-cli 4.23.0 → 4.24.0

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
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