heirloom 0.9.0 → 0.10.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.
@@ -0,0 +1,11 @@
1
+ module Stackster
2
+ module Exceptions
3
+ class Base < RuntimeError
4
+ attr_accessor :message
5
+
6
+ def initialize(message="")
7
+ @message = message
8
+ end
9
+ end
10
+ end
11
+ end
@@ -9,48 +9,59 @@ module Heirloom
9
9
  end
10
10
 
11
11
  def upload_file(args)
12
- bucket = args[:bucket]
13
- file = args[:file]
14
- id = args[:id]
15
- key_name = args[:key_name]
16
- key_folder = args[:key_folder]
17
- name = args[:name]
12
+ bucket = args[:bucket]
13
+ file = args[:file]
14
+ id = args[:id]
15
+ key_name = args[:key_name]
16
+ key_folder = args[:key_folder]
17
+ name = args[:name]
18
18
  public_readable = args[:public_readable]
19
19
 
20
+ body = File.open file
20
21
  s3_bucket = s3.get_bucket bucket
21
22
 
22
23
  @logger.info "Uploading s3://#{bucket}/#{key_folder}/#{key_name}"
23
24
 
24
25
  s3_bucket.files.create :key => "#{key_folder}/#{key_name}",
25
- :body => File.open(file),
26
+ :body => body,
26
27
  :public => public_readable
28
+ @logger.warn "File is readable by entire Internet." if public_readable
27
29
 
28
- @logger.info "File is readable by the public internet." if public_readable
30
+ body.close
29
31
  end
30
32
 
31
33
  def add_endpoint_attributes(args)
32
- bucket = args[:bucket]
33
- id = args[:id]
34
- name = args[:name]
35
- domain = "heirloom_#{name}"
34
+ bucket = args[:bucket]
35
+ id = args[:id]
36
+ name = args[:name]
37
+ key_name = args[:key_name]
38
+
39
+ domain = "heirloom_#{name}"
36
40
  key_folder = name
37
- key_name = "#{id}.tar.gz"
41
+ endpoint = endpoints[@region]
38
42
 
39
- s3_endpoint = "s3://#{bucket}/#{key_folder}/#{key_name}"
40
- http_endpoint = "http://#{endpoints[@region]}/#{bucket}/#{key_folder}/#{key_name}"
41
- https_endpoint = "https://#{endpoints[@region]}/#{bucket}/#{key_folder}/#{key_name}"
43
+ path = "#{bucket}/#{key_folder}/#{key_name}"
42
44
 
43
- sdb.put_attributes domain, id, { "#{@region}-s3-url" => s3_endpoint }
44
- @logger.info "Adding attribute #{s3_endpoint}."
45
+ end_point_attributes(path).each_pair do |key, value|
46
+ add_endpoint_attribute domain, id, key, value
47
+ end
48
+ end
45
49
 
46
- sdb.put_attributes domain, id, { "#{@region}-http-url" => http_endpoint }
47
- @logger.debug "Adding attribute #{http_endpoint}."
50
+ private
48
51
 
49
- sdb.put_attributes domain, id, { "#{@region}-https-url" => https_endpoint }
50
- @logger.debug "Adding attribute #{https_endpoint}."
52
+ def end_point_attributes(path)
53
+ {
54
+ "#{@region}-s3-url" => "s3://#{path}",
55
+ "#{@region}-http-url" => "http://#{endpoints[@region]}/#{path}",
56
+ "#{@region}-https-url" => "https://#{endpoints[@region]}/#{path}"
57
+ }
51
58
  end
52
59
 
53
- private
60
+ def add_endpoint_attribute(domain, id, key, value)
61
+ sdb.put_attributes domain, id, { key => value }
62
+ @logger.debug "Adding tag #{key}."
63
+ @logger.debug "Adding tag #{value}."
64
+ end
54
65
 
55
66
  def endpoints
56
67
  {
@@ -0,0 +1 @@
1
+ require 'heirloom/utils/file'
@@ -0,0 +1,30 @@
1
+ module Heirloom
2
+ module Utils
3
+ module File
4
+
5
+ def which(cmd)
6
+ exts = pathext ? pathext.split(';') : ['']
7
+ path.split(path_separator).each do |path|
8
+ exts.each { |ext|
9
+ exe = "#{path}/#{cmd}#{ext}"
10
+ return exe if ::File.executable? exe
11
+ }
12
+ end
13
+ return nil
14
+ end
15
+
16
+ def path_separator
17
+ ::File::PATH_SEPARATOR
18
+ end
19
+
20
+ def path
21
+ ENV['PATH']
22
+ end
23
+
24
+ def pathext
25
+ ENV['PATHEXT']
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module Heirloom
2
- VERSION = "0.9.0"
2
+ VERSION = "0.10.0"
3
3
  end
data/spec/acl/s3_spec.rb CHANGED
@@ -29,7 +29,7 @@ describe Heirloom do
29
29
  with("bucket", "key-folder/key.tar.gz", {"Owner"=>{"DisplayName"=>"Brett", "ID"=>"123"}, "AccessControlList"=>[{"Grantee"=>{"EmailAddress"=>"acct1@test.com"}, "Permission"=>"READ"}, {"Grantee"=>{"EmailAddress"=>"acct2@test.com"}, "Permission"=>"READ"}, {"Grantee"=>{"DisplayName"=>"Brett", "ID"=>"123"}, "Permission"=>"FULL_CONTROL"}]})
30
30
 
31
31
  @s3.allow_read_access_from_accounts :bucket => 'bucket',
32
- :key_name => 'key',
32
+ :key_name => 'key.tar.gz',
33
33
  :key_folder => 'key-folder',
34
34
  :accounts => ['acct1@test.com', 'acct2@test.com']
35
35
  end
@@ -3,28 +3,40 @@ require 'spec_helper'
3
3
  describe Heirloom do
4
4
 
5
5
  before do
6
- @config_mock = double('config')
7
- @logger_mock = double('logger')
6
+ @config_mock = mock 'config'
7
+ @logger_mock = mock 'logger'
8
8
  @logger_mock.stub :info => true, :debug => true
9
9
  @config_mock.should_receive(:logger).and_return(@logger_mock)
10
10
  @authorizer = Heirloom::Authorizer.new :config => @config_mock,
11
11
  :name => 'tim',
12
- :id => '123'
12
+ :id => '123.tar.gz'
13
13
  end
14
14
 
15
15
  it "should authorize access to an archive in all regions" do
16
- reader = double
17
- s3_acl = double
18
- accounts = [ "test@a.com", "a@test.com", "test@test.co", "test@test.co.uk" ]
19
- @authorizer.should_receive(:reader).exactly(2).times.
20
- and_return(reader)
21
- reader.should_receive(:get_bucket).exactly(2).times.
16
+ s3_acl_mock = mock 's3 acl'
17
+ reader_mock = mock 'reader mock'
18
+ reader_mock.stub :key_name => '123.tar.gz'
19
+ reader_mock.should_receive(:get_bucket).exactly(2).times.
22
20
  and_return('the-bucket')
23
- Heirloom::ACL::S3.should_receive(:new).exactly(2).
24
- times.and_return(s3_acl)
25
- s3_acl.should_receive(:allow_read_access_from_accounts).
21
+
22
+ accounts = [ "test@a.com", "a@test.com", "test@test.co", "test@test.co.uk" ]
23
+
24
+ Heirloom::Reader.should_receive(:new).
25
+ with(:config => @config_mock,
26
+ :name => 'tim',
27
+ :id => '123.tar.gz').
28
+ and_return reader_mock
29
+ Heirloom::ACL::S3.should_receive(:new).
30
+ with(:config => @config_mock,
31
+ :region => 'us-west-1').
32
+ and_return s3_acl_mock
33
+ Heirloom::ACL::S3.should_receive(:new).
34
+ with(:config => @config_mock,
35
+ :region => 'us-west-2').
36
+ and_return s3_acl_mock
37
+ s3_acl_mock.should_receive(:allow_read_access_from_accounts).
26
38
  exactly(2).times.
27
- with(:key_name => '123',
39
+ with(:key_name => '123.tar.gz',
28
40
  :key_folder => 'tim',
29
41
  :bucket => 'the-bucket',
30
42
  :accounts => accounts)
@@ -17,7 +17,7 @@ describe Heirloom do
17
17
  @reader_mock.should_receive(:get_bucket).
18
18
  with(:region => 'us-west-1').
19
19
  and_return 'bucket-us-west-1'
20
-
20
+ @reader_mock.stub :key_name => '123.tar.gz'
21
21
 
22
22
  @s3_destroyer_mock = mock 's3 destroyer'
23
23
  Heirloom::Destroyer::S3.should_receive(:new).
@@ -85,7 +85,7 @@ describe Heirloom do
85
85
  before do
86
86
  @s3_downloader_mock.should_receive(:download_file).
87
87
  with(:bucket => 'bucket-us-west-1',
88
- :key => 'tim/123.tar.gz').
88
+ :key => 'tim/123.tar.gz.gpg').
89
89
  and_return 'encrypted_data'
90
90
  Heirloom::Cipher::Data.should_receive(:new).
91
91
  with(:config => @config_mock).
@@ -136,10 +136,10 @@ describe Heirloom do
136
136
  end
137
137
 
138
138
  it "should return false if the decrypt_data returns false" do
139
- @downloader.download(:region => 'us-west-1',
139
+ @downloader.download(:region => 'us-west-1',
140
140
  :bucket_prefix => 'bucket',
141
- :extract => false,
142
- :secret => 'badsecret').should be_false
141
+ :extract => false,
142
+ :secret => 'badsecret').should be_false
143
143
  end
144
144
 
145
145
  end
@@ -52,7 +52,7 @@ describe Heirloom do
52
52
  with("select * from `heirloom_tim` where itemName() = '123'").
53
53
  and_return( { '123' =>
54
54
  { 'us-west-1-s3-url' =>
55
- [ 's3://the-bucket/the-buck/the-key' ]
55
+ [ 's3://the-bucket/the-name/123.tar.gz' ]
56
56
  }
57
57
  } )
58
58
  @reader.get_bucket(:region => 'us-west-1').should == 'the-bucket'
@@ -80,10 +80,24 @@ describe Heirloom do
80
80
  with("select * from `heirloom_tim` where itemName() = '123'").
81
81
  and_return( { '123' =>
82
82
  { 'us-west-1-s3-url' =>
83
- ['s3://the-url/the-bucket/the-key']
83
+ ['s3://the-url/the-bucket/123.tar.gz']
84
84
  }
85
85
  } )
86
- @reader.get_key(:region => 'us-west-1').should == 'the-bucket/the-key'
86
+ @reader.get_key(:region => 'us-west-1').should == 'the-bucket/123.tar.gz'
87
+ end
88
+
89
+ it "should return the encrypted key name" do
90
+ @sdb_mock.should_receive(:select).
91
+ with("select * from `heirloom_tim` where itemName() = '123'").
92
+ and_return( { '123' => { 'encrypted' => [ 'true' ] } } )
93
+ @reader.key_name.should == '123.tar.gz.gpg'
94
+ end
95
+
96
+ it "should return the unencrypted key name" do
97
+ @sdb_mock.should_receive(:select).
98
+ with("select * from `heirloom_tim` where itemName() = '123'").
99
+ and_return( { '123' => { 'encrypted' => [ 'false' ] } } )
100
+ @reader.key_name.should == '123.tar.gz'
87
101
  end
88
102
 
89
103
  it "should return the regions the archive has been uploaded to" do
@@ -92,11 +106,11 @@ describe Heirloom do
92
106
  with("select * from `heirloom_tim` where itemName() = '123'").
93
107
  and_return( { '123' =>
94
108
  { 'us-west-1-s3-url' =>
95
- ['s3://the-url-us-west-1/the-bucket/the-key'],
109
+ ['s3://the-url-us-west-1/the-bucket/123.tar.gz'],
96
110
  'build_by' =>
97
111
  ['user'],
98
112
  'us-east-1-s3-url' =>
99
- ['s3://the-url-us-east-1/the-bucket/the-key']
113
+ ['s3://the-url-us-east-1/the-bucket/123.tar.gz']
100
114
  }
101
115
  } )
102
116
  @reader.regions.should == ['us-west-1', 'us-east-1']
@@ -3,38 +3,65 @@ require 'spec_helper'
3
3
  describe Heirloom do
4
4
 
5
5
  before do
6
- @config_mock = double 'config'
7
- @logger_mock = double 'logger'
8
- @config_mock.should_receive(:logger).and_return(@logger_mock)
6
+ @config_mock = mock 'config'
7
+ @logger_stub = stub 'logger', :info => true
8
+ @config_mock.stub :logger => @logger_stub
9
9
  @uploader = Heirloom::Uploader.new :config => @config_mock,
10
10
  :name => 'tim',
11
11
  :id => '123'
12
+ @s3_mock = mock 's3'
12
13
  end
13
14
 
14
15
  it "should upload a new archive" do
15
- s3_mock = mock 's3'
16
16
  Heirloom::Uploader::S3.should_receive(:new).
17
17
  with(:config => @config_mock,
18
- :logger => @logger_mock,
18
+ :logger => @logger_stub,
19
19
  :region => 'us-west-1').
20
- and_return s3_mock
21
- s3_mock.should_receive(:upload_file).
22
- with(:bucket => 'prefix-us-west-1',
23
- :file => '/tmp/file',
24
- :id => '123',
25
- :key_folder => 'tim',
26
- :key_name => "123.tar.gz",
27
- :name => 'tim',
28
- :public_readable => true)
29
- s3_mock.should_receive(:add_endpoint_attributes).
30
- with(:bucket => 'prefix-us-west-1',
31
- :id => '123',
32
- :name => 'tim')
33
- @logger_mock.should_receive(:info)
20
+ and_return @s3_mock
21
+ @s3_mock.should_receive(:upload_file).
22
+ with(:bucket => 'prefix-us-west-1',
23
+ :file => '/tmp/file',
24
+ :id => '123',
25
+ :key_folder => 'tim',
26
+ :key_name => "123.tar.gz",
27
+ :name => 'tim',
28
+ :public_readable => true)
29
+ @s3_mock.should_receive(:add_endpoint_attributes).
30
+ with(:bucket => 'prefix-us-west-1',
31
+ :id => '123',
32
+ :key_name => '123.tar.gz',
33
+ :name => 'tim')
34
34
  @uploader.upload :file => '/tmp/file',
35
35
  :bucket_prefix => 'prefix',
36
36
  :regions => ['us-west-1'],
37
- :public_readable => true
37
+ :public_readable => true,
38
+ :secret => nil
39
+ end
40
+
41
+ it "should upload a new archive with .gpg if secret provided" do
42
+ Heirloom::Uploader::S3.should_receive(:new).
43
+ with(:config => @config_mock,
44
+ :logger => @logger_stub,
45
+ :region => 'us-west-1').
46
+ and_return @s3_mock
47
+ @s3_mock.should_receive(:upload_file).
48
+ with(:bucket => 'prefix-us-west-1',
49
+ :file => '/tmp/file',
50
+ :id => '123',
51
+ :key_folder => 'tim',
52
+ :key_name => "123.tar.gz.gpg",
53
+ :name => 'tim',
54
+ :public_readable => true)
55
+ @s3_mock.should_receive(:add_endpoint_attributes).
56
+ with(:bucket => 'prefix-us-west-1',
57
+ :id => '123',
58
+ :key_name => '123.tar.gz.gpg',
59
+ :name => 'tim')
60
+ @uploader.upload :file => '/tmp/file',
61
+ :bucket_prefix => 'prefix',
62
+ :regions => ['us-west-1'],
63
+ :public_readable => true,
64
+ :secret => 'secret12'
38
65
  end
39
66
 
40
67
  end
@@ -2,54 +2,71 @@ require 'spec_helper'
2
2
 
3
3
  describe Heirloom do
4
4
  before do
5
+ @encrypted_file_mock = mock 'encrypted mock'
6
+ @decrypted_file_mock = mock 'decrypted mock'
7
+ @encrypted_file_mock.stub :path => '/tmp/enc'
8
+ @decrypted_file_mock.stub :path => '/tmp/dec',
9
+ :read => 'plaintext'
5
10
  @logger_mock = mock 'logger', :info => true
6
- @logger_mock.stub :info => true
11
+ @logger_mock.stub :info => true,
12
+ :debug => true
7
13
  @config_mock = mock 'config'
8
14
  @config_mock.stub :logger => @logger_mock
9
15
  @data = Heirloom::Cipher::Data.new :config => @config_mock
10
16
  end
11
17
 
12
- context "with secret given" do
13
- before do
14
- @aes_mock = mock 'aes'
15
- OpenSSL::Cipher::AES256.should_receive(:new).
16
- with(:CBC).and_return @aes_mock
17
- end
18
+ context "when succesful" do
19
+ context "with secret given" do
20
+ it "should decrypt the given data" do
21
+ @data.should_receive(:which).with('gpg').and_return true
22
+ Tempfile.should_receive(:new).with('archive.tar.gz.gpg').
23
+ and_return @encrypted_file_mock
24
+ Tempfile.should_receive(:new).with('archive.tar.gz').
25
+ and_return @decrypted_file_mock
26
+ ::File.should_receive(:open).
27
+ with(@encrypted_file_mock,'w')
28
+ $?.stub :success? => true
18
29
 
19
- it "should decrypt the given data" do
20
- @aes_mock.should_receive(:decrypt)
21
- @aes_mock.should_receive(:key=).with Digest::SHA256.hexdigest 'mysecret'
22
- @aes_mock.should_receive(:iv=).with 'firstsixteenchar'
23
- @aes_mock.should_receive(:update).with('crypteddata').and_return 'cleartext'
24
- @aes_mock.stub :final => 'final'
25
- @data.decrypt_data(:data => 'firstsixteencharcrypteddata',
26
- :secret => 'mysecret').
27
- should == 'cleartextfinal'
30
+ command = 'gpg --batch --yes --cipher-algo AES256 --passphrase password --output /tmp/dec /tmp/enc 2>&1'
31
+ @data.should_receive(:`).with(command).and_return true
32
+ @data.decrypt_data(:data => 'crypted',
33
+ :secret => 'password').should == 'plaintext'
34
+ end
28
35
  end
29
36
 
30
- it "should rescue bad key error and return false" do
31
- @logger_mock.should_receive(:error).
32
- with "Unable to decrypt Heirloom: 'OpenSSL::Cipher::CipherError'"
33
- @aes_mock.should_receive(:decrypt)
34
- @aes_mock.should_receive(:key=).with Digest::SHA256.hexdigest 'badsecret'
35
- @aes_mock.should_receive(:iv=).with 'firstsixteenchar'
36
- @aes_mock.should_receive(:update).with('crypteddata').and_return 'crap'
37
- @aes_mock.should_receive(:final).and_raise OpenSSL::Cipher::CipherError
38
- @data.decrypt_data(:data => 'firstsixteencharcrypteddata',
39
- :secret => 'badsecret').
40
- should be_false
37
+ context "no secret given" do
38
+ it "should return the data if no secret given" do
39
+ @data.decrypt_data(:data => 'plaintext',
40
+ :secret => nil).should == 'plaintext'
41
+ end
41
42
  end
42
-
43
43
  end
44
44
 
45
- context "no secret given" do
46
- before do
47
- @data = Heirloom::Cipher::Data.new :config => @config_mock
48
- end
45
+ context "when unsuccesful" do
46
+ context "with secret given" do
47
+ it "should return false if gpg not in path" do
48
+ @logger_mock.should_receive(:error)
49
+ @data.should_receive(:which).with('gpg').and_return false
50
+ @data.decrypt_data(:data => 'crypted',
51
+ :secret => 'password').should be_false
52
+ end
53
+
54
+ it "should return false if decrypted fails" do
55
+ @logger_mock.should_receive(:error)
56
+ @data.should_receive(:which).with('gpg').and_return true
57
+ Tempfile.should_receive(:new).with('archive.tar.gz.gpg').
58
+ and_return @encrypted_file_mock
59
+ Tempfile.should_receive(:new).with('archive.tar.gz').
60
+ and_return @decrypted_file_mock
61
+ ::File.should_receive(:open).
62
+ with(@encrypted_file_mock,'w')
63
+ $?.stub :success? => false
49
64
 
50
- it "should return the data if no secret given" do
51
- @data.decrypt_data(:data => 'plaintext',
52
- :secret => nil).should == 'plaintext'
65
+ command = 'gpg --batch --yes --cipher-algo AES256 --passphrase password --output /tmp/dec /tmp/enc 2>&1'
66
+ @data.should_receive(:`).with(command).and_return true
67
+ @data.decrypt_data(:data => 'crypted',
68
+ :secret => 'password').should be_false
69
+ end
53
70
  end
54
71
  end
55
72