Fix GPG verification runtime handling
This commit is contained in:
@@ -1,13 +1,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from ..errors import GitQueryError, GitRunError
|
||||
from ..run import run
|
||||
import subprocess
|
||||
|
||||
from ..errors import GitNotRepositoryError, GitQueryError
|
||||
|
||||
|
||||
class GitLatestSigningKeyQueryError(GitQueryError):
|
||||
"""Raised when querying the latest commit signing key fails."""
|
||||
|
||||
|
||||
def _is_not_repository(stderr: str) -> bool:
|
||||
return "not a git repository" in (stderr or "").lower()
|
||||
|
||||
|
||||
def _looks_like_gpg_runtime_error(stderr: str) -> bool:
|
||||
lowered = (stderr or "").lower()
|
||||
markers = (
|
||||
"cannot run gpg",
|
||||
"can't check signature",
|
||||
"no public key",
|
||||
"failed to create temporary file",
|
||||
"can't connect to the keyboxd",
|
||||
"error opening key db",
|
||||
"gpg failed",
|
||||
"no such file or directory",
|
||||
)
|
||||
return any(marker in lowered for marker in markers)
|
||||
|
||||
|
||||
def get_latest_signing_key(*, cwd: str = ".") -> str:
|
||||
"""
|
||||
Return the GPG signing key ID of the latest commit, via:
|
||||
@@ -17,9 +37,46 @@ def get_latest_signing_key(*, cwd: str = ".") -> str:
|
||||
Returns:
|
||||
The key id string (may be empty if commit is not signed).
|
||||
"""
|
||||
cmd = ["git", "log", "-1", "--format=%GK"]
|
||||
try:
|
||||
return run(["log", "-1", "--format=%GK"], cwd=cwd).strip()
|
||||
except GitRunError as exc:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=cwd,
|
||||
check=False,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
except OSError as exc:
|
||||
raise GitLatestSigningKeyQueryError(
|
||||
"Failed to query latest signing key.",
|
||||
"Failed to query latest signing key.\n"
|
||||
f"Command: {' '.join(cmd)}\n"
|
||||
f"Reason: {exc}"
|
||||
) from exc
|
||||
|
||||
stdout = (result.stdout or "").strip()
|
||||
stderr = (result.stderr or "").strip()
|
||||
|
||||
if result.returncode != 0:
|
||||
if _is_not_repository(stderr):
|
||||
raise GitNotRepositoryError(
|
||||
f"Not a git repository: {cwd!r}\n"
|
||||
f"Command: {' '.join(cmd)}\n"
|
||||
f"STDERR:\n{stderr}"
|
||||
)
|
||||
raise GitLatestSigningKeyQueryError(
|
||||
"Failed to query latest signing key.\n"
|
||||
f"Command: {' '.join(cmd)}\n"
|
||||
f"Exit code: {result.returncode}\n"
|
||||
f"STDOUT:\n{stdout}\n"
|
||||
f"STDERR:\n{stderr}"
|
||||
)
|
||||
|
||||
if not stdout and stderr and _looks_like_gpg_runtime_error(stderr):
|
||||
raise GitLatestSigningKeyQueryError(
|
||||
"Failed to query latest signing key.\n"
|
||||
f"Command: {' '.join(cmd)}\n"
|
||||
f"STDERR:\n{stderr}"
|
||||
)
|
||||
|
||||
return stdout
|
||||
|
||||
@@ -16,6 +16,7 @@ def verify_repository(repo, repo_dir, mode="local", no_verification=False):
|
||||
|
||||
commit_hash = ""
|
||||
signing_key = ""
|
||||
signing_key_query_failed = False
|
||||
|
||||
# best-effort info collection
|
||||
try:
|
||||
@@ -59,6 +60,7 @@ def verify_repository(repo, repo_dir, mode="local", no_verification=False):
|
||||
except GitLatestSigningKeyQueryError as exc:
|
||||
error_details.append(str(exc))
|
||||
signing_key = ""
|
||||
signing_key_query_failed = True
|
||||
|
||||
commit_check_passed = True
|
||||
gpg_check_passed = True
|
||||
@@ -78,9 +80,10 @@ def verify_repository(repo, repo_dir, mode="local", no_verification=False):
|
||||
if expected_gpg_keys:
|
||||
if not signing_key:
|
||||
gpg_check_passed = False
|
||||
error_details.append(
|
||||
f"Expected one of GPG keys: {expected_gpg_keys}, but no signing key was found."
|
||||
)
|
||||
if not signing_key_query_failed:
|
||||
error_details.append(
|
||||
f"Expected one of GPG keys: {expected_gpg_keys}, but no signing key was found."
|
||||
)
|
||||
elif signing_key not in expected_gpg_keys:
|
||||
gpg_check_passed = False
|
||||
error_details.append(
|
||||
|
||||
Reference in New Issue
Block a user