소스 검색

Add support for gpg.minTrustLevel config option

Jelmer Vernooij 4 주 전
부모
커밋
e9fb676f9b
2개의 변경된 파일51개의 추가작업 그리고 2개의 파일을 삭제
  1. 38 2
      dulwich/signature.py
  2. 13 0
      tests/test_signature.py

+ 38 - 2
dulwich/signature.py

@@ -71,16 +71,30 @@ class SignatureVendor:
 
 
 class GPGSignatureVendor(SignatureVendor):
-    """Signature vendor that uses the GPG package for signing and verification."""
+    """Signature vendor that uses the GPG package for signing and verification.
+
+    Supports git config options:
+    - gpg.minTrustLevel: Minimum trust level for signature verification
+    """
 
     def __init__(self, config: "Config | None" = None) -> None:
         """Initialize the GPG package vendor.
 
         Args:
-          config: Optional Git configuration (currently unused by this vendor)
+          config: Optional Git configuration for settings like gpg.minTrustLevel
         """
         super().__init__(config)
 
+        # Parse gpg.minTrustLevel from config
+        self.min_trust_level = None
+        if config is not None:
+            try:
+                trust_level = config.get((b"gpg",), b"minTrustLevel")
+                if trust_level:
+                    self.min_trust_level = trust_level.decode("utf-8").lower()
+            except KeyError:
+                pass
+
     def sign(self, data: bytes, keyid: str | None = None) -> bytes:
         """Sign data with a GPG key.
 
@@ -126,14 +140,36 @@ class GPGSignatureVendor(SignatureVendor):
           gpg.errors.BadSignatures: if GPG signature verification fails
           gpg.errors.MissingSignatures: if the signature was not created by a key
             specified in keyids
+          ValueError: if signature trust level is below minimum configured level
         """
         import gpg
 
+        # Map trust level names to GPGME validity values
+        trust_level_map = {
+            "undefined": gpg.constants.validity.UNDEFINED,
+            "never": gpg.constants.validity.NEVER,
+            "marginal": gpg.constants.validity.MARGINAL,
+            "fully": gpg.constants.validity.FULL,
+            "ultimate": gpg.constants.validity.ULTIMATE,
+        }
+
         with gpg.Context() as ctx:
             verified_data, result = ctx.verify(
                 data,
                 signature=signature,
             )
+
+            # Check minimum trust level if configured
+            if self.min_trust_level is not None:
+                min_validity = trust_level_map.get(self.min_trust_level)
+                if min_validity is not None:
+                    for sig in result.signatures:
+                        if sig.validity < min_validity:
+                            raise ValueError(
+                                f"Signature trust level {sig.validity} is below "
+                                f"minimum required level {self.min_trust_level}"
+                            )
+
             if keyids:
                 keys = [ctx.get_key(key) for key in keyids]
                 for key in keys:

+ 13 - 0
tests/test_signature.py

@@ -54,6 +54,19 @@ class SignatureVendorTests(unittest.TestCase):
 class GPGSignatureVendorTests(unittest.TestCase):
     """Tests for GPGSignatureVendor."""
 
+    def test_min_trust_level_from_config(self) -> None:
+        """Test reading gpg.minTrustLevel from config."""
+        config = ConfigDict()
+        config.set((b"gpg",), b"minTrustLevel", b"marginal")
+
+        vendor = GPGSignatureVendor(config=config)
+        self.assertEqual(vendor.min_trust_level, "marginal")
+
+    def test_min_trust_level_default(self) -> None:
+        """Test default when gpg.minTrustLevel not in config."""
+        vendor = GPGSignatureVendor()
+        self.assertIsNone(vendor.min_trust_level)
+
     def test_sign_and_verify(self) -> None:
         """Test basic sign and verify cycle.