test_signature.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. # test_signature.py -- tests for signature.py
  2. # Copyright (C) 2025 Jelmer Vernooij <jelmer@jelmer.uk>
  3. #
  4. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  5. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  6. # General Public License as published by the Free Software Foundation; version 2.0
  7. # or (at your option) any later version. You can redistribute it and/or
  8. # modify it under the terms of either of these two licenses.
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. # You should have received a copy of the licenses; if not, see
  17. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  18. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  19. # License, Version 2.0.
  20. #
  21. """Tests for signature vendors."""
  22. import unittest
  23. from dulwich.signature import GPGSignatureVendor, SignatureVendor
  24. try:
  25. import gpg
  26. except ImportError:
  27. gpg = None
  28. class SignatureVendorTests(unittest.TestCase):
  29. """Tests for SignatureVendor base class."""
  30. def test_sign_not_implemented(self) -> None:
  31. """Test that sign raises NotImplementedError."""
  32. vendor = SignatureVendor()
  33. with self.assertRaises(NotImplementedError):
  34. vendor.sign(b"test data")
  35. def test_verify_not_implemented(self) -> None:
  36. """Test that verify raises NotImplementedError."""
  37. vendor = SignatureVendor()
  38. with self.assertRaises(NotImplementedError):
  39. vendor.verify(b"test data", b"fake signature")
  40. @unittest.skipIf(gpg is None, "gpg not available")
  41. class GPGSignatureVendorTests(unittest.TestCase):
  42. """Tests for GPGSignatureVendor."""
  43. def test_sign_and_verify(self) -> None:
  44. """Test basic sign and verify cycle.
  45. Note: This test requires a GPG key to be configured in the test
  46. environment. It may be skipped in environments without GPG setup.
  47. """
  48. vendor = GPGSignatureVendor()
  49. test_data = b"test data to sign"
  50. try:
  51. # Sign the data
  52. signature = vendor.sign(test_data)
  53. self.assertIsInstance(signature, bytes)
  54. self.assertGreater(len(signature), 0)
  55. # Verify the signature
  56. vendor.verify(test_data, signature)
  57. except gpg.errors.GPGMEError as e:
  58. # Skip test if no GPG key is available
  59. self.skipTest(f"GPG key not available: {e}")
  60. def test_verify_invalid_signature(self) -> None:
  61. """Test that verify raises an error for invalid signatures."""
  62. vendor = GPGSignatureVendor()
  63. test_data = b"test data"
  64. invalid_signature = b"this is not a valid signature"
  65. with self.assertRaises(gpg.errors.GPGMEError):
  66. vendor.verify(test_data, invalid_signature)
  67. def test_sign_with_keyid(self) -> None:
  68. """Test signing with a specific key ID.
  69. Note: This test requires a GPG key to be configured in the test
  70. environment. It may be skipped in environments without GPG setup.
  71. """
  72. vendor = GPGSignatureVendor()
  73. test_data = b"test data to sign"
  74. try:
  75. # Try to get a key from the keyring
  76. with gpg.Context() as ctx:
  77. keys = list(ctx.keylist(secret=True))
  78. if not keys:
  79. self.skipTest("No GPG keys available for testing")
  80. key = keys[0]
  81. signature = vendor.sign(test_data, keyid=key.fpr)
  82. self.assertIsInstance(signature, bytes)
  83. self.assertGreater(len(signature), 0)
  84. # Verify the signature
  85. vendor.verify(test_data, signature)
  86. except gpg.errors.GPGMEError as e:
  87. self.skipTest(f"GPG key not available: {e}")