relishable 0.6 → 0.7
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/Gemfile.lock +6 -2
- data/lib/relish/dynamo_helper.rb +63 -0
- data/lib/relish/encryption_helper.rb +57 -0
- data/lib/relish/release.rb +25 -0
- data/lib/relish.rb +25 -100
- metadata +25 -5
data/Gemfile.lock
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
relishable (0.
|
5
|
-
|
4
|
+
relishable (0.7)
|
5
|
+
fernet (~> 1.4)
|
6
|
+
fog (~> 1.6)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: http://rubygems.org/
|
9
10
|
specs:
|
10
11
|
builder (3.1.3)
|
11
12
|
excon (0.16.4)
|
13
|
+
fernet (1.4)
|
14
|
+
yajl-ruby
|
12
15
|
fog (1.6.0)
|
13
16
|
builder
|
14
17
|
excon (~> 0.14)
|
@@ -29,6 +32,7 @@ GEM
|
|
29
32
|
jruby-pageant (>= 1.1.1)
|
30
33
|
nokogiri (1.5.5)
|
31
34
|
ruby-hmac (0.4.0)
|
35
|
+
yajl-ruby (1.1.0)
|
32
36
|
|
33
37
|
PLATFORMS
|
34
38
|
ruby
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "fog"
|
2
|
+
|
3
|
+
class Relish
|
4
|
+
class DynamoHelper
|
5
|
+
|
6
|
+
def initialize(aws_access_key, aws_secret_key, table_name)
|
7
|
+
@aws_access_key = aws_access_key
|
8
|
+
@aws_secret_key = aws_secret_key
|
9
|
+
@table_name = table_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def db
|
13
|
+
@db ||= Fog::AWS::DynamoDB.new(:aws_access_key_id => @aws_access_key, :aws_secret_access_key => @aws_secret_key)
|
14
|
+
end
|
15
|
+
|
16
|
+
def query_current_version(id)
|
17
|
+
response = db.query(@table_name, {:S => id}, :ConsistentRead => true, :Limit => 1, :ScanIndexForward => false)
|
18
|
+
if response.status != 200
|
19
|
+
raise('status: #{response.status}')
|
20
|
+
end
|
21
|
+
if response.body['Count'] == 1
|
22
|
+
response.body['Items'].first
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def put_current_version(item)
|
27
|
+
response = db.put_item(@table_name, item, {:Expected => {:id => {:Exists => false}, :version => {:Exists => false}}})
|
28
|
+
if response.status != 200
|
29
|
+
raise('status: #{response.status}')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_version(id, version)
|
34
|
+
response = db.get_item(@table_name, {:HashKeyElement => {:S => id}, :RangeKeyElement => {:N => version}})
|
35
|
+
if response.status != 200
|
36
|
+
raise('status: #{response.status}')
|
37
|
+
end
|
38
|
+
response.body['Item']
|
39
|
+
end
|
40
|
+
|
41
|
+
def put_version(id, version, item)
|
42
|
+
response = db.put_item(@table_name, item, {:Expected => {:id => {:Value => {:S => id}}, :version => {:Value => {:N => version}}}})
|
43
|
+
if response.status != 200
|
44
|
+
raise('status: #{response.status}')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def put(item)
|
49
|
+
response = db.put_item(@table_name, item)
|
50
|
+
if response.status != 200
|
51
|
+
raise('status: #{response.status}')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def query(id, consistent, limit)
|
56
|
+
response = db.query(@table_name, {:S => id}, :ConsistentRead => consistent, :Limit => limit, :ScanIndexForward => false)
|
57
|
+
if response.status != 200
|
58
|
+
raise('status: #{response.status}')
|
59
|
+
end
|
60
|
+
response.body['Items']
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "fernet"
|
2
|
+
require "openssl"
|
3
|
+
|
4
|
+
class RelishDecryptionFailed < RuntimeError; end
|
5
|
+
|
6
|
+
class Relish
|
7
|
+
class EncryptionHelper
|
8
|
+
|
9
|
+
def initialize(static_secret, secrets)
|
10
|
+
@static_secret = static_secret
|
11
|
+
@secrets = secrets
|
12
|
+
end
|
13
|
+
|
14
|
+
def hmac_secrets
|
15
|
+
@hmac_secrets ||= @secrets.map do |secret|
|
16
|
+
OpenSSL::HMAC.hexdigest('sha256', @static_secret, secret)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def encrypt_env(env)
|
21
|
+
encrypt_key_with_secret("env", env, hmac_secrets.first)
|
22
|
+
end
|
23
|
+
|
24
|
+
def decrypt_env(encrypted_token)
|
25
|
+
hmac_secrets.each_with_index do |secret, i|
|
26
|
+
success, env = try_decrypt(secret, encrypted_token, "env")
|
27
|
+
if success
|
28
|
+
return env
|
29
|
+
end
|
30
|
+
end
|
31
|
+
raise RelishDecryptionFailed
|
32
|
+
end
|
33
|
+
|
34
|
+
def try_decrypt(secret, encrypted_token, hash_key)
|
35
|
+
decrypt_key(secret, encrypted_token, hash_key)
|
36
|
+
rescue OpenSSL::Cipher::CipherError => e
|
37
|
+
return false, {}
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def decrypt_key(secret, encrypted_token, hash_key)
|
43
|
+
verifier = Fernet.verifier(secret, encrypted_token)
|
44
|
+
verifier.enforce_ttl = false
|
45
|
+
unless verifier.valid?
|
46
|
+
return false, {}
|
47
|
+
end
|
48
|
+
[true, verifier.data[hash_key]]
|
49
|
+
end
|
50
|
+
|
51
|
+
def encrypt_key_with_secret(hash_key, value, secret)
|
52
|
+
Fernet.generate(secret) do |gen|
|
53
|
+
gen.data = {hash_key => value}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Relish
|
2
|
+
class Release
|
3
|
+
|
4
|
+
attr_accessor :item
|
5
|
+
|
6
|
+
def self.schema(attrs)
|
7
|
+
attrs.each do |attr, type|
|
8
|
+
class_eval "def #{attr}; @item['#{attr}']['#{type}'] if @item.key? '#{attr}' end", __FILE__, __LINE__
|
9
|
+
class_eval "def #{attr}= value; @item['#{attr}'] = {'#{type}' => value} end", __FILE__, __LINE__
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
schema :id => :S,
|
14
|
+
:version => :N,
|
15
|
+
:descr => :S,
|
16
|
+
:user_id => :N,
|
17
|
+
:slug_id => :S,
|
18
|
+
:slug_version => :N,
|
19
|
+
:stack => :S,
|
20
|
+
:language_pack => :S,
|
21
|
+
:env => :S,
|
22
|
+
:pstable => :S,
|
23
|
+
:addons => :S
|
24
|
+
end
|
25
|
+
end
|
data/lib/relish.rb
CHANGED
@@ -1,103 +1,28 @@
|
|
1
|
-
require "
|
1
|
+
require "relish/dynamo_helper"
|
2
|
+
require "relish/release"
|
3
|
+
require "relish/encryption_helper"
|
2
4
|
|
3
5
|
class Relish
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
def self.conf(*attrs)
|
8
|
-
attrs.each do |attr|
|
9
|
-
instance_eval "def #{attr}; @#{attr} end", __FILE__, __LINE__
|
10
|
-
instance_eval "def #{attr}= value; @#{attr} = value end", __FILE__, __LINE__
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
conf :aws_access_key, :aws_secret_key, :table_name
|
15
|
-
|
16
|
-
def self.schema(attrs)
|
17
|
-
attrs.each do |attr, type|
|
18
|
-
class_eval "def #{attr}; @item['#{attr}']['#{type}'] if @item.key? '#{attr}' end", __FILE__, __LINE__
|
19
|
-
class_eval "def #{attr}= value; @item['#{attr}'] = {'#{type}' => value} end", __FILE__, __LINE__
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
schema :id => :S,
|
24
|
-
:version => :N,
|
25
|
-
:descr => :S,
|
26
|
-
:user_id => :N,
|
27
|
-
:slug_id => :S,
|
28
|
-
:slug_version => :N,
|
29
|
-
:stack => :S,
|
30
|
-
:language_pack => :S,
|
31
|
-
:env_json => :S,
|
32
|
-
:pstable_json => :S,
|
33
|
-
:addons_json => :S
|
34
|
-
|
35
|
-
def self.db
|
36
|
-
@db ||= Fog::AWS::DynamoDB.new(:aws_access_key_id => aws_access_key, :aws_secret_access_key => aws_secret_key)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.db_query_current_version(id)
|
40
|
-
response = db.query(table_name, {:S => id}, :ConsistentRead => true, :Limit => 1, :ScanIndexForward => false)
|
41
|
-
if response.status != 200
|
42
|
-
raise('status: #{response.status}')
|
43
|
-
end
|
44
|
-
if response.body['Count'] == 1
|
45
|
-
response.body['Items'].first
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.db_put_current_version(item)
|
50
|
-
response = db.put_item(table_name, item, {:Expected => {:id => {:Exists => false}, :version => {:Exists => false}}})
|
51
|
-
if response.status != 200
|
52
|
-
raise('status: #{response.status}')
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.db_get_version(id, version)
|
57
|
-
response = db.get_item(table_name, {:HashKeyElement => {:S => id}, :RangeKeyElement => {:N => version}})
|
58
|
-
if response.status != 200
|
59
|
-
raise('status: #{response.status}')
|
60
|
-
end
|
61
|
-
response.body['Item']
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.db_put_version(id, version, item)
|
65
|
-
response = db.put_item(table_name, item, {:Expected => {:id => {:Value => {:S => id}}, :version => {:Value => {:N => version}}}})
|
66
|
-
if response.status != 200
|
67
|
-
raise('status: #{response.status}')
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def self.db_put(item)
|
72
|
-
response = db.put_item(table_name, item)
|
73
|
-
if response.status != 200
|
74
|
-
raise('status: #{response.status}')
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def self.db_query(id, limit)
|
79
|
-
response = db.query(table_name, {:S => id}, :ConsistentRead => true, :Limit => limit, :ScanIndexForward => false)
|
80
|
-
if response.status != 200
|
81
|
-
raise('status: #{response.status}')
|
82
|
-
end
|
83
|
-
response.body['Items']
|
7
|
+
def initialize(*args)
|
8
|
+
@db = DynamoHelper.new(*args)
|
84
9
|
end
|
85
10
|
|
86
|
-
def
|
87
|
-
release = new
|
11
|
+
def copy(id, version, data)
|
12
|
+
release = Release.new
|
88
13
|
release.item = {}
|
89
14
|
release.id = id
|
90
15
|
release.version = version
|
91
16
|
data.each do |k, v|
|
92
17
|
release.send("#{k}=", v.to_s) unless v.nil?
|
93
18
|
end
|
94
|
-
|
19
|
+
@db.put(release.item)
|
95
20
|
release
|
96
21
|
end
|
97
22
|
|
98
|
-
def
|
99
|
-
item =
|
100
|
-
release = new
|
23
|
+
def create(id, data)
|
24
|
+
item = @db.query_current_version(id)
|
25
|
+
release = Release.new
|
101
26
|
if item.nil?
|
102
27
|
release.item = {}
|
103
28
|
release.id = id
|
@@ -109,46 +34,46 @@ class Relish
|
|
109
34
|
data.each do |k, v|
|
110
35
|
release.send("#{k}=", v.to_s) unless v.nil?
|
111
36
|
end
|
112
|
-
|
37
|
+
@db.put_current_version(release.item)
|
113
38
|
release
|
114
39
|
end
|
115
40
|
|
116
|
-
def
|
117
|
-
item =
|
41
|
+
def current(id)
|
42
|
+
item = @db.query_current_version(id)
|
118
43
|
unless item.nil?
|
119
|
-
release = new
|
44
|
+
release = Release.new
|
120
45
|
release.item = item
|
121
46
|
release
|
122
47
|
end
|
123
48
|
end
|
124
49
|
|
125
|
-
def
|
126
|
-
item =
|
50
|
+
def read(id, version)
|
51
|
+
item = @db.get_version(id, version)
|
127
52
|
unless item.nil?
|
128
|
-
release = new
|
53
|
+
release = Release.new
|
129
54
|
release.item = item
|
130
55
|
release
|
131
56
|
end
|
132
57
|
end
|
133
58
|
|
134
|
-
def
|
135
|
-
items =
|
59
|
+
def dump(id, consistent=nil, limit=nil)
|
60
|
+
items = @db.query(id, limit)
|
136
61
|
items.map do |item|
|
137
|
-
release = new
|
62
|
+
release = Release.new
|
138
63
|
release.item = item
|
139
64
|
release
|
140
65
|
end
|
141
66
|
end
|
142
67
|
|
143
|
-
def
|
144
|
-
item =
|
68
|
+
def update(id, version, data)
|
69
|
+
item = @db.get_version(id, version)
|
145
70
|
unless item.nil?
|
146
|
-
release = new
|
71
|
+
release = Release.new
|
147
72
|
release.item = item
|
148
73
|
data.each do |k, v|
|
149
74
|
release.send("#{k}=", v.to_s) unless v.nil?
|
150
75
|
end
|
151
|
-
|
76
|
+
@db.put_version(id, version, release.item)
|
152
77
|
release
|
153
78
|
end
|
154
79
|
end
|
metadata
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relishable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.7'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Mark Fine
|
9
|
+
- Blake Gentry
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
@@ -16,23 +17,42 @@ dependencies:
|
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
|
-
- -
|
20
|
+
- - ~>
|
20
21
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
22
|
+
version: '1.6'
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
25
|
version_requirements: !ruby/object:Gem::Requirement
|
25
26
|
none: false
|
26
27
|
requirements:
|
27
|
-
- -
|
28
|
+
- - ~>
|
28
29
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
+
version: '1.6'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: fernet
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '1.4'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.4'
|
30
47
|
description: Release manager.
|
31
48
|
email: mark.fine@gmail.com
|
32
49
|
executables: []
|
33
50
|
extensions: []
|
34
51
|
extra_rdoc_files: []
|
35
52
|
files:
|
53
|
+
- lib/relish/dynamo_helper.rb
|
54
|
+
- lib/relish/encryption_helper.rb
|
55
|
+
- lib/relish/release.rb
|
36
56
|
- lib/relish.rb
|
37
57
|
- Gemfile
|
38
58
|
- Gemfile.lock
|