Do not allow creating a project that has a name or part of the path matching the existing public project

This commit is contained in:
clearml 2024-12-05 22:26:57 +02:00
parent 41b003f328
commit 543c579a2e
3 changed files with 37 additions and 3 deletions

View File

@ -40,7 +40,7 @@ from .sub_projects import (
_ids_with_children,
_ids_with_parents,
_get_project_depth,
ProjectsChildren,
ProjectsChildren, _get_writable_project_from_name,
)
log = config.logger(__file__)
@ -225,6 +225,18 @@ class ProjectBLL:
raise errors.bad_request.ProjectPathExceedsMax(max_depth=max_depth)
name, location = _validate_project_name(name)
existing = _get_writable_project_from_name(
company=company,
name=name,
)
if existing:
raise errors.bad_request.ExpectedUniqueData(
replacement_msg="Project with the same name already exists",
name=name,
company=company,
)
now = datetime.utcnow()
project = Project(
id=database.utils.id(),

View File

@ -2,6 +2,8 @@ import itertools
from datetime import datetime
from typing import Tuple, Optional, Sequence, Mapping
from boltons.iterutils import first
from apiserver import database
from apiserver.apierrors import errors
from apiserver.database.model import EntityVisibility
@ -96,10 +98,21 @@ def _get_writable_project_from_name(
"""
Return a project from name. If the project not found then return None
"""
qs = Project.objects(company=company, name=name)
qs = Project.objects(company__in=[company, ""], name=name)
if _only:
if "company" not in _only:
_only = ["company", *_only]
qs = qs.only(*_only)
return qs.first()
projects = list(qs)
if not projects:
return
project = first(p for p in projects if p.company == company)
if not project:
raise errors.bad_request.PublicProjectExists(name=name)
return project
ProjectsChildren = Mapping[str, Sequence[Project]]

View File

@ -439,6 +439,15 @@ class TestSubProjects(TestService):
self.assertEqual(res2.own_tasks, 0)
self.assertEqual(res2.own_models, 0)
def test_public_names_clash(self):
# cannot create a project with a name that match public existing project
with self.api.raises(errors.bad_request.PublicProjectExists):
project = self._temp_project(name="ClearML Examples")
# cannot create a subproject under a public project
with self.api.raises(errors.bad_request.PublicProjectExists):
project = self._temp_project(name="ClearML Examples/my project")
def test_get_all_with_stats(self):
project4, _ = self._temp_project_with_tasks(name="project1/project3/project4")
project5, _ = self._temp_project_with_tasks(name="project1/project3/project5")