conjur-cli 4.10.3 → 4.12.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 +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
|