Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Policyfile Revision ID Validation. #116

Merged
merged 4 commits into from
Feb 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ gemspec

gem 'rest-client', :github => 'opscode/rest-client'

gem 'chef-pedant', :github => 'opscode/chef-pedant', :tag => '1.0.44'
gem 'chef-pedant', :github => 'opscode/chef-pedant', :tag => '1.0.46'

gem 'chef', :github => 'opscode/chef', :tag => '12.1.0.rc.0'

60 changes: 44 additions & 16 deletions lib/chef_zero/endpoints/policies_endpoint.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
require 'ffi_yajl'

require 'chef/version_class'
require 'chef/exceptions'

require 'chef_zero/endpoints/rest_object_endpoint'
require 'chef_zero/chef_data/data_normalizer'

Expand Down Expand Up @@ -41,7 +45,8 @@ def delete(request)

def validate(request)
req_object = validate_json(request.body)
validate_name(request, req_object) ||
validate_revision_id(request, req_object) ||
validate_name(request, req_object) ||
validate_run_list(req_object) ||
validate_each_run_list_item(req_object) ||
validate_cookbook_locks_collection(req_object) ||
Expand All @@ -54,23 +59,35 @@ def validate_json(request_body)
# error(400, "Must specify #{identity_keys.map { |k| k.inspect }.join(' or ')} in JSON")
end

def validate_revision_id(request, req_object)
if !req_object.key?("revision_id")
error(400, "Field 'revision_id' missing")
elsif req_object["revision_id"].empty?
error(400, "Field 'revision_id' invalid")
elsif req_object["revision_id"].size > 255
error(400, "Field 'revision_id' invalid")
elsif req_object["revision_id"] !~ /^[\-[:alnum:]_\.\:]+$/
error(400, "Field 'revision_id' invalid")
end
end

def validate_name(request, req_object)
if !req_object.key?("name")
error(400, "Must specify 'name' in JSON")
elsif req_object["name"] != URI.decode(request.rest_path[4])
error(400, "'name' field in JSON must match the policy name in the URL")
error(400, "Field 'name' missing")
elsif req_object["name"] != (uri_policy_name = URI.decode(request.rest_path[4]))
error(400, "Field 'name' invalid : #{uri_policy_name} does not match #{req_object["name"]}")
elsif req_object["name"].size > 255
error(400, "'name' field in JSON must be 255 characters or fewer")
error(400, "Field 'name' invalid")
elsif req_object["name"] !~ /^[\-[:alnum:]_\.\:]+$/
error(400, "'name' field in JSON must be contain only alphanumeric, hypen, underscore, and dot characters")
error(400, "Field 'name' invalid")
end
end

def validate_run_list(req_object)
if !req_object.key?("run_list")
error(400, "Must specify 'run_list' in JSON")
error(400, "Field 'run_list' missing")
elsif !req_object["run_list"].kind_of?(Array)
error(400, "'run_list' must be an Array of run list items")
error(400, "Field 'run_list' is not a valid run list")
end
end

Expand All @@ -85,17 +102,17 @@ def validate_each_run_list_item(req_object)

def validate_run_list_item(run_list_item)
if !run_list_item.kind_of?(String)
error(400, "Items in run_list must be strings in fully qualified recipe format, like recipe[cookbook::recipe]")
error(400, "Field 'run_list' is not a valid run list")
elsif run_list_item !~ /\Arecipe\[[^\s]+::[^\s]+\]\Z/
error(400, "Items in run_list must be strings in fully qualified recipe format, like recipe[cookbook::recipe]")
error(400, "Field 'run_list' is not a valid run list")
end
end

def validate_cookbook_locks_collection(req_object)
if !req_object.key?("cookbook_locks")
error(400, "Must specify 'cookbook_locks' in JSON")
error(400, "Field 'cookbook_locks' missing")
elsif !req_object["cookbook_locks"].kind_of?(Hash)
error(400, "'cookbook_locks' must be a JSON object of cookbook_name: lock_data pairs")
error(400, "Field 'cookbook_locks' invalid")
end
end

Expand All @@ -112,14 +129,25 @@ def validate_cookbook_locks_item(cookbook_name, lock)
if !lock.kind_of?(Hash)
error(400, "cookbook_lock entries must be a JSON object")
elsif !lock.key?("identifier")
error(400, "cookbook_lock entries must contain an 'identifier' field")
elsif !lock.key?("dotted_decimal_identifier")
error(400, "cookbook_lock entries must contain an 'dotted_decimal_identifier' field")
error(400, "Field 'identifier' missing")
elsif lock["identifier"].size > 255
error(400, "cookbook_lock entries 'identifier' field must be 255 or fewer characters")
error(400, "Field 'identifier' invalid")
elsif !lock.key?("version")
error(400, "Field 'version' missing")
elsif lock.key?("dotted_decimal_identifier")
unless valid_version?(lock["dotted_decimal_identifier"])
error(400, "Field 'dotted_decimal_identifier' is not a valid version")
end
end
end

def valid_version?(version_string)
Chef::Version.new(version_string)
true
rescue Chef::Exceptions::InvalidCookbookVersion
false
end

end
end
end
Expand Down