chamber 2.10.1 → 2.10.2

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/chamber/encryption_methods/none.rb +2 -0
  5. data/lib/chamber/version.rb +1 -1
  6. metadata +22 -99
  7. metadata.gz.sig +0 -0
  8. data/spec/fixtures/settings.yml +0 -28
  9. data/spec/lib/chamber/commands/files_spec.rb +0 -24
  10. data/spec/lib/chamber/commands/heroku/clear_spec.rb +0 -12
  11. data/spec/lib/chamber/commands/heroku/compare_spec.rb +0 -12
  12. data/spec/lib/chamber/commands/heroku/pull_spec.rb +0 -12
  13. data/spec/lib/chamber/commands/heroku/push_spec.rb +0 -12
  14. data/spec/lib/chamber/commands/secure_spec.rb +0 -42
  15. data/spec/lib/chamber/commands/show_spec.rb +0 -59
  16. data/spec/lib/chamber/context_resolver_spec.rb +0 -164
  17. data/spec/lib/chamber/file_set_spec.rb +0 -250
  18. data/spec/lib/chamber/file_spec.rb +0 -241
  19. data/spec/lib/chamber/filters/boolean_conversion_filter_spec.rb +0 -57
  20. data/spec/lib/chamber/filters/decryption_filter_spec.rb +0 -252
  21. data/spec/lib/chamber/filters/encryption_filter_spec.rb +0 -195
  22. data/spec/lib/chamber/filters/environment_filter_spec.rb +0 -48
  23. data/spec/lib/chamber/filters/failed_decryption_filter_spec.rb +0 -54
  24. data/spec/lib/chamber/filters/insecure_filter_spec.rb +0 -82
  25. data/spec/lib/chamber/filters/namespace_filter_spec.rb +0 -92
  26. data/spec/lib/chamber/filters/secure_filter_spec.rb +0 -41
  27. data/spec/lib/chamber/filters/translate_secure_keys_filter_spec.rb +0 -39
  28. data/spec/lib/chamber/namespace_set_spec.rb +0 -129
  29. data/spec/lib/chamber/settings_spec.rb +0 -390
  30. data/spec/lib/chamber/types/secured_spec.rb +0 -70
  31. data/spec/lib/chamber_spec.rb +0 -314
  32. data/spec/rails-2-test/config.ru +0 -0
  33. data/spec/rails-2-test/config/application.rb +0 -6
  34. data/spec/rails-2-test/script/console +0 -0
  35. data/spec/rails-3-test/config.ru +0 -0
  36. data/spec/rails-3-test/config/application.rb +0 -6
  37. data/spec/rails-3-test/script/rails +0 -0
  38. data/spec/rails-4-test/bin/rails +0 -0
  39. data/spec/rails-4-test/config.ru +0 -0
  40. data/spec/rails-4-test/config/application.rb +0 -6
  41. data/spec/rails-engine-test/spec/dummy/config.ru +0 -0
  42. data/spec/rails-engine-test/spec/dummy/config/application.rb +0 -5
  43. data/spec/rails-engine-test/spec/dummy/script/rails +0 -0
  44. data/spec/spec_key +0 -27
  45. data/spec/spec_key.pub +0 -9
@@ -1,250 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspectacular'
3
- require 'chamber/file_set'
4
- require 'fileutils'
5
-
6
- module Chamber
7
- describe FileSet do
8
- before(:each) do
9
- FileUtils.mkdir '/tmp/settings' unless ::File.exist? '/tmp/settings'
10
- FileUtils.mkdir '/tmp/dash-set' unless ::File.exist? '/tmp/dash-set'
11
- end
12
- after(:each) { FileUtils.rm_rf '/tmp/settings' if ::File.exist? '/tmp/settings' }
13
-
14
- it 'can consider directories containing YAML files' do
15
- ::File.new('/tmp/settings/some_settings_file.yml', 'w+')
16
- ::File.new('/tmp/settings/another_settings_file.yml', 'w+')
17
-
18
- file_set = FileSet.new files: '/tmp/settings'
19
-
20
- expect(file_set.filenames).to eql [
21
- '/tmp/settings/another_settings_file.yml',
22
- '/tmp/settings/some_settings_file.yml',
23
- ]
24
-
25
- ::FileUtils.rm_rf('/tmp/settings')
26
- end
27
-
28
- it 'can consider globs of files' do
29
- ::File.new('/tmp/settings/some_settings_file.yml', 'w+')
30
- ::File.new('/tmp/settings/another_settings_file.yml', 'w+')
31
-
32
- file_set = FileSet.new files: '/tmp/settings/*.yml'
33
-
34
- expect(file_set.filenames).to eql [
35
- '/tmp/settings/another_settings_file.yml',
36
- '/tmp/settings/some_settings_file.yml',
37
- ]
38
-
39
- ::FileUtils.rm_rf('/tmp/settings')
40
- end
41
-
42
- it 'will process both *.yml and *.yml.erb files by default' do
43
- ::File.new('/tmp/settings/some_settings_file.yml', 'w+')
44
- ::File.new('/tmp/settings/another_settings_file.yml.erb', 'w+')
45
-
46
- file_set = FileSet.new files: '/tmp/settings'
47
-
48
- expect(file_set.filenames).to eql [
49
- '/tmp/settings/another_settings_file.yml.erb',
50
- '/tmp/settings/some_settings_file.yml',
51
- ]
52
-
53
- ::FileUtils.rm_rf('/tmp/settings')
54
- end
55
-
56
- it 'can consider namespaced files' do
57
- ::File.new('/tmp/settings/settings-blue.yml', 'w+')
58
-
59
- file_set = FileSet.new files: '/tmp/settings/settings-blue.yml',
60
- namespaces: ['blue']
61
-
62
- expect(file_set.filenames).to eql [
63
- '/tmp/settings/settings-blue.yml',
64
- ]
65
-
66
- ::FileUtils.rm_f('/tmp/settings/settings-blue.yml')
67
- end
68
-
69
- it 'does not consider namespaced files which are not relevant' do
70
- ::File.new('/tmp/settings/settings-blue.yml', 'w+')
71
-
72
- file_set = FileSet.new files: '/tmp/settings/settings-blue.yml',
73
- namespaces: ['green']
74
-
75
- expect(file_set.filenames).to be_empty
76
-
77
- ::FileUtils.rm_f('/tmp/settings/settings-blue.yml')
78
- end
79
-
80
- it 'does not consider non-namespaced files which have dashes in their paths as ' \
81
- 'namespaced' do
82
-
83
- ::File.new('/tmp/dash-set/settings.yml', 'w+')
84
-
85
- file_set = FileSet.new files: '/tmp/dash-set/settings*.yml',
86
- namespaces: ['blue']
87
-
88
- expect(file_set.filenames).to eql [
89
- '/tmp/dash-set/settings.yml',
90
- ]
91
-
92
- ::FileUtils.rm_r('/tmp/dash-set/settings.yml')
93
- end
94
-
95
- it 'removes any duplicate files' do
96
- ::File.new('/tmp/settings.yml', 'w+')
97
-
98
- file_set = FileSet.new files: [
99
- '/tmp/settings.yml',
100
- '/tmp/settings.yml',
101
- ]
102
-
103
- expect(file_set.filenames).to eql [
104
- '/tmp/settings.yml',
105
- ]
106
-
107
- ::FileUtils.rm_f('/tmp/settings.yml')
108
- end
109
-
110
- it 'can consider multiple file paths' do
111
- ::File.new('/tmp/settings.yml', 'w+')
112
- ::File.new('/tmp/settings/new_file.yml', 'w+')
113
-
114
- file_set = FileSet.new files: [
115
- '/tmp/settings.yml',
116
- '/tmp/settings/*.yml',
117
- ]
118
-
119
- expect(file_set.filenames).to eql [
120
- '/tmp/settings.yml',
121
- '/tmp/settings/new_file.yml',
122
- ]
123
-
124
- ::FileUtils.rm_rf('/tmp/settings*')
125
- end
126
-
127
- it 'can consider file paths as Pathnames' do
128
- ::File.new('/tmp/settings.yml', 'w+')
129
-
130
- file_set = FileSet.new files: '/tmp/settings.yml'
131
-
132
- expect(file_set.filenames).to eql [
133
- '/tmp/settings.yml',
134
- ]
135
-
136
- ::FileUtils.rm_rf('/tmp/settings*')
137
- end
138
-
139
- it 'can consider multiple namespaced files in the order the namespaces are specified' do
140
- ::File.new('/tmp/settings/settings-blue.yml', 'w+')
141
- ::File.new('/tmp/settings/settings-green.yml', 'w+')
142
-
143
- file_set = FileSet.new files: '/tmp/settings/settings*.yml',
144
- namespaces: %w{blue green}
145
-
146
- expect(file_set.filenames).to eql [
147
- '/tmp/settings/settings-blue.yml',
148
- '/tmp/settings/settings-green.yml',
149
- ]
150
-
151
- file_set = FileSet.new files: '/tmp/settings/settings*.yml',
152
- namespaces: %w{green blue}
153
-
154
- expect(file_set.filenames).to eql [
155
- '/tmp/settings/settings-green.yml',
156
- '/tmp/settings/settings-blue.yml',
157
- ]
158
-
159
- ::FileUtils.rm_f('/tmp/settings/settings*.yml')
160
- end
161
-
162
- it 'considers the generic file prior to any namespaced files' do
163
- ::File.new('/tmp/settings.yml', 'w+')
164
- ::File.new('/tmp/settings-blue.yml', 'w+')
165
-
166
- file_set = FileSet.new files: '/tmp/settings*.yml',
167
- namespaces: ['blue']
168
-
169
- expect(file_set.filenames).to eql [
170
- '/tmp/settings.yml',
171
- '/tmp/settings-blue.yml',
172
- ]
173
-
174
- ::FileUtils.rm_f('/tmp/settings*.yml')
175
- end
176
-
177
- it 'considers the generic file prior to any namespaced files' do
178
- ::File.new('/tmp/settings.yml', 'w+')
179
- ::File.new('/tmp/settings-blue.yml', 'w+')
180
-
181
- file_set = FileSet.new files: '/tmp/settings*.yml',
182
- namespaces: ['blue']
183
-
184
- expect(file_set.filenames).to eql [
185
- '/tmp/settings.yml',
186
- '/tmp/settings-blue.yml',
187
- ]
188
-
189
- ::FileUtils.rm_f('/tmp/settings*.yml')
190
- end
191
-
192
- it 'considers each glob independently, placing non-namespaced and namespaced ' \
193
- 'versions of the globs files above those in subsequent globs' do
194
-
195
- ::File.new('/tmp/settings/credentials-development.yml', 'w+')
196
- ::File.new('/tmp/settings/settings.yml', 'w+')
197
-
198
- file_set = FileSet.new files: [
199
- '/tmp/settings/credentials*.yml',
200
- '/tmp/settings/settings*.yml',
201
- ],
202
- namespaces: ['development']
203
-
204
- expect(file_set.filenames).to eql [
205
- '/tmp/settings/credentials-development.yml',
206
- '/tmp/settings/settings.yml',
207
- ]
208
-
209
- ::FileUtils.rm_rf('/tmp/settings')
210
- end
211
-
212
- it 'can display the filenames which were considered for the settings values' do
213
- ::File.new('/tmp/settings/some_settings_file.yml', 'w+')
214
- ::File.new('/tmp/settings/another_settings_file.yml', 'w+')
215
-
216
- file_set = FileSet.new files: '/tmp/settings/*.yml'
217
-
218
- expect(file_set.filenames).to eql [
219
- '/tmp/settings/another_settings_file.yml',
220
- '/tmp/settings/some_settings_file.yml',
221
- ]
222
-
223
- ::FileUtils.rm_rf('/tmp/settings')
224
- end
225
-
226
- it "can yield each file's settings when converting" do
227
- ::File.new('/tmp/settings.yml', 'w+')
228
-
229
- file_set = FileSet.new files: '/tmp/settings.yml'
230
-
231
- file_set.to_settings do |settings|
232
- expect(settings).to eql Settings.new
233
- end
234
-
235
- ::FileUtils.rm_f('/tmp/settings.yml')
236
- end
237
-
238
- it 'can convert settings without yielding to the block by using an intermediate ' \
239
- 'settings object' do
240
-
241
- ::File.new('/tmp/settings.yml', 'w+')
242
-
243
- file_set = FileSet.new files: '/tmp/settings.yml'
244
-
245
- expect(file_set.to_settings).to eql Settings.new
246
-
247
- ::FileUtils.rm_f('/tmp/settings.yml')
248
- end
249
- end
250
- end
@@ -1,241 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'rspectacular'
3
- require 'chamber/file'
4
- require 'chamber/settings'
5
- require 'chamber/filters/encryption_filter'
6
- require 'tempfile'
7
-
8
- # rubocop:disable Metrics/LineLength
9
- def create_tempfile_with_content(content)
10
- tempfile = Tempfile.new('settings')
11
- tempfile.puts content
12
- tempfile.rewind
13
- tempfile
14
- end
15
-
16
- module Chamber
17
- describe File do
18
- it 'can convert file contents to settings' do
19
- tempfile = create_tempfile_with_content '{ test: settings }'
20
- settings_file = File.new path: tempfile.path
21
-
22
- allow(Settings).to receive(:new).
23
- and_return :settings
24
-
25
- file_settings = settings_file.to_settings
26
-
27
- expect(file_settings).to eql :settings
28
- expect(Settings).to have_received(:new).
29
- with(settings: { 'test' => 'settings' },
30
- namespaces: {},
31
- decryption_key: nil,
32
- encryption_key: nil)
33
- end
34
-
35
- it 'can convert a file whose contents are empty' do
36
- tempfile = create_tempfile_with_content ''
37
- settings_file = File.new path: tempfile.path
38
-
39
- allow(Settings).to receive(:new).
40
- and_return :settings
41
-
42
- file_settings = settings_file.to_settings
43
-
44
- expect(file_settings).to eql :settings
45
- expect(Settings).to have_received(:new).
46
- with(settings: {},
47
- namespaces: {},
48
- decryption_key: nil,
49
- encryption_key: nil)
50
- end
51
-
52
- it 'throws an error when the file contents are malformed' do
53
- tempfile = create_tempfile_with_content '{ test : '
54
- settings_file = File.new path: tempfile.path
55
-
56
- expect { settings_file.to_settings }.to raise_error
57
- end
58
-
59
- it 'passes any namespaces through to the settings' do
60
- tempfile = create_tempfile_with_content '{ test: settings }'
61
- settings_file = File.new path: tempfile.path,
62
- namespaces: {
63
- environment: :development,
64
- }
65
-
66
- allow(Settings).to receive(:new)
67
-
68
- settings_file.to_settings
69
-
70
- expect(Settings).to have_received(:new).
71
- with(settings: { 'test' => 'settings' },
72
- namespaces: {
73
- environment: :development,
74
- },
75
- decryption_key: nil,
76
- encryption_key: nil)
77
- end
78
-
79
- it 'can handle files which contain ERB markup' do
80
- tempfile = create_tempfile_with_content '{ test: <%= 1 + 1 %> }'
81
- settings_file = File.new path: tempfile.path
82
-
83
- allow(Settings).to receive(:new)
84
-
85
- settings_file.to_settings
86
- expect(Settings).to have_received(:new).
87
- with(settings: { 'test' => 2 },
88
- namespaces: {},
89
- decryption_key: nil,
90
- encryption_key: nil)
91
- end
92
-
93
- it 'does not throw an error when attempting to convert a file which does not exist' do
94
- settings_file = File.new path: 'no/path'
95
-
96
- allow(Settings).to receive(:new).
97
- and_return :settings
98
-
99
- file_settings = settings_file.to_settings
100
-
101
- expect(file_settings).to eql :settings
102
- expect(Settings).to have_received(:new).
103
- with(settings: {},
104
- namespaces: {},
105
- decryption_key: nil,
106
- encryption_key: nil)
107
- end
108
-
109
- it 'can securely encrypt the settings contained in a file' do
110
- tempfile = create_tempfile_with_content <<-HEREDOC
111
- _secure_setting: hello
112
- HEREDOC
113
- settings_file = File.new path: tempfile.path,
114
- encryption_key: './spec/spec_key.pub'
115
-
116
- settings_file.secure
117
-
118
- settings_file = File.new path: tempfile.path
119
-
120
- expect(settings_file.to_settings.__send__(:raw_data)['_secure_setting']).to match Filters::EncryptionFilter::BASE64_STRING_PATTERN
121
- end
122
-
123
- it 'does not encrypt the settings contained in a file which are already secure' do
124
- tempfile = create_tempfile_with_content <<-HEREDOC
125
- _secure_setting: hello
126
- _secure_other_setting: g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBUKlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPOaDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6RrmydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpINA6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw==
127
- HEREDOC
128
-
129
- settings_file = File.new path: tempfile.path,
130
- encryption_key: './spec/spec_key.pub'
131
-
132
- settings_file.secure
133
-
134
- settings_file = File.new path: tempfile.path
135
- raw_data = settings_file.to_settings.__send__(:raw_data)
136
- secure_setting = raw_data['_secure_setting']
137
- other_secure_setting = raw_data['_secure_other_setting']
138
-
139
- expect(secure_setting).to match Filters::EncryptionFilter::BASE64_STRING_PATTERN
140
- expect(other_secure_setting).to eql 'g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBU' \
141
- 'KlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPO' \
142
- 'aDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6Rrm' \
143
- 'ydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+' \
144
- 'eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpIN' \
145
- 'A6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8' \
146
- 'uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x' \
147
- '+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw=='
148
- end
149
-
150
- it 'does not rewrite the entire file but only the encrypted settings' do
151
- tempfile = create_tempfile_with_content <<-HEREDOC
152
- default:
153
- stuff: &default
154
- _secure_setting: hello
155
- _secure_other_setting: g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBUKlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPOaDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6RrmydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpINA6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw==
156
-
157
- other:
158
- stuff:
159
- <<: *default
160
- _secure_another_setting: "Thanks for all the fish"
161
- regular_setting: <%= 1 + 1 %>
162
- HEREDOC
163
-
164
- settings_file = File.new path: tempfile.path,
165
- encryption_key: './spec/spec_key.pub'
166
-
167
- settings_file.secure
168
-
169
- file_contents = ::File.read(tempfile.path)
170
- secure_setting_encoded = file_contents[%r{ _secure_setting: ([A-Za-z0-9\+/]{342}==)$}, 1]
171
- secure_another_setting_encoded = file_contents[%r{ _secure_another_setting: ([A-Za-z0-9\+/]{342}==)$}, 1]
172
-
173
- expect(::File.read(tempfile.path)).to eql <<-HEREDOC
174
- default:
175
- stuff: &default
176
- _secure_setting: #{secure_setting_encoded}
177
- _secure_other_setting: g4ryOaWniDPht0x1pW10XWgtC7Bax2yQAM3+p9ZDMmBUKlVXgvCn8MvdvciX0126P7uuLylY7Pdbm8AnpjeaTvPOaDnDjPATkH1xpQG/HKBy+7zd67SMb3tJ3sxJNkYm6RrmydFHkDCghG37lvCnuZs1Jvd/mhpr/+thqKvtI+c/vzY+eFxM52lnoWWOgqwGCtUjb+PMbq+HjId6X8uRbpL1SpINA6WYJwvxTVK9XD/HYn67Fcqdova4dEHoqwzFfE+XVXM8uesE1DG3PFNhAzkT+mWXtBmo17i+K4wrOO06I13uDS3x+7LqoZz/Ez17SPXRJze4M/wyWfm43pnuVw==
178
-
179
- other:
180
- stuff:
181
- <<: *default
182
- _secure_another_setting: #{secure_another_setting_encoded}
183
- regular_setting: <%= 1 + 1 %>
184
- HEREDOC
185
- end
186
-
187
- it 'can handle encrypting multiline strings' do
188
- tempfile = create_tempfile_with_content <<-HEREDOC
189
- other:
190
- stuff:
191
- _secure_setting: |
192
- -----BEGIN RSA PRIVATE KEY-----
193
- uQ431irYF7XGEwmsfNUcw++6Enjmt9MItVZJrfL4cUr84L1ccOEX9AThsxz2nkiO
194
- GgU+HtwwueZDUZ8Pdn71+1CdVaSUeEkVaYKYuHwYVb1spGfreHQHRP90EMv3U5Ir
195
- xs0YFwKBgAJKGol+GM1oFodg48v4QA6hlF5z49v83wU+AS2f3aMVfjkTYgAEAoCT
196
- qoSi7wkYK3NvftVgVi8Z2+1WEzp3S590UkkHmjc5o+HfS657v2fnqkekJyinB+OH
197
- b5tySsPxt/3Un4D9EaGhjv44GMvL54vFI1Sqc8RsF/H8lRvj5ai5
198
- -----END RSA PRIVATE KEY-----
199
- something_else: 'right here'
200
- HEREDOC
201
-
202
- settings_file = File.new path: tempfile.path,
203
- encryption_key: './spec/spec_key.pub'
204
-
205
- settings_file.secure
206
-
207
- file_contents = ::File.read(tempfile.path)
208
- secure_setting_encoded = file_contents[/ _secure_setting: (.*)$/, 1]
209
-
210
- expect(::File.read(tempfile.path)).to eql <<-HEREDOC
211
- other:
212
- stuff:
213
- _secure_setting: #{secure_setting_encoded}
214
- something_else: 'right here'
215
- HEREDOC
216
- end
217
-
218
- it 'when rewriting the file, can handle names and values with regex special ' \
219
- 'characters' do
220
-
221
- tempfile = create_tempfile_with_content <<-HEREDOC
222
- stuff:
223
- _secure_another+_setting: "Thanks for +all the fish"
224
- HEREDOC
225
-
226
- settings_file = File.new path: tempfile.path,
227
- encryption_key: './spec/spec_key.pub'
228
-
229
- settings_file.secure
230
-
231
- file_contents = ::File.read(tempfile.path)
232
- secure_another_setting_encoded = file_contents[%r{ _secure_another\+_setting: ([A-Za-z0-9\+/]{342}==)$}, 1]
233
-
234
- expect(::File.read(tempfile.path)).to eql <<-HEREDOC
235
- stuff:
236
- _secure_another+_setting: #{secure_another_setting_encoded}
237
- HEREDOC
238
- end
239
- end
240
- end
241
- # rubocop:enable Metrics/LineLength