invar 0.7.0 → 0.9.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/.rubocop.yml +0 -12
- data/.ruby-version +1 -1
- data/.simplecov +8 -0
- data/Gemfile +10 -5
- data/README.md +27 -2
- data/RELEASE_NOTES.md +43 -0
- data/invar.gemspec +1 -1
- data/lib/invar/errors.rb +6 -4
- data/lib/invar/private_file.rb +1 -1
- data/lib/invar/rake/tasks.rb +95 -59
- data/lib/invar/reality.rb +2 -1
- data/lib/invar/scope.rb +3 -5
- data/lib/invar/test.rb +5 -2
- data/lib/invar/version.rb +1 -1
- data/lib/invar.rb +2 -2
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7bb218e77d7ce1acc82bf0160cc7386529f7e32e5a56cd2eea608bd2a191ad6
|
4
|
+
data.tar.gz: 6b209fa6041be75736d28783d996c8fe0ee1e529bdde7d94dcb8e1bbda23423d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da15b60c94678b1dc9a5e002b3f4bba02d7b2e1a77923483a2a5427839b0cff0fd0e137ce9e1ca847e6b493bb134be97f419a20bef7903adabe8de8b0f163ae9
|
7
|
+
data.tar.gz: 2d60ab3a7f5374478fe2ab872083ef4159620097e0cb65575eb6e6956b669c9fceaa86a39c085c637df125cebfc33f9ba52170a1a2389dce713de9d77da09c9d
|
data/.rubocop.yml
CHANGED
@@ -4,17 +4,6 @@ AllCops:
|
|
4
4
|
Exclude:
|
5
5
|
- 'bin/*'
|
6
6
|
|
7
|
-
TargetRubyVersion: 2.7
|
8
|
-
|
9
|
-
Layout/LineLength:
|
10
|
-
Exclude:
|
11
|
-
- 'spec/**/*.rb'
|
12
|
-
|
13
|
-
# setting to 6 to match RubyMine autoformat
|
14
|
-
Layout/FirstArrayElementIndentation:
|
15
|
-
IndentationWidth: 6
|
16
|
-
|
17
|
-
|
18
7
|
# rspec blocks are huge by design
|
19
8
|
Metrics/BlockLength:
|
20
9
|
Exclude:
|
@@ -23,4 +12,3 @@ Metrics/BlockLength:
|
|
23
12
|
Metrics/ModuleLength:
|
24
13
|
Exclude:
|
25
14
|
- 'spec/**/*.rb'
|
26
|
-
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-
|
1
|
+
ruby-3.1.4
|
data/.simplecov
ADDED
data/Gemfile
CHANGED
@@ -2,14 +2,19 @@
|
|
2
2
|
|
3
3
|
source 'https://rubygems.org'
|
4
4
|
|
5
|
+
# Gem's dependencies in invar.gemspec
|
6
|
+
gemspec
|
7
|
+
|
5
8
|
group :development do
|
6
9
|
gem 'bundler', '~> 2.3'
|
7
|
-
gem 'fakefs', '~> 2.5'
|
8
10
|
gem 'rake', '~> 13.0'
|
9
|
-
gem '
|
10
|
-
gem '
|
11
|
+
gem 'rubocop', '~> 1.56'
|
12
|
+
gem 'rubocop-performance', '~> 1.19'
|
11
13
|
gem 'yard', '~> 0.9'
|
12
14
|
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
+
group :test do
|
17
|
+
gem 'fakefs', '~> 2.5'
|
18
|
+
gem 'rspec', '~> 3.12'
|
19
|
+
gem 'simplecov', '~> 0.22'
|
20
|
+
end
|
data/README.md
CHANGED
@@ -26,7 +26,8 @@ variables have some downsides:
|
|
26
26
|
* Cannot be easily checked against a schema for early error detection
|
27
27
|
* Ruby's core ENV does not accept symbols as keys (a minor nuisance, but it counts)
|
28
28
|
|
29
|
-
> **Fun Fact:** Invar is named for an [alloy used in clockmaking](https://en.wikipedia.org/wiki/Invar) - it's short
|
29
|
+
> **Fun Fact:** Invar is named for an [alloy used in clockmaking](https://en.wikipedia.org/wiki/Invar) - it's short
|
30
|
+
> for "**invar**iable".
|
30
31
|
|
31
32
|
### Features
|
32
33
|
|
@@ -216,6 +217,10 @@ To open the file your system's default text editor (eg. nano):
|
|
216
217
|
|
217
218
|
bundle exec rake invar:config
|
218
219
|
|
220
|
+
> **Automation tip** You can provide new content over STDIN
|
221
|
+
>
|
222
|
+
> bundle exec rake invar:config < config_template.yml
|
223
|
+
|
219
224
|
#### Edit Secrets File
|
220
225
|
|
221
226
|
To edit the secrets file, run this and provide the file's encryption key:
|
@@ -223,7 +228,27 @@ To edit the secrets file, run this and provide the file's encryption key:
|
|
223
228
|
bundle exec rake invar:secrets
|
224
229
|
|
225
230
|
The file will be decrypted and opened in your default editor like the config file. Once you have exited the editor, it
|
226
|
-
will be re-encrypted. Remember to save your changes
|
231
|
+
will be re-encrypted. **Remember to save your changes!**
|
232
|
+
|
233
|
+
> **Automation tip** You can set the current encryption key in the `LOCKBOX_MASTER_KEY` environment variable:
|
234
|
+
>
|
235
|
+
> LOCKBOX_MASTER_KEY=sooper_sekret_key_here bundle exec rake invar:secrets
|
236
|
+
|
237
|
+
> **Automation tip** Like invar:config, you can provide new content over STDIN
|
238
|
+
>
|
239
|
+
> bundle exec rake invar:secrets < secrets_template.yml
|
240
|
+
|
241
|
+
#### Rotating the Secrets File Encryption Key
|
242
|
+
|
243
|
+
To re-encrypt the secrets file, run this and provide the file's current encryption key:
|
244
|
+
|
245
|
+
bundle exec rake invar:rotate
|
246
|
+
|
247
|
+
A new encryption key will be generated just like using `invar:init`.
|
248
|
+
|
249
|
+
> **Automation tip** you can set the current encryption key in the `LOCKBOX_MASTER_KEY` environment variable:
|
250
|
+
>
|
251
|
+
> LOCKBOX_MASTER_KEY=sooper_sekret_key_here bundle exec rake invar:rotate
|
227
252
|
|
228
253
|
### Code
|
229
254
|
|
data/RELEASE_NOTES.md
CHANGED
@@ -13,6 +13,49 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
13
13
|
|
14
14
|
### Minor Changes
|
15
15
|
|
16
|
+
* none
|
17
|
+
|
18
|
+
### Bugfixes
|
19
|
+
|
20
|
+
* none
|
21
|
+
|
22
|
+
## [0.9.0] - 2023-09-24
|
23
|
+
|
24
|
+
### Major Changes
|
25
|
+
|
26
|
+
* none
|
27
|
+
|
28
|
+
### Minor Changes
|
29
|
+
|
30
|
+
* Added Rake task for secrets file key rotation
|
31
|
+
* Added ability for invar:config and invar:secrets to take replacement content over `STDIN` instead of live editing
|
32
|
+
|
33
|
+
### Bugfixes
|
34
|
+
|
35
|
+
* none
|
36
|
+
|
37
|
+
## [0.8.0] - 2023-09-13
|
38
|
+
|
39
|
+
### Major Changes
|
40
|
+
|
41
|
+
* none
|
42
|
+
|
43
|
+
### Minor Changes
|
44
|
+
|
45
|
+
* Increased minimum Ruby to 3.1
|
46
|
+
|
47
|
+
### Bugfixes
|
48
|
+
|
49
|
+
* none
|
50
|
+
|
51
|
+
## [0.7.0] - 2023-08-06
|
52
|
+
|
53
|
+
### Major Changes
|
54
|
+
|
55
|
+
* none
|
56
|
+
|
57
|
+
### Minor Changes
|
58
|
+
|
16
59
|
* Tweaked file missing error messages
|
17
60
|
* Extracted testing helper features into a separate module
|
18
61
|
* Added support for multiple after_load hooks
|
data/invar.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ['lib']
|
29
29
|
|
30
|
-
spec.required_ruby_version = '>=
|
30
|
+
spec.required_ruby_version = '>= 3.1'
|
31
31
|
|
32
32
|
spec.add_dependency 'dry-schema', '>= 1.0'
|
33
33
|
spec.add_dependency 'lockbox', '>= 1.0'
|
data/lib/invar/errors.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :nodoc:
|
4
|
+
module Invar
|
3
5
|
# Raised when no config file can be found within the search paths.
|
4
6
|
class MissingConfigFileError < RuntimeError
|
5
7
|
end
|
@@ -41,11 +43,11 @@ module Invar
|
|
41
43
|
require 'invar/test'
|
42
44
|
HINT
|
43
45
|
|
44
|
-
PRETEND_MSG = "Method 'Invar::Scope#pretend' is defined in the testing extension. #{ HINT }"
|
45
|
-
HOOK_MSG = "Methods 'Invar.after_load and clear_hooks' are defined in the testing extension. #{ HINT }"
|
46
|
+
PRETEND_MSG = "Method 'Invar::Scope#pretend' is defined in the testing extension. #{ HINT }".freeze
|
47
|
+
HOOK_MSG = "Methods 'Invar.after_load and clear_hooks' are defined in the testing extension. #{ HINT }".freeze
|
46
48
|
end
|
47
49
|
|
48
50
|
# Raised when schema validation fails
|
49
51
|
class SchemaValidationError < RuntimeError
|
50
52
|
end
|
51
|
-
end
|
53
|
+
end
|
data/lib/invar/private_file.rb
CHANGED
@@ -9,7 +9,7 @@ module Invar
|
|
9
9
|
# Verifies a file is secure
|
10
10
|
class PrivateFile
|
11
11
|
extend Forwardable
|
12
|
-
def_delegators :@delegate_sd_obj, :stat, :to_s, :basename, :==, :chmod
|
12
|
+
def_delegators :@delegate_sd_obj, :stat, :to_s, :basename, :dirname, :extname, :==, :chmod, :rename, :write
|
13
13
|
|
14
14
|
# Mask for limiting to the lowest three octal digits (which store permissions)
|
15
15
|
PERMISSIONS_MASK = 0o777
|
data/lib/invar/rake/tasks.rb
CHANGED
@@ -30,8 +30,8 @@ module Invar
|
|
30
30
|
#
|
31
31
|
# @param (see #define)
|
32
32
|
# @see Tasks#define
|
33
|
-
def self.define(
|
34
|
-
new.define(
|
33
|
+
def self.define(...)
|
34
|
+
new.define(...)
|
35
35
|
end
|
36
36
|
|
37
37
|
# Defines helpful Rake tasks for the given namespace.
|
@@ -51,7 +51,7 @@ module Invar
|
|
51
51
|
define_init_task(app_namespace)
|
52
52
|
|
53
53
|
define_config_task(app_namespace)
|
54
|
-
|
54
|
+
define_secrets_tasks(app_namespace)
|
55
55
|
|
56
56
|
define_info_tasks(app_namespace)
|
57
57
|
end
|
@@ -62,8 +62,8 @@ module Invar
|
|
62
62
|
task :init, [:mode] do |_task, args|
|
63
63
|
mode = args.mode
|
64
64
|
|
65
|
-
config = ::Invar::Rake::Tasks::
|
66
|
-
secrets = ::Invar::Rake::Tasks::
|
65
|
+
config = ::Invar::Rake::Tasks::ConfigFileHandler.new(app_namespace)
|
66
|
+
secrets = ::Invar::Rake::Tasks::SecretsFileHandler.new(app_namespace)
|
67
67
|
|
68
68
|
case mode
|
69
69
|
when 'config'
|
@@ -71,7 +71,7 @@ module Invar
|
|
71
71
|
when 'secrets'
|
72
72
|
config = nil
|
73
73
|
else
|
74
|
-
raise "unknown mode #{ mode }. Must be one of 'config' or 'secrets'" unless mode.nil?
|
74
|
+
raise ArgumentError, "unknown mode '#{ mode }'. Must be one of 'config' or 'secrets'" unless mode.nil?
|
75
75
|
end
|
76
76
|
|
77
77
|
assert_init_conditions(config&.file_path, secrets&.file_path)
|
@@ -84,39 +84,44 @@ module Invar
|
|
84
84
|
def define_config_task(app_namespace)
|
85
85
|
desc 'Edit the config in your default editor'
|
86
86
|
task :configs do
|
87
|
-
::Invar::Rake::Tasks::
|
87
|
+
::Invar::Rake::Tasks::ConfigFileHandler.new(app_namespace).edit
|
88
88
|
end
|
89
89
|
|
90
90
|
# alias
|
91
91
|
task config: ['configs']
|
92
92
|
end
|
93
93
|
|
94
|
-
def
|
94
|
+
def define_secrets_tasks(app_namespace)
|
95
95
|
desc 'Edit the encrypted secrets file in your default editor'
|
96
96
|
task :secrets do
|
97
|
-
::Invar::Rake::Tasks::
|
97
|
+
::Invar::Rake::Tasks::SecretsFileHandler.new(app_namespace).edit
|
98
98
|
end
|
99
99
|
|
100
100
|
# alias
|
101
101
|
task secret: ['secrets']
|
102
|
+
|
103
|
+
desc 'Encrypt the secrets file with a new generated key'
|
104
|
+
task :rotate do
|
105
|
+
::Invar::Rake::Tasks::SecretsFileHandler.new(app_namespace).rotate
|
106
|
+
end
|
102
107
|
end
|
103
108
|
|
104
109
|
def define_info_tasks(app_namespace)
|
105
110
|
desc 'Show directories to be searched for the given namespace'
|
106
111
|
task :paths do
|
107
|
-
::Invar::Rake::Tasks::
|
112
|
+
::Invar::Rake::Tasks::StatusHandler.new(app_namespace).show_paths
|
108
113
|
end
|
109
114
|
end
|
110
115
|
|
111
116
|
def assert_init_conditions(config_file, secrets_file)
|
112
117
|
return unless config_file&.exist? || secrets_file&.exist?
|
113
118
|
|
114
|
-
msg = if !config_file
|
119
|
+
msg = if !config_file.exist?
|
115
120
|
<<~MSG
|
116
121
|
Abort: Secrets file already exists (#{ secrets_file })
|
117
122
|
Run this to init only the config file: bundle exec rake tasks invar:init[config]
|
118
123
|
MSG
|
119
|
-
elsif !secrets_file
|
124
|
+
elsif !secrets_file.exist?
|
120
125
|
<<~MSG
|
121
126
|
Abort: Config file already exists (#{ config_file })
|
122
127
|
Run this to init only the secrets file: bundle exec rake tasks invar:init[secrets]
|
@@ -133,7 +138,7 @@ module Invar
|
|
133
138
|
end
|
134
139
|
|
135
140
|
# Tasks that use a namespace for file searching
|
136
|
-
class
|
141
|
+
class NamespacedFileTask
|
137
142
|
def initialize(namespace)
|
138
143
|
@locator = FileLocator.new(namespace)
|
139
144
|
end
|
@@ -150,11 +155,9 @@ module Invar
|
|
150
155
|
end
|
151
156
|
|
152
157
|
# Configuration file actions.
|
153
|
-
class
|
158
|
+
class ConfigFileHandler < NamespacedFileTask
|
154
159
|
# Creates a config file in the appropriate location
|
155
160
|
def create
|
156
|
-
raise 'File already exists' if file_path.exist?
|
157
|
-
|
158
161
|
config_dir.mkpath
|
159
162
|
file_path.write CONFIG_TEMPLATE
|
160
163
|
file_path.chmod 0o600
|
@@ -164,79 +167,108 @@ module Invar
|
|
164
167
|
|
165
168
|
# Edits the existing config file in the appropriate location
|
166
169
|
def edit
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
system(ENV.fetch('EDITOR', 'editor'), configs_file.to_s, exception: true)
|
178
|
-
|
179
|
-
warn "File saved to: #{ configs_file }"
|
170
|
+
content = $stdin.tty? ? nil : $stdin.read
|
171
|
+
file_path = configs_file
|
172
|
+
|
173
|
+
if content
|
174
|
+
file_path.write content
|
175
|
+
else
|
176
|
+
system ENV.fetch('EDITOR', 'editor'), file_path.to_s, exception: true
|
177
|
+
end
|
178
|
+
|
179
|
+
warn "File saved to: #{ file_path }"
|
180
180
|
end
|
181
181
|
|
182
182
|
private
|
183
183
|
|
184
|
+
def configs_file
|
185
|
+
@locator.find 'config.yml'
|
186
|
+
rescue ::Invar::FileLocator::FileNotFoundError => e
|
187
|
+
warn <<~ERR
|
188
|
+
Abort: #{ e.message }. Searched in: #{ @locator.search_paths.join(', ') }
|
189
|
+
#{ CREATE_SUGGESTION }
|
190
|
+
ERR
|
191
|
+
exit 1
|
192
|
+
end
|
193
|
+
|
184
194
|
def filename
|
185
195
|
'config.yml'
|
186
196
|
end
|
187
197
|
end
|
188
198
|
|
189
199
|
# Secrets file actions.
|
190
|
-
class
|
200
|
+
class SecretsFileHandler < NamespacedFileTask
|
191
201
|
# Instructions hint for how to handle secret keys.
|
192
202
|
SECRETS_INSTRUCTIONS = <<~INST
|
193
|
-
Save this key to a secure password manager
|
203
|
+
Generated key. Save this key to a secure password manager, you will need it to edit the secrets.yml file:
|
194
204
|
INST
|
195
205
|
|
196
|
-
|
197
|
-
def create
|
198
|
-
raise 'File already exists' if file_path.exist?
|
206
|
+
SWAP_EXT = 'tmp'
|
199
207
|
|
208
|
+
# Creates a new encrypted secrets file and prints the generated encryption key to STDOUT
|
209
|
+
def create(content: SECRETS_TEMPLATE)
|
200
210
|
encryption_key = Lockbox.generate_key
|
201
211
|
|
202
212
|
write_encrypted_file(file_path,
|
203
213
|
encryption_key: encryption_key,
|
204
|
-
content:
|
214
|
+
content: content,
|
205
215
|
permissions: PrivateFile::DEFAULT_PERMISSIONS)
|
206
216
|
|
207
|
-
warn "Created file: #{ file_path }"
|
208
|
-
|
209
217
|
warn SECRETS_INSTRUCTIONS
|
210
|
-
warn 'Generated key is:'
|
211
218
|
puts encryption_key
|
212
219
|
end
|
213
220
|
|
214
|
-
#
|
215
|
-
#
|
221
|
+
# Updates the file with new content.
|
222
|
+
#
|
223
|
+
# Either the content is provided over STDIN or the default editor is opened with the decrypted contents of
|
224
|
+
# the secrets file. After closing the editor, the file will be updated with the new encrypted contents.
|
216
225
|
def edit
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
warn <<~ERR
|
221
|
-
Abort: #{ e.message }. Searched in: #{ @locator.search_paths.join(', ') }
|
222
|
-
#{ CREATE_SUGGESTION }
|
223
|
-
ERR
|
224
|
-
exit 1
|
225
|
-
end
|
226
|
-
|
227
|
-
edit_encrypted_file(secrets_file)
|
226
|
+
content = $stdin.tty? ? nil : $stdin.read
|
227
|
+
|
228
|
+
edit_encrypted_file(secrets_file, content: content)
|
228
229
|
|
229
230
|
warn "File saved to #{ secrets_file }"
|
230
231
|
end
|
231
232
|
|
233
|
+
def rotate
|
234
|
+
file_path = secrets_file
|
235
|
+
|
236
|
+
decrypted = read_encrypted_file(file_path, encryption_key: determine_key(file_path))
|
237
|
+
|
238
|
+
swap_file = file_path.dirname / [file_path.basename, SWAP_EXT].join('.')
|
239
|
+
file_path.rename swap_file
|
240
|
+
|
241
|
+
begin
|
242
|
+
create content: decrypted
|
243
|
+
swap_file.delete
|
244
|
+
rescue StandardError
|
245
|
+
swap_file.rename file_path.to_s
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
232
249
|
private
|
233
250
|
|
251
|
+
def secrets_file
|
252
|
+
@locator.find 'secrets.yml'
|
253
|
+
rescue ::Invar::FileLocator::FileNotFoundError => e
|
254
|
+
warn <<~ERR
|
255
|
+
Abort: #{ e.message }. Searched in: #{ @locator.search_paths.join(', ') }
|
256
|
+
#{ CREATE_SUGGESTION }
|
257
|
+
ERR
|
258
|
+
exit 1
|
259
|
+
end
|
260
|
+
|
234
261
|
def filename
|
235
262
|
'secrets.yml'
|
236
263
|
end
|
237
264
|
|
265
|
+
def read_encrypted_file(file_path, encryption_key:)
|
266
|
+
lockbox = build_lockbox(encryption_key)
|
267
|
+
lockbox.decrypt(file_path.binread)
|
268
|
+
end
|
269
|
+
|
238
270
|
def write_encrypted_file(file_path, encryption_key:, content:, permissions: nil)
|
239
|
-
lockbox =
|
271
|
+
lockbox = build_lockbox(encryption_key)
|
240
272
|
|
241
273
|
encrypted_data = lockbox.encrypt(content)
|
242
274
|
|
@@ -244,23 +276,27 @@ module Invar
|
|
244
276
|
# TODO: replace File.opens with photo_path.binwrite(uri.data) once FakeFS can handle it
|
245
277
|
File.open(file_path.to_s, 'wb') { |f| f.write encrypted_data }
|
246
278
|
file_path.chmod permissions if permissions
|
279
|
+
|
280
|
+
warn "Saved file: #{ file_path }"
|
247
281
|
end
|
248
282
|
|
249
|
-
def edit_encrypted_file(file_path)
|
283
|
+
def edit_encrypted_file(file_path, content: nil)
|
250
284
|
encryption_key = determine_key(file_path)
|
251
285
|
|
252
|
-
|
286
|
+
content ||= invoke_editor(file_path, encryption_key: encryption_key)
|
287
|
+
|
288
|
+
write_encrypted_file(file_path, encryption_key: encryption_key, content: content)
|
289
|
+
end
|
253
290
|
|
254
|
-
|
255
|
-
|
291
|
+
def invoke_editor(file_path, encryption_key:)
|
292
|
+
Tempfile.create(file_path.basename.to_s) do |tmp_file|
|
293
|
+
decrypted = read_encrypted_file(file_path, encryption_key: encryption_key)
|
256
294
|
|
257
295
|
tmp_file.write(decrypted)
|
258
296
|
tmp_file.rewind # rewind needed because file does not get closed after write
|
259
297
|
system(ENV.fetch('EDITOR', 'editor'), tmp_file.path, exception: true)
|
260
298
|
tmp_file.read
|
261
299
|
end
|
262
|
-
|
263
|
-
write_encrypted_file(file_path, encryption_key: encryption_key, content: file_str)
|
264
300
|
end
|
265
301
|
|
266
302
|
def determine_key(file_path)
|
@@ -282,7 +318,7 @@ module Invar
|
|
282
318
|
end
|
283
319
|
|
284
320
|
# General status tasks
|
285
|
-
class
|
321
|
+
class StatusHandler < NamespacedFileTask
|
286
322
|
# Prints the current paths to be searched in
|
287
323
|
def show_paths
|
288
324
|
warn @locator.search_paths.join("\n")
|
data/lib/invar/reality.rb
CHANGED
@@ -78,8 +78,9 @@ module Invar
|
|
78
78
|
begin
|
79
79
|
@secrets = Scope.new(load_secrets(locator, decryption_keyfile || DEFAULT_KEY_FILE_NAME))
|
80
80
|
rescue FileLocator::FileNotFoundError
|
81
|
+
hint = "Create encrypted secrets.yml in one of these locations: #{ search_paths }"
|
81
82
|
raise MissingSecretsFileError,
|
82
|
-
"No Invar secrets file found.
|
83
|
+
"No Invar secrets file found. #{ hint }"
|
83
84
|
end
|
84
85
|
|
85
86
|
freeze
|
data/lib/invar/scope.rb
CHANGED
@@ -26,11 +26,9 @@ module Invar
|
|
26
26
|
alias [] fetch
|
27
27
|
|
28
28
|
def method_missing(symbol, *args)
|
29
|
-
if symbol == :pretend
|
30
|
-
|
31
|
-
|
32
|
-
super
|
33
|
-
end
|
29
|
+
raise ::Invar::ImmutableRealityError, ::Invar::ImmutableRealityError::PRETEND_MSG if symbol == :pretend
|
30
|
+
|
31
|
+
super
|
34
32
|
end
|
35
33
|
|
36
34
|
# Returns a hash representation of this scope and subscopes.
|
data/lib/invar/test.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Specifically not calling require 'invar'
|
4
|
-
#
|
3
|
+
# Specifically not calling require 'invar' in this file to force applications to need to include it themselves,
|
4
|
+
# avoiding the situation where test suites include application dependencies for them and breaking when
|
5
5
|
# the app is run without the test suite
|
6
6
|
|
7
|
+
# :nodoc:
|
7
8
|
module Invar
|
8
9
|
# Namespace module containing mixins for parts of the main gem to enable modifications and data control
|
9
10
|
# in automated testing, while remaining immutable in the main gem and real runtime usage.
|
10
11
|
module TestExtension
|
12
|
+
# Methods to extend the Reality class
|
11
13
|
module RealityMethods
|
12
14
|
class << self
|
13
15
|
attr_accessor :__after_load_hooks__
|
16
|
+
|
14
17
|
RealityMethods.__after_load_hooks__ = []
|
15
18
|
end
|
16
19
|
|
data/lib/invar/version.rb
CHANGED
data/lib/invar.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: invar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robin Miller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-schema
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- ".rspec"
|
52
52
|
- ".rubocop.yml"
|
53
53
|
- ".ruby-version"
|
54
|
+
- ".simplecov"
|
54
55
|
- CODE_OF_CONDUCT.md
|
55
56
|
- Gemfile
|
56
57
|
- LICENSE.txt
|
@@ -80,14 +81,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
81
|
requirements:
|
81
82
|
- - ">="
|
82
83
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
84
|
+
version: '3.1'
|
84
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
86
|
requirements:
|
86
87
|
- - ">="
|
87
88
|
- !ruby/object:Gem::Version
|
88
89
|
version: '0'
|
89
90
|
requirements: []
|
90
|
-
rubygems_version: 3.4.
|
91
|
+
rubygems_version: 3.4.18
|
91
92
|
signing_key:
|
92
93
|
specification_version: 4
|
93
94
|
summary: Single source of truth for environmental configuration.
|