parameterstore_databag_wrapper 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +93 -0
- data/lib/amplify/encrypted_data_bag_item.rb +14 -0
- data/lib/amplify/encrypted_database_info.rb +21 -0
- data/lib/amplify/parameter_store_client.rb +78 -0
- data/lib/amplify/vault_data_bag_wrapper_base.rb +80 -0
- data/lib/parameterstore_databag_wrapper.rb +4 -0
- metadata +176 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 672727279e9753a52f2d2b5c5e007705aae58922
|
4
|
+
data.tar.gz: b76b801a5a47e61d47eab758795237a3fd48b10d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 63fd147bce8d7be7aff1f9d6bc163fc93caf5edc81f0883af2971d8ec135a23ed1e2bda9e1b7fb6c9348acb01eb78cf9db820d805bcfd9a6b34c29a39360429c
|
7
|
+
data.tar.gz: f0cb09b046a150b8ac82aafbe0dcacdc1c6eabf8fee5c86867a934c2d885d1530cd4c481d14e13b834b172ee7e2ec3d1fb0c18727d2755323d45508f35a4d70d
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright 2018 Amplify Education, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
parameterstore_databag_wrapper
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Usage
|
5
|
+
-----
|
6
|
+
Provides wrapper for Chef's EncryptedDataBagItem that adds support for reading secrets from ParameterStore and simplifies the obtainment of database secrets. This would be used with Chef Cookbooks to provide sensitive credentials and data to deployed nodes using ParameterStore as the source for the secrets.
|
7
|
+
|
8
|
+
Libraries
|
9
|
+
----
|
10
|
+
### Amplify::EncryptedDataBagItem
|
11
|
+
|
12
|
+
Read from Databags from either Chef or ParameterStore using the Amplify::EncryptedDataBagItem class. During local testing these values will be stored in an encrypted chef databag under `test/chef/data_bags/<data_bag_name>/local.json`. During deployment to a real environment, these values are stored in ParameterStore.
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
data_bag = Amplify::EncryptedDataBagItem.load('data_bag_name', 'environment_name')
|
16
|
+
some_value = data_bag[:some_value]
|
17
|
+
some_other_value = data_bag[:some_other_value]
|
18
|
+
```
|
19
|
+
|
20
|
+
### Amplify::EncryptedDatabaseInfo
|
21
|
+
Read database credentials and hostname information using the Amplify::EncryptedDatabaseInfo class. During local testing these values will be stored in an encrypted chef databag under `test/chef/data_bags/<database_name>/local.json`. During deployment these values are stored in ParameterStore.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
dbinfo = Amplify::EncryptedDatabaseInfo.load('some_db_name', 'environment_name')
|
25
|
+
host = dbinfo[:host]
|
26
|
+
user = dbinfo[:user]
|
27
|
+
password = dbinfo[:password]
|
28
|
+
```
|
29
|
+
|
30
|
+
parameterstore_databag_wrapper
|
31
|
+
============
|
32
|
+
|
33
|
+
Provides wrapper for EncryptedDataBagItem which adds support for reading secrets from ParameterStore and simplifies the obtainment of database secrets.
|
34
|
+
|
35
|
+
About Amplify
|
36
|
+
=============
|
37
|
+
|
38
|
+
Amplify builds innovative and compelling digital educational products that empower teachers and students across the country. We have a long history as the leading innovator in K-12 education - and have been described as the best tech company in education and the best education company in tech. While others try to shrink the learning experience into the technology, we use technology to expand what is possible in real classrooms with real students and teachers.
|
39
|
+
|
40
|
+
Learn more at https://www.amplify.com
|
41
|
+
|
42
|
+
Getting Started
|
43
|
+
===============
|
44
|
+
|
45
|
+
Prerequisites
|
46
|
+
-------------
|
47
|
+
|
48
|
+
* Ruby >= 2.2.3
|
49
|
+
* gems
|
50
|
+
* Runtime
|
51
|
+
* aws-sdk ~> 3.0
|
52
|
+
* chef ~> 12.0
|
53
|
+
* chef-zero ~> 5.3
|
54
|
+
* hashie ~> 3.5
|
55
|
+
* Testing
|
56
|
+
* aws-sdk ~> 3.0
|
57
|
+
* chef ~> 12.0
|
58
|
+
* chefspec ~> 7.1
|
59
|
+
* chef-zero ~> 5.3
|
60
|
+
* hashie ~> 3.5
|
61
|
+
* rake ~> 12.3
|
62
|
+
* rubocop ~> 0.54
|
63
|
+
* rspec ~> 3.7
|
64
|
+
* webmock ~> 3.3
|
65
|
+
* bundler
|
66
|
+
|
67
|
+
Installing/Building
|
68
|
+
----------
|
69
|
+
|
70
|
+
Install all dependencies using `bundle install`.
|
71
|
+
|
72
|
+
An installable packaged gem can be created if the following command is ran inside the repo's directory:
|
73
|
+
`gem build parameterstore_databag_wrapper.gemspec`
|
74
|
+
|
75
|
+
Running Tests
|
76
|
+
-------------
|
77
|
+
|
78
|
+
Using bundler, run `bundle exec rake test` to start all test suites.
|
79
|
+
|
80
|
+
Responsible Disclosure
|
81
|
+
======================
|
82
|
+
|
83
|
+
If you have any security issue to report, contact project maintainers privately.
|
84
|
+
You can reach us at <github@amplify.com>
|
85
|
+
|
86
|
+
Contributing
|
87
|
+
============
|
88
|
+
|
89
|
+
We welcome pull requests! For your pull request to be accepted smoothly, we suggest that you:
|
90
|
+
|
91
|
+
1. For any sizable change, first open a GitHub issue to discuss your idea.
|
92
|
+
2. Create a pull request. Explain why you want to make the change and what it’s for.
|
93
|
+
We’ll try to answer any PR’s promptly.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'amplify/vault_data_bag_wrapper_base'
|
2
|
+
|
3
|
+
module Amplify
|
4
|
+
module VaultSecrets
|
5
|
+
def self.read_from_vault(app_name, env)
|
6
|
+
EncryptedDataBagItem.load(app_name, env)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class EncryptedDataBagItem < VaultDataBagWrapperBase
|
10
|
+
def self.vault_path(app_name, env)
|
11
|
+
"secret/#{env}/databags/#{app_name}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Amplify
|
2
|
+
require 'amplify/vault_data_bag_wrapper_base'
|
3
|
+
|
4
|
+
class EncryptedDatabaseInfo < Amplify::VaultDataBagWrapperBase
|
5
|
+
def self.vault_path(db_name, env)
|
6
|
+
"secret/#{env}/dbs/standard/#{db_name}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.jdbc_url(db_name, env)
|
10
|
+
db_info = load(db_name, env)
|
11
|
+
|
12
|
+
db_username = db_info['user']
|
13
|
+
db_password = db_info['password']
|
14
|
+
db_host = db_info['host']
|
15
|
+
db_port = db_info['port']
|
16
|
+
db_name = db_info['database']
|
17
|
+
db_scheme = db_info['scheme']
|
18
|
+
"jdbc:#{db_scheme}://#{db_username}:#{db_password}@#{db_host}:#{db_port}/#{db_name}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
module Amplify
|
4
|
+
module ParameterStoreClient
|
5
|
+
@aws_region = 'us-east-1'
|
6
|
+
|
7
|
+
def self.aws_region=(val)
|
8
|
+
::Chef::Log.info "Setting aws_region to #{val}"
|
9
|
+
@aws_region = val
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.client
|
13
|
+
require 'aws-sdk'
|
14
|
+
Aws::SSM::Client.new(region: @aws_region)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.deep_merge(result, value)
|
18
|
+
result = result.merge(value) do |_key, oldval, newval|
|
19
|
+
if oldval.respond_to?(:merge) && newval.respond_to?(:merge)
|
20
|
+
deep_merge(oldval, newval)
|
21
|
+
else
|
22
|
+
newval
|
23
|
+
end
|
24
|
+
end
|
25
|
+
::Hashie::Mash.new(result)
|
26
|
+
end
|
27
|
+
|
28
|
+
# rubocop:disable Metrics/MethodLength
|
29
|
+
# rubocop:disable Lint/Loop
|
30
|
+
def self.get_parameters_by_path(prefix_path)
|
31
|
+
next_token = nil
|
32
|
+
result = []
|
33
|
+
|
34
|
+
begin
|
35
|
+
api_result = client.get_parameters_by_path(
|
36
|
+
path: prefix_path,
|
37
|
+
recursive: true,
|
38
|
+
max_results: 10,
|
39
|
+
next_token: next_token,
|
40
|
+
with_decryption: true
|
41
|
+
)
|
42
|
+
next_token = api_result.next_token
|
43
|
+
result = result.concat api_result.parameters
|
44
|
+
end until next_token.nil?
|
45
|
+
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
# rubocop:enable Metrics/MethodLength
|
50
|
+
# rubocop:enable Lint/Loop
|
51
|
+
def self.read(path)
|
52
|
+
prefix_path = "/#{path}"
|
53
|
+
result = get_parameters_by_path(prefix_path)
|
54
|
+
.reduce({}) { |aggregate, param| reduce_parameters(aggregate, param, prefix_path) }
|
55
|
+
|
56
|
+
result.empty? ? nil : result
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.reduce_parameters(result, parameter, prefix_path)
|
60
|
+
sub_path = remove_prefix(prefix_path, parameter.name)
|
61
|
+
name_parts = sub_path.split '/'
|
62
|
+
|
63
|
+
value = name_parts.reverse.reduce(parameter.value) do |leaf, root|
|
64
|
+
::Hashie::Mash.new(root => leaf)
|
65
|
+
end
|
66
|
+
|
67
|
+
deep_merge(result, value)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.remove_prefix(prefix_path, parameter_name)
|
71
|
+
# prefix_path = '/secret/<env>/databags'
|
72
|
+
# parameter_name = '/secret/<env>/databags/<app>/<name>'
|
73
|
+
first_index = prefix_path.length + 1 # add /
|
74
|
+
last_index = parameter_name.length - 1
|
75
|
+
parameter_name[first_index..last_index]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Amplify
|
2
|
+
class VaultDataBagWrapperBase
|
3
|
+
ALLOWED_STRATEGIES ||= [:app_name, :env, :parameter_store, :vault].freeze
|
4
|
+
@strategy = :app_name
|
5
|
+
attr_reader :strategy
|
6
|
+
|
7
|
+
def self.strategy=(val)
|
8
|
+
msg = "Data bag strategy #{val} is not valid. Valid strategies are #{ALLOWED_STRATEGIES}"
|
9
|
+
raise msg unless ALLOWED_STRATEGIES.include?(val)
|
10
|
+
::Chef::Log.info "Setting strategy to #{val}"
|
11
|
+
@strategy = val
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load(app_name, env)
|
15
|
+
::Chef::Log.info "Retrieving secrets using #{@strategy} strategy"
|
16
|
+
if @strategy == :vault
|
17
|
+
read_from_vault(app_name, env)
|
18
|
+
elsif @strategy == :env
|
19
|
+
chef_databag_load(env, app_name)
|
20
|
+
elsif @strategy == :parameter_store
|
21
|
+
read_from_parameter_store(app_name, env)
|
22
|
+
else
|
23
|
+
chef_databag_load(app_name, env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.chef_databag_load(name, item)
|
28
|
+
require 'hashie'
|
29
|
+
::Hashie::Mash.new(::Chef::EncryptedDataBagItem.load(name, item).to_hash)
|
30
|
+
rescue ::Net::HTTPServerException => e
|
31
|
+
::Chef::Log.error e
|
32
|
+
raise MissingDatabag, name: name, item: item
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.vault_path(_app_name, _env)
|
36
|
+
raise NotExtendedCorrectly, 'vault_path was not overriden.'
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.read_from_parameter_store(app_name, env)
|
40
|
+
path = vault_path(app_name, env)
|
41
|
+
secrets = Amplify::ParameterStoreClient.read(path)
|
42
|
+
raise SecretMissingError.new(path, env) if secrets.nil?
|
43
|
+
secrets
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.read_from_vault(app_name, env)
|
47
|
+
path = vault_path(app_name, env)
|
48
|
+
secrets = Amplify::VaultAuthClient.read(path, env)
|
49
|
+
raise SecretMissingError.new(path, env) if secrets.nil?
|
50
|
+
secrets
|
51
|
+
end
|
52
|
+
|
53
|
+
class NotExtendedCorrectly < StandardError
|
54
|
+
def initialize(message)
|
55
|
+
super("Amplify::VaultDataBagWrapperBase was not extended correctly: #{message}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class SecretMissingError < StandardError
|
61
|
+
def initialize(path, environment)
|
62
|
+
message = <<ERRORMESSAGE
|
63
|
+
Successfully authenticated with vault but...
|
64
|
+
Expecting #{path} to exist in #{environment}.
|
65
|
+
Please create DA-ticket to add secrets to vault
|
66
|
+
ERRORMESSAGE
|
67
|
+
super(message)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
class MissingDatabag < StandardError
|
71
|
+
def initialize(databag)
|
72
|
+
message = <<ERRORMESSAGE
|
73
|
+
Couldn't find #{databag[:name]}/#{databag[:item]}
|
74
|
+
You should only get this error during local converge.
|
75
|
+
Check: test/chef/data_bags/#{databag[:name]}/#{databag[:item]}.json
|
76
|
+
ERRORMESSAGE
|
77
|
+
super(message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: parameterstore_databag_wrapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Walsh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: chef
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: chefspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '7.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '7.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: chef-zero
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: hashie
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.5'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '12.3'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '12.3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.54'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.54'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.7'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.7'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.3'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.3'
|
139
|
+
description: "'Wrapper for obtaining secrets from ParameterStore for use with Chef
|
140
|
+
as EncryptedDatabags or Database secrets'"
|
141
|
+
email: devtools@amplify.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- LICENSE
|
147
|
+
- README.md
|
148
|
+
- lib/amplify/encrypted_data_bag_item.rb
|
149
|
+
- lib/amplify/encrypted_database_info.rb
|
150
|
+
- lib/amplify/parameter_store_client.rb
|
151
|
+
- lib/amplify/vault_data_bag_wrapper_base.rb
|
152
|
+
- lib/parameterstore_databag_wrapper.rb
|
153
|
+
homepage: http://rubygems.org/gems/parameterstore_databag_wrapper
|
154
|
+
licenses: []
|
155
|
+
metadata: {}
|
156
|
+
post_install_message:
|
157
|
+
rdoc_options: []
|
158
|
+
require_paths:
|
159
|
+
- lib
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
requirements: []
|
171
|
+
rubyforge_project:
|
172
|
+
rubygems_version: 2.5.2
|
173
|
+
signing_key:
|
174
|
+
specification_version: 3
|
175
|
+
summary: Secrets!
|
176
|
+
test_files: []
|