chef-zero 15.0.17 → 15.0.21
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.
- checksums.yaml +4 -4
- data/Gemfile +36 -31
- data/LICENSE +201 -201
- data/Rakefile +73 -68
- data/bin/chef-zero +111 -111
- data/chef-zero.gemspec +34 -33
- data/lib/chef_zero/chef_data/acl_path.rb +140 -140
- data/lib/chef_zero/chef_data/cookbook_data.rb +237 -237
- data/lib/chef_zero/chef_data/data_normalizer.rb +276 -276
- data/lib/chef_zero/chef_data/default_creator.rb +476 -476
- data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
- data/lib/chef_zero/data_store/data_error.rb +32 -32
- data/lib/chef_zero/data_store/data_not_found_error.rb +29 -29
- data/lib/chef_zero/data_store/default_facade.rb +143 -147
- data/lib/chef_zero/data_store/interface_v1.rb +67 -67
- data/lib/chef_zero/data_store/interface_v2.rb +18 -18
- data/lib/chef_zero/data_store/memory_store.rb +33 -33
- data/lib/chef_zero/data_store/memory_store_v2.rb +159 -159
- data/lib/chef_zero/data_store/raw_file_store.rb +143 -143
- data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +150 -150
- data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +105 -105
- data/lib/chef_zero/dist.rb +9 -9
- data/lib/chef_zero/endpoints/acl_endpoint.rb +39 -39
- data/lib/chef_zero/endpoints/acls_endpoint.rb +41 -41
- data/lib/chef_zero/endpoints/actor_default_key_endpoint.rb +78 -78
- data/lib/chef_zero/endpoints/actor_endpoint.rb +184 -184
- data/lib/chef_zero/endpoints/actor_key_endpoint.rb +62 -62
- data/lib/chef_zero/endpoints/actor_keys_endpoint.rb +129 -129
- data/lib/chef_zero/endpoints/actors_endpoint.rb +104 -104
- data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +32 -32
- data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/containers_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/controls_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/cookbook_artifact_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/cookbook_artifact_identifier_endpoint.rb +68 -68
- data/lib/chef_zero/endpoints/cookbook_artifacts_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
- data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +136 -136
- data/lib/chef_zero/endpoints/cookbooks_base.rb +80 -80
- data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
- data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
- data/lib/chef_zero/endpoints/dummy_endpoint.rb +29 -29
- data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +126 -126
- data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
- data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
- data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
- data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
- data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
- data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
- data/lib/chef_zero/endpoints/node_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/nodes_endpoint.rb +34 -34
- data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
- data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -30
- data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/organization_endpoint.rb +47 -47
- data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
- data/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/organization_user_key_endpoint.rb +17 -17
- data/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb +17 -17
- data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -43
- data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
- data/lib/chef_zero/endpoints/organizations_endpoint.rb +61 -61
- data/lib/chef_zero/endpoints/policies_endpoint.rb +26 -26
- data/lib/chef_zero/endpoints/policy_endpoint.rb +24 -24
- data/lib/chef_zero/endpoints/policy_group_endpoint.rb +46 -46
- data/lib/chef_zero/endpoints/policy_group_policy_endpoint.rb +83 -83
- data/lib/chef_zero/endpoints/policy_groups_endpoint.rb +38 -38
- data/lib/chef_zero/endpoints/policy_revision_endpoint.rb +66 -66
- data/lib/chef_zero/endpoints/policy_revisions_endpoint.rb +15 -15
- data/lib/chef_zero/endpoints/principal_endpoint.rb +55 -55
- data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
- data/lib/chef_zero/endpoints/rest_object_endpoint.rb +78 -78
- data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
- data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
- data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
- data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +51 -51
- data/lib/chef_zero/endpoints/search_endpoint.rb +208 -208
- data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
- data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -14
- data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
- data/lib/chef_zero/endpoints/universe_endpoint.rb +15 -15
- data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +41 -41
- data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
- data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
- data/lib/chef_zero/endpoints/version_endpoint.rb +13 -13
- data/lib/chef_zero/log.rb +7 -7
- data/lib/chef_zero/rest_base.rb +332 -332
- data/lib/chef_zero/rest_error_response.rb +11 -11
- data/lib/chef_zero/rest_request.rb +84 -88
- data/lib/chef_zero/rest_router.rb +72 -72
- data/lib/chef_zero/rspec.rb +355 -355
- data/lib/chef_zero/server.rb +730 -730
- data/lib/chef_zero/socketless_server_map.rb +92 -93
- data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
- data/lib/chef_zero/solr/query/phrase.rb +23 -23
- data/lib/chef_zero/solr/query/range_query.rb +46 -46
- data/lib/chef_zero/solr/query/regexpable_query.rb +30 -30
- data/lib/chef_zero/solr/query/subquery.rb +37 -37
- data/lib/chef_zero/solr/query/term.rb +45 -45
- data/lib/chef_zero/solr/query/unary_operator.rb +41 -41
- data/lib/chef_zero/solr/solr_doc.rb +53 -53
- data/lib/chef_zero/solr/solr_parser.rb +208 -208
- data/lib/chef_zero/version.rb +3 -3
- data/lib/chef_zero.rb +10 -10
- data/spec/run_oc_pedant.rb +226 -226
- data/spec/search_spec.rb +36 -36
- data/spec/server_spec.rb +96 -96
- data/spec/socketless_server_map_spec.rb +74 -74
- data/spec/support/oc_pedant.rb +149 -149
- data/spec/support/secrets.json +6 -6
- data/spec/support/stickywicket.pem +27 -27
- metadata +35 -18
@@ -1,476 +1,476 @@
|
|
1
|
-
require_relative "acl_path"
|
2
|
-
|
3
|
-
module ChefZero
|
4
|
-
module ChefData
|
5
|
-
#
|
6
|
-
# The DefaultCreator creates default values when you ask for them.
|
7
|
-
# - It relies on created and deleted being called when things get
|
8
|
-
# created and deleted, so that it knows the owners of said objects
|
9
|
-
# and knows to eliminate default values on delete.
|
10
|
-
# - get, list and exists? get data.
|
11
|
-
#
|
12
|
-
class DefaultCreator
|
13
|
-
def initialize(data, single_org, osc_compat, superusers = nil)
|
14
|
-
@data = data
|
15
|
-
@single_org = single_org
|
16
|
-
@osc_compat = osc_compat
|
17
|
-
@superusers = superusers || DEFAULT_SUPERUSERS
|
18
|
-
clear
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_reader :data
|
22
|
-
attr_reader :single_org
|
23
|
-
attr_reader :osc_compat
|
24
|
-
attr_reader :creators
|
25
|
-
attr_writer :deleted
|
26
|
-
|
27
|
-
PERMISSIONS = %w{create read update delete grant}.freeze
|
28
|
-
DEFAULT_SUPERUSERS = %w{pivotal}.freeze
|
29
|
-
|
30
|
-
def clear
|
31
|
-
@creators = { [] => @superusers }
|
32
|
-
@deleted = {}
|
33
|
-
end
|
34
|
-
|
35
|
-
def deleted(path)
|
36
|
-
# acl deletes mean nothing, they are entirely subservient to their
|
37
|
-
# parent object
|
38
|
-
if path[0] == "acls" || (path[0] == "organizations" && path[2] == "acls")
|
39
|
-
return false
|
40
|
-
end
|
41
|
-
|
42
|
-
result = exists?(path)
|
43
|
-
@deleted[path] = true
|
44
|
-
result
|
45
|
-
end
|
46
|
-
|
47
|
-
def deleted?(path)
|
48
|
-
1.upto(path.size) do |index|
|
49
|
-
return true if @deleted[path[0..-index]]
|
50
|
-
end
|
51
|
-
false
|
52
|
-
end
|
53
|
-
|
54
|
-
def created(path, creator, create_parents)
|
55
|
-
# If a parent has been deleted, we will need to clear that.
|
56
|
-
deleted_index = nil
|
57
|
-
0.upto(path.size - 1) do |index|
|
58
|
-
deleted_index = index if @deleted[path[0..index]]
|
59
|
-
end
|
60
|
-
|
61
|
-
# Walk up the tree, setting the creator on anything that doesn't exist
|
62
|
-
# (anything that is either deleted or was never created)
|
63
|
-
while (deleted_index && path.size > deleted_index) || !@creators[path]
|
64
|
-
@creators[path] = creator ? [ creator ] : []
|
65
|
-
@deleted.delete(path)
|
66
|
-
# Only do this once if create_parents is false
|
67
|
-
break if !create_parents || path.size == 0
|
68
|
-
|
69
|
-
path = path[0..-2]
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def superusers
|
74
|
-
@creators[[]]
|
75
|
-
end
|
76
|
-
|
77
|
-
def get(path)
|
78
|
-
return nil if deleted?(path)
|
79
|
-
|
80
|
-
result = case path[0]
|
81
|
-
when "acls"
|
82
|
-
# /acls/*
|
83
|
-
object_path = AclPath.get_object_path(path)
|
84
|
-
if data_exists?(object_path)
|
85
|
-
default_acl(path)
|
86
|
-
end
|
87
|
-
|
88
|
-
when "containers"
|
89
|
-
if path.size == 2 && exists?(path)
|
90
|
-
{}
|
91
|
-
end
|
92
|
-
|
93
|
-
when "users"
|
94
|
-
if path.size == 2 && data.exists?(path)
|
95
|
-
# User is empty user
|
96
|
-
{}
|
97
|
-
end
|
98
|
-
|
99
|
-
when "organizations"
|
100
|
-
if path.size >= 2
|
101
|
-
# /organizations/*/**
|
102
|
-
if data.exists_dir?(path[0..1])
|
103
|
-
get_org_default(path)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
result
|
109
|
-
end
|
110
|
-
|
111
|
-
def list(path)
|
112
|
-
return nil if deleted?(path)
|
113
|
-
|
114
|
-
if path.size == 0
|
115
|
-
return %w{containers users organizations acls}
|
116
|
-
end
|
117
|
-
|
118
|
-
case path[0]
|
119
|
-
when "acls"
|
120
|
-
if path.size == 1
|
121
|
-
[ "root" ] + (data.list(path + [ "containers" ]) - [ "organizations" ])
|
122
|
-
else
|
123
|
-
data.list(AclPath.get_object_path(path))
|
124
|
-
end
|
125
|
-
|
126
|
-
when "containers"
|
127
|
-
%w{containers users organizations}
|
128
|
-
|
129
|
-
when "users"
|
130
|
-
superusers
|
131
|
-
|
132
|
-
when "organizations"
|
133
|
-
if path.size == 1
|
134
|
-
single_org ? [ single_org ] : []
|
135
|
-
elsif path.size >= 2 && data.exists_dir?(path[0..1])
|
136
|
-
list_org_default(path)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def exists?(path)
|
142
|
-
return true if path.size == 0
|
143
|
-
|
144
|
-
parent_list = list(path[0..-2])
|
145
|
-
parent_list && parent_list.include?(path[-1])
|
146
|
-
end
|
147
|
-
|
148
|
-
protected
|
149
|
-
|
150
|
-
DEFAULT_ORG_SPINE = {
|
151
|
-
"clients" => {},
|
152
|
-
"cookbook_artifacts" => {},
|
153
|
-
"cookbooks" => {},
|
154
|
-
"data" => {},
|
155
|
-
"environments" => %w{_default},
|
156
|
-
"file_store" => {
|
157
|
-
"checksums" => {},
|
158
|
-
},
|
159
|
-
"nodes" => {},
|
160
|
-
"policies" => {},
|
161
|
-
"policy_groups" => {},
|
162
|
-
"roles" => {},
|
163
|
-
"sandboxes" => {},
|
164
|
-
"users" => {},
|
165
|
-
|
166
|
-
"org" => {},
|
167
|
-
"containers" => %w{clients containers cookbook_artifacts cookbooks data environments groups nodes policies policy_groups roles sandboxes},
|
168
|
-
"groups" => %w{admins billing-admins clients users},
|
169
|
-
"association_requests" => {},
|
170
|
-
}.freeze
|
171
|
-
|
172
|
-
def list_org_default(path)
|
173
|
-
if path.size >= 3 && path[2] == "acls"
|
174
|
-
if path.size == 3
|
175
|
-
# /organizations/ORG/acls
|
176
|
-
return [ "root" ] + data.list(path[0..1] + [ "containers" ])
|
177
|
-
elsif path.size == 4
|
178
|
-
# /organizations/ORG/acls/TYPE
|
179
|
-
return data.list(path[0..1] + [ path[3] ])
|
180
|
-
else
|
181
|
-
return nil
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
value = DEFAULT_ORG_SPINE
|
186
|
-
2.upto(path.size - 1) do |index|
|
187
|
-
value = nil if @deleted[path[0..index]]
|
188
|
-
break unless value
|
189
|
-
|
190
|
-
value = value[path[index]]
|
191
|
-
end
|
192
|
-
|
193
|
-
result = if value.is_a?(Hash)
|
194
|
-
value.keys
|
195
|
-
elsif value
|
196
|
-
value
|
197
|
-
end
|
198
|
-
|
199
|
-
if path.size == 3
|
200
|
-
if path[2] == "clients"
|
201
|
-
result << "#{path[1]}-validator"
|
202
|
-
if osc_compat
|
203
|
-
result << "#{path[1]}-webui"
|
204
|
-
end
|
205
|
-
elsif path[2] == "users"
|
206
|
-
if osc_compat
|
207
|
-
result << "admin"
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
result
|
213
|
-
end
|
214
|
-
|
215
|
-
def get_org_default(path)
|
216
|
-
if path[2] == "acls"
|
217
|
-
get_org_acl_default(path)
|
218
|
-
|
219
|
-
elsif path.size >= 4
|
220
|
-
if path[2] == "containers" && path.size == 4
|
221
|
-
if exists?(path)
|
222
|
-
return {}
|
223
|
-
else
|
224
|
-
return nil
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
# /organizations/(*)/clients/\1-validator
|
229
|
-
# /organizations/*/environments/_default
|
230
|
-
# /organizations/*/groups/{admins,billing-admins,clients,users}
|
231
|
-
case path[2..-1].join("/")
|
232
|
-
when "clients/#{path[1]}-validator"
|
233
|
-
{ "validator" => "true" }
|
234
|
-
|
235
|
-
when "clients/#{path[1]}-webui", "users/admin"
|
236
|
-
if osc_compat
|
237
|
-
{ "admin" => "true" }
|
238
|
-
end
|
239
|
-
|
240
|
-
when "environments/_default"
|
241
|
-
{ "description" => "The default Chef environment" }
|
242
|
-
|
243
|
-
when "groups/admins"
|
244
|
-
admins = data.list(path[0..1] + [ "users" ]).select do |name|
|
245
|
-
user = FFI_Yajl::Parser.parse(data.get(path[0..1] + [ "users", name ]))
|
246
|
-
user["admin"]
|
247
|
-
end
|
248
|
-
admins += data.list(path[0..1] + [ "clients" ]).select do |name|
|
249
|
-
client = FFI_Yajl::Parser.parse(data.get(path[0..1] + [ "clients", name ]))
|
250
|
-
client["admin"]
|
251
|
-
end
|
252
|
-
admins += @creators[path[0..1]] if @creators[path[0..1]]
|
253
|
-
{ "actors" => admins.uniq }
|
254
|
-
|
255
|
-
when "groups/billing-admins"
|
256
|
-
{}
|
257
|
-
|
258
|
-
when "groups/clients"
|
259
|
-
{ "clients" => data.list(path[0..1] + [ "clients" ]) }
|
260
|
-
|
261
|
-
when "groups/users"
|
262
|
-
users = data.list(path[0..1] + [ "users" ])
|
263
|
-
users |= @creators[path[0..1]] if @creators[path[0..1]]
|
264
|
-
{ "users" => users }
|
265
|
-
|
266
|
-
when "org"
|
267
|
-
{}
|
268
|
-
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
def get_org_acl_default(path)
|
274
|
-
object_path = AclPath.get_object_path(path)
|
275
|
-
# The actual things containers correspond to don't have to exist, as
|
276
|
-
# long as the container does
|
277
|
-
return nil unless data_exists?(object_path)
|
278
|
-
|
279
|
-
basic_acl =
|
280
|
-
case path[3..-1].join("/")
|
281
|
-
when "root", "containers/containers", "containers/groups"
|
282
|
-
{
|
283
|
-
"create" => { "groups" => %w{admins} },
|
284
|
-
"read" => { "groups" => %w{admins users} },
|
285
|
-
"update" => { "groups" => %w{admins} },
|
286
|
-
"delete" => { "groups" => %w{admins} },
|
287
|
-
"grant" => { "groups" => %w{admins} },
|
288
|
-
}
|
289
|
-
when "containers/environments", "containers/roles",
|
290
|
-
"containers/policy_groups", "containers/policies",
|
291
|
-
"containers/cookbooks", "containers/cookbook_artifacts",
|
292
|
-
"containers/data"
|
293
|
-
{
|
294
|
-
"create" => { "groups" => %w{admins users} },
|
295
|
-
"read" => { "groups" => %w{admins users clients} },
|
296
|
-
"update" => { "groups" => %w{admins users} },
|
297
|
-
"delete" => { "groups" => %w{admins users} },
|
298
|
-
"grant" => { "groups" => %w{admins} },
|
299
|
-
}
|
300
|
-
when "containers/nodes"
|
301
|
-
{
|
302
|
-
"create" => { "groups" => %w{admins users clients} },
|
303
|
-
"read" => { "groups" => %w{admins users clients} },
|
304
|
-
"update" => { "groups" => %w{admins users} },
|
305
|
-
"delete" => { "groups" => %w{admins users} },
|
306
|
-
"grant" => { "groups" => %w{admins} },
|
307
|
-
}
|
308
|
-
when "containers/clients"
|
309
|
-
{
|
310
|
-
"create" => { "groups" => %w{admins} },
|
311
|
-
"read" => { "groups" => %w{admins users} },
|
312
|
-
"update" => { "groups" => %w{admins} },
|
313
|
-
"delete" => { "groups" => %w{admins users} },
|
314
|
-
"grant" => { "groups" => %w{admins} },
|
315
|
-
}
|
316
|
-
when "containers/sandboxes"
|
317
|
-
{
|
318
|
-
"create" => { "groups" => %w{admins users} },
|
319
|
-
"read" => { "groups" => %w{admins} },
|
320
|
-
"update" => { "groups" => %w{admins} },
|
321
|
-
"delete" => { "groups" => %w{admins} },
|
322
|
-
"grant" => { "groups" => %w{admins} },
|
323
|
-
}
|
324
|
-
when "groups/admins", "groups/clients", "groups/users"
|
325
|
-
{
|
326
|
-
"create" => { "groups" => %w{admins} },
|
327
|
-
"read" => { "groups" => %w{admins} },
|
328
|
-
"update" => { "groups" => %w{admins} },
|
329
|
-
"delete" => { "groups" => %w{admins} },
|
330
|
-
"grant" => { "groups" => %w{admins} },
|
331
|
-
}
|
332
|
-
when "groups/billing-admins"
|
333
|
-
{
|
334
|
-
"create" => { "groups" => %w{} },
|
335
|
-
"read" => { "groups" => %w{billing-admins} },
|
336
|
-
"update" => { "groups" => %w{billing-admins} },
|
337
|
-
"delete" => { "groups" => %w{} },
|
338
|
-
"grant" => { "groups" => %w{} },
|
339
|
-
}
|
340
|
-
else
|
341
|
-
{}
|
342
|
-
end
|
343
|
-
|
344
|
-
default_acl(path, basic_acl)
|
345
|
-
end
|
346
|
-
|
347
|
-
def get_owners(acl_path)
|
348
|
-
unknown_owners = []
|
349
|
-
path = AclPath.get_object_path(acl_path)
|
350
|
-
if path
|
351
|
-
|
352
|
-
# Non-validator clients own themselves.
|
353
|
-
if path.size == 4 && path[0] == "organizations" && path[2] == "clients"
|
354
|
-
begin
|
355
|
-
client = FFI_Yajl::Parser.parse(data.get(path))
|
356
|
-
unless client["validator"]
|
357
|
-
unknown_owners |= [ path[3] ]
|
358
|
-
end
|
359
|
-
rescue
|
360
|
-
unknown_owners |= [ path[3] ]
|
361
|
-
end
|
362
|
-
|
363
|
-
# Add creators as owners (except any validator clients).
|
364
|
-
if @creators[path]
|
365
|
-
@creators[path].each do |creator|
|
366
|
-
begin
|
367
|
-
client = FFI_Yajl::Parser.parse(data.get(path[0..2] + [ creator ]))
|
368
|
-
next if client["validator"]
|
369
|
-
rescue
|
370
|
-
end
|
371
|
-
unknown_owners |= [ creator ]
|
372
|
-
end
|
373
|
-
end
|
374
|
-
else
|
375
|
-
unknown_owners |= @creators[path] if @creators[path]
|
376
|
-
end
|
377
|
-
owners = filter_owners(path, unknown_owners)
|
378
|
-
|
379
|
-
# ANGRY
|
380
|
-
# Non-default containers do not get superusers added to them,
|
381
|
-
# because reasons.
|
382
|
-
unless path.size == 4 && path[0] == "organizations" && path[2] == "containers" && !exists?(path)
|
383
|
-
owners[:users] += superusers
|
384
|
-
end
|
385
|
-
else
|
386
|
-
owners = { clients: [], users: [] }
|
387
|
-
end
|
388
|
-
|
389
|
-
owners[:users].uniq!
|
390
|
-
owners[:clients].uniq!
|
391
|
-
owners
|
392
|
-
end
|
393
|
-
|
394
|
-
# Figures out if an object was created by a user or client.
|
395
|
-
# If the object does not exist in the context
|
396
|
-
# of an organization, it can only be a user
|
397
|
-
#
|
398
|
-
# This isn't perfect, because we are never explicitly told
|
399
|
-
# if a requestor creating an object is a user or client -
|
400
|
-
# but it gets us reasonably close
|
401
|
-
def filter_owners(path, unknown_owners)
|
402
|
-
owners = { clients: [], users: [] }
|
403
|
-
unknown_owners.each do |entity|
|
404
|
-
if path[0] == "organizations" && path.length > 2
|
405
|
-
begin
|
406
|
-
data.get(["organizations", path[1], "clients", entity])
|
407
|
-
owners[:clients] |= [ entity ]
|
408
|
-
rescue
|
409
|
-
owners[:users] |= [ entity ]
|
410
|
-
end
|
411
|
-
else
|
412
|
-
owners[:users] |= [ entity ]
|
413
|
-
end
|
414
|
-
end
|
415
|
-
owners
|
416
|
-
end
|
417
|
-
|
418
|
-
def default_acl(acl_path, acl = {})
|
419
|
-
owners = get_owners(acl_path)
|
420
|
-
container_acl = nil
|
421
|
-
PERMISSIONS.each do |perm|
|
422
|
-
acl[perm] ||= {}
|
423
|
-
acl[perm]["users"] = owners[:users]
|
424
|
-
acl[perm]["clients"] = owners[:clients]
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
acl[perm]["actors"] = acl[perm]["clients"] + acl[perm]["users"]
|
435
|
-
end
|
436
|
-
acl
|
437
|
-
end
|
438
|
-
|
439
|
-
def get_container_acl(acl_path)
|
440
|
-
parent_path = AclPath.parent_acl_data_path(acl_path)
|
441
|
-
if parent_path
|
442
|
-
FFI_Yajl::Parser.parse(data.get(parent_path))
|
443
|
-
else
|
444
|
-
nil
|
445
|
-
end
|
446
|
-
end
|
447
|
-
|
448
|
-
def data_exists?(path)
|
449
|
-
if is_dir?(path)
|
450
|
-
data.exists_dir?(path)
|
451
|
-
else
|
452
|
-
data.exists?(path)
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
def is_dir?(path)
|
457
|
-
case path.size
|
458
|
-
when 0, 1
|
459
|
-
true
|
460
|
-
when 2
|
461
|
-
path[0] == "organizations" || (path[0] == "acls" && path[1] != "root")
|
462
|
-
when 3
|
463
|
-
# If it has a container, it is a directory.
|
464
|
-
path[0] == "organizations" &&
|
465
|
-
(path[2] == "acls" || data.exists?(path[0..1] + [ "containers", path[2] ]))
|
466
|
-
when 4
|
467
|
-
path[0] == "organizations" && (
|
468
|
-
(path[2] == "acls" && path[1] != "root") ||
|
469
|
-
%w{cookbooks cookbook_artifacts data policies policy_groups}.include?(path[2]))
|
470
|
-
else
|
471
|
-
false
|
472
|
-
end
|
473
|
-
end
|
474
|
-
end
|
475
|
-
end
|
476
|
-
end
|
1
|
+
require_relative "acl_path"
|
2
|
+
|
3
|
+
module ChefZero
|
4
|
+
module ChefData
|
5
|
+
#
|
6
|
+
# The DefaultCreator creates default values when you ask for them.
|
7
|
+
# - It relies on created and deleted being called when things get
|
8
|
+
# created and deleted, so that it knows the owners of said objects
|
9
|
+
# and knows to eliminate default values on delete.
|
10
|
+
# - get, list and exists? get data.
|
11
|
+
#
|
12
|
+
class DefaultCreator
|
13
|
+
def initialize(data, single_org, osc_compat, superusers = nil)
|
14
|
+
@data = data
|
15
|
+
@single_org = single_org
|
16
|
+
@osc_compat = osc_compat
|
17
|
+
@superusers = superusers || DEFAULT_SUPERUSERS
|
18
|
+
clear
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :data
|
22
|
+
attr_reader :single_org
|
23
|
+
attr_reader :osc_compat
|
24
|
+
attr_reader :creators
|
25
|
+
attr_writer :deleted
|
26
|
+
|
27
|
+
PERMISSIONS = %w{create read update delete grant}.freeze
|
28
|
+
DEFAULT_SUPERUSERS = %w{pivotal}.freeze
|
29
|
+
|
30
|
+
def clear
|
31
|
+
@creators = { [] => @superusers }
|
32
|
+
@deleted = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def deleted(path)
|
36
|
+
# acl deletes mean nothing, they are entirely subservient to their
|
37
|
+
# parent object
|
38
|
+
if path[0] == "acls" || (path[0] == "organizations" && path[2] == "acls")
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
result = exists?(path)
|
43
|
+
@deleted[path] = true
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def deleted?(path)
|
48
|
+
1.upto(path.size) do |index|
|
49
|
+
return true if @deleted[path[0..-index]]
|
50
|
+
end
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def created(path, creator, create_parents)
|
55
|
+
# If a parent has been deleted, we will need to clear that.
|
56
|
+
deleted_index = nil
|
57
|
+
0.upto(path.size - 1) do |index|
|
58
|
+
deleted_index = index if @deleted[path[0..index]]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Walk up the tree, setting the creator on anything that doesn't exist
|
62
|
+
# (anything that is either deleted or was never created)
|
63
|
+
while (deleted_index && path.size > deleted_index) || !@creators[path]
|
64
|
+
@creators[path] = creator ? [ creator ] : []
|
65
|
+
@deleted.delete(path)
|
66
|
+
# Only do this once if create_parents is false
|
67
|
+
break if !create_parents || path.size == 0
|
68
|
+
|
69
|
+
path = path[0..-2]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def superusers
|
74
|
+
@creators[[]]
|
75
|
+
end
|
76
|
+
|
77
|
+
def get(path)
|
78
|
+
return nil if deleted?(path)
|
79
|
+
|
80
|
+
result = case path[0]
|
81
|
+
when "acls"
|
82
|
+
# /acls/*
|
83
|
+
object_path = AclPath.get_object_path(path)
|
84
|
+
if data_exists?(object_path)
|
85
|
+
default_acl(path)
|
86
|
+
end
|
87
|
+
|
88
|
+
when "containers"
|
89
|
+
if path.size == 2 && exists?(path)
|
90
|
+
{}
|
91
|
+
end
|
92
|
+
|
93
|
+
when "users"
|
94
|
+
if path.size == 2 && data.exists?(path)
|
95
|
+
# User is empty user
|
96
|
+
{}
|
97
|
+
end
|
98
|
+
|
99
|
+
when "organizations"
|
100
|
+
if path.size >= 2
|
101
|
+
# /organizations/*/**
|
102
|
+
if data.exists_dir?(path[0..1])
|
103
|
+
get_org_default(path)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
result
|
109
|
+
end
|
110
|
+
|
111
|
+
def list(path)
|
112
|
+
return nil if deleted?(path)
|
113
|
+
|
114
|
+
if path.size == 0
|
115
|
+
return %w{containers users organizations acls}
|
116
|
+
end
|
117
|
+
|
118
|
+
case path[0]
|
119
|
+
when "acls"
|
120
|
+
if path.size == 1
|
121
|
+
[ "root" ] + (data.list(path + [ "containers" ]) - [ "organizations" ])
|
122
|
+
else
|
123
|
+
data.list(AclPath.get_object_path(path))
|
124
|
+
end
|
125
|
+
|
126
|
+
when "containers"
|
127
|
+
%w{containers users organizations}
|
128
|
+
|
129
|
+
when "users"
|
130
|
+
superusers
|
131
|
+
|
132
|
+
when "organizations"
|
133
|
+
if path.size == 1
|
134
|
+
single_org ? [ single_org ] : []
|
135
|
+
elsif path.size >= 2 && data.exists_dir?(path[0..1])
|
136
|
+
list_org_default(path)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def exists?(path)
|
142
|
+
return true if path.size == 0
|
143
|
+
|
144
|
+
parent_list = list(path[0..-2])
|
145
|
+
parent_list && parent_list.include?(path[-1])
|
146
|
+
end
|
147
|
+
|
148
|
+
protected
|
149
|
+
|
150
|
+
DEFAULT_ORG_SPINE = {
|
151
|
+
"clients" => {},
|
152
|
+
"cookbook_artifacts" => {},
|
153
|
+
"cookbooks" => {},
|
154
|
+
"data" => {},
|
155
|
+
"environments" => %w{_default},
|
156
|
+
"file_store" => {
|
157
|
+
"checksums" => {},
|
158
|
+
},
|
159
|
+
"nodes" => {},
|
160
|
+
"policies" => {},
|
161
|
+
"policy_groups" => {},
|
162
|
+
"roles" => {},
|
163
|
+
"sandboxes" => {},
|
164
|
+
"users" => {},
|
165
|
+
|
166
|
+
"org" => {},
|
167
|
+
"containers" => %w{clients containers cookbook_artifacts cookbooks data environments groups nodes policies policy_groups roles sandboxes},
|
168
|
+
"groups" => %w{admins billing-admins clients users},
|
169
|
+
"association_requests" => {},
|
170
|
+
}.freeze
|
171
|
+
|
172
|
+
def list_org_default(path)
|
173
|
+
if path.size >= 3 && path[2] == "acls"
|
174
|
+
if path.size == 3
|
175
|
+
# /organizations/ORG/acls
|
176
|
+
return [ "root" ] + data.list(path[0..1] + [ "containers" ])
|
177
|
+
elsif path.size == 4
|
178
|
+
# /organizations/ORG/acls/TYPE
|
179
|
+
return data.list(path[0..1] + [ path[3] ])
|
180
|
+
else
|
181
|
+
return nil
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
value = DEFAULT_ORG_SPINE
|
186
|
+
2.upto(path.size - 1) do |index|
|
187
|
+
value = nil if @deleted[path[0..index]]
|
188
|
+
break unless value
|
189
|
+
|
190
|
+
value = value[path[index]]
|
191
|
+
end
|
192
|
+
|
193
|
+
result = if value.is_a?(Hash)
|
194
|
+
value.keys
|
195
|
+
elsif value
|
196
|
+
value
|
197
|
+
end
|
198
|
+
|
199
|
+
if path.size == 3
|
200
|
+
if path[2] == "clients"
|
201
|
+
result << "#{path[1]}-validator"
|
202
|
+
if osc_compat
|
203
|
+
result << "#{path[1]}-webui"
|
204
|
+
end
|
205
|
+
elsif path[2] == "users"
|
206
|
+
if osc_compat
|
207
|
+
result << "admin"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
result
|
213
|
+
end
|
214
|
+
|
215
|
+
def get_org_default(path)
|
216
|
+
if path[2] == "acls"
|
217
|
+
get_org_acl_default(path)
|
218
|
+
|
219
|
+
elsif path.size >= 4
|
220
|
+
if path[2] == "containers" && path.size == 4
|
221
|
+
if exists?(path)
|
222
|
+
return {}
|
223
|
+
else
|
224
|
+
return nil
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# /organizations/(*)/clients/\1-validator
|
229
|
+
# /organizations/*/environments/_default
|
230
|
+
# /organizations/*/groups/{admins,billing-admins,clients,users}
|
231
|
+
case path[2..-1].join("/")
|
232
|
+
when "clients/#{path[1]}-validator"
|
233
|
+
{ "validator" => "true" }
|
234
|
+
|
235
|
+
when "clients/#{path[1]}-webui", "users/admin"
|
236
|
+
if osc_compat
|
237
|
+
{ "admin" => "true" }
|
238
|
+
end
|
239
|
+
|
240
|
+
when "environments/_default"
|
241
|
+
{ "description" => "The default Chef environment" }
|
242
|
+
|
243
|
+
when "groups/admins"
|
244
|
+
admins = data.list(path[0..1] + [ "users" ]).select do |name|
|
245
|
+
user = FFI_Yajl::Parser.parse(data.get(path[0..1] + [ "users", name ]))
|
246
|
+
user["admin"]
|
247
|
+
end
|
248
|
+
admins += data.list(path[0..1] + [ "clients" ]).select do |name|
|
249
|
+
client = FFI_Yajl::Parser.parse(data.get(path[0..1] + [ "clients", name ]))
|
250
|
+
client["admin"]
|
251
|
+
end
|
252
|
+
admins += @creators[path[0..1]] if @creators[path[0..1]]
|
253
|
+
{ "actors" => admins.uniq }
|
254
|
+
|
255
|
+
when "groups/billing-admins"
|
256
|
+
{}
|
257
|
+
|
258
|
+
when "groups/clients"
|
259
|
+
{ "clients" => data.list(path[0..1] + [ "clients" ]) }
|
260
|
+
|
261
|
+
when "groups/users"
|
262
|
+
users = data.list(path[0..1] + [ "users" ])
|
263
|
+
users |= @creators[path[0..1]] if @creators[path[0..1]]
|
264
|
+
{ "users" => users }
|
265
|
+
|
266
|
+
when "org"
|
267
|
+
{}
|
268
|
+
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def get_org_acl_default(path)
|
274
|
+
object_path = AclPath.get_object_path(path)
|
275
|
+
# The actual things containers correspond to don't have to exist, as
|
276
|
+
# long as the container does
|
277
|
+
return nil unless data_exists?(object_path)
|
278
|
+
|
279
|
+
basic_acl =
|
280
|
+
case path[3..-1].join("/")
|
281
|
+
when "root", "containers/containers", "containers/groups"
|
282
|
+
{
|
283
|
+
"create" => { "groups" => %w{admins} },
|
284
|
+
"read" => { "groups" => %w{admins users} },
|
285
|
+
"update" => { "groups" => %w{admins} },
|
286
|
+
"delete" => { "groups" => %w{admins} },
|
287
|
+
"grant" => { "groups" => %w{admins} },
|
288
|
+
}
|
289
|
+
when "containers/environments", "containers/roles",
|
290
|
+
"containers/policy_groups", "containers/policies",
|
291
|
+
"containers/cookbooks", "containers/cookbook_artifacts",
|
292
|
+
"containers/data"
|
293
|
+
{
|
294
|
+
"create" => { "groups" => %w{admins users} },
|
295
|
+
"read" => { "groups" => %w{admins users clients} },
|
296
|
+
"update" => { "groups" => %w{admins users} },
|
297
|
+
"delete" => { "groups" => %w{admins users} },
|
298
|
+
"grant" => { "groups" => %w{admins} },
|
299
|
+
}
|
300
|
+
when "containers/nodes"
|
301
|
+
{
|
302
|
+
"create" => { "groups" => %w{admins users clients} },
|
303
|
+
"read" => { "groups" => %w{admins users clients} },
|
304
|
+
"update" => { "groups" => %w{admins users} },
|
305
|
+
"delete" => { "groups" => %w{admins users} },
|
306
|
+
"grant" => { "groups" => %w{admins} },
|
307
|
+
}
|
308
|
+
when "containers/clients"
|
309
|
+
{
|
310
|
+
"create" => { "groups" => %w{admins} },
|
311
|
+
"read" => { "groups" => %w{admins users} },
|
312
|
+
"update" => { "groups" => %w{admins} },
|
313
|
+
"delete" => { "groups" => %w{admins users} },
|
314
|
+
"grant" => { "groups" => %w{admins} },
|
315
|
+
}
|
316
|
+
when "containers/sandboxes"
|
317
|
+
{
|
318
|
+
"create" => { "groups" => %w{admins users} },
|
319
|
+
"read" => { "groups" => %w{admins} },
|
320
|
+
"update" => { "groups" => %w{admins} },
|
321
|
+
"delete" => { "groups" => %w{admins} },
|
322
|
+
"grant" => { "groups" => %w{admins} },
|
323
|
+
}
|
324
|
+
when "groups/admins", "groups/clients", "groups/users"
|
325
|
+
{
|
326
|
+
"create" => { "groups" => %w{admins} },
|
327
|
+
"read" => { "groups" => %w{admins} },
|
328
|
+
"update" => { "groups" => %w{admins} },
|
329
|
+
"delete" => { "groups" => %w{admins} },
|
330
|
+
"grant" => { "groups" => %w{admins} },
|
331
|
+
}
|
332
|
+
when "groups/billing-admins"
|
333
|
+
{
|
334
|
+
"create" => { "groups" => %w{} },
|
335
|
+
"read" => { "groups" => %w{billing-admins} },
|
336
|
+
"update" => { "groups" => %w{billing-admins} },
|
337
|
+
"delete" => { "groups" => %w{} },
|
338
|
+
"grant" => { "groups" => %w{} },
|
339
|
+
}
|
340
|
+
else
|
341
|
+
{}
|
342
|
+
end
|
343
|
+
|
344
|
+
default_acl(path, basic_acl)
|
345
|
+
end
|
346
|
+
|
347
|
+
def get_owners(acl_path)
|
348
|
+
unknown_owners = []
|
349
|
+
path = AclPath.get_object_path(acl_path)
|
350
|
+
if path
|
351
|
+
|
352
|
+
# Non-validator clients own themselves.
|
353
|
+
if path.size == 4 && path[0] == "organizations" && path[2] == "clients"
|
354
|
+
begin
|
355
|
+
client = FFI_Yajl::Parser.parse(data.get(path))
|
356
|
+
unless client["validator"]
|
357
|
+
unknown_owners |= [ path[3] ]
|
358
|
+
end
|
359
|
+
rescue
|
360
|
+
unknown_owners |= [ path[3] ]
|
361
|
+
end
|
362
|
+
|
363
|
+
# Add creators as owners (except any validator clients).
|
364
|
+
if @creators[path]
|
365
|
+
@creators[path].each do |creator|
|
366
|
+
begin
|
367
|
+
client = FFI_Yajl::Parser.parse(data.get(path[0..2] + [ creator ]))
|
368
|
+
next if client["validator"]
|
369
|
+
rescue
|
370
|
+
end
|
371
|
+
unknown_owners |= [ creator ]
|
372
|
+
end
|
373
|
+
end
|
374
|
+
else
|
375
|
+
unknown_owners |= @creators[path] if @creators[path]
|
376
|
+
end
|
377
|
+
owners = filter_owners(path, unknown_owners)
|
378
|
+
|
379
|
+
# ANGRY
|
380
|
+
# Non-default containers do not get superusers added to them,
|
381
|
+
# because reasons.
|
382
|
+
unless path.size == 4 && path[0] == "organizations" && path[2] == "containers" && !exists?(path)
|
383
|
+
owners[:users] += superusers
|
384
|
+
end
|
385
|
+
else
|
386
|
+
owners = { clients: [], users: [] }
|
387
|
+
end
|
388
|
+
|
389
|
+
owners[:users].uniq!
|
390
|
+
owners[:clients].uniq!
|
391
|
+
owners
|
392
|
+
end
|
393
|
+
|
394
|
+
# Figures out if an object was created by a user or client.
|
395
|
+
# If the object does not exist in the context
|
396
|
+
# of an organization, it can only be a user
|
397
|
+
#
|
398
|
+
# This isn't perfect, because we are never explicitly told
|
399
|
+
# if a requestor creating an object is a user or client -
|
400
|
+
# but it gets us reasonably close
|
401
|
+
def filter_owners(path, unknown_owners)
|
402
|
+
owners = { clients: [], users: [] }
|
403
|
+
unknown_owners.each do |entity|
|
404
|
+
if path[0] == "organizations" && path.length > 2
|
405
|
+
begin
|
406
|
+
data.get(["organizations", path[1], "clients", entity])
|
407
|
+
owners[:clients] |= [ entity ]
|
408
|
+
rescue
|
409
|
+
owners[:users] |= [ entity ]
|
410
|
+
end
|
411
|
+
else
|
412
|
+
owners[:users] |= [ entity ]
|
413
|
+
end
|
414
|
+
end
|
415
|
+
owners
|
416
|
+
end
|
417
|
+
|
418
|
+
def default_acl(acl_path, acl = {})
|
419
|
+
owners = get_owners(acl_path)
|
420
|
+
container_acl = nil
|
421
|
+
PERMISSIONS.each do |perm|
|
422
|
+
acl[perm] ||= {}
|
423
|
+
acl[perm]["users"] = owners[:users]
|
424
|
+
acl[perm]["clients"] = owners[:clients]
|
425
|
+
|
426
|
+
# When we create containers, we don't merge groups (not sure why).
|
427
|
+
acl[perm]["groups"] ||= if acl_path[0] == "organizations" && acl_path[3] == "containers"
|
428
|
+
[]
|
429
|
+
else
|
430
|
+
container_acl ||= get_container_acl(acl_path) || {}
|
431
|
+
(container_acl[perm] ? container_acl[perm]["groups"] : []) || []
|
432
|
+
end
|
433
|
+
|
434
|
+
acl[perm]["actors"] = acl[perm]["clients"] + acl[perm]["users"]
|
435
|
+
end
|
436
|
+
acl
|
437
|
+
end
|
438
|
+
|
439
|
+
def get_container_acl(acl_path)
|
440
|
+
parent_path = AclPath.parent_acl_data_path(acl_path)
|
441
|
+
if parent_path
|
442
|
+
FFI_Yajl::Parser.parse(data.get(parent_path))
|
443
|
+
else
|
444
|
+
nil
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
def data_exists?(path)
|
449
|
+
if is_dir?(path)
|
450
|
+
data.exists_dir?(path)
|
451
|
+
else
|
452
|
+
data.exists?(path)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
def is_dir?(path)
|
457
|
+
case path.size
|
458
|
+
when 0, 1
|
459
|
+
true
|
460
|
+
when 2
|
461
|
+
path[0] == "organizations" || (path[0] == "acls" && path[1] != "root")
|
462
|
+
when 3
|
463
|
+
# If it has a container, it is a directory.
|
464
|
+
path[0] == "organizations" &&
|
465
|
+
(path[2] == "acls" || data.exists?(path[0..1] + [ "containers", path[2] ]))
|
466
|
+
when 4
|
467
|
+
path[0] == "organizations" && (
|
468
|
+
(path[2] == "acls" && path[1] != "root") ||
|
469
|
+
%w{cookbooks cookbook_artifacts data policies policy_groups}.include?(path[2]))
|
470
|
+
else
|
471
|
+
false
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|