Commit f642a460 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Limit level of nesting for groups

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parent 99fceff4
...@@ -7,6 +7,11 @@ class Namespace < ActiveRecord::Base ...@@ -7,6 +7,11 @@ class Namespace < ActiveRecord::Base
include Gitlab::CurrentSettings include Gitlab::CurrentSettings
include Routable include Routable
# Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of
# Android repo (15) + some extra backup.
NUMBER_OF_ANCESTORS_ALLOWED = 20
cache_markdown_field :description, pipeline: :description cache_markdown_field :description, pipeline: :description
has_many :projects, dependent: :destroy has_many :projects, dependent: :destroy
...@@ -29,6 +34,8 @@ class Namespace < ActiveRecord::Base ...@@ -29,6 +34,8 @@ class Namespace < ActiveRecord::Base
length: { maximum: 255 }, length: { maximum: 255 },
namespace: true namespace: true
validate :nesting_level_allowed
delegate :name, to: :owner, allow_nil: true, prefix: true delegate :name, to: :owner, allow_nil: true, prefix: true
after_update :move_dir, if: :path_changed? after_update :move_dir, if: :path_changed?
...@@ -194,7 +201,7 @@ class Namespace < ActiveRecord::Base ...@@ -194,7 +201,7 @@ class Namespace < ActiveRecord::Base
# Scopes the model on ancestors of the record # Scopes the model on ancestors of the record
def ancestors def ancestors
if parent_id if parent_id
path = route.path path = route ? route.path : full_path
paths = [] paths = []
until path.blank? until path.blank?
...@@ -270,4 +277,10 @@ class Namespace < ActiveRecord::Base ...@@ -270,4 +277,10 @@ class Namespace < ActiveRecord::Base
path_was path_was
end end
end end
def nesting_level_allowed
if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED
errors.add(:parent_id, "has too deep level of nesting")
end
end
end end
...@@ -3,21 +3,32 @@ require 'spec_helper' ...@@ -3,21 +3,32 @@ require 'spec_helper'
describe Namespace, models: true do describe Namespace, models: true do
let!(:namespace) { create(:namespace) } let!(:namespace) { create(:namespace) }
it { is_expected.to have_many :projects } describe 'associations' do
it { is_expected.to have_many :project_statistics } it { is_expected.to have_many :projects }
it { is_expected.to belong_to :parent } it { is_expected.to have_many :project_statistics }
it { is_expected.to have_many :children } it { is_expected.to belong_to :parent }
it { is_expected.to have_many :children }
end
it { is_expected.to validate_presence_of(:name) } describe 'validations' do
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) } it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_length_of(:name).is_at_most(255) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) }
it { is_expected.to validate_length_of(:name).is_at_most(255) }
it { is_expected.to validate_length_of(:description).is_at_most(255) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_length_of(:path).is_at_most(255) }
it { is_expected.to validate_presence_of(:owner) }
it { is_expected.to validate_length_of(:description).is_at_most(255) } it 'does not allow too deep nesting' do
ancestors = (1..21).to_a
nested = build(:namespace, parent: namespace)
it { is_expected.to validate_presence_of(:path) } allow(nested).to receive(:ancestors).and_return(ancestors)
it { is_expected.to validate_length_of(:path).is_at_most(255) }
it { is_expected.to validate_presence_of(:owner) } expect(nested).not_to be_valid
expect(nested.errors[:parent_id].first).to eq('has too deep level of nesting')
end
end
describe "Respond to" do describe "Respond to" do
it { is_expected.to respond_to(:human_name) } it { is_expected.to respond_to(:human_name) }
......
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