diff options
author | Bob Van Landuyt <bob@gitlab.com> | 2017-04-10 19:27:19 +0200 |
---|---|---|
committer | Bob Van Landuyt <bob@gitlab.com> | 2017-05-01 11:14:24 +0200 |
commit | e4f5b7ca2184473985ef216df676ddb737fb26af (patch) | |
tree | 3973c48d6a67f4473bdced644dfdd0b026835ad4 /spec/validators | |
parent | 74fcccaab30ac0f9e11ed9a076c008ade13a50d0 (diff) | |
download | gitlab-ce-e4f5b7ca2184473985ef216df676ddb737fb26af.tar.gz |
Improve detection of reserved words from routes
Diffstat (limited to 'spec/validators')
-rw-r--r-- | spec/validators/namespace_validator_spec.rb | 81 |
1 files changed, 67 insertions, 14 deletions
diff --git a/spec/validators/namespace_validator_spec.rb b/spec/validators/namespace_validator_spec.rb index 4b5dd59e048..7ddce74939d 100644 --- a/spec/validators/namespace_validator_spec.rb +++ b/spec/validators/namespace_validator_spec.rb @@ -2,27 +2,80 @@ require 'spec_helper' describe NamespaceValidator do let(:validator) { described_class.new(attributes: [:path]) } - describe 'RESERVED' do + + # Pass in a full path to remove the format segment: + # `/ci/lint(.:format)` -> `/ci/lint` + def without_format(path) + path.split('(', 2)[0] + end + + # Pass in a full path and get the last segment before a wildcard + # That's not a parameter + # `/*namespace_id/:project_id/builds/artifacts/*ref_name_and_path` + # -> 'artifacts' + def segment_before_last_wildcard(path) + path_segments = path.split('/').reject { |segment| segment.empty? } + last_wildcard_index = path_segments.rindex { |part| part.starts_with?('*') } + + index_of_non_param_segment = last_wildcard_index - 1 + part_before_wildcard = path_segments[index_of_non_param_segment] + while parameter?(part_before_wildcard) + index_of_non_param_segment -= 1 + part_before_wildcard = path_segments[index_of_non_param_segment] + end + + part_before_wildcard + end + + def parameter?(path_segment) + path_segment.starts_with?(':') || path_segment.starts_with?('*') + end + + let(:all_routes) do + Rails.application.routes.routes.routes. + map { |r| r.path.spec.to_s } + end + + let(:routes_without_format) { all_routes.map { |path| without_format(path) } } + + # Routes not starting with `/:` or `/*` + # all routes not starting with a param + let(:routes_not_starting_in_wildcard) { routes_without_format.select { |p| p !~ %r{^/[:*]} } } + + # All routes that start with a namespaced path, that have 1 or more + # path-segments before having another wildcard parameter. + # - Starting with paths: + # - `/*namespace_id/:project_id/` + # - `/*namespace_id/:id/` + # - Followed by one or more path-parts not starting with `:` or `/` + # - Followed by a path-part that includes a wildcard parameter `*` + # At the time of writing these routes match: http://rubular.com/r/QDxulzZlxZ + STARTING_WITH_NAMESPACE = /^\/\*namespace_id\/:(project_)?id/ + NON_PARAM_PARTS = /[^:*][a-z\-_\/]*/ + ANY_OTHER_PATH_PART = /[a-z\-_\/:]*/ + WILDCARD_SEGMENT = /\*/ + let(:namespaced_wildcard_routes) do + routes_without_format.select do |p| + p =~ %r{#{STARTING_WITH_NAMESPACE}\/#{NON_PARAM_PARTS}\/#{ANY_OTHER_PATH_PART}#{WILDCARD_SEGMENT}} + end + end + + describe 'TOP_LEVEL_ROUTES' do it 'includes all the top level namespaces' do - all_top_level_routes = Rails.application.routes.routes.routes. - map { |r| r.path.spec.to_s }. - select { |p| p !~ %r{^/[:*]} }. - map { |p| p.split('/')[1] }. - compact. - map { |p| p.split('(', 2)[0] }. - uniq + top_level_words = routes_not_starting_in_wildcard. + map { |p| p.split('/')[1] }. # Get the first part of the path + compact. + uniq - expect(described_class::RESERVED).to include(*all_top_level_routes) + expect(described_class::TOP_LEVEL_ROUTES).to include(*top_level_words) end end describe 'WILDCARD_ROUTES' do it 'includes all paths that can be used after a namespace/project path' do - all_wildcard_paths = Rails.application.routes.routes.routes. - map { |r| r.path.spec.to_s }. - select { |p| p =~ %r{^/\*namespace_id/:(project_)?id/[^:*]} }. - map { |p| p.split('/')[3].split('(', 2)[0] }. - uniq + all_wildcard_paths = namespaced_wildcard_routes.map do |path| + segment_before_last_wildcard(path) + end.uniq expect(described_class::WILDCARD_ROUTES).to include(*all_wildcard_paths) end |