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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +36 -31
  3. data/LICENSE +201 -201
  4. data/Rakefile +73 -68
  5. data/bin/chef-zero +111 -111
  6. data/chef-zero.gemspec +34 -33
  7. data/lib/chef_zero/chef_data/acl_path.rb +140 -140
  8. data/lib/chef_zero/chef_data/cookbook_data.rb +237 -237
  9. data/lib/chef_zero/chef_data/data_normalizer.rb +276 -276
  10. data/lib/chef_zero/chef_data/default_creator.rb +476 -476
  11. data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
  12. data/lib/chef_zero/data_store/data_error.rb +32 -32
  13. data/lib/chef_zero/data_store/data_not_found_error.rb +29 -29
  14. data/lib/chef_zero/data_store/default_facade.rb +143 -147
  15. data/lib/chef_zero/data_store/interface_v1.rb +67 -67
  16. data/lib/chef_zero/data_store/interface_v2.rb +18 -18
  17. data/lib/chef_zero/data_store/memory_store.rb +33 -33
  18. data/lib/chef_zero/data_store/memory_store_v2.rb +159 -159
  19. data/lib/chef_zero/data_store/raw_file_store.rb +143 -143
  20. data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +150 -150
  21. data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +105 -105
  22. data/lib/chef_zero/dist.rb +9 -9
  23. data/lib/chef_zero/endpoints/acl_endpoint.rb +39 -39
  24. data/lib/chef_zero/endpoints/acls_endpoint.rb +41 -41
  25. data/lib/chef_zero/endpoints/actor_default_key_endpoint.rb +78 -78
  26. data/lib/chef_zero/endpoints/actor_endpoint.rb +184 -184
  27. data/lib/chef_zero/endpoints/actor_key_endpoint.rb +62 -62
  28. data/lib/chef_zero/endpoints/actor_keys_endpoint.rb +129 -129
  29. data/lib/chef_zero/endpoints/actors_endpoint.rb +104 -104
  30. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +32 -32
  31. data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
  32. data/lib/chef_zero/endpoints/containers_endpoint.rb +25 -25
  33. data/lib/chef_zero/endpoints/controls_endpoint.rb +16 -16
  34. data/lib/chef_zero/endpoints/cookbook_artifact_endpoint.rb +24 -24
  35. data/lib/chef_zero/endpoints/cookbook_artifact_identifier_endpoint.rb +68 -68
  36. data/lib/chef_zero/endpoints/cookbook_artifacts_endpoint.rb +34 -34
  37. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
  38. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +136 -136
  39. data/lib/chef_zero/endpoints/cookbooks_base.rb +80 -80
  40. data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
  41. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
  42. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
  43. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
  44. data/lib/chef_zero/endpoints/dummy_endpoint.rb +29 -29
  45. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
  46. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +126 -126
  47. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
  48. data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
  49. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
  50. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
  51. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
  52. data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
  53. data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
  54. data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
  55. data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
  56. data/lib/chef_zero/endpoints/node_endpoint.rb +34 -34
  57. data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -22
  58. data/lib/chef_zero/endpoints/nodes_endpoint.rb +34 -34
  59. data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
  60. data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
  61. data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -30
  62. data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
  63. data/lib/chef_zero/endpoints/organization_endpoint.rb +47 -47
  64. data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
  65. data/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb +16 -16
  66. data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
  67. data/lib/chef_zero/endpoints/organization_user_key_endpoint.rb +17 -17
  68. data/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb +17 -17
  69. data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -43
  70. data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
  71. data/lib/chef_zero/endpoints/organizations_endpoint.rb +61 -61
  72. data/lib/chef_zero/endpoints/policies_endpoint.rb +26 -26
  73. data/lib/chef_zero/endpoints/policy_endpoint.rb +24 -24
  74. data/lib/chef_zero/endpoints/policy_group_endpoint.rb +46 -46
  75. data/lib/chef_zero/endpoints/policy_group_policy_endpoint.rb +83 -83
  76. data/lib/chef_zero/endpoints/policy_groups_endpoint.rb +38 -38
  77. data/lib/chef_zero/endpoints/policy_revision_endpoint.rb +66 -66
  78. data/lib/chef_zero/endpoints/policy_revisions_endpoint.rb +15 -15
  79. data/lib/chef_zero/endpoints/principal_endpoint.rb +55 -55
  80. data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
  81. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +78 -78
  82. data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
  83. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
  84. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
  85. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +51 -51
  86. data/lib/chef_zero/endpoints/search_endpoint.rb +208 -208
  87. data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
  88. data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -14
  89. data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
  90. data/lib/chef_zero/endpoints/universe_endpoint.rb +15 -15
  91. data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +41 -41
  92. data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
  93. data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
  94. data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
  95. data/lib/chef_zero/endpoints/version_endpoint.rb +13 -13
  96. data/lib/chef_zero/log.rb +7 -7
  97. data/lib/chef_zero/rest_base.rb +332 -332
  98. data/lib/chef_zero/rest_error_response.rb +11 -11
  99. data/lib/chef_zero/rest_request.rb +84 -88
  100. data/lib/chef_zero/rest_router.rb +72 -72
  101. data/lib/chef_zero/rspec.rb +355 -355
  102. data/lib/chef_zero/server.rb +730 -730
  103. data/lib/chef_zero/socketless_server_map.rb +92 -93
  104. data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
  105. data/lib/chef_zero/solr/query/phrase.rb +23 -23
  106. data/lib/chef_zero/solr/query/range_query.rb +46 -46
  107. data/lib/chef_zero/solr/query/regexpable_query.rb +30 -30
  108. data/lib/chef_zero/solr/query/subquery.rb +37 -37
  109. data/lib/chef_zero/solr/query/term.rb +45 -45
  110. data/lib/chef_zero/solr/query/unary_operator.rb +41 -41
  111. data/lib/chef_zero/solr/solr_doc.rb +53 -53
  112. data/lib/chef_zero/solr/solr_parser.rb +208 -208
  113. data/lib/chef_zero/version.rb +3 -3
  114. data/lib/chef_zero.rb +10 -10
  115. data/spec/run_oc_pedant.rb +226 -226
  116. data/spec/search_spec.rb +36 -36
  117. data/spec/server_spec.rb +96 -96
  118. data/spec/socketless_server_map_spec.rb +74 -74
  119. data/spec/support/oc_pedant.rb +149 -149
  120. data/spec/support/secrets.json +6 -6
  121. data/spec/support/stickywicket.pem +27 -27
  122. metadata +35 -18
data/bin/chef-zero CHANGED
@@ -1,111 +1,111 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Trap interrupts to quit cleanly.
4
- Signal.trap("INT") { exit 1 }
5
-
6
- require "rubygems" unless defined?(Gem)
7
- $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
8
-
9
- require "chef_zero/log"
10
- require "chef_zero/dist"
11
- require "chef_zero/version"
12
- require "chef_zero/server"
13
- require "chef_zero/data_store/raw_file_store"
14
- require "optparse" unless defined?(OptionParser)
15
-
16
- def parse_port(port)
17
- array = []
18
- port.split(",").each do |part|
19
- a, b = part.split("-", 2)
20
- if b
21
- array = array.concat(a.to_i.upto(b.to_i).to_a)
22
- else
23
- array = array.concat([a.to_i])
24
- end
25
- end
26
- array
27
- end
28
-
29
- options = {}
30
-
31
- OptionParser.new do |opts|
32
- opts.banner = "Usage: #{ChefZero::Dist::CLIENT} [ARGS]"
33
-
34
- opts.on("-H", "--host HOST", "Host to bind to (default: 127.0.0.1)") do |value|
35
- options[:host] ||= []
36
- options[:host] << value
37
- end
38
-
39
- opts.on("-p", "--port PORT", "Port to listen on (e.g. 8889, or 8500-8600 or 8885,8888)") do |value|
40
- options[:port] ||= []
41
- options[:port] += parse_port(value)
42
- end
43
-
44
- opts.on("--[no-]generate-keys", "Whether to generate actual keys or fake it (faster). Default: false.") do |value|
45
- options[:generate_real_keys] = value
46
- end
47
-
48
- opts.on("-d", "--daemon", "Run as a daemon process") do |value|
49
- options[:daemon] = value
50
- end
51
-
52
- opts.on("-l", "--log-level LEVEL", "Set the output log level") do |value|
53
- options[:log_level] = value
54
- end
55
-
56
- opts.on("--log-file FILE", "Log to a file") do |value|
57
- options[:log_file] = value
58
- end
59
-
60
- opts.on("--enterprise", "Whether to run in enterprise mode") do |value|
61
- options[:single_org] = nil
62
- options[:osc_compat] = false
63
- end
64
-
65
- opts.on("--multi-org", "Whether to run in multi-org mode") do |value|
66
- options[:single_org] = nil
67
- end
68
-
69
- opts.on("--file-store PATH", "Persist data to files at the given path") do |value|
70
- options[:data_store] = ChefZero::DataStore::RawFileStore.new(value)
71
- end
72
-
73
- opts.on("--[no-]ssl", "Use SSL with self-signed certificate(Auto generate before every run). Default: false.") do |value|
74
- options[:ssl] = value
75
- end
76
-
77
- opts.on_tail("-h", "--help", "Show this message") do
78
- puts opts
79
- exit
80
- end
81
-
82
- opts.on_tail("--version", "Show version") do
83
- puts ChefZero::VERSION
84
- exit
85
- end
86
- end.parse!
87
-
88
- if options[:data_store]
89
- options[:data_store] = ChefZero::DataStore::DefaultFacade.new(options[:data_store], options[:single_org], false)
90
- end
91
-
92
- if options[:log_file]
93
- ChefZero::Log.init(options[:log_file])
94
- end
95
-
96
- server = ChefZero::Server.new(options)
97
-
98
- if options[:daemon]
99
- if Process.respond_to?(:daemon)
100
- Process.daemon(true)
101
- server.start(true)
102
- else
103
- if ENV["OS"] == "Windows_NT"
104
- abort "Daemonization is not supported on Windows. Running 'start #{ChefZero::Dist::CLIENT}' will fork the process."
105
- else
106
- abort "Process.daemon requires Ruby >= 1.9"
107
- end
108
- end
109
- else
110
- server.start(true)
111
- end
1
+ #!/usr/bin/env ruby
2
+
3
+ # Trap interrupts to quit cleanly.
4
+ Signal.trap("INT") { exit 1 }
5
+
6
+ require "rubygems" unless defined?(Gem)
7
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
8
+
9
+ require "chef_zero/log"
10
+ require "chef_zero/dist"
11
+ require "chef_zero/version"
12
+ require "chef_zero/server"
13
+ require "chef_zero/data_store/raw_file_store"
14
+ require "optparse" unless defined?(OptionParser)
15
+
16
+ def parse_port(port)
17
+ array = []
18
+ port.split(",").each do |part|
19
+ a, b = part.split("-", 2)
20
+ if b
21
+ array = array.concat(a.to_i.upto(b.to_i).to_a)
22
+ else
23
+ array = array.push(a.to_i)
24
+ end
25
+ end
26
+ array
27
+ end
28
+
29
+ options = {}
30
+
31
+ OptionParser.new do |opts|
32
+ opts.banner = "Usage: #{ChefZero::Dist::CLIENT} [ARGS]"
33
+
34
+ opts.on("-H", "--host HOST", "Host to bind to (default: 127.0.0.1)") do |value|
35
+ options[:host] ||= []
36
+ options[:host] << value
37
+ end
38
+
39
+ opts.on("-p", "--port PORT", "Port to listen on (e.g. 8889, or 8500-8600 or 8885,8888)") do |value|
40
+ options[:port] ||= []
41
+ options[:port] += parse_port(value)
42
+ end
43
+
44
+ opts.on("--[no-]generate-keys", "Whether to generate actual keys or fake it (faster). Default: false.") do |value|
45
+ options[:generate_real_keys] = value
46
+ end
47
+
48
+ opts.on("-d", "--daemon", "Run as a daemon process") do |value|
49
+ options[:daemon] = value
50
+ end
51
+
52
+ opts.on("-l", "--log-level LEVEL", "Set the output log level") do |value|
53
+ options[:log_level] = value
54
+ end
55
+
56
+ opts.on("--log-file FILE", "Log to a file") do |value|
57
+ options[:log_file] = value
58
+ end
59
+
60
+ opts.on("--enterprise", "Whether to run in enterprise mode") do |value|
61
+ options[:single_org] = nil
62
+ options[:osc_compat] = false
63
+ end
64
+
65
+ opts.on("--multi-org", "Whether to run in multi-org mode") do |value|
66
+ options[:single_org] = nil
67
+ end
68
+
69
+ opts.on("--file-store PATH", "Persist data to files at the given path") do |value|
70
+ options[:data_store] = ChefZero::DataStore::RawFileStore.new(value)
71
+ end
72
+
73
+ opts.on("--[no-]ssl", "Use SSL with self-signed certificate(Auto generate before every run). Default: false.") do |value|
74
+ options[:ssl] = value
75
+ end
76
+
77
+ opts.on_tail("-h", "--help", "Show this message") do
78
+ puts opts
79
+ exit
80
+ end
81
+
82
+ opts.on_tail("--version", "Show version") do
83
+ puts ChefZero::VERSION
84
+ exit
85
+ end
86
+ end.parse!
87
+
88
+ if options[:data_store]
89
+ options[:data_store] = ChefZero::DataStore::DefaultFacade.new(options[:data_store], options[:single_org], false)
90
+ end
91
+
92
+ if options[:log_file]
93
+ ChefZero::Log.init(options[:log_file])
94
+ end
95
+
96
+ server = ChefZero::Server.new(options)
97
+
98
+ if options[:daemon]
99
+ if Process.respond_to?(:daemon)
100
+ Process.daemon(true)
101
+ server.start(true)
102
+ else
103
+ if ENV["OS"] == "Windows_NT"
104
+ abort "Daemonization is not supported on Windows. Running 'start #{ChefZero::Dist::CLIENT}' will fork the process."
105
+ else
106
+ abort "Process.daemon requires Ruby >= 1.9"
107
+ end
108
+ end
109
+ else
110
+ server.start(true)
111
+ end
data/chef-zero.gemspec CHANGED
@@ -1,33 +1,34 @@
1
- $:.unshift(__dir__ + "/lib")
2
- require "chef_zero/version"
3
-
4
- Gem::Specification.new do |s|
5
- s.name = "chef-zero"
6
- s.version = ChefZero::VERSION
7
- s.summary = "Self-contained, easy-setup, fast-start in-memory Chef server for testing and solo setup purposes"
8
- s.description = s.summary
9
- s.author = "Chef Software, Inc."
10
- s.email = "oss@chef.io"
11
- s.homepage = "https://github.com/chef/chef-zero"
12
- s.license = "Apache-2.0"
13
-
14
- s.required_ruby_version = ">= 3.0"
15
-
16
- # Note: 7.1.0 does not defaults its cache_format_version to 7.1 but 6.1 instead which gives deprecation warnings
17
- # Remove the version constraint when we can upgrade to 7.1.1 post stable release of Activesupport 7.1
18
- # Similar issue with 7.0 existed: https://github.com/rails/rails/pull/45293
19
- s.add_dependency "activesupport", "~> 7.0", "< 7.1"
20
- s.add_dependency "mixlib-log", ">= 2.0", "< 4.0"
21
- s.add_dependency "hashie", ">= 2.0", "< 5.0"
22
- s.add_dependency "uuidtools", "~> 2.1"
23
- s.add_dependency "ffi-yajl", "~> 2.2"
24
- s.add_dependency "rack", "~> 3.1", ">= 3.1.10"
25
- s.add_dependency "rackup", "~> 2.2", ">= 2.2.1"
26
- s.add_dependency "webrick"
27
-
28
- s.bindir = "bin"
29
- s.executables = ["chef-zero"]
30
- s.require_path = "lib"
31
- s.files = %w{LICENSE Gemfile Rakefile} + Dir.glob("*.gemspec") +
32
- Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
33
- end
1
+ $:.unshift(__dir__ + "/lib")
2
+ require "chef_zero/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "chef-zero"
6
+ s.version = ChefZero::VERSION
7
+ s.summary = "Self-contained, easy-setup, fast-start in-memory Chef server for testing and solo setup purposes"
8
+ s.description = s.summary
9
+ s.author = "Chef Software, Inc."
10
+ s.email = "oss@chef.io"
11
+ s.homepage = "https://github.com/chef/chef-zero"
12
+ s.license = "Apache-2.0"
13
+
14
+ s.required_ruby_version = ">= 3.0"
15
+
16
+ # Note: 7.1.0 does not defaults its cache_format_version to 7.1 but 6.1 instead which gives deprecation warnings
17
+ # Remove the version constraint when we can upgrade to 7.1.1 post stable release of Activesupport 7.1
18
+ # Similar issue with 7.0 existed: https://github.com/rails/rails/pull/45293
19
+ s.add_dependency "activesupport", ">= 7", "< 8.1"
20
+ s.add_dependency "mixlib-log", ">= 2.0", "< 4.0"
21
+ s.add_dependency "hashie", ">= 2.0", "< 6.0"
22
+ s.add_dependency "uuidtools", "~> 2.1"
23
+ s.add_dependency "ffi-yajl", ">= 2.2", "< 4.0"
24
+ s.add_dependency "rack", "~> 3.1", ">= 3.1.16"
25
+ s.add_dependency "rackup", "~> 2.2", ">= 2.2.1"
26
+ s.add_dependency "unf_ext", "~> 0.0.8"
27
+ s.add_dependency "webrick"
28
+
29
+ s.bindir = "bin"
30
+ s.executables = ["chef-zero"]
31
+ s.require_path = "lib"
32
+ s.files = %w{LICENSE Gemfile Rakefile} + Dir.glob("*.gemspec") +
33
+ Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
34
+ end
@@ -1,140 +1,140 @@
1
- module ChefZero
2
- module ChefData
3
- # Manages translations between REST and ACL data paths
4
- # and parent paths.
5
- #
6
- # Suggestions
7
- # - make /organizations/ORG/_acl and deprecate organization/_acl and organizations/_acl
8
- # - add endpoints for /containers/(users|organizations|containers)(/_acl)
9
- # - add PUT for */_acl
10
- # - add endpoints for /organizations/ORG/data/containers and /organizations/ORG/cookbooks/containers
11
- # - sane, fully documented ACL model
12
- # - sane inheritance / override model: if actors or groups are explicitly
13
- # specified on X, they are not inherited from X's parent
14
- # - stop adding pivotal to acls (he already has access to what he needs)
15
- module AclPath
16
- ORG_DATA_TYPES = %w{clients cookbook_artifacts cookbooks containers data environments groups
17
- nodes policies policy_groups roles sandboxes}.freeze
18
- TOP_DATA_TYPES = %w{containers organizations users}.freeze
19
-
20
- # ACL data paths for a partition are:
21
- # / -> /acls/root
22
- # /TYPE -> /acls/containers/TYPE
23
- # /TYPE/NAME -> /acls/TYPE/NAME
24
- #
25
- # The root partition "/" has its own acls, so it looks like this:
26
- #
27
- # / -> /acls/root
28
- # /users -> /acls/containers/users
29
- # /organizations -> /acls/containers/organizations
30
- # /users/schlansky -> /acls/users/schlansky
31
- #
32
- # Each organization is its own partition, so it looks like this:
33
- #
34
- # /organizations/blah -> /organizations/blah/acls/root
35
- # /organizations/blah/roles -> /organizations/blah/acls/containers/roles
36
- # /organizations/blah/roles/web -> /organizations/blah/acls/roles/web
37
- # /organizations/ORG is its own partition. ACLs for anything under it follow
38
-
39
- # This method takes a Chef REST path and returns the chef-zero path
40
- # used to look up the ACL. If an object does not have an ACL directly,
41
- # it will return nil. Paths like /organizations/ORG/data/bag/item will
42
- # return nil, because it is the parent path (data/bag) that has an ACL.
43
- def self.get_acl_data_path(path)
44
- # Things under organizations have their own acls hierarchy
45
- if path[0] == "organizations" && path.size >= 2
46
- under_org = partition_acl_data_path(path[2..-1], ORG_DATA_TYPES)
47
- if under_org
48
- path[0..1] + under_org
49
- end
50
- else
51
- partition_acl_data_path(path, TOP_DATA_TYPES)
52
- end
53
- end
54
-
55
- #
56
- # Reverse transform from acl_data_path to path.
57
- # /acls/root -> /
58
- # /acls/** -> /**
59
- # /organizations/ORG/acls/root -> /organizations/ORG
60
- # /organizations/ORG/acls/** -> /organizations/ORG/**
61
- #
62
- # This means that /acls/containers/nodes maps to
63
- # /containers/nodes, not /nodes.
64
- #
65
- def self.get_object_path(acl_data_path)
66
- if acl_data_path[0] == "acls"
67
- if acl_data_path[1] == "root"
68
- []
69
- else
70
- acl_data_path[1..-1]
71
- end
72
- elsif acl_data_path[0] == "organizations" && acl_data_path[2] == "acls"
73
- if acl_data_path[3] == "root"
74
- acl_data_path[0..1]
75
- else
76
- acl_data_path[0..1] + acl_data_path[3..-1]
77
- end
78
- end
79
- end
80
-
81
- # Method *assumes* acl_data_path is valid.
82
- # /organizations/BLAH's parent is /organizations
83
- #
84
- # An example traversal up the whole tree:
85
- # /organizations/foo/acls/nodes/mario ->
86
- # /organizations/foo/acls/containers/nodes ->
87
- # /organizations/foo/acls/containers/containers ->
88
- # /organizations/foo/acls/root ->
89
- # /acls/containers/organizations ->
90
- # /acls/containers/containers ->
91
- # /acls/root ->
92
- # nil
93
- def self.parent_acl_data_path(acl_data_path)
94
- if acl_data_path[0] == "organizations"
95
- under_org = partition_parent_acl_data_path(acl_data_path[2..-1])
96
- if under_org
97
- acl_data_path[0..1] + under_org
98
- else
99
- # ACL data path is /organizations/X/acls/root; therefore parent is "/organizations"
100
- %w{acls containers organizations}
101
- end
102
- else
103
- partition_parent_acl_data_path(acl_data_path)
104
- end
105
- end
106
-
107
- # /acls/root -> nil
108
- # /acls/containers/containers -> /acls/root
109
- # /acls/TYPE/X -> /acls/containers/TYPE
110
- #
111
- # Method *assumes* acl_data_path is valid.
112
- # Returns nil if the path is /acls/root
113
- private_class_method
114
- def self.partition_parent_acl_data_path(acl_data_path)
115
- if acl_data_path.size == 3
116
- if acl_data_path == %w{acls containers containers}
117
- %w{acls root}
118
- else
119
- [ "acls", "containers", acl_data_path[1]]
120
- end
121
- else
122
- nil
123
- end
124
- end
125
-
126
- private_class_method
127
- def self.partition_acl_data_path(path, data_types)
128
- if path.size == 0
129
- %w{acls root}
130
- elsif data_types.include?(path[0])
131
- if path.size == 0
132
- [ "acls", "containers", path[0] ]
133
- elsif path.size == 2
134
- [ "acls", path[0], path[1] ]
135
- end
136
- end
137
- end
138
- end
139
- end
140
- end
1
+ module ChefZero
2
+ module ChefData
3
+ # Manages translations between REST and ACL data paths
4
+ # and parent paths.
5
+ #
6
+ # Suggestions
7
+ # - make /organizations/ORG/_acl and deprecate organization/_acl and organizations/_acl
8
+ # - add endpoints for /containers/(users|organizations|containers)(/_acl)
9
+ # - add PUT for */_acl
10
+ # - add endpoints for /organizations/ORG/data/containers and /organizations/ORG/cookbooks/containers
11
+ # - sane, fully documented ACL model
12
+ # - sane inheritance / override model: if actors or groups are explicitly
13
+ # specified on X, they are not inherited from X's parent
14
+ # - stop adding pivotal to acls (he already has access to what he needs)
15
+ module AclPath
16
+ ORG_DATA_TYPES = %w{clients cookbook_artifacts cookbooks containers data environments groups
17
+ nodes policies policy_groups roles sandboxes}.freeze
18
+ TOP_DATA_TYPES = %w{containers organizations users}.freeze
19
+
20
+ # ACL data paths for a partition are:
21
+ # / -> /acls/root
22
+ # /TYPE -> /acls/containers/TYPE
23
+ # /TYPE/NAME -> /acls/TYPE/NAME
24
+ #
25
+ # The root partition "/" has its own acls, so it looks like this:
26
+ #
27
+ # / -> /acls/root
28
+ # /users -> /acls/containers/users
29
+ # /organizations -> /acls/containers/organizations
30
+ # /users/schlansky -> /acls/users/schlansky
31
+ #
32
+ # Each organization is its own partition, so it looks like this:
33
+ #
34
+ # /organizations/blah -> /organizations/blah/acls/root
35
+ # /organizations/blah/roles -> /organizations/blah/acls/containers/roles
36
+ # /organizations/blah/roles/web -> /organizations/blah/acls/roles/web
37
+ # /organizations/ORG is its own partition. ACLs for anything under it follow
38
+
39
+ # This method takes a Chef REST path and returns the chef-zero path
40
+ # used to look up the ACL. If an object does not have an ACL directly,
41
+ # it will return nil. Paths like /organizations/ORG/data/bag/item will
42
+ # return nil, because it is the parent path (data/bag) that has an ACL.
43
+ def self.get_acl_data_path(path)
44
+ # Things under organizations have their own acls hierarchy
45
+ if path[0] == "organizations" && path.size >= 2
46
+ under_org = partition_acl_data_path(path[2..-1], ORG_DATA_TYPES)
47
+ if under_org
48
+ path[0..1] + under_org
49
+ end
50
+ else
51
+ partition_acl_data_path(path, TOP_DATA_TYPES)
52
+ end
53
+ end
54
+
55
+ #
56
+ # Reverse transform from acl_data_path to path.
57
+ # /acls/root -> /
58
+ # /acls/** -> /**
59
+ # /organizations/ORG/acls/root -> /organizations/ORG
60
+ # /organizations/ORG/acls/** -> /organizations/ORG/**
61
+ #
62
+ # This means that /acls/containers/nodes maps to
63
+ # /containers/nodes, not /nodes.
64
+ #
65
+ def self.get_object_path(acl_data_path)
66
+ if acl_data_path[0] == "acls"
67
+ if acl_data_path[1] == "root"
68
+ []
69
+ else
70
+ acl_data_path[1..-1]
71
+ end
72
+ elsif acl_data_path[0] == "organizations" && acl_data_path[2] == "acls"
73
+ if acl_data_path[3] == "root"
74
+ acl_data_path[0..1]
75
+ else
76
+ acl_data_path[0..1] + acl_data_path[3..-1]
77
+ end
78
+ end
79
+ end
80
+
81
+ # Method *assumes* acl_data_path is valid.
82
+ # /organizations/BLAH's parent is /organizations
83
+ #
84
+ # An example traversal up the whole tree:
85
+ # /organizations/foo/acls/nodes/mario ->
86
+ # /organizations/foo/acls/containers/nodes ->
87
+ # /organizations/foo/acls/containers/containers ->
88
+ # /organizations/foo/acls/root ->
89
+ # /acls/containers/organizations ->
90
+ # /acls/containers/containers ->
91
+ # /acls/root ->
92
+ # nil
93
+ def self.parent_acl_data_path(acl_data_path)
94
+ if acl_data_path[0] == "organizations"
95
+ under_org = partition_parent_acl_data_path(acl_data_path[2..-1])
96
+ if under_org
97
+ acl_data_path[0..1] + under_org
98
+ else
99
+ # ACL data path is /organizations/X/acls/root; therefore parent is "/organizations"
100
+ %w{acls containers organizations}
101
+ end
102
+ else
103
+ partition_parent_acl_data_path(acl_data_path)
104
+ end
105
+ end
106
+
107
+ # /acls/root -> nil
108
+ # /acls/containers/containers -> /acls/root
109
+ # /acls/TYPE/X -> /acls/containers/TYPE
110
+ #
111
+ # Method *assumes* acl_data_path is valid.
112
+ # Returns nil if the path is /acls/root
113
+ private_class_method
114
+ def self.partition_parent_acl_data_path(acl_data_path)
115
+ if acl_data_path.size == 3
116
+ if acl_data_path == %w{acls containers containers}
117
+ %w{acls root}
118
+ else
119
+ [ "acls", "containers", acl_data_path[1]]
120
+ end
121
+ else
122
+ nil
123
+ end
124
+ end
125
+
126
+ private_class_method
127
+ def self.partition_acl_data_path(path, data_types)
128
+ if path.size == 0
129
+ %w{acls root}
130
+ elsif data_types.include?(path[0])
131
+ if path.size == 0
132
+ [ "acls", "containers", path[0] ]
133
+ elsif path.size == 2
134
+ [ "acls", path[0], path[1] ]
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end