secret_keys_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 59a7a3c0cdf8e3bfc3404976d8abd554835ec5e7de3b118c405a721d6754fb92
4
+ data.tar.gz: 780e597db65702e0133aadef39e63ed4517e13b9eef007d0b5d0ed438b05501b
5
+ SHA512:
6
+ metadata.gz: 4ae600744e21eebc2f5ba171e4820a76f8aa68e6c3b6525cddb40eae5ce50c0dd7c9962e2241eaea062906cc85ffcdc2d7b746752a803c2d7952b7130e148f90
7
+ data.tar.gz: bcc0a28007499a9299b519bb472b09f0019c7cfd1feba19df291d3f1738e72395b29bbe0dfaf64b2f5b24c5d279dc3d36467d55cc6529c5341ab9a4df0d44313
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby: ["2.5", "2.6", "2.7"]
12
+ rails: ["5.0", "5.1", "5.2", "6.0"]
13
+ include:
14
+ - ruby: "2.4"
15
+ rails: "4.2"
16
+ name: "test (Ruby ${{ matrix.ruby }}, Rails ${{ matrix.rails }})"
17
+ env:
18
+ BUNDLE_JOBS: 4
19
+ BUNDLE_RETRY: 3
20
+ BUNDLE_PATH: vendor/bundle
21
+ BUNDLE_CLEAN: "true"
22
+ BUNDLE_GEMFILE: gemfiles/rails_${{ matrix.rails }}.gemfile
23
+ steps:
24
+ - uses: actions/checkout@v2
25
+ - uses: actions/setup-ruby@v1
26
+ with:
27
+ ruby-version: ${{ matrix.ruby }}
28
+ - name: Bundle Cache
29
+ uses: actions/cache@v1
30
+ with:
31
+ path: vendor/bundle
32
+ key: ${{ runner.os }}-${{ matrix.rails }}-gems-${{ hashFiles(env.BUNDLE_GEMFILE) }}
33
+ restore-keys: ${{ runner.os }}-${{ matrix.rails }}-gems-
34
+ - name: Bundler Downgrade
35
+ run: |
36
+ gem uninstall bundler -x
37
+ gem install bundler -v "< 2" --no-document
38
+ if: ${{ matrix.rails == '4.2' }}
39
+ - name: Bundle Install
40
+ run: bundle install
41
+ - name: Test
42
+ run: bundle exec rake test
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /gemfiles/.bundle
10
+ /gemfiles/*.lock
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.0
6
+ before_install: gem install bundler -v 2.1.2
@@ -0,0 +1,20 @@
1
+ appraise "rails-6.0" do
2
+ gem "rails", "~> 6.0.0"
3
+ end
4
+
5
+ appraise "rails-5.2" do
6
+ gem "rails", "~> 5.2.0"
7
+ end
8
+
9
+ appraise "rails-5.1" do
10
+ gem "rails", "~> 5.1.0"
11
+ end
12
+
13
+ appraise "rails-5.0" do
14
+ gem "rails", "~> 5.0.0"
15
+ end
16
+
17
+ appraise "rails-4.2" do
18
+ gem "rails", "~> 4.2.0"
19
+ gem "sprockets", "< 4"
20
+ end
@@ -0,0 +1,6 @@
1
+ # SecretKeysRails Change Log
2
+
3
+ ## 0.1.0 - 2020-05-26
4
+
5
+ ### Added
6
+ - Initial release.
data/Gemfile ADDED
@@ -0,0 +1,27 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in secret_keys_rails.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+
8
+ # Tests
9
+ gem "minitest", "~> 5.0"
10
+ gem "minitest-reporters", "~> 1.4.2"
11
+
12
+ # Run each test in isolation, so we can better test how changes would affect
13
+ # the app loading.
14
+ gem "minitest-fork_executor", "~> 1.0.1"
15
+
16
+ # Run against multiple Rails versions.
17
+ gem "appraisal", "~> 2.2.0"
18
+
19
+ # Perform tests inside a Rails app, so we can simulate how this plugin
20
+ # interacts with application loading.
21
+ gem "combustion", "~> 1.3.0"
22
+
23
+ # Test how this gem interacts with other gems inside the Combustion Rails test
24
+ # app.
25
+ group :test_app do
26
+ gem "config", "~> 2.2.1"
27
+ end
@@ -0,0 +1,212 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ secret_keys_rails (0.1.0)
5
+ ice_nine
6
+ rails (>= 4)
7
+ secret_keys
8
+ thor
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ actioncable (6.0.3.1)
14
+ actionpack (= 6.0.3.1)
15
+ nio4r (~> 2.0)
16
+ websocket-driver (>= 0.6.1)
17
+ actionmailbox (6.0.3.1)
18
+ actionpack (= 6.0.3.1)
19
+ activejob (= 6.0.3.1)
20
+ activerecord (= 6.0.3.1)
21
+ activestorage (= 6.0.3.1)
22
+ activesupport (= 6.0.3.1)
23
+ mail (>= 2.7.1)
24
+ actionmailer (6.0.3.1)
25
+ actionpack (= 6.0.3.1)
26
+ actionview (= 6.0.3.1)
27
+ activejob (= 6.0.3.1)
28
+ mail (~> 2.5, >= 2.5.4)
29
+ rails-dom-testing (~> 2.0)
30
+ actionpack (6.0.3.1)
31
+ actionview (= 6.0.3.1)
32
+ activesupport (= 6.0.3.1)
33
+ rack (~> 2.0, >= 2.0.8)
34
+ rack-test (>= 0.6.3)
35
+ rails-dom-testing (~> 2.0)
36
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
37
+ actiontext (6.0.3.1)
38
+ actionpack (= 6.0.3.1)
39
+ activerecord (= 6.0.3.1)
40
+ activestorage (= 6.0.3.1)
41
+ activesupport (= 6.0.3.1)
42
+ nokogiri (>= 1.8.5)
43
+ actionview (6.0.3.1)
44
+ activesupport (= 6.0.3.1)
45
+ builder (~> 3.1)
46
+ erubi (~> 1.4)
47
+ rails-dom-testing (~> 2.0)
48
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
49
+ activejob (6.0.3.1)
50
+ activesupport (= 6.0.3.1)
51
+ globalid (>= 0.3.6)
52
+ activemodel (6.0.3.1)
53
+ activesupport (= 6.0.3.1)
54
+ activerecord (6.0.3.1)
55
+ activemodel (= 6.0.3.1)
56
+ activesupport (= 6.0.3.1)
57
+ activestorage (6.0.3.1)
58
+ actionpack (= 6.0.3.1)
59
+ activejob (= 6.0.3.1)
60
+ activerecord (= 6.0.3.1)
61
+ marcel (~> 0.3.1)
62
+ activesupport (6.0.3.1)
63
+ concurrent-ruby (~> 1.0, >= 1.0.2)
64
+ i18n (>= 0.7, < 2)
65
+ minitest (~> 5.1)
66
+ tzinfo (~> 1.1)
67
+ zeitwerk (~> 2.2, >= 2.2.2)
68
+ ansi (1.5.0)
69
+ appraisal (2.2.0)
70
+ bundler
71
+ rake
72
+ thor (>= 0.14.0)
73
+ builder (3.2.4)
74
+ combustion (1.3.0)
75
+ activesupport (>= 3.0.0)
76
+ railties (>= 3.0.0)
77
+ thor (>= 0.14.6)
78
+ concurrent-ruby (1.1.6)
79
+ config (2.2.1)
80
+ deep_merge (~> 1.2, >= 1.2.1)
81
+ dry-validation (~> 1.0, >= 1.0.0)
82
+ crass (1.0.6)
83
+ deep_merge (1.2.1)
84
+ dry-configurable (0.11.5)
85
+ concurrent-ruby (~> 1.0)
86
+ dry-core (~> 0.4, >= 0.4.7)
87
+ dry-equalizer (~> 0.2)
88
+ dry-container (0.7.2)
89
+ concurrent-ruby (~> 1.0)
90
+ dry-configurable (~> 0.1, >= 0.1.3)
91
+ dry-core (0.4.9)
92
+ concurrent-ruby (~> 1.0)
93
+ dry-equalizer (0.3.0)
94
+ dry-inflector (0.2.0)
95
+ dry-initializer (3.0.3)
96
+ dry-logic (1.0.6)
97
+ concurrent-ruby (~> 1.0)
98
+ dry-core (~> 0.2)
99
+ dry-equalizer (~> 0.2)
100
+ dry-schema (1.5.1)
101
+ concurrent-ruby (~> 1.0)
102
+ dry-configurable (~> 0.8, >= 0.8.3)
103
+ dry-core (~> 0.4)
104
+ dry-equalizer (~> 0.2)
105
+ dry-initializer (~> 3.0)
106
+ dry-logic (~> 1.0)
107
+ dry-types (~> 1.4)
108
+ dry-types (1.4.0)
109
+ concurrent-ruby (~> 1.0)
110
+ dry-container (~> 0.3)
111
+ dry-core (~> 0.4, >= 0.4.4)
112
+ dry-equalizer (~> 0.3)
113
+ dry-inflector (~> 0.1, >= 0.1.2)
114
+ dry-logic (~> 1.0, >= 1.0.2)
115
+ dry-validation (1.5.0)
116
+ concurrent-ruby (~> 1.0)
117
+ dry-container (~> 0.7, >= 0.7.1)
118
+ dry-core (~> 0.4)
119
+ dry-equalizer (~> 0.2)
120
+ dry-initializer (~> 3.0)
121
+ dry-schema (~> 1.5)
122
+ erubi (1.9.0)
123
+ globalid (0.4.2)
124
+ activesupport (>= 4.2.0)
125
+ i18n (1.8.2)
126
+ concurrent-ruby (~> 1.0)
127
+ ice_nine (0.11.2)
128
+ loofah (2.5.0)
129
+ crass (~> 1.0.2)
130
+ nokogiri (>= 1.5.9)
131
+ mail (2.7.1)
132
+ mini_mime (>= 0.1.1)
133
+ marcel (0.3.3)
134
+ mimemagic (~> 0.3.2)
135
+ method_source (1.0.0)
136
+ mimemagic (0.3.5)
137
+ mini_mime (1.0.2)
138
+ mini_portile2 (2.4.0)
139
+ minitest (5.14.1)
140
+ minitest-fork_executor (1.0.1)
141
+ minitest
142
+ minitest-reporters (1.4.2)
143
+ ansi
144
+ builder
145
+ minitest (>= 5.0)
146
+ ruby-progressbar
147
+ nio4r (2.5.2)
148
+ nokogiri (1.10.9)
149
+ mini_portile2 (~> 2.4.0)
150
+ rack (2.2.2)
151
+ rack-test (1.1.0)
152
+ rack (>= 1.0, < 3)
153
+ rails (6.0.3.1)
154
+ actioncable (= 6.0.3.1)
155
+ actionmailbox (= 6.0.3.1)
156
+ actionmailer (= 6.0.3.1)
157
+ actionpack (= 6.0.3.1)
158
+ actiontext (= 6.0.3.1)
159
+ actionview (= 6.0.3.1)
160
+ activejob (= 6.0.3.1)
161
+ activemodel (= 6.0.3.1)
162
+ activerecord (= 6.0.3.1)
163
+ activestorage (= 6.0.3.1)
164
+ activesupport (= 6.0.3.1)
165
+ bundler (>= 1.3.0)
166
+ railties (= 6.0.3.1)
167
+ sprockets-rails (>= 2.0.0)
168
+ rails-dom-testing (2.0.3)
169
+ activesupport (>= 4.2.0)
170
+ nokogiri (>= 1.6)
171
+ rails-html-sanitizer (1.3.0)
172
+ loofah (~> 2.3)
173
+ railties (6.0.3.1)
174
+ actionpack (= 6.0.3.1)
175
+ activesupport (= 6.0.3.1)
176
+ method_source
177
+ rake (>= 0.8.7)
178
+ thor (>= 0.20.3, < 2.0)
179
+ rake (12.3.3)
180
+ ruby-progressbar (1.10.1)
181
+ secret_keys (1.0.0.pre)
182
+ sprockets (4.0.0)
183
+ concurrent-ruby (~> 1.0)
184
+ rack (> 1, < 3)
185
+ sprockets-rails (3.2.1)
186
+ actionpack (>= 4.0)
187
+ activesupport (>= 4.0)
188
+ sprockets (>= 3.0.0)
189
+ thor (1.0.1)
190
+ thread_safe (0.3.6)
191
+ tzinfo (1.2.7)
192
+ thread_safe (~> 0.1)
193
+ websocket-driver (0.7.2)
194
+ websocket-extensions (>= 0.1.0)
195
+ websocket-extensions (0.1.4)
196
+ zeitwerk (2.3.0)
197
+
198
+ PLATFORMS
199
+ ruby
200
+
201
+ DEPENDENCIES
202
+ appraisal (~> 2.2.0)
203
+ combustion (~> 1.3.0)
204
+ config (~> 2.2.1)
205
+ minitest (~> 5.0)
206
+ minitest-fork_executor (~> 1.0.1)
207
+ minitest-reporters (~> 1.4.2)
208
+ rake (~> 12.0)
209
+ secret_keys_rails!
210
+
211
+ BUNDLED WITH
212
+ 1.17.3
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Nick Muerdter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,152 @@
1
+ # SecretKeysRails
2
+
3
+ [![CI](https://github.com/GUI/secret_keys_rails/workflows/CI/badge.svg)](https://github.com/GUI/secret_keys_rails/actions?workflow=CI)
4
+
5
+ An alternative to Rails encrypted credentials that uses the [SecretKeys](https://github.com/bdurand/secret_keys) library. The primary difference this offers versus the default Rails encrypted credentials strategy is that this uses an encrypted file format that only encrypts the values of the file (the hash keys are unencrypted). This allows for easier git diffs/merges while still keeping the secret values encrypted (but the overall structure of the file will not be encrypted). This gem provides some convenience wrappers on top of the SecretKeys library for integration with Rails applications.
6
+
7
+ As an example, the encrypted version of:
8
+
9
+ ```yml
10
+ foo: bar
11
+ baz: qux
12
+ ```
13
+
14
+ Might be encrypted as:
15
+
16
+ ```yml
17
+ ".encrypted":
18
+ ".salt": 82acce8beeeb422f
19
+ ".key": "$AES$:AJedc/6fDmjRHyh8Ln3K5y/WDzmbQVAsPWkDOFMLpaERVpKPS4I"
20
+ foo: "$AES$:d3mPCOkdfcWAD6BJGjvZT00BtKqAtLVKNvrlE191qg"
21
+ baz: "$AES$:t05Yel2BwiacEnsIXnnVoqTyXLsXU6oWZbSG7kOIDQ"
22
+ ```
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem "secret_keys_rails"
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ ```
35
+ bundle install
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ### Creating or Editing Secrets
41
+
42
+ To open an interactive editor to create or edit the default encrypted `config/secret_keys.yml` file:
43
+
44
+ ```
45
+ rake secret_keys:edit
46
+ ```
47
+
48
+ All string values you enter will be encrypted after saving and closing this editing session.
49
+
50
+ If editing the file for the first time, an encryption key will be generated for you and saved to `config/secret_keys.yml.key`. This encryption key should be kept private and only shared to users that need to decrypt the encrypted values.
51
+
52
+ ### Showing Secrets
53
+
54
+ To view all the encrypted secrets in unencrypted form for the default `config/secret_keys.yml` file:
55
+
56
+ ```
57
+ rake secret_keys:show
58
+ ```
59
+
60
+ ### Using Secrets
61
+
62
+ Unencrypted secrets are available in your application via the `SecretKeysRails.secrets` hash. This hash is an instance of [`ActiveSupport::HashWithIndifferentAccess`](https://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html), so keys can be accessed as either symbols or strings.
63
+
64
+ ```ruby
65
+ # Symbol or strings can be used for accessing keys.
66
+ SecretKeysRails.secrets[:some_api_key]
67
+ SecretKeysRails.secrets["some_api_key"]
68
+
69
+ # Use fetch to raise an error if the key isn't present.
70
+ SecretKeysRails.secrets.fetch(:some_api_key)
71
+
72
+ # Other standard Hash methods can be used for access, lig dig.
73
+ SecretKeysRails.secrets.dig(:some_api_key)
74
+ ```
75
+
76
+ ### Encryption Key
77
+
78
+ In order to decrypt the secrets, the encryption key must be set. The encryption key may either be stored in the `config/secret_keys.yml.key` file or set in the `SECRET_KEYS_ENCRYPTION_KEY` environment variable.
79
+
80
+ By default, if the encryption key is not set, then `SecretKeysRails.secrets` will return an empty hash. If you want to require the encryption key be set, then you can change the [`SecretKeysRails.require_encryption_key`](#secretkeysrailsrequire_encryption_key) setting to raise an error if the encryption key is not set.
81
+
82
+ ### Environment Specific Secrets
83
+
84
+ The commands support passing an `--environment` option to create an environment specific override. That override will take precedence over the global `config/secret_keys.yml` file when running in that environment. So:
85
+
86
+ ```
87
+ rake secret_keys:edit -- --environment development
88
+ ```
89
+
90
+ will create `config/secret_keys/development.yml` with the corresponding encryption key in `config/secret_keys/development.yml.key` if the credentials file doesn't exist.
91
+
92
+ The encryption key can also be put in `ENV["SECRET_KEYS_ENCRYPTION_KEY"]`, which takes precedence over the file encryption key.
93
+
94
+ In addition to that, the default credentials lookup paths can be overridden through the [`SecretKeysRails.secrets_path`](#secretkeysrailssecrets_path) and [`SecretKeysRails.key_path`](#secretkeysrailskey_path) settings.
95
+
96
+ ## Configuration
97
+
98
+ You may adjust RailsSecretKeys configuration by adding a `config/initializers/secret_keys_rails.rb` file with setting changes. Note that the initializer must exist at this path to be properly loaded (this ensures that RailsSecretKeys is available early on in the Rails load process, so other parts of Rails and other gems can integrate with it).
99
+
100
+ #### `SecretKeysRails.require_encryption_key`
101
+
102
+ Raise an error if the encryption key isn't set.
103
+
104
+ ```ruby
105
+ SecretKeysRails.require_encryption_key = true # Defaults to `false`
106
+ ```
107
+
108
+ #### `SecretKeysRails.secrets_path`
109
+
110
+ Set a custom path to the secret keys encrypted file.
111
+
112
+ ```ruby
113
+ SecretKeysRails.secret_path = "config/my_keys.yml" # Defaults to `config/secret_keys/<ENV>.yml` or `config/secret_keys.yml`
114
+ ```
115
+
116
+ #### `SecretKeysRails.key_path`
117
+
118
+ Set a custom path to the encryption key path.
119
+
120
+ ```ruby
121
+ SecretKeysRails.key_path = "config/my_keys.yml.key" # Defaults to `config/secret_keys/<ENV>.yml.key` or `config/secret_keys.yml.key`
122
+ ```
123
+
124
+ ## Design
125
+
126
+ The underlying [SecretKeys](https://github.com/bdurand/secret_keys) library is more flexible in a few ways. This gem is slightly more opinionated for integration with Rails, and we attempt to more closely match the behavior of the default Rails encrypted credentials experience. The primary differences are:
127
+
128
+ - The secret keys files are always stored as YAML.
129
+ - The secret keys files exist at specific paths (`config/secret_keys.yml` or `config/secrets_keys/<ENV>.yml`).
130
+ - The encryption key can be read from a specific path (`config/secret_keys.yml.key` or `config/secrets_keys/<ENV>.yml.key`).
131
+ - All values in the file will be encrypted.
132
+ - An interactive edit command is supplied for editing the decrypted file.
133
+ - Keys are returned as a deeply frozen `ActiveSupport::HashWithIndifferentAccess`.
134
+
135
+ ## Known Limitations
136
+
137
+ - Only string values will be encrypted. Numbers, booleans, and null values will not be encrypted.
138
+ - Comments in the YAML file will be stripped.
139
+
140
+ ## Development
141
+
142
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
143
+
144
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
145
+
146
+ ## Contributing
147
+
148
+ Bug reports and pull requests are welcome on GitHub at https://github.com/GUI/secret_keys_rails.
149
+
150
+ ## License
151
+
152
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ t.warning = false
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "secret_keys_rails"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "secret_keys_rails/commands/secret_keys_command"
4
+
5
+ rails_root = if ENV["RAILS_ROOT"]
6
+ Pathname.new(ENV["RAILS_ROOT"]).expand_path
7
+ elsif File.exist?(File.join(Dir.pwd, "config/environment.rb"))
8
+ Pathname.new(Dir.pwd)
9
+ elsif ENV["BUNDLE_GEMFILE"] && File.exist?(File.expand_path("../config/environment.rb", ENV["BUNDLE_GEMFILE"]))
10
+ Pathname.new(File.expand_path("..", ENV["BUNDLE_GEMFILE"]))
11
+ else
12
+ Pathname.new(Dir.pwd).expand_path
13
+ end
14
+
15
+ Dir.chdir(rails_root) do
16
+ SecretKeysRails::Commands::SecretKeysCommand.start(ARGV)
17
+ end
@@ -0,0 +1,18 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake", "~> 12.0"
6
+ gem "minitest", "~> 5.0"
7
+ gem "minitest-reporters", "~> 1.4.2"
8
+ gem "minitest-fork_executor", "~> 1.0.1"
9
+ gem "appraisal", "~> 2.2.0"
10
+ gem "combustion", "~> 1.3.0"
11
+ gem "rails", "~> 4.2.0"
12
+ gem "sprockets", "< 4"
13
+
14
+ group :test_app do
15
+ gem "config", "~> 2.2.1"
16
+ end
17
+
18
+ gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake", "~> 12.0"
6
+ gem "minitest", "~> 5.0"
7
+ gem "minitest-reporters", "~> 1.4.2"
8
+ gem "minitest-fork_executor", "~> 1.0.1"
9
+ gem "appraisal", "~> 2.2.0"
10
+ gem "combustion", "~> 1.3.0"
11
+ gem "rails", "~> 5.0.0"
12
+
13
+ group :test_app do
14
+ gem "config", "~> 2.2.1"
15
+ end
16
+
17
+ gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake", "~> 12.0"
6
+ gem "minitest", "~> 5.0"
7
+ gem "minitest-reporters", "~> 1.4.2"
8
+ gem "minitest-fork_executor", "~> 1.0.1"
9
+ gem "appraisal", "~> 2.2.0"
10
+ gem "combustion", "~> 1.3.0"
11
+ gem "rails", "~> 5.1.0"
12
+
13
+ group :test_app do
14
+ gem "config", "~> 2.2.1"
15
+ end
16
+
17
+ gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake", "~> 12.0"
6
+ gem "minitest", "~> 5.0"
7
+ gem "minitest-reporters", "~> 1.4.2"
8
+ gem "minitest-fork_executor", "~> 1.0.1"
9
+ gem "appraisal", "~> 2.2.0"
10
+ gem "combustion", "~> 1.3.0"
11
+ gem "rails", "~> 5.2.0"
12
+
13
+ group :test_app do
14
+ gem "config", "~> 2.2.1"
15
+ end
16
+
17
+ gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake", "~> 12.0"
6
+ gem "minitest", "~> 5.0"
7
+ gem "minitest-reporters", "~> 1.4.2"
8
+ gem "minitest-fork_executor", "~> 1.0.1"
9
+ gem "appraisal", "~> 2.2.0"
10
+ gem "combustion", "~> 1.3.0"
11
+ gem "rails", "~> 6.0.0"
12
+
13
+ group :test_app do
14
+ gem "config", "~> 2.2.1"
15
+ end
16
+
17
+ gemspec path: "../"
@@ -0,0 +1,119 @@
1
+ require "active_support/core_ext/hash/indifferent_access"
2
+ require "ice_nine"
3
+ require "secret_keys"
4
+ require "secret_keys_rails/errors"
5
+ require "secret_keys_rails/version"
6
+
7
+ module SecretKeysRails
8
+ @secrets = nil
9
+ @require_encryption_key = false
10
+ @secrets_path = nil
11
+ @key_path = nil
12
+ class << self
13
+ attr_accessor :require_encryption_key
14
+ attr_writer :secrets_path
15
+ attr_writer :key_path
16
+
17
+ def secrets_path(env = nil)
18
+ if @secrets_path
19
+ Pathname.new(@secrets_path)
20
+ elsif env
21
+ Pathname.new("config/secret_keys/#{env}.yml")
22
+ else
23
+ Pathname.new("config/secret_keys.yml")
24
+ end
25
+ end
26
+
27
+ def key_path(env = nil)
28
+ if @key_path
29
+ Pathname.new(@key_path)
30
+ elsif env
31
+ Pathname.new("config/secret_keys/#{env}.yml.key")
32
+ else
33
+ Pathname.new("config/secret_keys.yml.key")
34
+ end
35
+ end
36
+
37
+ def key(env = nil)
38
+ key = nil
39
+
40
+ if ENV["SECRET_KEYS_ENCRYPTION_KEY"]
41
+ key = ENV["SECRET_KEYS_ENCRYPTION_KEY"]
42
+ else
43
+ path = self.key_path(env)
44
+ if File.exist?(path)
45
+ key = File.read(path).strip
46
+ end
47
+ end
48
+
49
+ if !key && self.require_encryption_key
50
+ raise MissingKeyError.new("Missing encryption key to decrypt file with. Ask your team for your master key and write it to #{self.key_path(env)} or put it in the ENV['SECRET_KEYS_ENCRYPTION_KEY'].")
51
+ end
52
+
53
+ key
54
+ end
55
+
56
+ def secrets
57
+ unless @secrets
58
+ raise NotLoadedError.new("Secrets have not been loaded. Rails should automatically load the secrets on startup.")
59
+ end
60
+
61
+ @secrets
62
+ end
63
+
64
+ def load
65
+ # Determine whether we should try to load the environment-specific secret
66
+ # keys file (eg, config/secret_keys/ENV.yml), or whether we should use the
67
+ # default file (config/secret_keys.yml).
68
+ secrets_path = nil
69
+ key = nil
70
+ if Pathname.new("config/secret_keys/#{::Rails.env}.yml").exist?
71
+ secrets_path = self.secrets_path(::Rails.env)
72
+ key = self.key(::Rails.env)
73
+ else
74
+ secrets_path = self.secrets_path
75
+ key = self.key
76
+ end
77
+
78
+ # Decrypt the file with the SecretKeys library.
79
+ if secrets_path.exist? && key
80
+ secrets = SecretKeys.new(secrets_path, key).to_h
81
+ else
82
+ secrets = {}
83
+ end
84
+
85
+ # Use a HashWithIndifferentAccess for easier key access, and also deep
86
+ # freeze the object to prevent unintended modifications of the secrets at
87
+ # runtime.
88
+ @secrets = IceNine.deep_freeze(secrets.with_indifferent_access)
89
+
90
+ # If there is a `secret_key_base` secret present, then use that for the
91
+ # default Rails secret_key_base definition (depending on Rails version,
92
+ # this can be read out of a few different places).
93
+ if @secrets.key?(:secret_key_base)
94
+ if ::Rails.application.respond_to?(:credentials)
95
+ Rails.application.credentials.secret_key_base = @secrets.fetch(:secret_key_base)
96
+ end
97
+ if ::Rails.application.respond_to?(:secrets)
98
+ Rails.application.secrets.secret_key_base = @secrets.fetch(:secret_key_base)
99
+ end
100
+ if ::Rails.application.config.respond_to?(:secret_key_base=)
101
+ Rails.application.config.secret_key_base = @secrets.fetch(:secret_key_base)
102
+ end
103
+ end
104
+ end
105
+
106
+ def read(env = nil)
107
+ secrets_path = self.secrets_path(env)
108
+ unless secrets_path.exist?
109
+ raise MissingSecretsError.new("File '#{secrets_path}' does not exist. Use `rake secret_keys:edit` to create it.")
110
+ end
111
+
112
+ SecretKeys.new(secrets_path, self.key(env))
113
+ end
114
+ end
115
+ end
116
+
117
+ if defined?(::Rails)
118
+ require "secret_keys_rails/railtie"
119
+ end
@@ -0,0 +1,123 @@
1
+ require "secret_keys_rails"
2
+ require "thor"
3
+ require "securerandom"
4
+ require "yaml"
5
+
6
+ module SecretKeysRails
7
+ module Commands
8
+ class SecretKeysCommand < Thor
9
+ include Thor::Actions
10
+
11
+ class_option :environment, :aliases => "-e", :type => :string, :desc => "Specifies the environment to run the command under (test/development/production)."
12
+
13
+ def self.exit_on_failure?
14
+ true
15
+ end
16
+
17
+ def self.rake_args
18
+ args = ARGV.dup
19
+ if args[0]
20
+ args[0] = args[0].sub(/\Asecret_keys:/, "")
21
+ end
22
+ if args[1] == "--"
23
+ args.delete_at(1)
24
+ end
25
+ args
26
+ end
27
+
28
+ desc "show", "Decrypt and show the unencrypted secret keys"
29
+ def show
30
+ SecretKeysRails.require_encryption_key = true
31
+ secrets = SecretKeysRails.read(options["environment"])
32
+ STDOUT.write(yaml_dump(secrets.to_h))
33
+ rescue SecretKeysRails::Error => e
34
+ STDERR.puts e.message
35
+ exit 1
36
+ end
37
+
38
+ desc "edit", "Opens a temporary file in `$EDITOR` with the decrypted contents to edit the encrypted credentials."
39
+ def edit
40
+ key = ensure_key(options["environment"])
41
+ ensure_secrets(key, options["environment"])
42
+ edit_secrets(options["environment"])
43
+
44
+ rescue SecretKeysRails::Error => e
45
+ STDERR.puts e.message
46
+ exit 1
47
+ end
48
+
49
+ private
50
+
51
+ def ensure_key(env = nil)
52
+ key = SecretKeysRails.key(env)
53
+ unless key
54
+ key_path = SecretKeysRails.key_path(env)
55
+ unless key_path.exist?
56
+ key = SecureRandom.hex(32)
57
+
58
+ puts "Adding #{key_path} to store the encryption key: #{key}"
59
+ puts ""
60
+ puts "Save this in a password manager your team can access."
61
+ puts ""
62
+ puts "If you lose the key, no one, including you, can access anything encrypted with it."
63
+
64
+ puts ""
65
+ create_file key_path, key
66
+ chmod key_path, 0600
67
+ puts ""
68
+
69
+ ignore = "\n/#{key_path}\n"
70
+ if File.exist?(".gitignore")
71
+ unless File.read(".gitignore").include?(ignore)
72
+ puts "Ignoring #{key_path} so it won't end up in Git history:"
73
+ puts ""
74
+ append_to_file ".gitignore", ignore
75
+ puts ""
76
+ end
77
+ else
78
+ puts "IMPORTANT: Don't commit #{key_path}. Add this to your ignore file:"
79
+ puts set_color(ignore, :green, :bold)
80
+ end
81
+ end
82
+ end
83
+
84
+ key
85
+ end
86
+
87
+ def ensure_secrets(key, env = nil)
88
+ secrets_path = SecretKeysRails.secrets_path(env)
89
+ unless secrets_path.exist?
90
+ secrets = SecretKeys.new({
91
+ "secret_key_base" => SecureRandom.hex(64),
92
+ }, key)
93
+ secrets.save(secrets_path.to_s)
94
+ end
95
+ end
96
+
97
+ def edit_secrets(env = nil)
98
+ secrets = SecretKeysRails.read(env)
99
+
100
+ secrets_path = SecretKeysRails.secrets_path(env)
101
+ tmp_file = "#{Process.pid}.#{secrets_path.basename.to_s}"
102
+ tmp_path = Pathname.new(File.join(Dir.tmpdir, tmp_file))
103
+ tmp_path.binwrite(yaml_dump(secrets.to_h))
104
+
105
+ system("#{ENV["EDITOR"]} #{tmp_path}")
106
+
107
+ updated_contents = tmp_path.binread
108
+ secrets.keys.each do |key|
109
+ secrets.encrypt!(key)
110
+ end
111
+ secrets.replace(YAML.safe_load(updated_contents))
112
+ secrets.keys.each do |key|
113
+ secrets.encrypt!(key)
114
+ end
115
+ secrets.save(secrets_path.to_s)
116
+ end
117
+
118
+ def yaml_dump(obj)
119
+ YAML.dump(obj).sub(/\A---\n/, "")
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,6 @@
1
+ module SecretKeysRails
2
+ class Error < StandardError; end
3
+ class MissingKeyError < Error; end
4
+ class MissingSecretsError < Error; end
5
+ class NotLoadedError < Error; end
6
+ end
@@ -0,0 +1,31 @@
1
+ require "rails/railtie"
2
+
3
+ module SecretKeysRails
4
+ class Railtie < ::Rails::Railtie
5
+ # Load the secret keys as early as possible, so it can be used in other
6
+ # parts of the Rails configuration, like database.yml files.
7
+ config.before_configuration do
8
+ # Load the optional initializer manually (since this before_configuration
9
+ # phase is before when initializers are usually loaded), so that any
10
+ # customizations can be read in.
11
+ initializer = ::Rails.root.join("config", "initializers", "secret_keys_rails.rb")
12
+ require initializer if File.exist?(initializer)
13
+
14
+ SecretKeysRails.load
15
+ end
16
+
17
+ # Try to ensure our own "before_configuration" hook gets loaded before any
18
+ # others that have already been loaded, so that these secrets can be used
19
+ # as part of other gem's own before_configuration hooks (eg, in the
20
+ # "config" gem's settings.yml files).
21
+ load_hooks = ActiveSupport.instance_variable_get(:@load_hooks)
22
+ if load_hooks && load_hooks[:before_configuration]
23
+ load_hooks[:before_configuration] = load_hooks[:before_configuration].rotate(-1)
24
+ end
25
+
26
+ # Load our custom rake tasks.
27
+ rake_tasks do
28
+ load "secret_keys_rails/railtie/secret_keys.rake"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ namespace :secret_keys do
2
+ desc "Show the secret keys"
3
+ task :show do
4
+ require "secret_keys_rails/commands/secret_keys_command"
5
+ SecretKeysRails::Commands::SecretKeysCommand.start(SecretKeysRails::Commands::SecretKeysCommand.rake_args)
6
+ end
7
+
8
+ desc "Edit the secret keys"
9
+ task :edit do
10
+ require "secret_keys_rails/commands/secret_keys_command"
11
+ SecretKeysRails::Commands::SecretKeysCommand.start(SecretKeysRails::Commands::SecretKeysCommand.rake_args)
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module SecretKeysRails
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,32 @@
1
+ require_relative 'lib/secret_keys_rails/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "secret_keys_rails"
5
+ spec.version = SecretKeysRails::VERSION
6
+ spec.authors = ["Nick Muerdter"]
7
+ spec.email = ["12112+GUI@users.noreply.github.com"]
8
+
9
+ spec.summary = %q{Git-friendly encrypted secrets for Rails.}
10
+ spec.homepage = "https://github.com/GUI/secret_keys_rails"
11
+ spec.license = "MIT"
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13
+
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+ spec.metadata["source_code_uri"] = "https://github.com/GUI/secret_keys_rails"
16
+ spec.metadata["source_code_uri"] = "https://github.com/GUI/secret_keys_rails/tree/v#{SecretKeysRails::VERSION}"
17
+ spec.metadata["changelog_uri"] = "https://github.com/GUI/secret_keys_rails/blob/v#{SecretKeysRails::VERSION}/CHANGELOG.md"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "secret_keys"
29
+ spec.add_dependency "rails", ">= 4"
30
+ spec.add_dependency "ice_nine"
31
+ spec.add_dependency "thor"
32
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: secret_keys_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick Muerdter
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-05-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: secret_keys
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ice_nine
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - 12112+GUI@users.noreply.github.com
72
+ executables:
73
+ - secret_keys_rails
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".github/workflows/main.yml"
78
+ - ".gitignore"
79
+ - ".travis.yml"
80
+ - Appraisals
81
+ - CHANGELOG.md
82
+ - Gemfile
83
+ - Gemfile.lock
84
+ - LICENSE.txt
85
+ - README.md
86
+ - Rakefile
87
+ - bin/console
88
+ - bin/setup
89
+ - exe/secret_keys_rails
90
+ - gemfiles/rails_4.2.gemfile
91
+ - gemfiles/rails_5.0.gemfile
92
+ - gemfiles/rails_5.1.gemfile
93
+ - gemfiles/rails_5.2.gemfile
94
+ - gemfiles/rails_6.0.gemfile
95
+ - lib/secret_keys_rails.rb
96
+ - lib/secret_keys_rails/commands/secret_keys_command.rb
97
+ - lib/secret_keys_rails/errors.rb
98
+ - lib/secret_keys_rails/railtie.rb
99
+ - lib/secret_keys_rails/railtie/secret_keys.rake
100
+ - lib/secret_keys_rails/version.rb
101
+ - secret_keys_rails.gemspec
102
+ homepage: https://github.com/GUI/secret_keys_rails
103
+ licenses:
104
+ - MIT
105
+ metadata:
106
+ homepage_uri: https://github.com/GUI/secret_keys_rails
107
+ source_code_uri: https://github.com/GUI/secret_keys_rails/tree/v0.1.0
108
+ changelog_uri: https://github.com/GUI/secret_keys_rails/blob/v0.1.0/CHANGELOG.md
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 2.3.0
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 3.1.2
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Git-friendly encrypted secrets for Rails.
128
+ test_files: []