pebblebed 0.0.22 → 0.0.23

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -152,3 +152,10 @@ For some pebbles Pebblebed may furnish a richer client with helper methods. This
152
152
  augmented client in the `/lib/pebblebed/clients` folder and naming the class `Pebblebed::<YourPebbleName>Client`. For
153
153
  an example of this see `CheckpointClient` which in addition to the common http-methods provides the method `me` which
154
154
  returns the logged in user and `god?` which checks whether she's a god(dess).
155
+
156
+ Troubleshooting
157
+ ===============
158
+
159
+ When something fails, say you're trying to post to grove using a pebblebed connector, it might be a good idea to try the same thing from command line first:
160
+
161
+ curl -XPOST 'http://example.com/api/grove/v1/posts/post.todo:dna.org.a.b' --data '{"session":"session_name","post":{"document": {"body": "Hello Grove!"},"tags": ["welcome", "tutorial"]}}' -H "Content-Type: application/json"
@@ -0,0 +1,85 @@
1
+ # Models the checkpoint group access data for one identity
2
+ module Pebblebed
3
+ module Security
4
+ class AccessData
5
+ attr_reader :group_ids
6
+
7
+ def initialize(data)
8
+ if data[:subtrees] || data[:group_ids]
9
+ @group_ids = Set.new(data[:group_ids])
10
+ @subtrees = Set.new
11
+ data[:subtrees].each do |subtree|
12
+ @subtrees << subtree.split('.')
13
+ end
14
+ else
15
+ # Assume this is a /identities/:id/memberships result from checkpoint
16
+ parse_checkpoint_record(data)
17
+ end
18
+ end
19
+
20
+ # Takes a path (possibly with wildcards) and returns
21
+ # any subtrees that are relevant to determine accessibility
22
+ # to restricted content in a query of documents in that
23
+ # wildcard_path. All relevant subtrees are guaranteed to be
24
+ # returned, but not all returned subtrees are guaranteed to be
25
+ # relevant. I.e. some irrelevant subtrees may be returned.
26
+ # (If the path does not use wildcards, relevance is
27
+ # guaranteed.)
28
+ def relevant_subtrees(wildcard_path)
29
+ pristine = self.class.pristine_path(wildcard_path)
30
+ intersecting_subtrees(pristine)
31
+ end
32
+
33
+ def subtrees
34
+ @subtrees.map { |subtree| subtree.join('.') }
35
+ end
36
+
37
+ private
38
+
39
+ # Takes a path possibly containing wildcard characters and returns
40
+ # a superset path that just contains proper labels. E.g. "a.b.c|d.*" returns
41
+ # "a.b"
42
+ def self.pristine_path(wildcard_path)
43
+ result = []
44
+ wildcard_path.split('.').each do |label|
45
+ break unless Pebblebed::Uid.valid_label?(label)
46
+ result << label
47
+ end
48
+ result.join('.')
49
+ end
50
+
51
+ # Returns any subtrees that "intersect" the provided location. That is
52
+ # they are either supersets of the location ("a.b" is a superset of "a.b.c")
53
+ # or subsets ("a.b.c.d" is a subset of "a.b.c"). Also exact matches are returned
54
+ # ('a.b.c' matches 'a.b.c', duh!)
55
+ def intersecting_subtrees(location)
56
+ location = location.split('.')
57
+ result = []
58
+ @subtrees.each do |subtree|
59
+ if subtree.length >= location.length
60
+ # is this a subset tree?
61
+ result << subtree if location == subtree[0...location.length]
62
+ else
63
+ # is this a superset tree?
64
+ result << subtree if subtree == location[0...subtree.length]
65
+ end
66
+ end
67
+ result.map { |subtree| subtree.join('.') }
68
+ end
69
+
70
+ # Initializes the instance with data from a checkpoint GET /identities/:id/memberships request
71
+ def parse_checkpoint_record(memberships_record)
72
+ @group_ids = Set.new
73
+ @subtrees = Set.new
74
+ memberships_record['memberships'].each do |membership|
75
+ @group_ids << membership['membership']['group_id']
76
+ end
77
+ memberships_record['groups'].each do |group|
78
+ group['group']['subtrees'].each do |subtree|
79
+ @subtrees << subtree.split('.')
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,33 @@
1
+ # A class that helps
2
+ module Pebblebed
3
+ module Security
4
+ class Client
5
+ IDENTITY_MEMBERSHIPS_TTL = 10*60
6
+
7
+ def initialize(connector)
8
+ @connector = connector
9
+ @access_data = {} # Memoized identity access data records
10
+ end
11
+
12
+ # Returns an object representing the current access data for a given identity
13
+ def access_data_for(identity)
14
+ identity = identity.id unless identity.is_a?(Numeric)
15
+ return @access_data[identity] if @access_data[identity]
16
+ membership_data = fetch_membership_data_for(identity)
17
+ result = Pebblebed::Security::AccessData.new(membership_data)
18
+ @access_data[identity] = result
19
+ result
20
+ end
21
+
22
+ private
23
+
24
+ def fetch_membership_data_for(identity_id)
25
+ result = Pebblebed.memcached.fetch("identity_membership_data:#{identity}", IDENTITY_MEMBERSHIPS_TTL) do
26
+ @connector.checkpoint.get("/identities/#{identity}/memberships").to_json
27
+ end
28
+ JSON.parse(result)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,94 @@
1
+ # Listens to security configuration updates and lets the client application
2
+ # register custom handlers for each event.
3
+ module Pebblebed
4
+ module Security
5
+ class Listener
6
+
7
+ def initialize(options)
8
+ @app_name = options[:app_name]
9
+ @handlers = {:group => {}, :group_membership => {}, :group_subtree => {}}
10
+ end
11
+
12
+ def start
13
+ @thread ||= Thread.new do
14
+ process
15
+ end
16
+ end
17
+
18
+ def stop
19
+ @thread.kill if @thread
20
+ @thread = nil
21
+ end
22
+
23
+ def on_group_declared(&block)
24
+ @handlers[:group][:create] = block
25
+ @handlers[:group][:update] = block
26
+ end
27
+
28
+ def on_group_removed(&block)
29
+ @handlers[:group][:delete] = block
30
+ end
31
+
32
+ def on_subtree_declared(&block)
33
+ @handlers[:group_subtree][:create] = block
34
+ @handlers[:group_subtree][:update] = block
35
+ end
36
+
37
+ def on_subtree_removed(&block)
38
+ @handlers[:group_subtree][:delete] = block
39
+ end
40
+
41
+ def on_membership_declared(&block)
42
+ @handlers[:group_membership][:create] = block
43
+ @handlers[:group_membership][:update] = block
44
+ end
45
+
46
+ def on_membership_removed(&block)
47
+ @handlers[:group_membership][:delete] = block
48
+ end
49
+
50
+ private
51
+
52
+ # Subscribe to queue and handle incoming messages
53
+ def process
54
+ river = Pebblebed::River.new
55
+ queue_options = {
56
+ :name => "#{@app_name}.security_listener",
57
+ :path => '**',
58
+ :klass => 'group|group_membership|group_subtree',
59
+ :event => '**',
60
+ :interval => 1
61
+ }
62
+ queue = river.queue queue_options
63
+ queue.subscribe(ack: true) do |message|
64
+ consider message
65
+ end
66
+ end
67
+
68
+ # Parse an incoming message and pass it on
69
+ def consider(message)
70
+ payload = JSON.parse(message[:payload])
71
+ event = payload['event']
72
+ attributes = payload['attributes']
73
+ klass = Pebblebed::Uid.raw_parse(payload['uid']).first
74
+ handle(event, klass, attributes)
75
+ end
76
+
77
+ # Determines the correct event handler for the message and calls it
78
+ def handle(event, klass, attributes)
79
+ event_handler = @handlers[klass.to_sym][event.to_sym]
80
+ return unless event_handler
81
+ case klass
82
+ when 'group'
83
+ event_handler.call(:id => attributes['id'], :label => attributes['label'])
84
+ when 'group_membership'
85
+ event_handler.call(:group_id => attributes['group_id'],
86
+ :identity_id => attributes['identity_id'])
87
+ when 'group_subtree'
88
+ event_handler.call(:group_id => attributes['group_id'],
89
+ :location => attributes['location'])
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
data/lib/pebblebed/uid.rb CHANGED
@@ -116,29 +116,31 @@ module Pebblebed
116
116
  stars_are_solitary?(path) && pipes_are_interleaved?(path) && carets_are_leading?(path) && stars_are_terminating?(path)
117
117
  end
118
118
 
119
- # a.*.c is valid
119
+ # a.*.c is accepted
120
120
  # a.*b.c is not
121
+ # A later rule ensures that * always falls at the end of a path
121
122
  def stars_are_solitary?(path)
122
123
  !path.split('.').any? {|s| s.match(/.+\*|\*.+/)}
123
124
  end
124
125
 
125
- # a.b|c.d is valid
126
+ # a.b|c.d is accepted
126
127
  # a.|b.c is not
127
128
  def pipes_are_interleaved?(path)
128
129
  !path.split('.').any? {|s| s.match(/^\||\|$/)}
129
130
  end
130
131
 
131
- # a.^b.c is valid
132
+ # a.^b.c is accepted
132
133
  # a.b^c.d is not
133
134
  def carets_are_leading?(path)
134
135
  !path.split('.').any? {|s| s.match(/.+\^|\^$/) }
135
136
  end
136
137
 
137
- # a.b.* is valid
138
+ # a.b.* is accepted
138
139
  # *.b.c is not
139
140
  def stars_are_terminating?(path)
140
141
  path !~ /.*\*\.\w/
141
142
  end
143
+
142
144
  end
143
145
  end
144
146
 
@@ -1,3 +1,3 @@
1
1
  module Pebblebed
2
- VERSION = "0.0.22"
2
+ VERSION = "0.0.23"
3
3
  end
data/lib/pebblebed.rb CHANGED
@@ -10,3 +10,6 @@ require 'pebblebed/clients/quorum_client'
10
10
  require 'pebblebed/parts'
11
11
  require 'pebblebed/river'
12
12
  require 'pebblebed/labels'
13
+ require 'pebblebed/security/access_data'
14
+ require 'pebblebed/security/client'
15
+ require 'pebblebed/security/listener'
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'pebblebed/uid'
3
+ require 'pebblebed/security/access_data'
4
+
5
+ describe Pebblebed::Security::AccessData do
6
+ let :access_data do
7
+ Pebblebed::Security::AccessData.new(
8
+ :groups => [1,2,3],
9
+ :subtrees => ['a.b', 'a.b.c.d.e', 'a.c.d', 'a.c.e.f']
10
+ )
11
+ end
12
+
13
+ it "can calculate a pristine path" do
14
+ Pebblebed::Security::AccessData.pristine_path("a.b.c|d").should eq "a.b"
15
+ Pebblebed::Security::AccessData.pristine_path("a.b").should eq "a.b"
16
+ end
17
+
18
+ it "can calculate relevant paths" do
19
+ access_data.relevant_subtrees('a.b').sort.should eq ['a.b', 'a.b.c.d.e']
20
+ access_data.relevant_subtrees('a.b.c').sort.should eq ['a.b', 'a.b.c.d.e']
21
+ access_data.relevant_subtrees('a.c.e').sort.should eq ['a.c.e.f']
22
+ access_data.relevant_subtrees('a.*').sort.should eq ['a.b', 'a.b.c.d.e', 'a.c.d', 'a.c.e.f']
23
+ end
24
+
25
+ it "can parse a checkpoint record" do
26
+ record = {
27
+ 'memberships' => [
28
+ {'membership' => {'id' => 10, 'group_id' => 1, 'identity_id' => 1}},
29
+ {'membership' => {'id' => 20, 'group_id' => 2, 'identity_id' => 1}},
30
+ ],
31
+ 'groups' => [
32
+ {'group' => {'id' => 1, 'label' => "group_1", 'subtrees' => ["a.b.c"]}},
33
+ {'group' => {'id' => 2, 'label' => "group_2", 'subtrees' => ["a.c.d.c"]}}
34
+ ]
35
+ }
36
+ ad = Pebblebed::Security::AccessData.new(record)
37
+ ad.subtrees.sort.should eq ['a.b.c', 'a.c.d.c']
38
+ ad.group_ids.sort.should eq [1,2]
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'pebblebed/uid'
3
+ require 'pebblebed/security/access_data'
4
+ require 'pebblebed/security/client'
5
+
6
+ describe Pebblebed::Security::Client do
7
+ let :client do
8
+ Pebblebed::Security::Client.new(nil)
9
+ end
10
+
11
+ let :sample_memberships_record do
12
+ {
13
+ 'memberships' => [
14
+ {'membership' => {'id' => 10, 'group_id' => 1, 'identity_id' => 1}},
15
+ {'membership' => {'id' => 20, 'group_id' => 2, 'identity_id' => 1}},
16
+ ],
17
+ 'groups' => [
18
+ {'group' => {'id' => 1, 'label' => "group_1", 'subtrees' => ["a.b.c"]}},
19
+ {'group' => {'id' => 2, 'label' => "group_2", 'subtrees' => ["a.c.d.c"]}}
20
+ ]
21
+ }
22
+ end
23
+
24
+ it "can fetch access_data" do
25
+ client.stub(:fetch_membership_data_for).and_return(sample_memberships_record)
26
+ ad = client.access_data_for(1)
27
+ ad.subtrees.sort.should eq ['a.b.c', 'a.c.d.c']
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'pebblebed/uid'
3
+ require 'pebblebed/security/listener'
4
+
5
+ describe Pebblebed::Security::Listener do
6
+ let :listener do
7
+ Pebblebed::Security::Listener.new(:app_name => "test")
8
+ end
9
+
10
+ it "can generate events from incoming messages" do
11
+ the_attrs = nil
12
+ listener.on_group_declared do |attrs|
13
+ the_attrs = attrs
14
+ end
15
+ message = {:payload => {
16
+ 'event' => 'create',
17
+ 'uid' => 'group:abc.groups$10',
18
+ 'attributes' => {
19
+ 'id' => 10,
20
+ 'label' => 'the_label'
21
+ }
22
+ }.to_json}
23
+ listener.send(:consider, message)
24
+ the_attrs[:id].should eq 10
25
+ end
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pebblebed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.22
4
+ version: 0.0.23
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-09-07 00:00:00.000000000 Z
13
+ date: 2012-09-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
17
- requirement: &70305565590520 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,15 @@ dependencies:
22
22
  version: '0'
23
23
  type: :development
24
24
  prerelease: false
25
- version_requirements: *70305565590520
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: rake
28
- requirement: &70305565590060 !ruby/object:Gem::Requirement
33
+ requirement: !ruby/object:Gem::Requirement
29
34
  none: false
30
35
  requirements:
31
36
  - - ! '>='
@@ -33,10 +38,15 @@ dependencies:
33
38
  version: '0'
34
39
  type: :development
35
40
  prerelease: false
36
- version_requirements: *70305565590060
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: simplecov
39
- requirement: &70305565589480 !ruby/object:Gem::Requirement
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  none: false
41
51
  requirements:
42
52
  - - ! '>='
@@ -44,10 +54,15 @@ dependencies:
44
54
  version: '0'
45
55
  type: :development
46
56
  prerelease: false
47
- version_requirements: *70305565589480
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
48
63
  - !ruby/object:Gem::Dependency
49
64
  name: deepstruct
50
- requirement: &70305565588760 !ruby/object:Gem::Requirement
65
+ requirement: !ruby/object:Gem::Requirement
51
66
  none: false
52
67
  requirements:
53
68
  - - ! '>='
@@ -55,10 +70,15 @@ dependencies:
55
70
  version: 0.0.2
56
71
  type: :runtime
57
72
  prerelease: false
58
- version_requirements: *70305565588760
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: 0.0.2
59
79
  - !ruby/object:Gem::Dependency
60
80
  name: curb
61
- requirement: &70305565588160 !ruby/object:Gem::Requirement
81
+ requirement: !ruby/object:Gem::Requirement
62
82
  none: false
63
83
  requirements:
64
84
  - - ! '>='
@@ -66,10 +86,15 @@ dependencies:
66
86
  version: 0.7.14
67
87
  type: :runtime
68
88
  prerelease: false
69
- version_requirements: *70305565588160
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: 0.7.14
70
95
  - !ruby/object:Gem::Dependency
71
96
  name: yajl-ruby
72
- requirement: &70305565587700 !ruby/object:Gem::Requirement
97
+ requirement: !ruby/object:Gem::Requirement
73
98
  none: false
74
99
  requirements:
75
100
  - - ! '>='
@@ -77,10 +102,15 @@ dependencies:
77
102
  version: '0'
78
103
  type: :runtime
79
104
  prerelease: false
80
- version_requirements: *70305565587700
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
81
111
  - !ruby/object:Gem::Dependency
82
112
  name: queryparams
83
- requirement: &70305565609740 !ruby/object:Gem::Requirement
113
+ requirement: !ruby/object:Gem::Requirement
84
114
  none: false
85
115
  requirements:
86
116
  - - ! '>='
@@ -88,10 +118,15 @@ dependencies:
88
118
  version: '0'
89
119
  type: :runtime
90
120
  prerelease: false
91
- version_requirements: *70305565609740
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
92
127
  - !ruby/object:Gem::Dependency
93
128
  name: futurevalue
94
- requirement: &70305565608660 !ruby/object:Gem::Requirement
129
+ requirement: !ruby/object:Gem::Requirement
95
130
  none: false
96
131
  requirements:
97
132
  - - ! '>='
@@ -99,10 +134,15 @@ dependencies:
99
134
  version: '0'
100
135
  type: :runtime
101
136
  prerelease: false
102
- version_requirements: *70305565608660
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
103
143
  - !ruby/object:Gem::Dependency
104
144
  name: pathbuilder
105
- requirement: &70305565607720 !ruby/object:Gem::Requirement
145
+ requirement: !ruby/object:Gem::Requirement
106
146
  none: false
107
147
  requirements:
108
148
  - - ! '>='
@@ -110,10 +150,15 @@ dependencies:
110
150
  version: '0'
111
151
  type: :runtime
112
152
  prerelease: false
113
- version_requirements: *70305565607720
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
114
159
  - !ruby/object:Gem::Dependency
115
160
  name: nokogiri
116
- requirement: &70305565606900 !ruby/object:Gem::Requirement
161
+ requirement: !ruby/object:Gem::Requirement
117
162
  none: false
118
163
  requirements:
119
164
  - - ! '>='
@@ -121,10 +166,15 @@ dependencies:
121
166
  version: '0'
122
167
  type: :runtime
123
168
  prerelease: false
124
- version_requirements: *70305565606900
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ! '>='
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
125
175
  - !ruby/object:Gem::Dependency
126
176
  name: i18n
127
- requirement: &70305565605840 !ruby/object:Gem::Requirement
177
+ requirement: !ruby/object:Gem::Requirement
128
178
  none: false
129
179
  requirements:
130
180
  - - ! '>='
@@ -132,10 +182,15 @@ dependencies:
132
182
  version: '0'
133
183
  type: :runtime
134
184
  prerelease: false
135
- version_requirements: *70305565605840
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ none: false
187
+ requirements:
188
+ - - ! '>='
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
136
191
  - !ruby/object:Gem::Dependency
137
192
  name: activesupport
138
- requirement: &70305565603700 !ruby/object:Gem::Requirement
193
+ requirement: !ruby/object:Gem::Requirement
139
194
  none: false
140
195
  requirements:
141
196
  - - ! '>='
@@ -143,10 +198,15 @@ dependencies:
143
198
  version: '0'
144
199
  type: :runtime
145
200
  prerelease: false
146
- version_requirements: *70305565603700
201
+ version_requirements: !ruby/object:Gem::Requirement
202
+ none: false
203
+ requirements:
204
+ - - ! '>='
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
147
207
  - !ruby/object:Gem::Dependency
148
208
  name: bunny
149
- requirement: &70305565602840 !ruby/object:Gem::Requirement
209
+ requirement: !ruby/object:Gem::Requirement
150
210
  none: false
151
211
  requirements:
152
212
  - - ! '>='
@@ -154,7 +214,12 @@ dependencies:
154
214
  version: '0'
155
215
  type: :runtime
156
216
  prerelease: false
157
- version_requirements: *70305565602840
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ none: false
219
+ requirements:
220
+ - - ! '>='
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
158
223
  description: Development tools for working with Pebblebed
159
224
  email:
160
225
  - katrina@bengler.no
@@ -180,6 +245,9 @@ files:
180
245
  - lib/pebblebed/parts.rb
181
246
  - lib/pebblebed/river.rb
182
247
  - lib/pebblebed/river/subscription.rb
248
+ - lib/pebblebed/security/access_data.rb
249
+ - lib/pebblebed/security/client.rb
250
+ - lib/pebblebed/security/listener.rb
183
251
  - lib/pebblebed/sinatra.rb
184
252
  - lib/pebblebed/uid.rb
185
253
  - lib/pebblebed/uid_query.rb
@@ -194,6 +262,9 @@ files:
194
262
  - spec/mockcached.rb
195
263
  - spec/river_spec.rb
196
264
  - spec/river_subscription_spec.rb
265
+ - spec/security/access_data_spec.rb
266
+ - spec/security/client_spec.rb
267
+ - spec/security/listener_spec.rb
197
268
  - spec/spec_helper.rb
198
269
  - spec/uid_query_spec.rb
199
270
  - spec/uid_spec.rb
@@ -209,15 +280,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
209
280
  - - ! '>='
210
281
  - !ruby/object:Gem::Version
211
282
  version: '0'
283
+ segments:
284
+ - 0
285
+ hash: 4364516963973573943
212
286
  required_rubygems_version: !ruby/object:Gem::Requirement
213
287
  none: false
214
288
  requirements:
215
289
  - - ! '>='
216
290
  - !ruby/object:Gem::Version
217
291
  version: '0'
292
+ segments:
293
+ - 0
294
+ hash: 4364516963973573943
218
295
  requirements: []
219
296
  rubyforge_project: pebblebed
220
- rubygems_version: 1.8.15
297
+ rubygems_version: 1.8.24
221
298
  signing_key:
222
299
  specification_version: 3
223
300
  summary: Development tools for working with Pebblebed
@@ -231,6 +308,9 @@ test_files:
231
308
  - spec/mockcached.rb
232
309
  - spec/river_spec.rb
233
310
  - spec/river_subscription_spec.rb
311
+ - spec/security/access_data_spec.rb
312
+ - spec/security/client_spec.rb
313
+ - spec/security/listener_spec.rb
234
314
  - spec/spec_helper.rb
235
315
  - spec/uid_query_spec.rb
236
316
  - spec/uid_spec.rb