conjur-cli 4.10.3 → 4.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/conjur.gemspec +1 -1
- data/lib/conjur/authn.rb +9 -1
- data/lib/conjur/command/audit.rb +21 -11
- data/lib/conjur/command/init.rb +4 -1
- data/lib/conjur/command/rspec/audit_helpers.rb +69 -0
- data/lib/conjur/command/rspec/describe_command.rb +1 -0
- data/lib/conjur/command/rspec/helpers.rb +1 -0
- data/lib/conjur/config.rb +11 -7
- data/lib/conjur/dsl/runner.rb +1 -1
- data/lib/conjur/version.rb +1 -1
- data/spec/authn_spec.rb +17 -0
- data/spec/command/audit_spec.rb +268 -1
- data/spec/command/init_spec.rb +17 -15
- data/spec/config_spec.rb +48 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4340c1ab3fdec7c2cb49b4fa1ec442298df85a50
|
4
|
+
data.tar.gz: 4acef5138095751da921eba71e2a13780fddd9d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d52290d6b3fb8a86df68d8bbc2faff5bd24e4b382f570096b74fe1d24b724592abb724df3e580448f52f93edf0376be8167e3b6fc4ff0b6c4daa45c90af959a
|
7
|
+
data.tar.gz: 70fa8e0a22fe5cc93eb51b08b07b0e8ee875b8336c6e4e06fa9fa5d66e2bae27345c50005e947c814fe6d2139448f76467b93bbfc20547201b5f499c9988cc79
|
data/conjur.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
|
18
18
|
|
19
19
|
gem.add_dependency 'activesupport'
|
20
|
-
gem.add_dependency 'conjur-api', '>=4.9.
|
20
|
+
gem.add_dependency 'conjur-api', '>=4.9.2'
|
21
21
|
gem.add_dependency 'gli', '>=2.8.0'
|
22
22
|
gem.add_dependency 'highline'
|
23
23
|
gem.add_dependency 'netrc'
|
data/lib/conjur/authn.rb
CHANGED
@@ -54,7 +54,15 @@ module Conjur::Authn
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def get_credentials(options = {})
|
57
|
-
@credentials ||= (read_credentials || fetch_credentials(options))
|
57
|
+
@credentials ||= (env_credentials || read_credentials || fetch_credentials(options))
|
58
|
+
end
|
59
|
+
|
60
|
+
def env_credentials
|
61
|
+
if (login = ENV['CONJUR_AUTHN_LOGIN']) && (api_key = ENV['CONJUR_AUTHN_API_KEY'])
|
62
|
+
[ login, api_key ]
|
63
|
+
else
|
64
|
+
nil
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
def read_credentials
|
data/lib/conjur/command/audit.rb
CHANGED
@@ -11,22 +11,30 @@ class Conjur::Command
|
|
11
11
|
'resource:deny' => lambda{|e| "denied #{e[:privilege]} from #{e[:grantee]} on #{e[:resource]}" },
|
12
12
|
'resource:permitted_roles' => lambda{|e| "listed roles permitted to #{e[:privilege]} on #{e[:resource]}" },
|
13
13
|
'role:check' => lambda{|e| "checked that #{e[:role] == e[:user] ? 'they' : e[:role]} can #{e[:privilege]} #{e[:resource]} (#{e[:allowed]})" },
|
14
|
-
'role:grant' => lambda{|e| "granted role #{e[:role]} to #{e[:member]} #{e[:admin_option] ? '
|
14
|
+
'role:grant' => lambda{|e| "granted role #{e[:role]} to #{e[:member]} #{e[:admin_option] ? 'with' : 'without'} admin" },
|
15
15
|
'role:revoke' => lambda{|e| "revoked role #{e[:role]} from #{e[:member]}" },
|
16
|
-
'role:create' => lambda{|e| "created role #{e[:role]}" }
|
16
|
+
'role:create' => lambda{|e| "created role #{e[:role]}" },
|
17
|
+
'audit' => lambda{ |e|
|
18
|
+
action_part = [ e[:facility], e[:action] ].compact.join(":")
|
19
|
+
actor_part = e[:role] ? "by #{e[:role]}" : nil
|
20
|
+
resource_part = e[:resource_id] ? "on #{e[:resource_id]}" : nil
|
21
|
+
allowed_part = e.has_key?(:allowed) ? "(allowed: #{e[:allowed]})" : nil
|
22
|
+
message_part = e[:audit_message] ? "; message: #{e[:audit_message]}" : ""
|
23
|
+
statement = [ action_part, actor_part, resource_part, allowed_part ].compact.join(" ")
|
24
|
+
"reported #{statement}"+ message_part
|
25
|
+
}
|
17
26
|
}
|
18
27
|
|
19
|
-
|
20
28
|
def short_event_format e
|
21
29
|
e.symbolize_keys!
|
22
30
|
s = "[#{Time.parse(e[:timestamp])}]"
|
23
31
|
s << " #{e[:user]}"
|
24
32
|
s << " (as #{e[:acting_as]})" if e[:acting_as] != e[:user]
|
25
|
-
formatter = SHORT_FORMATS["#{e[:kind]}:#{e[:action]}"]
|
33
|
+
formatter = SHORT_FORMATS["#{e[:kind]}:#{e[:action]}"] || SHORT_FORMATS[e[:kind]]
|
26
34
|
if formatter
|
27
35
|
s << " " << formatter.call(e)
|
28
36
|
else
|
29
|
-
s << " unknown event: #{e[:
|
37
|
+
s << " unknown event: #{e[:kind]}:#{e[:action]}!"
|
30
38
|
end
|
31
39
|
s << " (failed with #{e[:error]})" if e[:error]
|
32
40
|
s
|
@@ -53,6 +61,10 @@ class Conjur::Command
|
|
53
61
|
|
54
62
|
def show_audit_events events, options
|
55
63
|
events = [events] unless events.kind_of?(Array)
|
64
|
+
# offset and limit options seem to be broken. this is a temporary workaround (should be applied on server-side eventually)
|
65
|
+
events = events.drop(options[:offset]) if options[:offset]
|
66
|
+
events = events.take(options[:limit]) if options[:limit]
|
67
|
+
|
56
68
|
if options[:short]
|
57
69
|
events.each{|e| puts short_event_format(e)}
|
58
70
|
else
|
@@ -82,14 +94,13 @@ class Conjur::Command
|
|
82
94
|
end
|
83
95
|
end
|
84
96
|
|
85
|
-
desc "
|
86
|
-
command
|
97
|
+
desc "Fetch audit events"
|
98
|
+
command :audit do |audit|
|
87
99
|
audit.desc "Show all audit events visible to the current user"
|
88
100
|
audit_feed_command audit, :all do |args, options|
|
89
101
|
api.audit(options){ |es| show_audit_events es, options }
|
90
102
|
end
|
91
103
|
|
92
|
-
|
93
104
|
audit.desc "Show audit events related to a role"
|
94
105
|
audit.arg_name 'role'
|
95
106
|
audit_feed_command audit, :role do |args, options|
|
@@ -97,13 +108,12 @@ class Conjur::Command
|
|
97
108
|
api.audit_role(id, options){ |es| show_audit_events es, options }
|
98
109
|
end
|
99
110
|
|
100
|
-
|
101
111
|
audit.desc "Show audit events related to a resource"
|
102
112
|
audit.arg_name 'resource'
|
103
113
|
audit_feed_command audit, :resource do |args, options|
|
104
114
|
id = full_resource_id(require_arg args, "resource")
|
105
115
|
api.audit_resource(id, options){|es| show_audit_events es, options}
|
106
|
-
end
|
116
|
+
end
|
107
117
|
end
|
108
118
|
end
|
109
|
-
end
|
119
|
+
end
|
data/lib/conjur/command/init.rb
CHANGED
@@ -94,7 +94,10 @@ class Conjur::Command::Init < Conjur::Command
|
|
94
94
|
|
95
95
|
exit_now! "account is required" if account.blank?
|
96
96
|
|
97
|
-
config = {
|
97
|
+
config = {
|
98
|
+
account: account,
|
99
|
+
plugins: []
|
100
|
+
}
|
98
101
|
|
99
102
|
config[:appliance_url] = "https://#{hostname}/api" unless hostname.blank?
|
100
103
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
shared_context "default audit behavior" do
|
2
|
+
let(:common_prefix) { "[#{default_audit_event["timestamp"]}] #{default_audit_event["user"]}" }
|
3
|
+
|
4
|
+
let(:default_audit_event) {
|
5
|
+
{
|
6
|
+
"request" => {
|
7
|
+
"ip" => "1.2.3.4",
|
8
|
+
"url"=>"https://conjur/api",
|
9
|
+
"method"=>"POST",
|
10
|
+
"uuid" => "abcdef",
|
11
|
+
"params"=> {
|
12
|
+
"controller"=>"role",
|
13
|
+
"action"=>"create",
|
14
|
+
"account"=>"the-account"
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"user" => "account:user:alice",
|
18
|
+
"acting_as" => "account:group:admins",
|
19
|
+
"conjur" => { # new behaviour
|
20
|
+
"user" => "account:user:alice",
|
21
|
+
"role" => "account:group:admins",
|
22
|
+
"domain" => "authz",
|
23
|
+
"env" => "test",
|
24
|
+
"account" => "the-account"
|
25
|
+
},
|
26
|
+
"completely_custom_field" => "with some value",
|
27
|
+
"kind" => "some_asset",
|
28
|
+
"action" => "some_action",
|
29
|
+
"user" => "account:user:alice",
|
30
|
+
"id" => 12345,
|
31
|
+
"timestamp" => Time.now().to_s,
|
32
|
+
"event_id" => "xaxaxaxaxa",
|
33
|
+
"resources" => ["the-account:layer:resources/production", "layer:resources/frontend"],
|
34
|
+
"roles" => ["the-account:group:roles/qa", "group:roles/ssh_users"]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
shared_examples_for "it supports standard prefix:" do
|
39
|
+
describe "if acting_as is the same as user" do
|
40
|
+
let(:audit_event) { test_event.tap { |e| e["acting_as"]=e["user"] } }
|
41
|
+
it "prints default prefix" do
|
42
|
+
expect { invoke }.to write(common_prefix)
|
43
|
+
end
|
44
|
+
it "does not print 'acting_as' statement" do
|
45
|
+
expect { invoke }.to_not write(common_prefix+" (as ")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "if acting_as is different from user" do
|
50
|
+
it 'prints default prefix followed by (acting as..) statement' do
|
51
|
+
expect { invoke }.to write(common_prefix+" (as #{audit_event['acting_as']})")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
shared_examples_for "it recognizes error messages:" do
|
57
|
+
describe "if :error is not empty" do
|
58
|
+
let(:audit_event) { test_event.merge("error"=>"everything's down") }
|
59
|
+
it 'appends (failed with...) statement' do
|
60
|
+
expect { invoke }.to write(" (failed with everything's down)")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe "if :error is empty" do
|
64
|
+
it 'does not print "failed with" statement' do
|
65
|
+
expect { invoke }.not_to write(" (failed with ")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/conjur/config.rb
CHANGED
@@ -31,7 +31,11 @@ module Conjur
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def default_config_files
|
34
|
-
[ File.join("/etc", "conjur.conf"), ( ENV['CONJURRC'] || File.expand_path("~/.conjurrc")
|
34
|
+
[ File.join("/etc", "conjur.conf"), ( ENV['CONJURRC'] || [ File.expand_path("~/.conjurrc"), '.conjurrc'] ) ].flatten.tap do |f|
|
35
|
+
if f.include?'.conjurrc' and File.file?('.conjurrc') and not ENV['CONJURRC']=='.conjurrc'
|
36
|
+
$stderr.puts "WARNING: .conjurrc file from current directory is used. This behaviour is deprecated. Use ENV['CONJURRC'] to explicitly define custom configuration file if needed"
|
37
|
+
end
|
38
|
+
end
|
35
39
|
end
|
36
40
|
|
37
41
|
def load(config_files = default_config_files)
|
@@ -55,14 +59,14 @@ module Conjur
|
|
55
59
|
require 'conjur/configuration'
|
56
60
|
keys = Config.keys.dup
|
57
61
|
keys.delete(:plugins)
|
58
|
-
|
62
|
+
|
59
63
|
cfg = Conjur.configuration
|
60
64
|
keys.each do |k|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
65
|
+
if Conjur.configuration.respond_to?("#{k}_env_var") && (env_var = Conjur.configuration.send("#{k}_env_var")) && (v = ENV[env_var])
|
66
|
+
if Conjur.log
|
67
|
+
Conjur.log << "Not overriding environment setting #{k}=#{v}\n"
|
68
|
+
end
|
69
|
+
next
|
66
70
|
end
|
67
71
|
value = Config[k]
|
68
72
|
cfg.set k, value if value
|
data/lib/conjur/dsl/runner.rb
CHANGED
@@ -195,7 +195,7 @@ module Conjur
|
|
195
195
|
api.send(create_method, options)
|
196
196
|
end
|
197
197
|
end
|
198
|
-
if annotations.kind_of?
|
198
|
+
if annotations.kind_of?(Hash) && !annotations.blank?
|
199
199
|
# TODO: fix API to make 'annotations' available directly on objects
|
200
200
|
# https://basecamp.com/1949725/projects/4268938-api-version-4-x/todos/84970444-high-support
|
201
201
|
obj_as_resource = obj.resource
|
data/lib/conjur/version.rb
CHANGED
data/spec/authn_spec.rb
CHANGED
@@ -2,6 +2,23 @@ require 'conjur/authn'
|
|
2
2
|
require 'conjur/config'
|
3
3
|
|
4
4
|
describe Conjur::Authn do
|
5
|
+
describe "credentials from environment" do
|
6
|
+
before {
|
7
|
+
Conjur::Authn.instance_variable_set("@credentials", nil)
|
8
|
+
ENV.should_receive(:[]).with("CONJUR_AUTHN_LOGIN").and_return "the-login"
|
9
|
+
ENV.should_receive(:[]).with("CONJUR_AUTHN_API_KEY").and_return "the-api-key"
|
10
|
+
}
|
11
|
+
after {
|
12
|
+
Conjur::Authn.instance_variable_set("@credentials", nil)
|
13
|
+
}
|
14
|
+
it "are used to authn" do
|
15
|
+
Conjur::Authn.get_credentials.should == [ "the-login", "the-api-key" ]
|
16
|
+
end
|
17
|
+
it "are not written to netrc" do
|
18
|
+
Conjur::Authn.stub(:write_credentials).and_raise "should not write credentials"
|
19
|
+
Conjur::Authn.get_credentials
|
20
|
+
end
|
21
|
+
end
|
5
22
|
describe "netrc" do
|
6
23
|
before {
|
7
24
|
Conjur::Authn.instance_variable_set("@netrc", nil)
|
data/spec/command/audit_spec.rb
CHANGED
@@ -80,4 +80,271 @@ describe Conjur::Command::Audit, logged_in: true do
|
|
80
80
|
describe "audit:all" do
|
81
81
|
it_calls_the_api "audit:all", :audit, {}
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
|
+
describe "output formatting:" do
|
85
|
+
include_context "default audit behavior"
|
86
|
+
|
87
|
+
before {
|
88
|
+
api.stub(:audit_event_feed).and_yield([audit_event])
|
89
|
+
}
|
90
|
+
|
91
|
+
describe_command "audit all" do
|
92
|
+
let(:audit_event) { default_audit_event }
|
93
|
+
it 'prints full JSON retrieved from API' do
|
94
|
+
expect { invoke }.to write( JSON.pretty_generate(audit_event) )
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe_command "audit all -s" do
|
99
|
+
let(:common_prefix) { "[#{default_audit_event["timestamp"]}] #{default_audit_event["user"]}" }
|
100
|
+
let(:audit_event) { test_event }
|
101
|
+
shared_examples_for "it supports standard prefix:" do
|
102
|
+
describe "if acting_as is the same as user" do
|
103
|
+
let(:audit_event) { test_event.tap { |e| e["acting_as"]=e["user"] } }
|
104
|
+
it "prints default prefix" do
|
105
|
+
expect { invoke }.to write(common_prefix)
|
106
|
+
end
|
107
|
+
it "does not print 'acting_as' statement" do
|
108
|
+
expect { invoke }.to_not write(common_prefix+" (as ")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "if acting_as is different from user" do
|
113
|
+
it 'prints default prefix followed by (acting as..) statement' do
|
114
|
+
expect { invoke }.to write(common_prefix+" (as #{audit_event['acting_as']})")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
shared_examples_for "it recognizes error messages:" do
|
120
|
+
describe "if :error is not empty" do
|
121
|
+
let(:audit_event) { test_event.merge("error"=>"everything's down") }
|
122
|
+
it 'appends (failed with...) statement' do
|
123
|
+
expect { invoke }.to write(" (failed with everything's down)")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
describe "if :error is empty" do
|
127
|
+
it 'does not print "failed with" statement' do
|
128
|
+
expect { invoke }.not_to write(" (failed with ")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "(unknown kind:action)" do
|
135
|
+
let(:test_event) { default_audit_event }
|
136
|
+
it_behaves_like "it supports standard prefix:"
|
137
|
+
it_behaves_like "it recognizes error messages:"
|
138
|
+
it "prints 'unknown event: <kind>:<action>'" do
|
139
|
+
expect { invoke }.to write(" unknown event: some_asset:some_action!")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "(resource:check)" do
|
144
|
+
let(:test_event) { default_audit_event.merge("kind"=>"resource",
|
145
|
+
"action"=>"check",
|
146
|
+
"privilege"=>"fry",
|
147
|
+
"resource"=>"food:bacon",
|
148
|
+
"allowed" => "false"
|
149
|
+
)
|
150
|
+
}
|
151
|
+
it_behaves_like "it supports standard prefix:"
|
152
|
+
it_behaves_like "it recognizes error messages:"
|
153
|
+
it "prints 'checked that they...'" do
|
154
|
+
expect { invoke }.to write(" checked that they can fry food:bacon (false)")
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "(resource:create)" do
|
160
|
+
let(:test_event) { default_audit_event.merge("kind"=>"resource", "action" => "create",
|
161
|
+
"resource" => "food:bacon",
|
162
|
+
"owner" => "user:cook"
|
163
|
+
)
|
164
|
+
}
|
165
|
+
it_behaves_like "it supports standard prefix:"
|
166
|
+
it_behaves_like "it recognizes error messages:"
|
167
|
+
it "prints 'created resource ... owned by ... '" do
|
168
|
+
expect { invoke }.to write(" created resource food:bacon owned by user:cook")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "(resource:update)" do
|
173
|
+
let(:test_event) { default_audit_event.merge("kind"=>"resource", "action" => "update",
|
174
|
+
"resource" => "food:bacon",
|
175
|
+
"owner" => "user:cook"
|
176
|
+
)
|
177
|
+
}
|
178
|
+
it_behaves_like "it supports standard prefix:"
|
179
|
+
it_behaves_like "it recognizes error messages:"
|
180
|
+
it "prints 'gave .. to .. '" do
|
181
|
+
expect { invoke }.to write(" gave food:bacon to user:cook")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "(resource:destroy)" do
|
186
|
+
let(:test_event) { default_audit_event.merge("kind"=>"resource", "action" => "destroy",
|
187
|
+
"resource" => "food:bacon"
|
188
|
+
)
|
189
|
+
}
|
190
|
+
it_behaves_like "it supports standard prefix:"
|
191
|
+
it_behaves_like "it recognizes error messages:"
|
192
|
+
it "prints 'destroyed resource ... '" do
|
193
|
+
expect { invoke }.to write(" destroyed resource food:bacon")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "(resource:permit)" do
|
198
|
+
let(:test_event) { default_audit_event.merge("kind"=>"resource", "action" => "permit",
|
199
|
+
"resource" => "food:bacon",
|
200
|
+
"privilege" => "fry",
|
201
|
+
"grantee" => "user:cook"
|
202
|
+
)
|
203
|
+
}
|
204
|
+
it_behaves_like "it supports standard prefix:"
|
205
|
+
it_behaves_like "it recognizes error messages:"
|
206
|
+
it "prints 'permitted .. to .. (grant option: .. ) '" do
|
207
|
+
expect { invoke }.to write(" permitted user:cook to fry food:bacon (grant option: false)")
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe "(resource:deny)" do
|
212
|
+
let(:test_event) { default_audit_event.merge("kind"=>"resource", "action" => "deny",
|
213
|
+
"resource" => "food:bacon",
|
214
|
+
"privilege" => "fry",
|
215
|
+
"grantee" => "user:cook"
|
216
|
+
)
|
217
|
+
}
|
218
|
+
it_behaves_like "it supports standard prefix:"
|
219
|
+
it_behaves_like "it recognizes error messages:"
|
220
|
+
it "prints 'denied .. from .. on ..'" do
|
221
|
+
expect { invoke }.to write(" denied fry from user:cook on food:bacon")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "(resource:permitted_roles)" do
|
226
|
+
let(:test_event) { default_audit_event.merge("kind"=>"resource", "action" => "permitted_roles",
|
227
|
+
"resource" => "food:bacon",
|
228
|
+
"privilege" => "fry"
|
229
|
+
)
|
230
|
+
}
|
231
|
+
it_behaves_like "it supports standard prefix:"
|
232
|
+
it_behaves_like "it recognizes error messages:"
|
233
|
+
it "prints 'listed roles permitted to .. on ..'" do
|
234
|
+
expect { invoke }.to write(" listed roles permitted to fry on food:bacon")
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "(role:check)" do
|
239
|
+
let(:options_set) {
|
240
|
+
{
|
241
|
+
"kind"=>"role", "action" => "check",
|
242
|
+
"resource" => "food:bacon",
|
243
|
+
"privilege" => "fry",
|
244
|
+
"allowed" => "false"
|
245
|
+
}
|
246
|
+
}
|
247
|
+
describe 'on themselves' do
|
248
|
+
let(:test_event) { default_audit_event.merge(options_set).merge("role" => default_audit_event["user"]) }
|
249
|
+
it_behaves_like "it supports standard prefix:"
|
250
|
+
it_behaves_like "it recognizes error messages:"
|
251
|
+
it "prints 'checked that they...'" do
|
252
|
+
expect { invoke }.to write(" checked that they can fry food:bacon (false)")
|
253
|
+
end
|
254
|
+
end
|
255
|
+
describe 'on others' do
|
256
|
+
let(:test_event) { default_audit_event.merge(options_set).merge("role" => "some:other:guy") }
|
257
|
+
it_behaves_like "it supports standard prefix:"
|
258
|
+
it_behaves_like "it recognizes error messages:"
|
259
|
+
it "prints 'checked that they...'" do
|
260
|
+
expect { invoke }.to write(" checked that some:other:guy can fry food:bacon (false)")
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe "(role:grant)" do
|
266
|
+
let(:options_set) {
|
267
|
+
{
|
268
|
+
"kind"=>"role", "action" => "grant",
|
269
|
+
"member" => "other:guy",
|
270
|
+
"role" => "super:user"
|
271
|
+
}
|
272
|
+
}
|
273
|
+
describe 'without admin option' do
|
274
|
+
let(:test_event) { default_audit_event.merge(options_set) }
|
275
|
+
it_behaves_like "it supports standard prefix:"
|
276
|
+
it_behaves_like "it recognizes error messages:"
|
277
|
+
it "prints 'granted role .. to .. without admin'" do
|
278
|
+
expect { invoke }.to write(" granted role super:user to other:guy without admin")
|
279
|
+
end
|
280
|
+
end
|
281
|
+
describe 'with admin option' do
|
282
|
+
let(:test_event) { default_audit_event.merge(options_set).merge("admin_option" => true) }
|
283
|
+
it_behaves_like "it supports standard prefix:"
|
284
|
+
it_behaves_like "it recognizes error messages:"
|
285
|
+
it "prints 'granted role .. to .. with admin'" do
|
286
|
+
expect { invoke }.to write(" granted role super:user to other:guy with admin")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe "(role:revoke)" do
|
292
|
+
let(:test_event) { default_audit_event.merge("kind"=>"role", "action" => "revoke",
|
293
|
+
"role" => "super:user",
|
294
|
+
"member" => "other:guy"
|
295
|
+
)
|
296
|
+
}
|
297
|
+
it_behaves_like "it supports standard prefix:"
|
298
|
+
it_behaves_like "it recognizes error messages:"
|
299
|
+
it "prints 'revoked role .. from .." do
|
300
|
+
expect { invoke }.to write(" revoked role super:user from other:guy")
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
describe "(role:create)" do
|
305
|
+
let(:test_event) { default_audit_event.merge("kind"=>"role", "action" => "create",
|
306
|
+
"role" => "super:user",
|
307
|
+
)
|
308
|
+
}
|
309
|
+
it_behaves_like "it supports standard prefix:"
|
310
|
+
it_behaves_like "it recognizes error messages:"
|
311
|
+
it "prints 'created role .. " do
|
312
|
+
expect { invoke }.to write(" created role super:user")
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
describe "limit and offset" do
|
319
|
+
let(:events) { (1 .. 5).map { |x| { event: x } } }
|
320
|
+
before {
|
321
|
+
api.stub(:audit_event_feed).and_yield(events)
|
322
|
+
}
|
323
|
+
|
324
|
+
describe_command "audit all" do
|
325
|
+
it "prints all the elements" do
|
326
|
+
(expect { invoke }.to write).should == events.map {|e| JSON.pretty_generate(e)}.join("\n")+"\n"
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe_command "audit all -l 2" do
|
331
|
+
it "prints only <limit> elements" do
|
332
|
+
(expect { invoke }.to write).should == events[0..1].map {|e| JSON.pretty_generate(e)}.join("\n")+"\n"
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
describe_command "audit all -o 2" do
|
337
|
+
it "skips <offset> elements" do
|
338
|
+
(expect { invoke }.to write).should == events[2..4].map {|e| JSON.pretty_generate(e)}.join("\n")+"\n"
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
describe_command "audit all -o 2 -l 2" do
|
343
|
+
it "skips <offset> elements and prints only <limit> of remaining part" do
|
344
|
+
(expect { invoke }.to write).should == events[2..3].map {|e| JSON.pretty_generate(e)}.join("\n")+"\n"
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
data/spec/command/init_spec.rb
CHANGED
@@ -83,20 +83,21 @@ describe Conjur::Command::Init do
|
|
83
83
|
expect { invoke }.to raise_error(GLI::CustomExit, /unable to retrieve certificate/i)
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
86
|
+
# KEG: These tests have a nasty habit of hanging
|
87
|
+
# describe_command 'init -a the-account -h google.com' do
|
88
|
+
# it "writes the config and cert" do
|
89
|
+
# HighLine.any_instance.stub(:ask).and_return "yes"
|
90
|
+
# File.should_receive(:open).twice
|
91
|
+
# invoke
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
# describe_command 'init -a the-account -h https://google.com' do
|
95
|
+
# it "writes the config and cert" do
|
96
|
+
# HighLine.any_instance.stub(:ask).and_return "yes"
|
97
|
+
# File.should_receive(:open).twice
|
98
|
+
# invoke
|
99
|
+
# end
|
100
|
+
# end
|
100
101
|
describe_command 'init -a the-account -h localhost -c the-cert' do
|
101
102
|
it "writes config and cert files" do
|
102
103
|
File.should_receive(:open).twice
|
@@ -111,7 +112,8 @@ describe Conjur::Command::Init do
|
|
111
112
|
expect(YAML.load(File.read(File.join(tmpdir, ".conjurrc")))).to eq({
|
112
113
|
account: 'the-account',
|
113
114
|
appliance_url: "https://localhost/api",
|
114
|
-
cert_file: "#{tmpdir}/conjur-the-account.pem"
|
115
|
+
cert_file: "#{tmpdir}/conjur-the-account.pem",
|
116
|
+
plugins: [],
|
115
117
|
}.stringify_keys)
|
116
118
|
|
117
119
|
File.read(File.join(tmpdir, "conjur-the-account.pem")).should == "the-cert\n"
|
data/spec/config_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'conjur/authn'
|
2
2
|
require 'conjur/config'
|
3
|
+
require 'conjur/command/rspec/output_matchers'
|
3
4
|
|
4
5
|
describe Conjur::Config do
|
5
6
|
after {
|
@@ -15,6 +16,7 @@ describe Conjur::Config do
|
|
15
16
|
ENV['HOME'] = realhome
|
16
17
|
end
|
17
18
|
|
19
|
+
let(:deprecation_warning) { "WARNING: .conjurrc file from current directory is used. This behaviour is deprecated. Use ENV['CONJURRC'] to explicitly define custom configuration file if needed" }
|
18
20
|
context "when CONJURRC is not set" do
|
19
21
|
around do |example|
|
20
22
|
oldrc = ENV.delete 'CONJURRC'
|
@@ -22,7 +24,53 @@ describe Conjur::Config do
|
|
22
24
|
ENV['CONJURRC'] = oldrc
|
23
25
|
end
|
24
26
|
|
27
|
+
it { should include('/etc/conjur.conf') }
|
25
28
|
it { should include('/home/isfake/.conjurrc') }
|
29
|
+
it { should include('.conjurrc') }
|
30
|
+
context "When .conjurrc is present" do
|
31
|
+
before { File.stub(:file?).with('.conjurrc').and_return true }
|
32
|
+
it "Issues a deprecation warning" do
|
33
|
+
expect { subject }.to write(deprecation_warning).to(:stderr)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
context "When .conjurrc is missing" do
|
37
|
+
before { File.stub(:file?).with('.conjurrc').and_return false }
|
38
|
+
it "Does not issue a deprecation warning" do
|
39
|
+
expect { subject }.to_not write(deprecation_warning).to(:stderr)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when CONJURRC is set" do
|
45
|
+
around do |example|
|
46
|
+
oldrc = ENV['CONJURRC']
|
47
|
+
ENV['CONJURRC']='stub_conjurrc'
|
48
|
+
example.run
|
49
|
+
ENV['CONJURRC'] = oldrc
|
50
|
+
end
|
51
|
+
it { should include('/etc/conjur.conf') }
|
52
|
+
it { should include('stub_conjurrc') }
|
53
|
+
it { should_not include('/home/isfake/.conjurrc') }
|
54
|
+
it { should_not include('.conjurrc') }
|
55
|
+
it "Does not issue a deprecation warning" do
|
56
|
+
expect { subject }.to_not write(deprecation_warning).to(:stderr)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when CONJURRC is set to .conjurrc" do
|
61
|
+
around do |example|
|
62
|
+
oldrc = ENV['CONJURRC']
|
63
|
+
ENV['CONJURRC']='.conjurrc'
|
64
|
+
example.run
|
65
|
+
ENV['CONJURRC'] = oldrc
|
66
|
+
end
|
67
|
+
before { File.stub(:file?).with('.conjurrc').and_return true }
|
68
|
+
it { should include('/etc/conjur.conf') }
|
69
|
+
it { should include('.conjurrc') }
|
70
|
+
it { should_not include('/home/isfake/.conjurrc') }
|
71
|
+
it "Does not issue a deprecation warning" do
|
72
|
+
expect { subject }.to_not write(deprecation_warning).to(:stderr)
|
73
|
+
end
|
26
74
|
end
|
27
75
|
end
|
28
76
|
|
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.
|
4
|
+
version: 4.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafał Rzepecki
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-08-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 4.9.
|
34
|
+
version: 4.9.2
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - '>='
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 4.9.
|
41
|
+
version: 4.9.2
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: gli
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -255,6 +255,7 @@ files:
|
|
255
255
|
- lib/conjur/command/pubkeys.rb
|
256
256
|
- lib/conjur/command/resources.rb
|
257
257
|
- lib/conjur/command/roles.rb
|
258
|
+
- lib/conjur/command/rspec/audit_helpers.rb
|
258
259
|
- lib/conjur/command/rspec/describe_command.rb
|
259
260
|
- lib/conjur/command/rspec/helpers.rb
|
260
261
|
- lib/conjur/command/rspec/mock_services.rb
|