store_agent 1.0.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +5 -0
  6. data/LICENSE +202 -0
  7. data/README.md +433 -0
  8. data/Rakefile +2 -0
  9. data/lib/store_agent.rb +31 -0
  10. data/lib/store_agent/config.rb +152 -0
  11. data/lib/store_agent/data_encoder.rb +32 -0
  12. data/lib/store_agent/data_encoder/gzip_encoder.rb +50 -0
  13. data/lib/store_agent/data_encoder/openssl_aes_256_cbc_encoder.rb +65 -0
  14. data/lib/store_agent/exceptions.rb +87 -0
  15. data/lib/store_agent/node.rb +26 -0
  16. data/lib/store_agent/node/attachment.rb +93 -0
  17. data/lib/store_agent/node/attachment/metadata.rb +120 -0
  18. data/lib/store_agent/node/attachment/permission.rb +121 -0
  19. data/lib/store_agent/node/object.rb +233 -0
  20. data/lib/store_agent/node/object/directory_object.rb +264 -0
  21. data/lib/store_agent/node/object/file_object.rb +197 -0
  22. data/lib/store_agent/node/object/virtual_object.rb +25 -0
  23. data/lib/store_agent/node/prepend_module/locker.rb +125 -0
  24. data/lib/store_agent/node/prepend_module/path_validator.rb +138 -0
  25. data/lib/store_agent/node/prepend_module/permission_checker.rb +96 -0
  26. data/lib/store_agent/user.rb +111 -0
  27. data/lib/store_agent/validator.rb +60 -0
  28. data/lib/store_agent/version.rb +19 -0
  29. data/lib/store_agent/version_manager.rb +101 -0
  30. data/lib/store_agent/version_manager/ruby_git.rb +100 -0
  31. data/lib/store_agent/version_manager/rugged_git.rb +133 -0
  32. data/lib/store_agent/workspace.rb +88 -0
  33. data/spec/spec_helper.rb +47 -0
  34. data/spec/store_agent/data_encoder/encoder_shared_context.rb +74 -0
  35. data/spec/store_agent/data_encoder/gzip_encoder_spec.rb +41 -0
  36. data/spec/store_agent/data_encoder/openssl_aes_256_cbc_encoder_spec.rb +42 -0
  37. data/spec/store_agent/data_encoder_spec.rb +78 -0
  38. data/spec/store_agent/node/directory_object_spec.rb +563 -0
  39. data/spec/store_agent/node/file_object_spec.rb +379 -0
  40. data/spec/store_agent/node/locker_spec.rb +191 -0
  41. data/spec/store_agent/node/metadata_spec.rb +339 -0
  42. data/spec/store_agent/node/object_spec.rb +73 -0
  43. data/spec/store_agent/node/path_validator_spec.rb +121 -0
  44. data/spec/store_agent/node/permission_spec.rb +232 -0
  45. data/spec/store_agent/user_spec.rb +127 -0
  46. data/spec/store_agent/version_manager/git_shared_context.rb +286 -0
  47. data/spec/store_agent/version_manager/ruby_git_spec.rb +32 -0
  48. data/spec/store_agent/version_manager/rugged_git_spec.rb +32 -0
  49. data/spec/store_agent/workspace_spec.rb +107 -0
  50. data/spec/store_agent_spec.rb +53 -0
  51. data/store_agent.gemspec +33 -0
  52. metadata +252 -0
@@ -0,0 +1,25 @@
1
+ #--
2
+ # Copyright 2015 realglobe, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #++
16
+
17
+ module StoreAgent
18
+ module Node
19
+ class VirtualObject < Object # :nodoc:
20
+ def exists?
21
+ false
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,125 @@
1
+ #--
2
+ # Copyright 2015 realglobe, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #++
16
+
17
+ module StoreAgent
18
+ module Node
19
+ # オブジェクトの読み書き時にファイルをロックするモジュール
20
+ module Locker
21
+ def create(*)
22
+ lock!(lock_mode: File::LOCK_EX, recursive: true) do
23
+ super
24
+ end
25
+ end
26
+
27
+ def read(*)
28
+ lock!(lock_mode: File::LOCK_SH, recursive: true) do
29
+ super
30
+ end
31
+ end
32
+
33
+ def update(*)
34
+ lock!(lock_mode: File::LOCK_EX, recursive: true) do
35
+ super
36
+ end
37
+ end
38
+
39
+ def delete(*, recursive: true)
40
+ lock!(lock_mode: File::LOCK_EX, recursive: recursive) do
41
+ super
42
+ end
43
+ end
44
+
45
+ def touch(*)
46
+ lock!(lock_mode: File::LOCK_SH, recursive: true) do
47
+ super
48
+ end
49
+ end
50
+
51
+ # TODO
52
+ # コピー元を共有ロック、コピー先を排他ロックする
53
+ def copy(dest_path = nil, *)
54
+ super
55
+ end
56
+
57
+ # TODO
58
+ # 移動元と移動先を排他ロックする
59
+ def move(dest_path = nil, *)
60
+ super
61
+ end
62
+
63
+ def get_metadata(*) # :nodoc:
64
+ lock!(lock_mode: File::LOCK_SH, recursive: true) do
65
+ super
66
+ end
67
+ end
68
+
69
+ def get_permissions(*) # :nodoc:
70
+ lock!(lock_mode: File::LOCK_SH, recursive: true) do
71
+ super
72
+ end
73
+ end
74
+
75
+ def chown(*)
76
+ lock!(lock_mode: File::LOCK_EX, recursive: false) do
77
+ super
78
+ end
79
+ end
80
+
81
+ # TODO recursive_to_root, recursive_to_leaf
82
+ # TODO lock_shared recursive_to_root
83
+ # 親階層のファイルをロックしていないので、同時にファイル削除などが実行されると問題が発生する可能性がある
84
+ def set_permission(*)
85
+ lock!(lock_mode: File::LOCK_EX, recursive: false) do
86
+ super
87
+ end
88
+ end
89
+
90
+ # TODO
91
+ def unset_permission(*)
92
+ lock!(lock_mode: File::LOCK_EX, recursive: false) do
93
+ super
94
+ end
95
+ end
96
+
97
+ protected
98
+
99
+ # TODO
100
+ def lock_file_path
101
+ "#{metadata.file_path}.lock"
102
+ end
103
+
104
+ def lock!(lock_mode: File::LOCK_SH, recursive: false, &block)
105
+ proc = Proc.new do
106
+ if !File.exists?(dirname = File.dirname(lock_file_path))
107
+ FileUtils.mkdir(dirname)
108
+ end
109
+ open(lock_file_path, File::RDWR | File::CREAT) do |f|
110
+ timeout(StoreAgent.config.lock_timeout) do
111
+ f.flock(lock_mode)
112
+ end
113
+ f.truncate(0)
114
+ yield
115
+ end
116
+ end
117
+ if recursive && !root?
118
+ parent_directory.lock!(lock_mode: lock_mode, recursive: recursive, &proc)
119
+ else
120
+ proc.call
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,138 @@
1
+ #--
2
+ # Copyright 2015 realglobe, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #++
16
+
17
+ module StoreAgent
18
+ module Node
19
+ # オブジェクトの操作時に、パスが不正でないかをチェックするモジュール
20
+ module PathValidator
21
+ def create(*)
22
+ if !root?
23
+ parent_directory.be_present!
24
+ end
25
+ be_absent!
26
+ be_not_reserved!
27
+ super
28
+ end
29
+
30
+ def read(*, revision: nil)
31
+ if revision.nil?
32
+ be_present!
33
+ end
34
+ be_not_reserved!
35
+ super
36
+ end
37
+
38
+ def update(*)
39
+ be_present!
40
+ be_not_reserved!
41
+ super
42
+ end
43
+
44
+ def delete(*)
45
+ be_present!
46
+ be_not_root!
47
+ be_not_reserved!
48
+ super
49
+ end
50
+
51
+ def touch(*)
52
+ be_present!
53
+ be_not_reserved!
54
+ super
55
+ end
56
+
57
+ # TODO
58
+ def copy(dest_path = nil, *)
59
+ be_present!
60
+ be_not_reserved!
61
+ super
62
+ end
63
+
64
+ # TODO
65
+ def move(dest_path = nil, *)
66
+ be_present!
67
+ be_not_root!
68
+ be_not_reserved!
69
+ super
70
+ end
71
+
72
+ def get_metadata(*) # :nodoc:
73
+ be_present!
74
+ be_not_reserved!
75
+ super
76
+ end
77
+
78
+ def get_permissions(*) # :nodoc:
79
+ be_present!
80
+ be_not_reserved!
81
+ super
82
+ end
83
+
84
+ def chown(*)
85
+ be_present!
86
+ be_not_reserved!
87
+ super
88
+ end
89
+
90
+ def set_permission(*)
91
+ be_present!
92
+ be_not_reserved!
93
+ super
94
+ end
95
+
96
+ def unset_permission(*)
97
+ be_present!
98
+ be_not_reserved!
99
+ super
100
+ end
101
+
102
+ protected
103
+
104
+ def be_present!
105
+ if !exists?
106
+ raise StoreAgent::InvalidPathError, "object not found: #{path}"
107
+ end
108
+ end
109
+
110
+ def be_absent!
111
+ if exists?
112
+ raise StoreAgent::InvalidPathError, "object already exists: #{path}"
113
+ end
114
+ end
115
+
116
+ def be_not_root!
117
+ if root?
118
+ raise StoreAgent::InvalidPathError, "can't delete root node"
119
+ end
120
+ end
121
+
122
+ def be_not_reserved!
123
+ basename = File.basename(path)
124
+ reserved_extensions = [] <<
125
+ StoreAgent.config.metadata_extension <<
126
+ StoreAgent.config.permission_extension
127
+ reserved_extensions.each do |extension|
128
+ if basename.end_with?(extension)
129
+ raise StoreAgent::InvalidPathError, "extension '#{extension}' is reserved"
130
+ end
131
+ end
132
+ if StoreAgent.reserved_filenames.include?(basename)
133
+ raise StoreAgent::InvalidPathError, "filename '#{basename}' is reserved"
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,96 @@
1
+ #--
2
+ # Copyright 2015 realglobe, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #++
16
+
17
+ module StoreAgent
18
+ module Node
19
+ # オブジェクトの操作時に権限があるかどうかをチェックするモジュール
20
+ module PermissionChecker
21
+ def create(*)
22
+ if !root?
23
+ parent_directory.authorize!("write")
24
+ end
25
+ super
26
+ end
27
+
28
+ def read(*)
29
+ authorize!("read")
30
+ super
31
+ end
32
+
33
+ def update(*)
34
+ authorize!("write")
35
+ super
36
+ end
37
+
38
+ def delete(*)
39
+ authorize!("write")
40
+ super
41
+ end
42
+
43
+ def touch(*)
44
+ authorize!("read")
45
+ super
46
+ end
47
+
48
+ # TODO
49
+ # コピー先のwrite権限をチェックする
50
+ def copy(dest_path = nil, *)
51
+ authorize!("read")
52
+ super
53
+ end
54
+
55
+ # TODO
56
+ # コピー先のwrite権限をチェックする
57
+ def move(dest_path = nil, *)
58
+ authorize!("write")
59
+ super
60
+ end
61
+
62
+ def get_metadata(*) # :nodoc:
63
+ authorize!("read")
64
+ super
65
+ end
66
+
67
+ def get_permissions(*) # :nodoc:
68
+ authorize!("read")
69
+ super
70
+ end
71
+
72
+ def chown(*)
73
+ authorize!("chown")
74
+ super
75
+ end
76
+
77
+ def set_permission(*)
78
+ authorize!("chmod")
79
+ super
80
+ end
81
+
82
+ def unset_permission(*)
83
+ authorize!("chmod")
84
+ super
85
+ end
86
+
87
+ protected
88
+
89
+ def authorize!(permission_name)
90
+ if !permission.allow?(permission_name)
91
+ raise StoreAgent::PermissionDeniedError.new(object: self, permission: permission_name)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,111 @@
1
+ #--
2
+ # Copyright 2015 realglobe, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #++
16
+
17
+ module StoreAgent
18
+ # オブジェクトの操作を行うユーザー
19
+ class User
20
+ include StoreAgent::Validator
21
+
22
+ attr_reader :identifiers
23
+
24
+ # ユーザーの初期化は以下のようにして行う
25
+ # StoreAgent::User.new("foo")
26
+ # StoreAgent::User.new("foo", "bar")
27
+ # StoreAgent::User.new(["foo", "bar", "baz"])
28
+ # StoreAgent::User.new("foo", ["bar", "hoge"], "fuga")
29
+ def initialize(*identifiers)
30
+ identifiers.compact!
31
+ if identifiers.empty?
32
+ raise ArgumentError, "identifier(s) is required"
33
+ end
34
+ @identifiers = identifiers.map do |identifier|
35
+ if identifier.is_a?(Array)
36
+ stringify_map_identifier(identifier)
37
+ else
38
+ stringify_identifier(identifier)
39
+ end
40
+ end
41
+ end
42
+
43
+ def identifier_array # :nodoc:
44
+ [identifiers.last].flatten
45
+ end
46
+
47
+ def identifier
48
+ identifier_array.first
49
+ end
50
+
51
+ def super_user?
52
+ false
53
+ end
54
+
55
+ def guest?
56
+ false
57
+ end
58
+
59
+ # 操作対象のワークスペースを指定する
60
+ def workspace(namespace)
61
+ StoreAgent::Workspace.new(current_user: self, namespace: namespace)
62
+ end
63
+
64
+ private
65
+
66
+ def stringify_identifier(identifier)
67
+ validates_to_be_string_or_symbol!(identifier)
68
+ validates_to_be_excluded_slash!(identifier)
69
+ validates_to_be_not_superuser_identifier!(identifier)
70
+ validates_to_be_not_guest_identifier!(identifier)
71
+ identifier.to_s
72
+ end
73
+
74
+ def stringify_map_identifier(identifiers_array)
75
+ case identifiers_array.length
76
+ when 0
77
+ raise ArgumentError, "identifier(s) contains empty array"
78
+ when 1
79
+ stringify_identifier(identifiers_array.first)
80
+ else
81
+ identifiers_array.map{|id| stringify_identifier(id)}
82
+ end
83
+ end
84
+ end
85
+
86
+ # スーパーユーザーは全オブジェクトに対して全権限を持つ
87
+ # super_user = StoreAgent::Superuser.new
88
+ # super_user.workspace("ws").file("file.txt").create
89
+ class Superuser < User
90
+ def initialize(*)
91
+ @identifiers = [StoreAgent.config.superuser_identifier]
92
+ end
93
+
94
+ def super_user? # :nodoc:
95
+ true
96
+ end
97
+ end
98
+
99
+ # ゲストユーザーはデフォルトの設定では何の権限も持たない
100
+ # guest = StoreAgent::Guest.new
101
+ # guest.workspace("ws").file("file.txt").read
102
+ class Guest < User
103
+ def initialize(*)
104
+ @identifiers = [StoreAgent.config.guest_identifier]
105
+ end
106
+
107
+ def guest? # :nodoc:
108
+ true
109
+ end
110
+ end
111
+ end