Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a30da0a1
Commit
a30da0a1
authored
Aug 30, 2021
by
charlie ablett
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add owner validation for project namespaces
Only user namespaces must have an owner Changelog: added
parent
6914cf3c
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
109 additions
and
52 deletions
+109
-52
app/models/namespace.rb
app/models/namespace.rb
+5
-1
app/models/namespaces/project_namespace.rb
app/models/namespaces/project_namespace.rb
+2
-0
app/models/project.rb
app/models/project.rb
+32
-9
db/migrate/20210824102624_add_project_namespace_index_to_project.rb
.../20210824102624_add_project_namespace_index_to_project.rb
+0
-17
db/migrate/20210824102750_add_project_namespace_foreign_key_to_project.rb
...824102750_add_project_namespace_foreign_key_to_project.rb
+0
-19
spec/models/namespace_spec.rb
spec/models/namespace_spec.rb
+6
-0
spec/models/namespaces/project_namespace_spec.rb
spec/models/namespaces/project_namespace_spec.rb
+4
-0
spec/models/project_spec.rb
spec/models/project_spec.rb
+60
-6
No files found.
app/models/namespace.rb
View file @
a30da0a1
...
@@ -57,7 +57,7 @@ class Namespace < ApplicationRecord
...
@@ -57,7 +57,7 @@ class Namespace < ApplicationRecord
has_one
:admin_note
,
inverse_of: :namespace
has_one
:admin_note
,
inverse_of: :namespace
accepts_nested_attributes_for
:admin_note
,
update_only:
true
accepts_nested_attributes_for
:admin_note
,
update_only:
true
validates
:owner
,
presence:
true
,
if:
->
(
n
)
{
n
.
type
.
nil
?
}
validates
:owner
,
presence:
true
,
if:
->
(
n
)
{
n
.
owner_required
?
}
validates
:name
,
validates
:name
,
presence:
true
,
presence:
true
,
length:
{
maximum:
255
}
length:
{
maximum:
255
}
...
@@ -266,6 +266,10 @@ class Namespace < ApplicationRecord
...
@@ -266,6 +266,10 @@ class Namespace < ApplicationRecord
type
.
nil?
||
type
==
Namespaces
::
UserNamespace
.
sti_name
||
!
(
group?
||
project?
)
type
.
nil?
||
type
==
Namespaces
::
UserNamespace
.
sti_name
||
!
(
group?
||
project?
)
end
end
def
owner_required?
user?
end
def
find_fork_of
(
project
)
def
find_fork_of
(
project
)
return
unless
project
.
fork_network
return
unless
project
.
fork_network
...
...
app/models/namespaces/project_namespace.rb
View file @
a30da0a1
...
@@ -4,6 +4,8 @@ module Namespaces
...
@@ -4,6 +4,8 @@ module Namespaces
class
ProjectNamespace
<
Namespace
class
ProjectNamespace
<
Namespace
has_one
:project
,
foreign_key: :project_namespace_id
,
inverse_of: :project_namespace
has_one
:project
,
foreign_key: :project_namespace_id
,
inverse_of: :project_namespace
validates
:project
,
presence:
true
def
self
.
sti_name
def
self
.
sti_name
'Project'
'Project'
end
end
...
...
app/models/project.rb
View file @
a30da0a1
...
@@ -211,6 +211,7 @@ class Project < ApplicationRecord
...
@@ -211,6 +211,7 @@ class Project < ApplicationRecord
has_one
:unify_circuit_integration
,
class_name:
'Integrations::UnifyCircuit'
has_one
:unify_circuit_integration
,
class_name:
'Integrations::UnifyCircuit'
has_one
:webex_teams_integration
,
class_name:
'Integrations::WebexTeams'
has_one
:webex_teams_integration
,
class_name:
'Integrations::WebexTeams'
has_one
:youtrack_integration
,
class_name:
'Integrations::Youtrack'
has_one
:youtrack_integration
,
class_name:
'Integrations::Youtrack'
has_one
:zentao_integration
,
class_name:
'Integrations::Zentao'
has_one
:root_of_fork_network
,
has_one
:root_of_fork_network
,
foreign_key:
'root_project_id'
,
foreign_key:
'root_project_id'
,
...
@@ -340,6 +341,7 @@ class Project < ApplicationRecord
...
@@ -340,6 +341,7 @@ class Project < ApplicationRecord
# build traces. Currently there's no efficient way of removing this data in
# build traces. Currently there's no efficient way of removing this data in
# bulk that doesn't involve loading the rows into memory. As a result we're
# bulk that doesn't involve loading the rows into memory. As a result we're
# still using `dependent: :destroy` here.
# still using `dependent: :destroy` here.
has_many
:pending_builds
,
class_name:
'Ci::PendingBuild'
has_many
:builds
,
class_name:
'Ci::Build'
,
inverse_of: :project
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_many
:builds
,
class_name:
'Ci::Build'
,
inverse_of: :project
,
dependent: :destroy
# rubocop:disable Cop/ActiveRecordDependent
has_many
:processables
,
class_name:
'Ci::Processable'
,
inverse_of: :project
has_many
:processables
,
class_name:
'Ci::Processable'
,
inverse_of: :project
has_many
:build_trace_chunks
,
class_name:
'Ci::BuildTraceChunk'
,
through: :builds
,
source: :trace_chunks
has_many
:build_trace_chunks
,
class_name:
'Ci::BuildTraceChunk'
,
through: :builds
,
source: :trace_chunks
...
@@ -1458,7 +1460,7 @@ class Project < ApplicationRecord
...
@@ -1458,7 +1460,7 @@ class Project < ApplicationRecord
end
end
def
disabled_integrations
def
disabled_integrations
[]
[
:zentao
]
end
end
def
find_or_initialize_integration
(
name
)
def
find_or_initialize_integration
(
name
)
...
@@ -1677,6 +1679,10 @@ class Project < ApplicationRecord
...
@@ -1677,6 +1679,10 @@ class Project < ApplicationRecord
end
end
end
end
def
membership_locked?
false
end
def
bots
def
bots
users
.
project_bot
users
.
project_bot
end
end
...
@@ -1784,6 +1790,9 @@ class Project < ApplicationRecord
...
@@ -1784,6 +1790,9 @@ class Project < ApplicationRecord
Ci
::
Runner
.
from_union
([
runners
,
group_runners
,
available_shared_runners
])
Ci
::
Runner
.
from_union
([
runners
,
group_runners
,
available_shared_runners
])
end
end
# Once issue 339937 is fixed, please search for all mentioned of
# https://gitlab.com/gitlab-org/gitlab/-/issues/339937,
# and remove the allow_cross_joins_across_databases.
def
active_runners
def
active_runners
strong_memoize
(
:active_runners
)
do
strong_memoize
(
:active_runners
)
do
all_available_runners
.
active
all_available_runners
.
active
...
@@ -1791,7 +1800,9 @@ class Project < ApplicationRecord
...
@@ -1791,7 +1800,9 @@ class Project < ApplicationRecord
end
end
def
any_online_runners?
(
&
block
)
def
any_online_runners?
(
&
block
)
online_runners_with_tags
.
any?
(
&
block
)
::
Gitlab
::
Database
.
allow_cross_joins_across_databases
(
url:
'https://gitlab.com/gitlab-org/gitlab/-/issues/339937'
)
do
online_runners_with_tags
.
any?
(
&
block
)
end
end
end
def
valid_runners_token?
(
token
)
def
valid_runners_token?
(
token
)
...
@@ -1800,7 +1811,15 @@ class Project < ApplicationRecord
...
@@ -1800,7 +1811,15 @@ class Project < ApplicationRecord
# rubocop: disable CodeReuse/ServiceClass
# rubocop: disable CodeReuse/ServiceClass
def
open_issues_count
(
current_user
=
nil
)
def
open_issues_count
(
current_user
=
nil
)
Projects
::
OpenIssuesCountService
.
new
(
self
,
current_user
).
count
return
Projects
::
OpenIssuesCountService
.
new
(
self
,
current_user
).
count
unless
current_user
.
nil?
BatchLoader
.
for
(
self
).
batch
(
replace_methods:
false
)
do
|
projects
,
loader
|
issues_count_per_project
=
::
Projects
::
BatchOpenIssuesCountService
.
new
(
projects
).
refresh_cache_and_retrieve_data
issues_count_per_project
.
each
do
|
project
,
count
|
loader
.
call
(
project
,
count
)
end
end
end
end
# rubocop: enable CodeReuse/ServiceClass
# rubocop: enable CodeReuse/ServiceClass
...
@@ -2259,7 +2278,7 @@ class Project < ApplicationRecord
...
@@ -2259,7 +2278,7 @@ class Project < ApplicationRecord
# rubocop: disable CodeReuse/ServiceClass
# rubocop: disable CodeReuse/ServiceClass
def
forks_count
def
forks_count
BatchLoader
.
for
(
self
).
batch
do
|
projects
,
loader
|
BatchLoader
.
for
(
self
).
batch
(
replace_methods:
false
)
do
|
projects
,
loader
|
fork_count_per_project
=
::
Projects
::
BatchForksCountService
.
new
(
projects
).
refresh_cache_and_retrieve_data
fork_count_per_project
=
::
Projects
::
BatchForksCountService
.
new
(
projects
).
refresh_cache_and_retrieve_data
fork_count_per_project
.
each
do
|
project
,
count
|
fork_count_per_project
.
each
do
|
project
,
count
|
...
@@ -2511,6 +2530,10 @@ class Project < ApplicationRecord
...
@@ -2511,6 +2530,10 @@ class Project < ApplicationRecord
ci_config_path
.
blank?
||
ci_config_path
==
Gitlab
::
FileDetector
::
PATTERNS
[
:gitlab_ci
]
ci_config_path
.
blank?
||
ci_config_path
==
Gitlab
::
FileDetector
::
PATTERNS
[
:gitlab_ci
]
end
end
def
uses_external_project_ci_config?
!!
(
ci_config_path
=~
%r{@.+/.+}
)
end
def
limited_protected_branches
(
limit
)
def
limited_protected_branches
(
limit
)
protected_branches
.
limit
(
limit
)
protected_branches
.
limit
(
limit
)
end
end
...
@@ -2619,6 +2642,10 @@ class Project < ApplicationRecord
...
@@ -2619,6 +2642,10 @@ class Project < ApplicationRecord
repository
.
gitlab_ci_yml_for
(
sha
,
ci_config_path_or_default
)
repository
.
gitlab_ci_yml_for
(
sha
,
ci_config_path_or_default
)
end
end
def
ci_config_external_project
Project
.
find_by_full_path
(
ci_config_path
.
split
(
'@'
,
2
).
last
)
end
def
enabled_group_deploy_keys
def
enabled_group_deploy_keys
return
GroupDeployKey
.
none
unless
group
return
GroupDeployKey
.
none
unless
group
...
@@ -2881,12 +2908,8 @@ class Project < ApplicationRecord
...
@@ -2881,12 +2908,8 @@ class Project < ApplicationRecord
update_column
(
:has_external_issue_tracker
,
integrations
.
external_issue_trackers
.
any?
)
if
Gitlab
::
Database
.
read_write?
update_column
(
:has_external_issue_tracker
,
integrations
.
external_issue_trackers
.
any?
)
if
Gitlab
::
Database
.
read_write?
end
end
def
active_runners_with_tags
@active_runners_with_tags
||=
active_runners
.
with_tags
end
def
online_runners_with_tags
def
online_runners_with_tags
@online_runners_with_tags
||=
active_runners
_
with_tags
.
online
@online_runners_with_tags
||=
active_runners
.
with_tags
.
online
end
end
end
end
...
...
db/migrate/20210824102624_add_project_namespace_index_to_project.rb
deleted
100644 → 0
View file @
6914cf3c
# frozen_string_literal: true
class
AddProjectNamespaceIndexToProject
<
ActiveRecord
::
Migration
[
6.1
]
include
Gitlab
::
Database
::
MigrationHelpers
disable_ddl_transaction!
INDEX_NAME
=
'index_projects_on_project_namespace_id'
def
up
add_concurrent_index
:projects
,
:project_namespace_id
,
name:
INDEX_NAME
,
unique:
true
end
def
down
remove_concurrent_index_by_name
:projects
,
INDEX_NAME
end
end
db/migrate/20210824102750_add_project_namespace_foreign_key_to_project.rb
deleted
100644 → 0
View file @
6914cf3c
# frozen_string_literal: true
class
AddProjectNamespaceForeignKeyToProject
<
ActiveRecord
::
Migration
[
6.1
]
include
Gitlab
::
Database
::
MigrationHelpers
disable_ddl_transaction!
TARGET_COLUMN
=
:project_namespace_id
def
up
add_concurrent_foreign_key
:projects
,
:namespaces
,
column:
TARGET_COLUMN
,
on_delete: :cascade
end
def
down
with_lock_retries
do
remove_foreign_key_if_exists
(
:projects
,
column:
TARGET_COLUMN
)
end
end
end
spec/models/namespace_spec.rb
View file @
a30da0a1
...
@@ -344,6 +344,12 @@ RSpec.describe Namespace do
...
@@ -344,6 +344,12 @@ RSpec.describe Namespace do
end
end
end
end
describe
'#owner_required?'
do
specify
{
expect
(
build
(
:project_namespace
).
owner_required?
).
to
be_falsey
}
specify
{
expect
(
build
(
:group
).
owner_required?
).
to
be_falsey
}
specify
{
expect
(
build
(
:namespace
).
owner_required?
).
to
be_truthy
}
end
describe
'#visibility_level_field'
do
describe
'#visibility_level_field'
do
it
{
expect
(
namespace
.
visibility_level_field
).
to
eq
(
:visibility_level
)
}
it
{
expect
(
namespace
.
visibility_level_field
).
to
eq
(
:visibility_level
)
}
end
end
...
...
spec/models/namespaces/project_namespace_spec.rb
View file @
a30da0a1
...
@@ -7,6 +7,10 @@ RSpec.describe Namespaces::ProjectNamespace, type: :model do
...
@@ -7,6 +7,10 @@ RSpec.describe Namespaces::ProjectNamespace, type: :model do
it
{
is_expected
.
to
have_one
(
:project
).
with_foreign_key
(
:project_namespace_id
).
inverse_of
(
:project_namespace
)
}
it
{
is_expected
.
to
have_one
(
:project
).
with_foreign_key
(
:project_namespace_id
).
inverse_of
(
:project_namespace
)
}
end
end
describe
'validations'
do
it
{
is_expected
.
not_to
validate_presence_of
:owner
}
end
context
'when deleting project namespace'
do
context
'when deleting project namespace'
do
# using delete rather than destroy due to `delete` skipping AR hooks/callbacks
# using delete rather than destroy due to `delete` skipping AR hooks/callbacks
# so it's ensured to work at the DB level. Uses ON DELETE CASCADE on foreign key
# so it's ensured to work at the DB level. Uses ON DELETE CASCADE on foreign key
...
...
spec/models/project_spec.rb
View file @
a30da0a1
...
@@ -138,6 +138,7 @@ RSpec.describe Project, factory_default: :keep do
...
@@ -138,6 +138,7 @@ RSpec.describe Project, factory_default: :keep do
it
{
is_expected
.
to
have_many
(
:timelogs
)
}
it
{
is_expected
.
to
have_many
(
:timelogs
)
}
it
{
is_expected
.
to
have_many
(
:error_tracking_errors
).
class_name
(
'ErrorTracking::Error'
)
}
it
{
is_expected
.
to
have_many
(
:error_tracking_errors
).
class_name
(
'ErrorTracking::Error'
)
}
it
{
is_expected
.
to
have_many
(
:error_tracking_client_keys
).
class_name
(
'ErrorTracking::ClientKey'
)
}
it
{
is_expected
.
to
have_many
(
:error_tracking_client_keys
).
class_name
(
'ErrorTracking::ClientKey'
)
}
it
{
is_expected
.
to
have_many
(
:pending_builds
).
class_name
(
'Ci::PendingBuild'
)
}
# GitLab Pages
# GitLab Pages
it
{
is_expected
.
to
have_many
(
:pages_domains
)
}
it
{
is_expected
.
to
have_many
(
:pages_domains
)
}
...
@@ -617,6 +618,12 @@ RSpec.describe Project, factory_default: :keep do
...
@@ -617,6 +618,12 @@ RSpec.describe Project, factory_default: :keep do
end
end
end
end
describe
'#membership_locked?'
do
it
'returns false'
do
expect
(
build
(
:project
)).
not_to
be_membership_locked
end
end
describe
'#autoclose_referenced_issues'
do
describe
'#autoclose_referenced_issues'
do
context
'when DB entry is nil'
do
context
'when DB entry is nil'
do
let
(
:project
)
{
build
(
:project
,
autoclose_referenced_issues:
nil
)
}
let
(
:project
)
{
build
(
:project
,
autoclose_referenced_issues:
nil
)
}
...
@@ -1066,12 +1073,12 @@ RSpec.describe Project, factory_default: :keep do
...
@@ -1066,12 +1073,12 @@ RSpec.describe Project, factory_default: :keep do
project
.
open_issues_count
(
user
)
project
.
open_issues_count
(
user
)
end
end
it
'invokes the count service with no current_user'
do
it
'invokes the
batch
count service with no current_user'
do
count_service
=
instance_double
(
Projects
::
OpenIssuesCountService
)
count_service
=
instance_double
(
Projects
::
Batch
OpenIssuesCountService
)
expect
(
Projects
::
OpenIssuesCountService
).
to
receive
(
:new
).
with
(
project
,
nil
).
and_return
(
count_service
)
expect
(
Projects
::
BatchOpenIssuesCountService
).
to
receive
(
:new
).
with
([
project
]
).
and_return
(
count_service
)
expect
(
count_service
).
to
receive
(
:
count
)
expect
(
count_service
).
to
receive
(
:
refresh_cache_and_retrieve_data
).
and_return
({}
)
project
.
open_issues_count
project
.
open_issues_count
.
to_s
end
end
end
end
...
@@ -2555,7 +2562,7 @@ RSpec.describe Project, factory_default: :keep do
...
@@ -2555,7 +2562,7 @@ RSpec.describe Project, factory_default: :keep do
end
end
describe
'#uses_default_ci_config?'
do
describe
'#uses_default_ci_config?'
do
let
(
:project
)
{
build
(
:project
)}
let
(
:project
)
{
build
(
:project
)
}
it
'has a custom ci config path'
do
it
'has a custom ci config path'
do
project
.
ci_config_path
=
'something_custom'
project
.
ci_config_path
=
'something_custom'
...
@@ -2576,6 +2583,44 @@ RSpec.describe Project, factory_default: :keep do
...
@@ -2576,6 +2583,44 @@ RSpec.describe Project, factory_default: :keep do
end
end
end
end
describe
'#uses_external_project_ci_config?'
do
subject
(
:uses_external_project_ci_config
)
{
project
.
uses_external_project_ci_config?
}
let
(
:project
)
{
build
(
:project
)
}
context
'when ci_config_path is configured with external project'
do
before
do
project
.
ci_config_path
=
'.gitlab-ci.yml@hello/world'
end
it
{
is_expected
.
to
eq
(
true
)
}
end
context
'when ci_config_path is nil'
do
before
do
project
.
ci_config_path
=
nil
end
it
{
is_expected
.
to
eq
(
false
)
}
end
context
'when ci_config_path is configured with a file in the project'
do
before
do
project
.
ci_config_path
=
'hello/world/gitlab-ci.yml'
end
it
{
is_expected
.
to
eq
(
false
)
}
end
context
'when ci_config_path is configured with remote file'
do
before
do
project
.
ci_config_path
=
'https://example.org/file.yml'
end
it
{
is_expected
.
to
eq
(
false
)
}
end
end
describe
'#latest_successful_build_for_ref'
do
describe
'#latest_successful_build_for_ref'
do
let_it_be
(
:project
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:pipeline
)
{
create_pipeline
(
project
)
}
let_it_be
(
:pipeline
)
{
create_pipeline
(
project
)
}
...
@@ -7028,6 +7073,15 @@ RSpec.describe Project, factory_default: :keep do
...
@@ -7028,6 +7073,15 @@ RSpec.describe Project, factory_default: :keep do
end
end
end
end
describe
'#ci_config_external_project'
do
subject
(
:ci_config_external_project
)
{
project
.
ci_config_external_project
}
let
(
:other_project
)
{
create
(
:project
)
}
let
(
:project
)
{
build
(
:project
,
ci_config_path:
".gitlab-ci.yml@
#{
other_project
.
full_path
}
"
)
}
it
{
is_expected
.
to
eq
(
other_project
)
}
end
describe
'#enabled_group_deploy_keys'
do
describe
'#enabled_group_deploy_keys'
do
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:project
)
{
create
(
:project
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment