from odoo.exceptions import AccessError from .common import CommonTest class TestRemote(CommonTest): """Test class for git remote.""" @classmethod def setUpClass(cls): super().setUpClass() # Create another manager for testing cls.manager_2 = cls.Users.create( { "name": "Second Manager", "login": "manager2", "email": "manager2@test.com", "groups_id": [(4, cls.env.ref("cetmix_tower_server.group_manager").id)], } ) # Create test project and source as root cls.project = cls.GitProject.create( { "name": "Test Project", } ) cls.source = cls.GitSource.create( { "name": "Test Source", "git_project_id": cls.project.id, } ) cls.repo_cetmix_tower = cls.Repo.create( { "name": "Cetmix Tower", "url": "https://github.com/cetmix-test/cetmix-tower.git", } ) cls.remote = cls.GitRemote.create( { "repo_id": cls.repo_cetmix_tower.id, "source_id": cls.source.id, "head_type": "branch", "head": "main", } ) cls.repo_test = cls.Repo.create( { "name": "Test Repository", "url": "https://github.com/cetmix-test/test.git", } ) def test_user_access(self): """Test that regular users have no access to git remotes""" user_remote = self.GitRemote.with_user(self.user) # Test CRUD operations with self.assertRaises(AccessError): user_remote.create( { "repo_id": self.repo_test.id, "url_protocol": "https", "source_id": self.source.id, "head": "main", } ) with self.assertRaises(AccessError): user_remote.search([("id", "=", self.remote.id)]) with self.assertRaises(AccessError): self.remote.with_user(self.user).write({"head": "dev"}) with self.assertRaises(AccessError): self.remote.with_user(self.user).unlink() def test_manager_read_access(self): """Test manager read access rules""" manager_remote = self.GitRemote.with_user(self.manager) # Manager not in project user_ids or manager_ids - should not read self.assertFalse(manager_remote.search([("id", "=", self.remote.id)])) # Add manager to project user_ids - should read self.project.write({"user_ids": [(4, self.manager.id)]}) remote = manager_remote.search([("id", "=", self.remote.id)]) self.assertTrue(remote) self.assertEqual(remote.head, "main") # Remove from user_ids, add to manager_ids - should read self.project.write( {"user_ids": [(3, self.manager.id)], "manager_ids": [(4, self.manager.id)]} ) remote = manager_remote.search([("id", "=", self.remote.id)]) self.assertTrue(remote.exists()) def test_manager_write_access(self): """Test manager write/create access rules""" manager_remote = self.GitRemote.with_user(self.manager) # Create project as manager - should be added to manager_ids automatically project = self.GitProject.with_user(self.manager).create( { "name": "Manager Project", } ) source = self.GitSource.create( { "name": "Manager Source", "git_project_id": project.id, } ) # Create remote in own project - should succeed new_remote = manager_remote.create( { "repo_id": self.repo_test.id, "url_protocol": "https", "source_id": source.id, "head_type": "branch", "head": "main", } ) self.assertTrue(new_remote.exists()) # Write to own remote - should succeed new_remote.write({"head": "dev"}) self.assertEqual(new_remote.head, "dev") # Write to other's remote - should fail with self.assertRaises(AccessError): self.remote.with_user(self.manager).write({"head": "dev"}) def test_manager_unlink_access(self): """Test manager unlink access rules""" # Create project and remote as manager_2 project = self.GitProject.with_user(self.manager_2).create( { "name": "Manager 2 Project", } ) source = self.GitSource.create( { "name": "Manager 2 Source", "git_project_id": project.id, } ) remote = self.GitRemote.with_user(self.manager_2).create( { "repo_id": self.repo_test.id, "url_protocol": "https", "source_id": source.id, "head_type": "branch", "head": "main", } ) # Try delete as different manager - should fail even if added to manager_ids project.write({"manager_ids": [(4, self.manager.id)]}) with self.assertRaises(AccessError): remote.with_user(self.manager).unlink() # Create remote as manager and try delete - should succeed own_remote = self.GitRemote.with_user(self.manager).create( { "repo_id": self.repo_test.id, "url_protocol": "https", "source_id": source.id, "head_type": "branch", "head": "main", } ) self.assertTrue(own_remote.exists()) own_remote.with_user(self.manager).unlink() self.assertFalse(own_remote.exists()) def test_root_access(self): """Test root access rules""" root_remote = self.GitRemote.with_user(self.root) # Create new_remote = root_remote.create( { "repo_id": self.repo_test.id, "url_protocol": "https", "source_id": self.source.id, "head_type": "branch", "head": "main", } ) self.assertTrue(new_remote.exists()) # Read remote = root_remote.search([("id", "=", self.remote.id)]) self.assertTrue(remote) self.assertEqual(remote.head, "main") # Write self.remote.with_user(self.root).write({"head": "dev"}) self.assertEqual(self.remote.head, "dev") # Delete new_remote.with_user(self.root).unlink() self.assertFalse(new_remote.exists()) def test_remote_provider_protocol_and_name(self): """Test if remote provider is detected correctly""" # -- 1-- # GitHub + https # Check if remote provider is detected correctly self.assertEqual( self.remote_github_https.repo_provider, "github", "Provider is not detected correctly", ) self.assertEqual( self.remote_github_https.url_protocol, "https", "Protocol is not detected correctly", ) self.assertEqual( self.remote_github_https.name, "remote_1", "Name is not prepared correctly", ) # -- 2 -- # GitLab + ssh # Check if remote provider is detected correctly self.assertEqual( self.remote_gitlab_ssh.repo_provider, "gitlab", "Provider is not detected correctly", ) self.assertEqual( self.remote_gitlab_ssh.url_protocol, "ssh", "Protocol is not detected correctly", ) self.assertEqual( self.remote_gitlab_ssh.name, "remote_3", "Name is not prepared correctly", ) # -- 3 -- # Bitbucket + https # Check if remote provider is detected correctly self.assertEqual( self.remote_bitbucket_https.repo_provider, "bitbucket", "Provider is not detected correctly", ) self.assertEqual( self.remote_bitbucket_https.url_protocol, "https", "Protocol is not detected correctly", ) self.assertEqual( self.remote_bitbucket_https.name, "remote_1", "Name is not prepared correctly", ) # -- 4 -- # Other + ssh # Check if remote provider is detected correctly self.assertEqual( self.remote_other_ssh.repo_provider, "gitlab", # this is how giturlparse detects the provider "Provider is not detected correctly", ) self.assertEqual( self.remote_other_ssh.url_protocol, "ssh", "Protocol is not detected correctly", ) self.assertEqual( self.remote_other_ssh.name, "remote_2", "Name is not prepared correctly", ) def test_git_aggregator_prepare_url(self): """Test if url is prepared correctly""" # -- 1 -- # GitHub + https self.remote_github_https.repo_id.is_private = False self.assertEqual( self.remote_github_https._git_aggregator_prepare_url(), self.remote_github_https.repo_id.url, "URL is not prepared correctly", ) # -- 2 -- # GitHub + https -> private self.remote_github_https.repo_id.is_private = True self.assertEqual( self.remote_github_https._git_aggregator_prepare_url(), "https://$GITHUB_TOKEN:x-oauth-basic@github.com/cetmix-test/cetmix-tower-test.git", "URL is not prepared correctly", ) # -- 3 -- # Gitlab + https self.remote_gitlab_https.repo_id.is_private = False self.assertEqual( self.remote_gitlab_https._git_aggregator_prepare_url(), self.remote_gitlab_https.repo_id.url, "URL is not prepared correctly", ) # -- 4 -- # Gitlab + https -> private self.remote_gitlab_https.repo_id.is_private = True self.assertEqual( self.remote_gitlab_https._git_aggregator_prepare_url(), "https://$GITLAB_TOKEN_NAME:$GITLAB_TOKEN@my.gitlab.com/cetmix-test/cetmix-tower-test.git", "URL is not prepared correctly", ) # -- 5 -- # Bitbucket + https self.remote_bitbucket_https.repo_id.is_private = False self.assertEqual( self.remote_bitbucket_https._git_aggregator_prepare_url(), self.remote_bitbucket_https.repo_id.url, "URL is not prepared correctly", ) # -- 6 -- # Bitbucket + https -> private self.remote_bitbucket_https.repo_id.is_private = True self.assertEqual( self.remote_bitbucket_https._git_aggregator_prepare_url(), "https://x-token-auth:$BITBUCKET_TOKEN@bitbucket.com/cetmix-test/cetmix-tower-test-enterprise.git", "URL is not prepared correctly", ) # -- 7 -- # Other + ssh self.remote_other_ssh.repo_id.is_private = False self.assertEqual( self.remote_other_ssh._git_aggregator_prepare_url(), self.remote_other_ssh.repo_id.url_ssh, "URL is not prepared correctly", ) def test_git_aggregator_prepare_head(self): """Test if head is prepared correctly""" # -- 1 -- # GitHub + PR/MR as link self.assertEqual( self.remote_github_https._git_aggregator_prepare_head(), "refs/pull/123/head", "Head is not prepared correctly", ) # -- 2 -- # GitHub + PR/MR as number self.remote_github_https.write({"head": "123", "head_type": "pr"}) self.assertEqual( self.remote_github_https._git_aggregator_prepare_head(), "refs/pull/123/head", "Head is not prepared correctly", ) # -- 3 -- # GitHub + branch as name self.remote_github_https.write({"head": "main", "head_type": "branch"}) self.assertEqual( self.remote_github_https._git_aggregator_prepare_head(), self.remote_github_https.head, "Head is not prepared correctly", ) # -- 4 -- # GitHub + branch as link self.remote_github_https.write( { "head": "https://github.com/cetmix-test/cetmix-tower/tree/14.0-demo-branch", "head_type": "branch", } ) self.assertEqual( self.remote_github_https._git_aggregator_prepare_head(), "14.0-demo-branch", "Head is not prepared correctly", ) # -- 5 -- # GitHub + commit as number self.remote_github_https.write({"head": "1234567890", "head_type": "commit"}) self.assertEqual( self.remote_github_https._git_aggregator_prepare_head(), "1234567890", "Head is not prepared correctly", ) # -- 6 -- # GitHub + commit as link self.remote_github_https.head = ( "https://github.com/cetmix-test/cetmix-tower/commit/1234567890" ) self.assertEqual( self.remote_github_https._git_aggregator_prepare_head(), "1234567890", "Head is not prepared correctly", ) def test_manager_server_based_access(self): """Test manager access to remotes through server relationships""" manager_remote = self.GitRemote.with_user(self.manager) # Create a server where manager is a user server = self.Server.create( { "name": "Test Server", "ip_v4_address": "localhost", "ssh_username": "admin", "ssh_password": "password", "os_id": self.os_debian_10.id, "user_ids": [(4, self.manager.id)], } ) # Link project to server file = self.File.create( { "name": "test_file", "server_id": server.id, } ) self.GitProjectRel.create( { "server_id": server.id, "file_id": file.id, "git_project_id": self.project.id, "project_format": "git_aggregator", } ) # Manager should be able to read remote through server relationship remote = manager_remote.search([("id", "=", self.remote.id)]) self.assertTrue(remote) self.assertEqual(remote.head, "main") # Remove manager from server users server.write({"user_ids": [(3, self.manager.id)]}) # Manager should not be able to read remote anymore self.assertFalse(manager_remote.search([("id", "=", self.remote.id)])) # Add manager to server managers server.write({"manager_ids": [(4, self.manager.id)]}) # Manager should be able to read remote again remote = manager_remote.search([("id", "=", self.remote.id)]) self.assertTrue(remote) self.assertEqual(remote.head, "main")