Commit 50d9204f authored by Sean McGivern's avatar Sean McGivern

Merge branch '29583-routes-like-fix' into 'master'

Escape route path for LIKE queries

Closes #29583

See merge request !10117
parents 5f729268 3750766f
...@@ -195,7 +195,7 @@ class Namespace < ActiveRecord::Base ...@@ -195,7 +195,7 @@ class Namespace < ActiveRecord::Base
# Scopes the model on direct and indirect children of the record # Scopes the model on direct and indirect children of the record
def descendants def descendants
self.class.joins(:route).where('routes.path LIKE ?', "#{route.path}/%").reorder('routes.path ASC') self.class.joins(:route).merge(Route.inside_path(route.path)).reorder('routes.path ASC')
end end
def user_ids_for_project_authorizations def user_ids_for_project_authorizations
......
...@@ -238,7 +238,7 @@ class Project < ActiveRecord::Base ...@@ -238,7 +238,7 @@ class Project < ActiveRecord::Base
# We need routes alias rs for JOIN so it does not conflict with # We need routes alias rs for JOIN so it does not conflict with
# includes(:route) which we use in ProjectsFinder. # includes(:route) which we use in ProjectsFinder.
joins("INNER JOIN routes rs ON rs.source_id = projects.id AND rs.source_type = 'Project'"). joins("INNER JOIN routes rs ON rs.source_id = projects.id AND rs.source_type = 'Project'").
where('rs.path LIKE ?', "#{path}/%") where('rs.path LIKE ?', "#{sanitize_sql_like(path)}/%")
end end
# "enabled" here means "not disabled". It includes private features! # "enabled" here means "not disabled". It includes private features!
......
...@@ -10,9 +10,11 @@ class Route < ActiveRecord::Base ...@@ -10,9 +10,11 @@ class Route < ActiveRecord::Base
after_update :rename_descendants after_update :rename_descendants
scope :inside_path, -> (path) { where('routes.path LIKE ?', "#{sanitize_sql_like(path)}/%") }
def rename_descendants def rename_descendants
if path_changed? || name_changed? if path_changed? || name_changed?
descendants = Route.where('path LIKE ?', "#{path_was}/%") descendants = self.class.inside_path(path_was)
descendants.each do |route| descendants.each do |route|
attributes = {} attributes = {}
......
...@@ -1762,11 +1762,18 @@ describe Project, models: true do ...@@ -1762,11 +1762,18 @@ describe Project, models: true do
end end
describe 'inside_path' do describe 'inside_path' do
let!(:project1) { create(:empty_project) } let!(:project1) { create(:empty_project, namespace: create(:namespace, path: 'name_pace')) }
let!(:project2) { create(:empty_project) } let!(:project2) { create(:empty_project) }
let!(:project3) { create(:empty_project, namespace: create(:namespace, path: 'namespace')) }
let!(:path) { project1.namespace.full_path } let!(:path) { project1.namespace.full_path }
it { expect(Project.inside_path(path)).to eq([project1]) } it 'returns 1 project' do
expect(Project.inside_path(path).count).to eq(1)
end
it 'returns correct project' do
expect(Project.inside_path(path)).to eq([project1])
end
end end
describe '#route_map_for' do describe '#route_map_for' do
......
require 'spec_helper' require 'spec_helper'
describe Route, models: true do describe Route, models: true do
let!(:group) { create(:group, path: 'gitlab', name: 'gitlab') } let!(:group) { create(:group, path: 'git_lab', name: 'git_lab') }
let!(:route) { group.route } let!(:route) { group.route }
describe 'relationships' do describe 'relationships' do
...@@ -14,10 +14,28 @@ describe Route, models: true do ...@@ -14,10 +14,28 @@ describe Route, models: true do
it { is_expected.to validate_uniqueness_of(:path) } it { is_expected.to validate_uniqueness_of(:path) }
end end
describe '.inside_path' do
let!(:nested_group) { create(:group, path: 'test', name: 'test', parent: group) }
let!(:deep_nested_group) { create(:group, path: 'foo', name: 'foo', parent: nested_group) }
let!(:another_group) { create(:group, path: 'other') }
let!(:similar_group) { create(:group, path: 'gitllab') }
let!(:another_group_nested) { create(:group, path: 'another', name: 'another', parent: similar_group) }
it 'returns 2 routes' do
expect(Route.inside_path('git_lab').count).to eq(2)
end
it 'returns correct routes' do
expect(Route.inside_path('git_lab')).to match_array([nested_group.route, deep_nested_group.route])
end
end
describe '#rename_descendants' do describe '#rename_descendants' do
let!(:nested_group) { create(:group, path: 'test', name: 'test', parent: group) } let!(:nested_group) { create(:group, path: 'test', name: 'test', parent: group) }
let!(:deep_nested_group) { create(:group, path: 'foo', name: 'foo', parent: nested_group) } let!(:deep_nested_group) { create(:group, path: 'foo', name: 'foo', parent: nested_group) }
let!(:similar_group) { create(:group, path: 'gitlab-org', name: 'gitlab-org') } let!(:similar_group) { create(:group, path: 'gitlab-org', name: 'gitlab-org') }
let!(:another_group) { create(:group, path: 'gittlab', name: 'gitllab') }
let!(:another_group_nested) { create(:group, path: 'git_lab', name: 'git_lab', parent: another_group) }
context 'path update' do context 'path update' do
context 'when route name is set' do context 'when route name is set' do
...@@ -28,6 +46,8 @@ describe Route, models: true do ...@@ -28,6 +46,8 @@ describe Route, models: true do
expect(described_class.exists?(path: 'bar/test')).to be_truthy expect(described_class.exists?(path: 'bar/test')).to be_truthy
expect(described_class.exists?(path: 'bar/test/foo')).to be_truthy expect(described_class.exists?(path: 'bar/test/foo')).to be_truthy
expect(described_class.exists?(path: 'gitlab-org')).to be_truthy expect(described_class.exists?(path: 'gitlab-org')).to be_truthy
expect(described_class.exists?(path: 'gittlab')).to be_truthy
expect(described_class.exists?(path: 'gittlab/git_lab')).to be_truthy
end end
end end
...@@ -44,7 +64,7 @@ describe Route, models: true do ...@@ -44,7 +64,7 @@ describe Route, models: true do
context 'name update' do context 'name update' do
it "updates children routes with new path" do it "updates children routes with new path" do
route.update_attributes(name: 'bar') route.update_attributes(name: 'bar')
expect(described_class.exists?(name: 'bar')).to be_truthy expect(described_class.exists?(name: 'bar')).to be_truthy
expect(described_class.exists?(name: 'bar / test')).to be_truthy expect(described_class.exists?(name: 'bar / test')).to be_truthy
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment