Skip to content

Commit

Permalink
fix!: GitLab repository branch prefix can be updated by any user
Browse files Browse the repository at this point in the history
This closes request #28848 GitLab repository branch prefix can be updated by any user

Any user is able to update the branch prefix of any GitLab repository integration
using the REST route PATCH /gitlab_repositories/{id}.

This is wrong, only Git adminsitrators must be allowed to do that.

Change-Id: I70febc7cc3b49d5687d8f6a3f1a061710f6cf5ef
  • Loading branch information
yannis-rossetto committed Sep 20, 2022
1 parent ee5b4e1 commit a06cb42
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

namespace Tuleap\Gitlab\Artifact\Action;

use GitPermissionsManager;
use GitUserNotAdminException;
use PFUser;
use Tuleap\Git\Branch\BranchName;
use Tuleap\Git\Branch\InvalidBranchNameException;
use Tuleap\Gitlab\Repository\GitlabRepositoryIntegrationFactory;
Expand All @@ -32,21 +35,28 @@ final class CreateBranchPrefixUpdater

public function __construct(
private GitlabRepositoryIntegrationFactory $integration_factory,
private GitPermissionsManager $git_permissions_manager,
private SaveIntegrationBranchPrefix $branch_prefix_saver,
) {
}

/**
* @throws GitlabRepositoryIntegrationNotFoundException
* @throws InvalidBranchNameException
* @throws GitUserNotAdminException
*/
public function updateBranchPrefix(int $integration_id, string $prefix): void
public function updateBranchPrefix(PFUser $user, int $integration_id, string $prefix): void
{
$gitlab_repository = $this->integration_factory->getIntegrationById($integration_id);
if (! $gitlab_repository) {
throw new GitlabRepositoryIntegrationNotFoundException($integration_id);
}

$project = $gitlab_repository->getProject();
if (! $this->git_permissions_manager->userIsGitAdmin($user, $project)) {
throw new GitUserNotAdminException();
}

BranchName::fromBranchNameShortHand($prefix . self::FAKE_BRANCH_NAME);

$this->branch_prefix_saver->setCreateBranchPrefixForIntegration(
Expand Down
8 changes: 6 additions & 2 deletions plugins/gitlab/include/REST/v1/GitlabRepositoryResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,15 @@ protected function patchId(
$prefix_updater = new CreateBranchPrefixUpdater(
new GitlabRepositoryIntegrationFactory(
new GitlabRepositoryIntegrationDao(),
ProjectManager::instance()
ProjectManager::instance(),
),
new CreateBranchPrefixDao()
$this->getGitPermissionsManager(),
new CreateBranchPrefixDao(),
);

try {
$prefix_updater->updateBranchPrefix(
$current_user,
$id,
$patch_representation->create_branch_prefix
);
Expand All @@ -490,6 +492,8 @@ protected function patchId(
400,
$exception->getMessage()
);
} catch (GitUserNotAdminException $exception) {
throw new RestException(401, "User must be Git administrator.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@

namespace Tuleap\Gitlab\Artifact\Action;

use GitPermissionsManager;
use GitUserNotAdminException;
use Tuleap\Git\Branch\InvalidBranchNameException;
use Tuleap\Gitlab\Repository\GitlabRepositoryIntegrationFactory;
use Tuleap\Gitlab\Repository\GitlabRepositoryIntegrationNotFoundException;
use Tuleap\Gitlab\Test\Builder\RepositoryIntegrationBuilder;
use Tuleap\Gitlab\Test\Stubs\SaveIntegrationBranchPrefixStub;
use Tuleap\Test\Builders\UserTestBuilder;
use Tuleap\Test\PHPUnit\TestCase;

final class CreateBranchPrefixUpdaterTest extends TestCase
Expand All @@ -38,11 +41,16 @@ final class CreateBranchPrefixUpdaterTest extends TestCase
private $integration_factory;
private SaveIntegrationBranchPrefixStub $branch_prefix_saver;
private string $branch_prefix;
/**
* @var GitPermissionsManager&\PHPUnit\Framework\MockObject\MockObject
*/
private $git_permissions_manager;

protected function setUp(): void
{
$this->integration_factory = $this->createMock(GitlabRepositoryIntegrationFactory::class);
$this->branch_prefix_saver = SaveIntegrationBranchPrefixStub::withCallCount();
$this->integration_factory = $this->createMock(GitlabRepositoryIntegrationFactory::class);
$this->git_permissions_manager = $this->createMock(GitPermissionsManager::class);
$this->branch_prefix_saver = SaveIntegrationBranchPrefixStub::withCallCount();

$this->branch_prefix = 'dev-';
}
Expand All @@ -51,10 +59,15 @@ private function updateBranchPrefix(): void
{
$updater = new CreateBranchPrefixUpdater(
$this->integration_factory,
$this->branch_prefix_saver
$this->git_permissions_manager,
$this->branch_prefix_saver,
);

$updater->updateBranchPrefix(self::INTEGRATION_ID, $this->branch_prefix);
$updater->updateBranchPrefix(
UserTestBuilder::anActiveUser()->build(),
self::INTEGRATION_ID,
$this->branch_prefix,
);
}

public function testItStoresTheBranchPrefix(): void
Expand All @@ -65,6 +78,11 @@ public function testItStoresTheBranchPrefix(): void
->with(self::INTEGRATION_ID)
->willReturn(RepositoryIntegrationBuilder::aGitlabRepositoryIntegration(self::INTEGRATION_ID)->build());

$this->git_permissions_manager
->expects(self::once())
->method('userIsGitAdmin')
->willReturn(true);

$this->updateBranchPrefix();

self::assertSame(1, $this->branch_prefix_saver->getCallCount());
Expand All @@ -78,6 +96,11 @@ public function testItStoresTheBranchPrefixWithSomeSpecialChars(): void
->with(self::INTEGRATION_ID)
->willReturn(RepositoryIntegrationBuilder::aGitlabRepositoryIntegration(self::INTEGRATION_ID)->build());

$this->git_permissions_manager
->expects(self::once())
->method('userIsGitAdmin')
->willReturn(true);

$this->branch_prefix = 'dev/';
$this->updateBranchPrefix();

Expand All @@ -98,6 +121,25 @@ public function testItThrowsAnExceptionIfIntegrationNotFoundTheBranchPrefix(): v
self::assertSame(0, $this->branch_prefix_saver->getCallCount());
}

public function testItThrowsAnExceptionIfUserIsNotGitAdministrator(): void
{
$this->integration_factory
->expects(self::once())
->method('getIntegrationById')
->with(self::INTEGRATION_ID)
->willReturn(RepositoryIntegrationBuilder::aGitlabRepositoryIntegration(self::INTEGRATION_ID)->build());

$this->git_permissions_manager
->expects(self::once())
->method('userIsGitAdmin')
->willReturn(false);

$this->expectException(GitUserNotAdminException::class);
$this->updateBranchPrefix();

self::assertSame(0, $this->branch_prefix_saver->getCallCount());
}

public function testItThrowsAnExceptionIfBranchPrefixIsNotValid(): void
{
$this->integration_factory
Expand All @@ -106,6 +148,11 @@ public function testItThrowsAnExceptionIfBranchPrefixIsNotValid(): void
->with(self::INTEGRATION_ID)
->willReturn(RepositoryIntegrationBuilder::aGitlabRepositoryIntegration(self::INTEGRATION_ID)->build());

$this->git_permissions_manager
->expects(self::once())
->method('userIsGitAdmin')
->willReturn(true);

$this->branch_prefix = 'dev:';

$this->expectException(InvalidBranchNameException::class);
Expand Down

0 comments on commit a06cb42

Please sign in to comment.