Coverage for src/gitlabracadabra/gitlab/pygit2.py: 28%

40 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-10 17:02 +0100

1# 

2# Copyright (C) 2019-2025 Mathieu Parent <math.parent@gmail.com> 

3# 

4# This program is free software: you can redistribute it and/or modify 

5# it under the terms of the GNU Lesser General Public License as published by 

6# the Free Software Foundation, either version 3 of the License, or 

7# (at your option) any later version. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU Lesser General Public License for more details. 

13# 

14# You should have received a copy of the GNU Lesser General Public License 

15# along with this program. If not, see <http://www.gnu.org/licenses/>. 

16 

17 

18from __future__ import annotations 

19 

20from typing import TYPE_CHECKING 

21from urllib.parse import urlparse 

22 

23from pygit2 import Passthrough, RemoteCallbacks, UserPass 

24 

25from gitlabracadabra.gitlab.pygitlab import PyGitlab 

26 

27if TYPE_CHECKING: 27 ↛ 28line 27 didn't jump to line 28 because the condition on line 27 was never true

28 from pygit2.enums import CredentialType 

29 

30 

31class PyGit2(PyGitlab): 

32 """PyGit2 wrapper.""" 

33 

34 def pygit2_certificate_check( 

35 self, 

36 certificate: None, # noqa: ARG002 

37 valid: bool, # noqa: ARG002,FBT001 

38 host: str, 

39 ) -> bool: 

40 """Check certificate. 

41 

42 Args: 

43 _certificate: Currently always None. 

44 valid: Whether the TLS/SSH library thinks the certificate is valid. 

45 host: The hostname we want to connect to. 

46 

47 Returns: 

48 True to connect, False to abort. 

49 

50 Raises: 

51 Passthrough: Use default behavior. 

52 """ 

53 if self.pygitlab.ssl_verify is True: 

54 raise Passthrough 

55 if self.pygitlab.ssl_verify is False: 

56 allowed_host = urlparse(self.api_url).hostname 

57 if allowed_host is not None and host in {allowed_host, allowed_host.encode()}: 

58 return True 

59 raise Passthrough 

60 # self.pygitlab.ssl_verify is a CA path, no way to verify 

61 return False 

62 

63 def pygit2_credentials( 

64 self, 

65 url: str, 

66 username_from_url: str | None, # noqa: ARG002 

67 allowed_types: CredentialType, # noqa: ARG002 

68 ) -> object: 

69 """Get PyGit2 credentials. 

70 

71 Args: 

72 url: The url of the remote. 

73 _username_from_url: Username extracted from the url, if any. 

74 _allowed_types: Combination of bitflags representing the credential types supported by the remote. 

75 

76 Returns: 

77 A pygit2.UserPass. 

78 

79 Raises: 

80 ValueError: No credentials found. 

81 """ 

82 target_hostname = urlparse(url).hostname 

83 allowed_hostname = urlparse(self.api_url).hostname 

84 if allowed_hostname != target_hostname: 

85 msg = f"Target hostname {target_hostname} not matching allowed hostname {allowed_hostname}" 

86 raise ValueError( 

87 msg, 

88 ) 

89 if self.pygitlab.private_token: 

90 return UserPass("oauth2", self.pygitlab.private_token) # type: ignore[no-untyped-call] 

91 if self.pygitlab.oauth_token: 

92 return UserPass("oauth2", self.pygitlab.oauth_token) # type: ignore[no-untyped-call] 

93 if self.pygitlab.job_token: 

94 return UserPass("gitlab-ci-token", self.pygitlab.job_token) # type: ignore[no-untyped-call] 

95 if self.pygitlab.http_username and self.pygitlab.http_password: 

96 return UserPass(self.pygitlab.http_username, self.pygitlab.http_password) # type: ignore[no-untyped-call] 

97 msg = "No PyGit2 credentials for {target_hostname}" 

98 raise ValueError(msg) 

99 

100 @property 

101 def pygit2_remote_callbacks(self) -> RemoteCallbacks: 

102 """Get PyGit2 RemoteCallbacks. 

103 

104 Returns: 

105 A pygit2.RemoteCallbacks. 

106 """ 

107 cb = RemoteCallbacks() # type: ignore[no-untyped-call] 

108 cb.credentials = self.pygit2_credentials # type: ignore[method-assign] 

109 if self.pygitlab.ssl_verify is not True: 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true

110 cb.certificate_check = self.pygit2_certificate_check # type: ignore[method-assign] 

111 return cb