chef-zero 4.3.0 → 4.3.1

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -201
  3. data/README.md +155 -155
  4. data/Rakefile +31 -31
  5. data/bin/chef-zero +100 -100
  6. data/lib/chef_zero.rb +10 -10
  7. data/lib/chef_zero/chef_data/acl_path.rb +139 -139
  8. data/lib/chef_zero/chef_data/cookbook_data.rb +240 -240
  9. data/lib/chef_zero/chef_data/data_normalizer.rb +208 -207
  10. data/lib/chef_zero/chef_data/default_creator.rb +446 -446
  11. data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
  12. data/lib/chef_zero/data_store/data_error.rb +31 -31
  13. data/lib/chef_zero/data_store/data_not_found_error.rb +28 -28
  14. data/lib/chef_zero/data_store/default_facade.rb +149 -149
  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 +155 -155
  19. data/lib/chef_zero/data_store/raw_file_store.rb +147 -147
  20. data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +142 -142
  21. data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +107 -107
  22. data/lib/chef_zero/endpoints/acl_endpoint.rb +38 -38
  23. data/lib/chef_zero/endpoints/acls_endpoint.rb +29 -29
  24. data/lib/chef_zero/endpoints/actor_endpoint.rb +94 -94
  25. data/lib/chef_zero/endpoints/actors_endpoint.rb +64 -64
  26. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +31 -31
  27. data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
  28. data/lib/chef_zero/endpoints/containers_endpoint.rb +13 -13
  29. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
  30. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +119 -119
  31. data/lib/chef_zero/endpoints/cookbooks_base.rb +65 -65
  32. data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
  33. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
  34. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
  35. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
  36. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
  37. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +123 -123
  38. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
  39. data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
  40. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
  41. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
  42. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
  43. data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
  44. data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
  45. data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
  46. data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
  47. data/lib/chef_zero/endpoints/node_endpoint.rb +17 -17
  48. data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -22
  49. data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
  50. data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
  51. data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -30
  52. data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
  53. data/lib/chef_zero/endpoints/organization_endpoint.rb +46 -46
  54. data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
  55. data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
  56. data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -43
  57. data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
  58. data/lib/chef_zero/endpoints/organizations_endpoint.rb +62 -62
  59. data/lib/chef_zero/endpoints/policies_endpoint.rb +151 -151
  60. data/lib/chef_zero/endpoints/principal_endpoint.rb +42 -42
  61. data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
  62. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +63 -63
  63. data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
  64. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
  65. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
  66. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +50 -50
  67. data/lib/chef_zero/endpoints/search_endpoint.rb +194 -194
  68. data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
  69. data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -14
  70. data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
  71. data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +40 -40
  72. data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
  73. data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
  74. data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
  75. data/lib/chef_zero/endpoints/version_endpoint.rb +12 -12
  76. data/lib/chef_zero/log.rb +7 -7
  77. data/lib/chef_zero/rest_base.rb +242 -242
  78. data/lib/chef_zero/rest_error_response.rb +11 -11
  79. data/lib/chef_zero/rest_request.rb +69 -69
  80. data/lib/chef_zero/rest_router.rb +45 -45
  81. data/lib/chef_zero/rspec.rb +308 -308
  82. data/lib/chef_zero/server.rb +642 -642
  83. data/lib/chef_zero/socketless_server_map.rb +92 -92
  84. data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
  85. data/lib/chef_zero/solr/query/phrase.rb +23 -23
  86. data/lib/chef_zero/solr/query/range_query.rb +46 -46
  87. data/lib/chef_zero/solr/query/regexpable_query.rb +29 -29
  88. data/lib/chef_zero/solr/query/subquery.rb +37 -37
  89. data/lib/chef_zero/solr/query/term.rb +45 -45
  90. data/lib/chef_zero/solr/query/unary_operator.rb +43 -43
  91. data/lib/chef_zero/solr/solr_doc.rb +53 -53
  92. data/lib/chef_zero/solr/solr_parser.rb +203 -203
  93. data/lib/chef_zero/version.rb +3 -3
  94. data/spec/run_oc_pedant.rb +63 -63
  95. data/spec/search_spec.rb +32 -32
  96. data/spec/server_spec.rb +92 -92
  97. data/spec/socketless_server_map_spec.rb +76 -76
  98. data/spec/support/oc_pedant.rb +132 -132
  99. data/spec/support/stickywicket.pem +27 -27
  100. metadata +3 -3
@@ -1,20 +1,20 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/rest_base'
3
- require 'uuidtools'
4
-
5
- module ChefZero
6
- module Endpoints
7
- # /organizations/NAME/_validator_key
8
- class OrganizationValidatorKeyEndpoint < RestBase
9
- def post(request)
10
- org_name = request.rest_path[-2]
11
- validator_path = [ 'organizations', org_name, 'clients', "#{org_name}-validator"]
12
- validator = FFI_Yajl::Parser.parse(get_data(request, validator_path), :create_additions => false)
13
- private_key, public_key = server.gen_key_pair
14
- validator['public_key'] = public_key
15
- set_data(request, validator_path, FFI_Yajl::Encoder.encode(validator, :pretty => true))
16
- json_response(200, { 'private_key' => private_key })
17
- end
18
- end
19
- end
20
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/rest_base'
3
+ require 'uuidtools'
4
+
5
+ module ChefZero
6
+ module Endpoints
7
+ # /organizations/NAME/_validator_key
8
+ class OrganizationValidatorKeyEndpoint < RestBase
9
+ def post(request)
10
+ org_name = request.rest_path[-2]
11
+ validator_path = [ 'organizations', org_name, 'clients', "#{org_name}-validator"]
12
+ validator = FFI_Yajl::Parser.parse(get_data(request, validator_path), :create_additions => false)
13
+ private_key, public_key = server.gen_key_pair
14
+ validator['public_key'] = public_key
15
+ set_data(request, validator_path, FFI_Yajl::Encoder.encode(validator, :pretty => true))
16
+ json_response(200, { 'private_key' => private_key })
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,62 +1,62 @@
1
- require 'ffi_yajl'
2
- require 'chef_zero/rest_base'
3
- require 'uuidtools'
4
-
5
- module ChefZero
6
- module Endpoints
7
- # /organizations
8
- class OrganizationsEndpoint < RestBase
9
- def get(request)
10
- result = {}
11
- data_store.list(request.rest_path).each do |name|
12
- result[name] = build_uri(request.base_uri, request.rest_path + [name])
13
- end
14
- json_response(200, result)
15
- end
16
-
17
- def post(request)
18
- contents = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
19
- name = contents['name']
20
- full_name = contents['full_name']
21
- if name.nil?
22
- error(400, "Must specify 'name' in JSON")
23
- elsif full_name.nil?
24
- error(400, "Must specify 'full_name' in JSON")
25
- elsif exists_data_dir?(request, request.rest_path + [ name ])
26
- error(409, "Organization already exists")
27
- else
28
- create_data_dir(request, request.rest_path, name, :requestor => request.requestor)
29
-
30
- org = {
31
- "guid" => UUIDTools::UUID.random_create.to_s.gsub('-', ''),
32
- "assigned_at" => Time.now.to_s
33
- }.merge(contents)
34
- org_path = request.rest_path + [ name ]
35
- set_data(request, org_path + [ 'org' ], FFI_Yajl::Encoder.encode(org, :pretty => true))
36
-
37
- if server.generate_real_keys?
38
- # Create the validator client
39
- validator_name = "#{name}-validator"
40
- validator_path = org_path + [ 'clients', validator_name ]
41
- private_key, public_key = server.gen_key_pair
42
- validator = FFI_Yajl::Encoder.encode({
43
- 'validator' => true,
44
- 'public_key' => public_key
45
- }, :pretty => true)
46
- set_data(request, validator_path, validator)
47
- end
48
-
49
-
50
- json_response(201, {
51
- "uri" => "#{build_uri(request.base_uri, org_path)}",
52
- "name" => name,
53
- "org_type" => org["org_type"],
54
- "full_name" => full_name,
55
- "clientname" => validator_name,
56
- "private_key" => private_key
57
- })
58
- end
59
- end
60
- end
61
- end
62
- end
1
+ require 'ffi_yajl'
2
+ require 'chef_zero/rest_base'
3
+ require 'uuidtools'
4
+
5
+ module ChefZero
6
+ module Endpoints
7
+ # /organizations
8
+ class OrganizationsEndpoint < RestBase
9
+ def get(request)
10
+ result = {}
11
+ data_store.list(request.rest_path).each do |name|
12
+ result[name] = build_uri(request.base_uri, request.rest_path + [name])
13
+ end
14
+ json_response(200, result)
15
+ end
16
+
17
+ def post(request)
18
+ contents = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
19
+ name = contents['name']
20
+ full_name = contents['full_name']
21
+ if name.nil?
22
+ error(400, "Must specify 'name' in JSON")
23
+ elsif full_name.nil?
24
+ error(400, "Must specify 'full_name' in JSON")
25
+ elsif exists_data_dir?(request, request.rest_path + [ name ])
26
+ error(409, "Organization already exists")
27
+ else
28
+ create_data_dir(request, request.rest_path, name, :requestor => request.requestor)
29
+
30
+ org = {
31
+ "guid" => UUIDTools::UUID.random_create.to_s.gsub('-', ''),
32
+ "assigned_at" => Time.now.to_s
33
+ }.merge(contents)
34
+ org_path = request.rest_path + [ name ]
35
+ set_data(request, org_path + [ 'org' ], FFI_Yajl::Encoder.encode(org, :pretty => true))
36
+
37
+ if server.generate_real_keys?
38
+ # Create the validator client
39
+ validator_name = "#{name}-validator"
40
+ validator_path = org_path + [ 'clients', validator_name ]
41
+ private_key, public_key = server.gen_key_pair
42
+ validator = FFI_Yajl::Encoder.encode({
43
+ 'validator' => true,
44
+ 'public_key' => public_key
45
+ }, :pretty => true)
46
+ set_data(request, validator_path, validator)
47
+ end
48
+
49
+
50
+ json_response(201, {
51
+ "uri" => "#{build_uri(request.base_uri, org_path)}",
52
+ "name" => name,
53
+ "org_type" => org["org_type"],
54
+ "full_name" => full_name,
55
+ "clientname" => validator_name,
56
+ "private_key" => private_key
57
+ })
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,151 +1,151 @@
1
- require 'ffi_yajl'
2
-
3
- require 'chef_zero/endpoints/rest_object_endpoint'
4
- require 'chef_zero/chef_data/data_normalizer'
5
-
6
- module ChefZero
7
- module Endpoints
8
- # /policies/:group/:name
9
- class PoliciesEndpoint < RestObjectEndpoint
10
- def initialize(server)
11
- super(server, 'id')
12
- end
13
-
14
- def get(request)
15
- already_json_response(200, get_data(request))
16
- end
17
-
18
- # Right now we're allowing PUT to create.
19
- def put(request)
20
- error = validate(request)
21
- return error if error
22
-
23
- code =
24
- if data_store.exists?(request.rest_path)
25
- set_data(request, request.rest_path, request.body, :data_store_exceptions)
26
- 200
27
- else
28
- name = request.rest_path[4]
29
- data_store.create(request.rest_path[0..3], name, request.body, :create_dir)
30
- 201
31
- end
32
- already_json_response(code, request.body)
33
- end
34
-
35
- def delete(request)
36
- result = get_data(request, request.rest_path)
37
- delete_data(request, request.rest_path, :data_store_exceptions)
38
- already_json_response(200, result)
39
- end
40
-
41
- private
42
-
43
- def validate(request)
44
- req_object = validate_json(request.body)
45
- validate_revision_id(request, req_object) ||
46
- validate_name(request, req_object) ||
47
- validate_run_list(req_object) ||
48
- validate_each_run_list_item(req_object) ||
49
- validate_cookbook_locks_collection(req_object) ||
50
- validate_each_cookbook_locks_item(req_object)
51
- end
52
-
53
- def validate_json(request_body)
54
- FFI_Yajl::Parser.parse(request_body)
55
- # TODO: rescue parse error, return 400
56
- # error(400, "Must specify #{identity_keys.map { |k| k.inspect }.join(' or ')} in JSON")
57
- end
58
-
59
- def validate_revision_id(request, req_object)
60
- if !req_object.key?("revision_id")
61
- error(400, "Field 'revision_id' missing")
62
- elsif req_object["revision_id"].empty?
63
- error(400, "Field 'revision_id' invalid")
64
- elsif req_object["revision_id"].size > 255
65
- error(400, "Field 'revision_id' invalid")
66
- elsif req_object["revision_id"] !~ /^[\-[:alnum:]_\.\:]+$/
67
- error(400, "Field 'revision_id' invalid")
68
- end
69
- end
70
-
71
- def validate_name(request, req_object)
72
- if !req_object.key?("name")
73
- error(400, "Field 'name' missing")
74
- elsif req_object["name"] != (uri_policy_name = URI.decode(request.rest_path[4]))
75
- error(400, "Field 'name' invalid : #{uri_policy_name} does not match #{req_object["name"]}")
76
- elsif req_object["name"].size > 255
77
- error(400, "Field 'name' invalid")
78
- elsif req_object["name"] !~ /^[\-[:alnum:]_\.\:]+$/
79
- error(400, "Field 'name' invalid")
80
- end
81
- end
82
-
83
- def validate_run_list(req_object)
84
- if !req_object.key?("run_list")
85
- error(400, "Field 'run_list' missing")
86
- elsif !req_object["run_list"].kind_of?(Array)
87
- error(400, "Field 'run_list' is not a valid run list")
88
- end
89
- end
90
-
91
- def validate_each_run_list_item(req_object)
92
- req_object["run_list"].each do |run_list_item|
93
- if res_400 = validate_run_list_item(run_list_item)
94
- return res_400
95
- end
96
- end
97
- nil
98
- end
99
-
100
- def validate_run_list_item(run_list_item)
101
- if !run_list_item.kind_of?(String)
102
- error(400, "Field 'run_list' is not a valid run list")
103
- elsif run_list_item !~ /\Arecipe\[[^\s]+::[^\s]+\]\Z/
104
- error(400, "Field 'run_list' is not a valid run list")
105
- end
106
- end
107
-
108
- def validate_cookbook_locks_collection(req_object)
109
- if !req_object.key?("cookbook_locks")
110
- error(400, "Field 'cookbook_locks' missing")
111
- elsif !req_object["cookbook_locks"].kind_of?(Hash)
112
- error(400, "Field 'cookbook_locks' invalid")
113
- end
114
- end
115
-
116
- def validate_each_cookbook_locks_item(req_object)
117
- req_object["cookbook_locks"].each do |cookbook_name, lock|
118
- if res_400 = validate_cookbook_locks_item(cookbook_name, lock)
119
- return res_400
120
- end
121
- end
122
- nil
123
- end
124
-
125
- def validate_cookbook_locks_item(cookbook_name, lock)
126
- if !lock.kind_of?(Hash)
127
- error(400, "cookbook_lock entries must be a JSON object")
128
- elsif !lock.key?("identifier")
129
- error(400, "Field 'identifier' missing")
130
- elsif lock["identifier"].size > 255
131
- error(400, "Field 'identifier' invalid")
132
- elsif !lock.key?("version")
133
- error(400, "Field 'version' missing")
134
- elsif lock.key?("dotted_decimal_identifier")
135
- unless valid_version?(lock["dotted_decimal_identifier"])
136
- error(400, "Field 'dotted_decimal_identifier' is not a valid version")
137
- end
138
- end
139
- end
140
-
141
- def valid_version?(version_string)
142
- Gem::Version.new(version_string)
143
- true
144
- rescue ArgumentError
145
- false
146
- end
147
-
148
- end
149
- end
150
- end
151
-
1
+ require 'ffi_yajl'
2
+
3
+ require 'chef_zero/endpoints/rest_object_endpoint'
4
+ require 'chef_zero/chef_data/data_normalizer'
5
+
6
+ module ChefZero
7
+ module Endpoints
8
+ # /policies/:group/:name
9
+ class PoliciesEndpoint < RestObjectEndpoint
10
+ def initialize(server)
11
+ super(server, 'id')
12
+ end
13
+
14
+ def get(request)
15
+ already_json_response(200, get_data(request))
16
+ end
17
+
18
+ # Right now we're allowing PUT to create.
19
+ def put(request)
20
+ error = validate(request)
21
+ return error if error
22
+
23
+ code =
24
+ if data_store.exists?(request.rest_path)
25
+ set_data(request, request.rest_path, request.body, :data_store_exceptions)
26
+ 200
27
+ else
28
+ name = request.rest_path[4]
29
+ data_store.create(request.rest_path[0..3], name, request.body, :create_dir)
30
+ 201
31
+ end
32
+ already_json_response(code, request.body)
33
+ end
34
+
35
+ def delete(request)
36
+ result = get_data(request, request.rest_path)
37
+ delete_data(request, request.rest_path, :data_store_exceptions)
38
+ already_json_response(200, result)
39
+ end
40
+
41
+ private
42
+
43
+ def validate(request)
44
+ req_object = validate_json(request.body)
45
+ validate_revision_id(request, req_object) ||
46
+ validate_name(request, req_object) ||
47
+ validate_run_list(req_object) ||
48
+ validate_each_run_list_item(req_object) ||
49
+ validate_cookbook_locks_collection(req_object) ||
50
+ validate_each_cookbook_locks_item(req_object)
51
+ end
52
+
53
+ def validate_json(request_body)
54
+ FFI_Yajl::Parser.parse(request_body)
55
+ # TODO: rescue parse error, return 400
56
+ # error(400, "Must specify #{identity_keys.map { |k| k.inspect }.join(' or ')} in JSON")
57
+ end
58
+
59
+ def validate_revision_id(request, req_object)
60
+ if !req_object.key?("revision_id")
61
+ error(400, "Field 'revision_id' missing")
62
+ elsif req_object["revision_id"].empty?
63
+ error(400, "Field 'revision_id' invalid")
64
+ elsif req_object["revision_id"].size > 255
65
+ error(400, "Field 'revision_id' invalid")
66
+ elsif req_object["revision_id"] !~ /^[\-[:alnum:]_\.\:]+$/
67
+ error(400, "Field 'revision_id' invalid")
68
+ end
69
+ end
70
+
71
+ def validate_name(request, req_object)
72
+ if !req_object.key?("name")
73
+ error(400, "Field 'name' missing")
74
+ elsif req_object["name"] != (uri_policy_name = URI.decode(request.rest_path[4]))
75
+ error(400, "Field 'name' invalid : #{uri_policy_name} does not match #{req_object["name"]}")
76
+ elsif req_object["name"].size > 255
77
+ error(400, "Field 'name' invalid")
78
+ elsif req_object["name"] !~ /^[\-[:alnum:]_\.\:]+$/
79
+ error(400, "Field 'name' invalid")
80
+ end
81
+ end
82
+
83
+ def validate_run_list(req_object)
84
+ if !req_object.key?("run_list")
85
+ error(400, "Field 'run_list' missing")
86
+ elsif !req_object["run_list"].kind_of?(Array)
87
+ error(400, "Field 'run_list' is not a valid run list")
88
+ end
89
+ end
90
+
91
+ def validate_each_run_list_item(req_object)
92
+ req_object["run_list"].each do |run_list_item|
93
+ if res_400 = validate_run_list_item(run_list_item)
94
+ return res_400
95
+ end
96
+ end
97
+ nil
98
+ end
99
+
100
+ def validate_run_list_item(run_list_item)
101
+ if !run_list_item.kind_of?(String)
102
+ error(400, "Field 'run_list' is not a valid run list")
103
+ elsif run_list_item !~ /\Arecipe\[[^\s]+::[^\s]+\]\Z/
104
+ error(400, "Field 'run_list' is not a valid run list")
105
+ end
106
+ end
107
+
108
+ def validate_cookbook_locks_collection(req_object)
109
+ if !req_object.key?("cookbook_locks")
110
+ error(400, "Field 'cookbook_locks' missing")
111
+ elsif !req_object["cookbook_locks"].kind_of?(Hash)
112
+ error(400, "Field 'cookbook_locks' invalid")
113
+ end
114
+ end
115
+
116
+ def validate_each_cookbook_locks_item(req_object)
117
+ req_object["cookbook_locks"].each do |cookbook_name, lock|
118
+ if res_400 = validate_cookbook_locks_item(cookbook_name, lock)
119
+ return res_400
120
+ end
121
+ end
122
+ nil
123
+ end
124
+
125
+ def validate_cookbook_locks_item(cookbook_name, lock)
126
+ if !lock.kind_of?(Hash)
127
+ error(400, "cookbook_lock entries must be a JSON object")
128
+ elsif !lock.key?("identifier")
129
+ error(400, "Field 'identifier' missing")
130
+ elsif lock["identifier"].size > 255
131
+ error(400, "Field 'identifier' invalid")
132
+ elsif !lock.key?("version")
133
+ error(400, "Field 'version' missing")
134
+ elsif lock.key?("dotted_decimal_identifier")
135
+ unless valid_version?(lock["dotted_decimal_identifier"])
136
+ error(400, "Field 'dotted_decimal_identifier' is not a valid version")
137
+ end
138
+ end
139
+ end
140
+
141
+ def valid_version?(version_string)
142
+ Gem::Version.new(version_string)
143
+ true
144
+ rescue ArgumentError
145
+ false
146
+ end
147
+
148
+ end
149
+ end
150
+ end
151
+