vault_api 1.0.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 +7 -0
- data/CHANGELOG +9 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +124 -0
- data/LICENSE.txt +23 -0
- data/README.md +226 -0
- data/Rakefile +16 -0
- data/bin/vault_conf +43 -0
- data/lib/vault_api/api.rb +29 -0
- data/lib/vault_api/client/entries.rb +129 -0
- data/lib/vault_api/client/paths.rb +19 -0
- data/lib/vault_api/client/policies.rb +75 -0
- data/lib/vault_api/client/secrets.rb +43 -0
- data/lib/vault_api/client/users.rb +66 -0
- data/lib/vault_api/client.rb +16 -0
- data/lib/vault_api/configuration.rb +45 -0
- data/lib/vault_api/connection.rb +18 -0
- data/lib/vault_api/error.rb +48 -0
- data/lib/vault_api/request.rb +65 -0
- data/lib/vault_api/version.rb +5 -0
- data/lib/vault_api.rb +57 -0
- data/vault_api.gemspec +63 -0
- metadata +319 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# VaultApi::Client::Policies
|
|
4
|
+
module VaultApi
|
|
5
|
+
class Client
|
|
6
|
+
module Policies
|
|
7
|
+
def create_initial_user_policy(username)
|
|
8
|
+
puts "Creating #{username}_policy"
|
|
9
|
+
if VaultApi.put_policy("#{username}_policy", policy_json(username))
|
|
10
|
+
puts "Created #{username}_policy"
|
|
11
|
+
true
|
|
12
|
+
else
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def read_policy(username)
|
|
18
|
+
VaultApi.policy("#{username}_policy")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_policy(username, path = '', capabilities = [])
|
|
22
|
+
policy_rules = {}
|
|
23
|
+
policy_rules[:path] ||= {}
|
|
24
|
+
policy_rules[:path][path.to_s] ||= {}
|
|
25
|
+
policy_rules[:path][path.to_s][:capabilities] = capabilities
|
|
26
|
+
VaultApi.put_policy("#{username}_policy", policy_rules.to_json)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update_policy(username, path = '', capabilities = [])
|
|
30
|
+
policy = VaultApi.policy("#{username}_policy")
|
|
31
|
+
policy_rules = JSON.parse(policy.rules).with_indifferent_access
|
|
32
|
+
policy_rules[:path][path.to_s] ||= {}
|
|
33
|
+
policy_rules[:path][path.to_s][:capabilities] = capabilities
|
|
34
|
+
VaultApi.put_policy("#{username}_policy", policy_rules.to_json)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def delete_policy(username)
|
|
38
|
+
VaultApi.delete_policy("#{username}_policy")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def policy_json(username)
|
|
44
|
+
{
|
|
45
|
+
path: {
|
|
46
|
+
"secret/#{VaultApi.env}/#{username}/*" => {
|
|
47
|
+
capabilities: %w[create read update delete list]
|
|
48
|
+
},
|
|
49
|
+
"#{VaultApi.secret_global_base_path}/*" => {
|
|
50
|
+
capabilities: %w[read list]
|
|
51
|
+
},
|
|
52
|
+
:'secret/*' => {
|
|
53
|
+
capabilities: %w[read list]
|
|
54
|
+
},
|
|
55
|
+
:'auth/token/lookup-self' => {
|
|
56
|
+
capabilities: %w[read]
|
|
57
|
+
},
|
|
58
|
+
:'sys/capabilities-self' => {
|
|
59
|
+
capabilities: %w[update read]
|
|
60
|
+
},
|
|
61
|
+
:'sys/mounts' => {
|
|
62
|
+
capabilities: %w[read]
|
|
63
|
+
},
|
|
64
|
+
:'sys/auth' => {
|
|
65
|
+
capabilities: %w[read]
|
|
66
|
+
},
|
|
67
|
+
"sys/policy/#{username}_policy" => {
|
|
68
|
+
capabilities: %w[read]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}.to_json
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
# VaultApi::Client::Secrets
|
|
6
|
+
module VaultApi
|
|
7
|
+
class Client
|
|
8
|
+
module Secrets
|
|
9
|
+
def secrets(user_name = nil)
|
|
10
|
+
VaultApi.list(VaultApi.secret_base_path(user_name))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def read_secret(config_name, user_name = nil)
|
|
14
|
+
VaultApi.read("#{VaultApi.secret_base_path(user_name)}/#{config_name}").data
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add_secret(config_file_path, user_name = nil)
|
|
18
|
+
file_basename = File.basename(config_file_path, '.yml')
|
|
19
|
+
secret_path = "#{VaultApi.secret_base_path(user_name)}/#{file_basename}"
|
|
20
|
+
|
|
21
|
+
output_json = JSON.dump(YAML.load_file(config_file_path))
|
|
22
|
+
obj = JSON.parse(output_json)
|
|
23
|
+
content = obj[VaultApi.env.to_s]
|
|
24
|
+
VaultApi.write(secret_path, content)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def update_secret(config_file_path, user_name = nil)
|
|
28
|
+
add_secret(config_file_path, user_name) # overwrites existing file
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def upload_secrets(config_folder_path, user_name = nil)
|
|
32
|
+
Dir.chdir config_folder_path
|
|
33
|
+
Dir.glob('*.yml').each do |file|
|
|
34
|
+
add_secret("#{config_folder_path}/#{file}", user_name)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def delete_secret(config_name, user_name = nil)
|
|
39
|
+
VaultApi.delete("#{VaultApi.secret_base_path(user_name)}/#{config_name}")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/https'
|
|
4
|
+
require 'uri'
|
|
5
|
+
require 'securerandom'
|
|
6
|
+
|
|
7
|
+
# VaultApi::Client::Users
|
|
8
|
+
module VaultApi
|
|
9
|
+
class Client
|
|
10
|
+
module Users
|
|
11
|
+
def create_user(username)
|
|
12
|
+
secure_password = SecureRandom.hex(12)
|
|
13
|
+
|
|
14
|
+
creds = {
|
|
15
|
+
'password' => secure_password.to_s,
|
|
16
|
+
'policies' => "#{username}_policy"
|
|
17
|
+
}
|
|
18
|
+
uri = URI.parse("#{VaultApi.address}/v1/#{VaultApi.auth_users_path}/#{username}")
|
|
19
|
+
|
|
20
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
21
|
+
http.use_ssl = true
|
|
22
|
+
|
|
23
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
|
24
|
+
request.body = creds.to_json
|
|
25
|
+
request['X-Vault-Token'] = VaultApi.token.to_s
|
|
26
|
+
|
|
27
|
+
http.request(request)
|
|
28
|
+
|
|
29
|
+
creds
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def create_user_with_secret(username)
|
|
33
|
+
users = VaultApi.list(VaultApi.auth_users_path)
|
|
34
|
+
|
|
35
|
+
if users.include? username.to_s
|
|
36
|
+
puts "Vault user '#{username}' already exists."
|
|
37
|
+
# exit 1
|
|
38
|
+
else
|
|
39
|
+
create_initial_user_policy(username)
|
|
40
|
+
creds = create_user(username)
|
|
41
|
+
add_secrets_to_user_from_global(username)
|
|
42
|
+
|
|
43
|
+
creds
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def add_secrets_to_user_from_global(username)
|
|
48
|
+
global_path = VaultApi.secret_global_base_path
|
|
49
|
+
secrets = VaultApi.list(global_path)
|
|
50
|
+
|
|
51
|
+
secrets.each do |filename|
|
|
52
|
+
path_admin = "#{global_path}/#{filename}"
|
|
53
|
+
data = VaultApi.read(path_admin).data
|
|
54
|
+
user_path = "secret/#{VaultApi.env}/#{username}/#{filename}"
|
|
55
|
+
VaultApi.write(user_path, data)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def delete_user(username)
|
|
60
|
+
VaultApi.delete("/#{VaultApi.auth_users_path}/#{username}")
|
|
61
|
+
delete_policy(username)
|
|
62
|
+
delete_path(VaultApi.secret_user_base_path(username))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path('api', __dir__)
|
|
4
|
+
|
|
5
|
+
module VaultApi
|
|
6
|
+
# Wrapper for the VaultApi REST API.
|
|
7
|
+
class Client < API
|
|
8
|
+
Dir[File.expand_path('client/*.rb', __dir__)].each { |f| require f }
|
|
9
|
+
|
|
10
|
+
include VaultApi::Client::Paths
|
|
11
|
+
include VaultApi::Client::Users
|
|
12
|
+
include VaultApi::Client::Entries
|
|
13
|
+
include VaultApi::Client::Secrets
|
|
14
|
+
include VaultApi::Client::Policies
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module VaultApi
|
|
4
|
+
module Configuration
|
|
5
|
+
VALID_OPTIONS_KEYS = %i[
|
|
6
|
+
address
|
|
7
|
+
token
|
|
8
|
+
user
|
|
9
|
+
password
|
|
10
|
+
env
|
|
11
|
+
|
|
12
|
+
logger
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
# Use the default Faraday adapter.
|
|
16
|
+
# DEFAULT_ADAPTER = Faraday.default_adapter
|
|
17
|
+
|
|
18
|
+
# By default use the main api URL.
|
|
19
|
+
DEFAULT_ADDRESS = ''
|
|
20
|
+
|
|
21
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
|
22
|
+
|
|
23
|
+
# Convenience method to allow configuration options to be set in a block
|
|
24
|
+
def configure
|
|
25
|
+
yield self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def options
|
|
29
|
+
VALID_OPTIONS_KEYS.each_with_object({}) do |key, option|
|
|
30
|
+
option[key] = send(key)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# When this module is extended, reset all settings.
|
|
35
|
+
def self.extended(base)
|
|
36
|
+
base.reset
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Reset all configuration settings to default values.
|
|
40
|
+
def reset
|
|
41
|
+
self.address = DEFAULT_ADDRESS
|
|
42
|
+
# self.adapter = DEFAULT_ADAPTER
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'vault'
|
|
4
|
+
module VaultApi
|
|
5
|
+
module Connection
|
|
6
|
+
# private
|
|
7
|
+
|
|
8
|
+
def connection
|
|
9
|
+
if token
|
|
10
|
+
connection_obj = Vault::Client.new(address: address, token: token)
|
|
11
|
+
else
|
|
12
|
+
connection_obj = Vault::Client.new(address: address)
|
|
13
|
+
connection_obj.auth.userpass(user, password)
|
|
14
|
+
end
|
|
15
|
+
connection_obj
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module VaultApi
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
def initialize(e)
|
|
6
|
+
@wrapped_exception = nil
|
|
7
|
+
|
|
8
|
+
if e.respond_to?(:backtrace)
|
|
9
|
+
super(e.message)
|
|
10
|
+
@wrapped_exception = e
|
|
11
|
+
else
|
|
12
|
+
super(e.to_s)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def backtrace
|
|
17
|
+
if @wrapped_exception
|
|
18
|
+
@wrapped_exception.backtrace
|
|
19
|
+
else
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def inspect
|
|
25
|
+
inner = ''
|
|
26
|
+
inner << " wrapped=#{@wrapped_exception.inspect}" if @wrapped_exception
|
|
27
|
+
inner << " #{super}" if inner.empty?
|
|
28
|
+
%(#<#{self.class}#{inner}>)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class ConnectionError < Error; end
|
|
33
|
+
class AuthorizationError < Error; end
|
|
34
|
+
class BadRequestError < Error; end
|
|
35
|
+
class RecordNotFoundError < Error; end
|
|
36
|
+
|
|
37
|
+
class TimeoutError < Error; end
|
|
38
|
+
class NotFoundError < Error; end
|
|
39
|
+
class SSLError < Error; end
|
|
40
|
+
class ParseError < Error; end
|
|
41
|
+
class UnauthorizedError < Error; end
|
|
42
|
+
|
|
43
|
+
%i[Error
|
|
44
|
+
ConnectionError AuthorizationError BadRequestError RecordNotFoundError
|
|
45
|
+
TimeoutError NotFoundError SSLError ParseError UnauthorizedError].each do |const|
|
|
46
|
+
Error.const_set(const, VaultApi.const_get(const))
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module VaultApi
|
|
4
|
+
module Request
|
|
5
|
+
def list(params)
|
|
6
|
+
request(:list, params)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def read(params)
|
|
10
|
+
request(:read, params)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def write(path, config)
|
|
14
|
+
request(:write, path, config)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def delete(params)
|
|
18
|
+
request(:delete, params)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def policy(params)
|
|
22
|
+
request_sys(:policy, params)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def put_policy(params, rules)
|
|
26
|
+
request_sys(:put_policy, params, rules)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def delete_policy(params)
|
|
30
|
+
request_sys(:delete_policy, params)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def request(method, *params)
|
|
36
|
+
begin
|
|
37
|
+
response = case method
|
|
38
|
+
when :write
|
|
39
|
+
connection.logical.send(method, params[0], params[1])
|
|
40
|
+
else
|
|
41
|
+
connection.logical.send(method, params[0])
|
|
42
|
+
end
|
|
43
|
+
rescue StandardError => e
|
|
44
|
+
raise Error, e
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
response
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def request_sys(method, *params)
|
|
51
|
+
begin
|
|
52
|
+
response = case method
|
|
53
|
+
when :put_policy
|
|
54
|
+
connection.sys.send(method, params[0], params[1])
|
|
55
|
+
else
|
|
56
|
+
connection.sys.send(method, params[0])
|
|
57
|
+
end
|
|
58
|
+
rescue StandardError => e
|
|
59
|
+
raise Error, e
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
response
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/vault_api.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pry'
|
|
4
|
+
require 'active_support/all'
|
|
5
|
+
|
|
6
|
+
require 'vault_api/api'
|
|
7
|
+
require 'vault_api/client'
|
|
8
|
+
require 'vault_api/version'
|
|
9
|
+
|
|
10
|
+
require File.expand_path('vault_api/configuration', __dir__)
|
|
11
|
+
require File.expand_path('vault_api/api', __dir__)
|
|
12
|
+
require File.expand_path('vault_api/client', __dir__)
|
|
13
|
+
require File.expand_path('vault_api/error', __dir__)
|
|
14
|
+
|
|
15
|
+
module VaultApi
|
|
16
|
+
extend Configuration
|
|
17
|
+
# Alias for VaultApi::Client.new
|
|
18
|
+
# @return [VaultApi::Client]
|
|
19
|
+
def self.client(options = {})
|
|
20
|
+
VaultApi::Client.new(options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Delegate to VaultApi::Client
|
|
24
|
+
def self.method_missing(method, *args, &block)
|
|
25
|
+
return super unless client.respond_to?(method)
|
|
26
|
+
|
|
27
|
+
client.send(method, *args, &block)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.secret_base_path(user_name = nil)
|
|
31
|
+
if user_name.present?
|
|
32
|
+
secret_user_base_path(user_name)
|
|
33
|
+
elsif VaultApi.user.present? # && VaultApi.password.present?
|
|
34
|
+
secret_user_base_path
|
|
35
|
+
elsif VaultApi.token.present?
|
|
36
|
+
secret_global_base_path
|
|
37
|
+
else
|
|
38
|
+
''
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.secret_global_base_path
|
|
43
|
+
"secret/global/#{VaultApi.env}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.secret_user_base_path(user_name = nil)
|
|
47
|
+
if user_name.present?
|
|
48
|
+
"secret/#{VaultApi.env}/#{user_name}"
|
|
49
|
+
else
|
|
50
|
+
"secret/#{VaultApi.env}/#{VaultApi.user}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.auth_users_path
|
|
55
|
+
'auth/userpass/users'
|
|
56
|
+
end
|
|
57
|
+
end
|
data/vault_api.gemspec
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
require 'vault_api/version'
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = 'vault_api'
|
|
9
|
+
spec.version = VaultApi::VERSION
|
|
10
|
+
spec.authors = ['Sachin S Wagh']
|
|
11
|
+
spec.email = ['sachinwagh2392@gmail.com']
|
|
12
|
+
|
|
13
|
+
spec.summary = 'Client for the vault_api API'
|
|
14
|
+
spec.description = 'Client for the vault_api API'
|
|
15
|
+
spec.homepage = ''
|
|
16
|
+
spec.license = 'MIT'
|
|
17
|
+
|
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
|
20
|
+
if spec.respond_to?(:metadata)
|
|
21
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
22
|
+
else
|
|
23
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
|
24
|
+
'public gem pushes.'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
28
|
+
f.match(%r{^(test|spec|features)/})
|
|
29
|
+
end
|
|
30
|
+
# spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
31
|
+
|
|
32
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
33
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
34
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
35
|
+
spec.require_paths = ['lib']
|
|
36
|
+
|
|
37
|
+
spec.add_development_dependency 'bundler'
|
|
38
|
+
spec.add_development_dependency 'byebug'
|
|
39
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
40
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
41
|
+
spec.add_development_dependency 'rspec-expectations'
|
|
42
|
+
spec.add_development_dependency 'rspec-mocks'
|
|
43
|
+
spec.add_development_dependency 'rspec_junit_formatter'
|
|
44
|
+
|
|
45
|
+
###
|
|
46
|
+
spec.add_development_dependency 'awesome_print'
|
|
47
|
+
spec.add_development_dependency 'pry'
|
|
48
|
+
spec.add_development_dependency 'rubocop'
|
|
49
|
+
spec.add_development_dependency 'rubocop-rspec'
|
|
50
|
+
|
|
51
|
+
spec.add_runtime_dependency 'activesupport'
|
|
52
|
+
# spec.add_runtime_dependency 'faraday'
|
|
53
|
+
# spec.add_runtime_dependency 'faraday_middleware'
|
|
54
|
+
spec.add_runtime_dependency 'hashie'
|
|
55
|
+
spec.add_runtime_dependency 'nokogiri'
|
|
56
|
+
# spec.add_runtime_dependency 'vcr'
|
|
57
|
+
spec.add_runtime_dependency 'rest-client'
|
|
58
|
+
spec.add_runtime_dependency 'vcr', '3.0'
|
|
59
|
+
###
|
|
60
|
+
|
|
61
|
+
spec.add_runtime_dependency('vault')
|
|
62
|
+
spec.add_runtime_dependency('webmock')
|
|
63
|
+
end
|