sekrets 0.4.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.
data/README ADDED
@@ -0,0 +1,134 @@
1
+ NAME
2
+ sekrets.rb
3
+
4
+ SYNOPSIS
5
+ sekrets is a command line tool and library used to securely manage encrypted
6
+ files and settings in your rails' applications and git repositories.
7
+
8
+ INSTALL
9
+ gem install sekrets
10
+ gem 'sekrets'
11
+
12
+ DESCRIPTION
13
+ TL;DR
14
+ # create an encrypted config file
15
+
16
+ ruby -r yaml -e'puts({:api_key => 1234}.to_yaml)' | sekrets write config/settings.yml.enc --key 42
17
+
18
+ # display it
19
+
20
+ sekrets read config/settings.yml.enc --key 42
21
+
22
+ # edit it
23
+
24
+ sekrets edit config/settings.yml.enc --key 42
25
+
26
+ # see that it's encrypted
27
+
28
+ cat config/settings.yml.enc
29
+
30
+ # commit it
31
+
32
+ git add config/settings.yml.enc
33
+
34
+ # put the decryption key in a file
35
+
36
+ echo 42 > sekrets.key
37
+
38
+ # ignore this file in git
39
+
40
+ echo sekrets.key >> .gitgnore
41
+
42
+ # make sure this file gets deployed on your server
43
+
44
+ echo " require 'sekrets/capistrano' " >> Capfile
45
+
46
+ # commit and deploy
47
+
48
+ git add config/settings.yml.enc
49
+ git commit -am'encrypted settings yo'
50
+ git pull && git push && cap staging deploy
51
+
52
+ # access these settings in your application code
53
+
54
+ settings = Sekrets.settings_for('./config/settings.yml.enc')
55
+
56
+
57
+ DESCRIPTION
58
+ sekrets provides commandline tools and a library to manage and access
59
+ encrypted files in your code base.
60
+
61
+ it allows one to check encrypted infomation into a repository and to manage
62
+ it alongside the rest of the code base. it elimnates the need to check in
63
+ unencrypted information, keys, or other sensitive infomation.
64
+
65
+ sekrets provides both a general mechanism for managing arbitrary encrypted
66
+ files and a specific mechanism for managing encrypted config files.
67
+
68
+
69
+ KEY LOOKUP
70
+ for *all* operations, from the command line or otherwise, sekrets uses the
71
+ following algorithm to search for a decryption key:
72
+
73
+ - any key passed directly as a parameter to a library call will be preferred
74
+
75
+ - otherwise the code looks for a companion key file. for example, given the
76
+ file 'config/sekrets.yml.enc' sekrets will look for a key at
77
+
78
+ config/sekrets.yml.enc.key
79
+
80
+ and
81
+
82
+ config/sekrets.yml.enc.k
83
+
84
+ if either of these is found to be non-empty the contents of the file will
85
+ be used as the decryption key for that file. you should *never* commit
86
+ these key files and also add them to your .gitignore - or similar.
87
+
88
+ - next a project key file is looked for. the path of this file is
89
+
90
+ ./sekrets.key
91
+
92
+ normally and, in a rails' application
93
+
94
+ RAILS_ROOT/sekrets.key
95
+
96
+ - if that is not found sekrets looks for the key in the environment under
97
+ the env var
98
+
99
+ SEKRETS_KEY
100
+
101
+ the env var used is configurable in the library
102
+
103
+ - next the global key file is search for, the path of this file is
104
+
105
+ ~/.sekrets.key
106
+
107
+ - finally, if no key has yet been specified or found, the user is prompted
108
+ to input the key. prompt only occurs if the user us attached to a tty.
109
+ so, for example, no prompt will hang and application being started in the
110
+ background such as a rails' application being managed by passenger.
111
+
112
+
113
+ see Sekrets.key_for for more details
114
+
115
+ KEY DISTRIBUTION
116
+ sekrets does *not* attempt to solve the key distribution problem for you,
117
+ with one exception:
118
+
119
+ if you are using capistrano to do a 'vanilla' ssh based deploy a simple
120
+ recipe is provided which will detect a local keyfile and scp it onto the
121
+ remote server(s) on deploy.
122
+
123
+ sekrets assumes that the local keyfile, if it exists, is correct.
124
+
125
+ in plain english the capistrano recipe does:
126
+
127
+ scp ./sekrets.key deploy@remote.host.com:/rails_root/current/sekrets.key
128
+
129
+ it goes without saying that the local keyfile should *never* be checked in
130
+ and also should be in .gitignore
131
+
132
+ distribution of this key among developers is outside the scope of the
133
+ library. likely unencrypted email is the best mechanism for distribution
134
+ ;-/
data/Rakefile ADDED
@@ -0,0 +1,390 @@
1
+ This.rubyforge_project = 'codeforpeople'
2
+ This.author = "Ara T. Howard"
3
+ This.email = "ara.t.howard@gmail.com"
4
+ This.homepage = "https://github.com/ahoward/#{ This.lib }"
5
+
6
+
7
+ task :default do
8
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
9
+ end
10
+
11
+ task :test do
12
+ run_tests!
13
+ end
14
+
15
+ namespace :test do
16
+ task(:unit){ run_tests!(:unit) }
17
+ task(:functional){ run_tests!(:functional) }
18
+ task(:integration){ run_tests!(:integration) }
19
+ end
20
+
21
+ def run_tests!(which = nil)
22
+ which ||= '**'
23
+ test_dir = File.join(This.dir, "test")
24
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
25
+ test_rbs = Dir.glob(test_glob).sort
26
+
27
+ div = ('=' * 119)
28
+ line = ('-' * 119)
29
+
30
+ test_rbs.each_with_index do |test_rb, index|
31
+ testno = index + 1
32
+ command = "#{ File.basename(This.ruby) } -I ./lib -I ./test/lib #{ test_rb }"
33
+
34
+ puts
35
+ say(div, :color => :cyan, :bold => true)
36
+ say("@#{ testno } => ", :bold => true, :method => :print)
37
+ say(command, :color => :cyan, :bold => true)
38
+ say(line, :color => :cyan, :bold => true)
39
+
40
+ system(command)
41
+
42
+ say(line, :color => :cyan, :bold => true)
43
+
44
+ status = $?.exitstatus
45
+
46
+ if status.zero?
47
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
48
+ say("SUCCESS", :color => :green, :bold => true)
49
+ else
50
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
51
+ say("FAILURE", :color => :red, :bold => true)
52
+ end
53
+ say(line, :color => :cyan, :bold => true)
54
+
55
+ exit(status) unless status.zero?
56
+ end
57
+ end
58
+
59
+
60
+ task :gemspec do
61
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
62
+ ignore_directories = ['pkg', 'db']
63
+ ignore_files = ['test/log', 'test/db.yml', 'a.rb', 'b.rb'] + Dir['db/*'] + %w'db'
64
+
65
+ shiteless =
66
+ lambda do |list|
67
+ list.delete_if do |entry|
68
+ next unless test(?e, entry)
69
+ extension = File.basename(entry).split(%r/[.]/).last
70
+ ignore_extensions.any?{|ext| ext === extension}
71
+ end
72
+ list.delete_if do |entry|
73
+ next unless test(?d, entry)
74
+ dirname = File.expand_path(entry)
75
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
76
+ end
77
+ list.delete_if do |entry|
78
+ next unless test(?f, entry)
79
+ filename = File.expand_path(entry)
80
+ ignore_files.any?{|file| File.expand_path(file) == filename}
81
+ end
82
+ end
83
+
84
+ lib = This.lib
85
+ object = This.object
86
+ version = This.version
87
+ files = shiteless[Dir::glob("**/**")]
88
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
89
+ #has_rdoc = true #File.exist?('doc')
90
+ test_files = test(?e, "test/#{ lib }.rb") ? "test/#{ lib }.rb" : nil
91
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
92
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
93
+
94
+ if This.extensions.nil?
95
+ This.extensions = []
96
+ extensions = This.extensions
97
+ %w( Makefile configure extconf.rb ).each do |ext|
98
+ extensions << ext if File.exists?(ext)
99
+ end
100
+ end
101
+ extensions = [extensions].flatten.compact
102
+
103
+ # TODO
104
+ if This.dependencies.nil?
105
+ dependencies = []
106
+ else
107
+ case This.dependencies
108
+ when Hash
109
+ dependencies = This.dependencies.values
110
+ when Array
111
+ dependencies = This.dependencies
112
+ end
113
+ end
114
+
115
+ template =
116
+ if test(?e, 'gemspec.erb')
117
+ Template{ IO.read('gemspec.erb') }
118
+ else
119
+ Template {
120
+ <<-__
121
+ ## <%= lib %>.gemspec
122
+ #
123
+
124
+ Gem::Specification::new do |spec|
125
+ spec.name = <%= lib.inspect %>
126
+ spec.version = <%= version.inspect %>
127
+ spec.platform = Gem::Platform::RUBY
128
+ spec.summary = <%= lib.inspect %>
129
+ spec.description = <%= description.inspect %>
130
+
131
+ spec.files =\n<%= files.sort.pretty_inspect %>
132
+ spec.executables = <%= executables.inspect %>
133
+
134
+ spec.require_path = "lib"
135
+
136
+ spec.test_files = <%= test_files.inspect %>
137
+
138
+ <% dependencies.each do |lib_version| %>
139
+ spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
140
+ <% end %>
141
+
142
+ spec.extensions.push(*<%= extensions.inspect %>)
143
+
144
+ spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
145
+ spec.author = <%= This.author.inspect %>
146
+ spec.email = <%= This.email.inspect %>
147
+ spec.homepage = <%= This.homepage.inspect %>
148
+ end
149
+ __
150
+ }
151
+ end
152
+
153
+ Fu.mkdir_p(This.pkgdir)
154
+ gemspec = "#{ lib }.gemspec"
155
+ open(gemspec, "w"){|fd| fd.puts(template)}
156
+ This.gemspec = gemspec
157
+ end
158
+
159
+ task :gem => [:clean, :gemspec] do
160
+ Fu.mkdir_p(This.pkgdir)
161
+ before = Dir['*.gem']
162
+ cmd = "gem build #{ This.gemspec }"
163
+ `#{ cmd }`
164
+ after = Dir['*.gem']
165
+ gem = ((after - before).first || after.first) or abort('no gem!')
166
+ Fu.mv(gem, This.pkgdir)
167
+ This.gem = File.join(This.pkgdir, File.basename(gem))
168
+ end
169
+
170
+ task :readme do
171
+ samples = ''
172
+ prompt = '~ > '
173
+ lib = This.lib
174
+ version = This.version
175
+
176
+ Dir['sample*/*'].sort.each do |sample|
177
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
178
+
179
+ cmd = "cat #{ sample }"
180
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
181
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
182
+
183
+ cmd = "ruby #{ sample }"
184
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
185
+
186
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
187
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
188
+ end
189
+
190
+ template =
191
+ if test(?e, 'readme.erb')
192
+ Template{ IO.read('readme.erb') }
193
+ else
194
+ Template {
195
+ <<-__
196
+ NAME
197
+ #{ lib }
198
+
199
+ DESCRIPTION
200
+
201
+ INSTALL
202
+ gem install #{ lib }
203
+
204
+ SAMPLES
205
+ #{ samples }
206
+ __
207
+ }
208
+ end
209
+
210
+ open("README", "w"){|fd| fd.puts template}
211
+ end
212
+
213
+
214
+ task :clean do
215
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
216
+ end
217
+
218
+
219
+ task :release => [:clean, :gemspec, :gem] do
220
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
221
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
222
+ raise "no gems?" if gems.size < 1
223
+
224
+ cmd = "gem push #{ This.gem }"
225
+ puts cmd
226
+ puts
227
+ system(cmd)
228
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
229
+
230
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
231
+ puts cmd
232
+ puts
233
+ system(cmd)
234
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
235
+ end
236
+
237
+
238
+
239
+
240
+
241
+ BEGIN {
242
+ # support for this rakefile
243
+ #
244
+ $VERBOSE = nil
245
+
246
+ require 'ostruct'
247
+ require 'erb'
248
+ require 'fileutils'
249
+ require 'rbconfig'
250
+ require 'pp'
251
+
252
+ # fu shortcut
253
+ #
254
+ Fu = FileUtils
255
+
256
+ # cache a bunch of stuff about this rakefile/environment
257
+ #
258
+ This = OpenStruct.new
259
+
260
+ This.file = File.expand_path(__FILE__)
261
+ This.dir = File.dirname(This.file)
262
+ This.pkgdir = File.join(This.dir, 'pkg')
263
+
264
+ # grok lib
265
+ #
266
+ lib = ENV['LIB']
267
+ unless lib
268
+ lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
269
+ end
270
+ This.lib = lib
271
+
272
+ # grok version
273
+ #
274
+ version = ENV['VERSION']
275
+ unless version
276
+ require "./lib/#{ This.lib }"
277
+ This.name = lib.capitalize
278
+ This.object = eval(This.name)
279
+ version = This.object.send(:version)
280
+ end
281
+ This.version = version
282
+
283
+ # see if dependencies are export by the module
284
+ #
285
+ if This.object.respond_to?(:dependencies)
286
+ This.dependencies = This.object.dependencies
287
+ end
288
+
289
+ # we need to know the name of the lib an it's version
290
+ #
291
+ abort('no lib') unless This.lib
292
+ abort('no version') unless This.version
293
+
294
+ # discover full path to this ruby executable
295
+ #
296
+ c = Config::CONFIG
297
+ bindir = c["bindir"] || c['BINDIR']
298
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
299
+ ruby_ext = c['EXEEXT'] || ''
300
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
301
+ This.ruby = ruby
302
+
303
+ # some utils
304
+ #
305
+ module Util
306
+ def indent(s, n = 2)
307
+ s = unindent(s)
308
+ ws = ' ' * n
309
+ s.gsub(%r/^/, ws)
310
+ end
311
+
312
+ def unindent(s)
313
+ indent = nil
314
+ s.each_line do |line|
315
+ next if line =~ %r/^\s*$/
316
+ indent = line[%r/^\s*/] and break
317
+ end
318
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
319
+ end
320
+ extend self
321
+ end
322
+
323
+ # template support
324
+ #
325
+ class Template
326
+ def initialize(&block)
327
+ @block = block
328
+ @template = block.call.to_s
329
+ end
330
+ def expand(b=nil)
331
+ ERB.new(Util.unindent(@template)).result((b||@block).binding)
332
+ end
333
+ alias_method 'to_s', 'expand'
334
+ end
335
+ def Template(*args, &block) Template.new(*args, &block) end
336
+
337
+ # colored console output support
338
+ #
339
+ This.ansi = {
340
+ :clear => "\e[0m",
341
+ :reset => "\e[0m",
342
+ :erase_line => "\e[K",
343
+ :erase_char => "\e[P",
344
+ :bold => "\e[1m",
345
+ :dark => "\e[2m",
346
+ :underline => "\e[4m",
347
+ :underscore => "\e[4m",
348
+ :blink => "\e[5m",
349
+ :reverse => "\e[7m",
350
+ :concealed => "\e[8m",
351
+ :black => "\e[30m",
352
+ :red => "\e[31m",
353
+ :green => "\e[32m",
354
+ :yellow => "\e[33m",
355
+ :blue => "\e[34m",
356
+ :magenta => "\e[35m",
357
+ :cyan => "\e[36m",
358
+ :white => "\e[37m",
359
+ :on_black => "\e[40m",
360
+ :on_red => "\e[41m",
361
+ :on_green => "\e[42m",
362
+ :on_yellow => "\e[43m",
363
+ :on_blue => "\e[44m",
364
+ :on_magenta => "\e[45m",
365
+ :on_cyan => "\e[46m",
366
+ :on_white => "\e[47m"
367
+ }
368
+ def say(phrase, *args)
369
+ options = args.last.is_a?(Hash) ? args.pop : {}
370
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
371
+ keys = options.keys
372
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
373
+
374
+ color = options[:color]
375
+ bold = options.has_key?(:bold)
376
+
377
+ parts = [phrase]
378
+ parts.unshift(This.ansi[color]) if color
379
+ parts.unshift(This.ansi[:bold]) if bold
380
+ parts.push(This.ansi[:clear]) if parts.size > 1
381
+
382
+ method = options[:method] || :puts
383
+
384
+ Kernel.send(method, parts.join)
385
+ end
386
+
387
+ # always run out of the project dir
388
+ #
389
+ Dir.chdir(This.dir)
390
+ }