如何使用GitPython验证Git已签名提交并识别对应GPG公钥指纹
GPG提交签名验证与指纹获取实现方案
最简方案:调用Git内置验证命令(推荐)
- 优势:不需要手动解析提交内容、处理GPG逻辑,Git底层已经封装了完整的校验流程,准确率最高
- 实现逻辑:直接用
subprocess调用git verify-commit --raw <提交哈希>命令,该命令会自动调用本地GPG密钥环完成验证,解析输出即可拿到验证状态和对应的密钥指纹
完整代码示例:
from git import Repo import subprocess def get_commit_verify_result(repo_dir: str, commit_sha: str) -> tuple[bool, str|None]: # 调用git内置验证命令,--raw参数输出结构化结果 cmd = [ "git", "-C", repo_dir, "verify-commit", "--raw", commit_sha ] # git verify-commit的结构化输出默认打印到stderr res = subprocess.run(cmd, capture_output=True, text=True) is_valid = False gpg_fingerprint = None for line in res.stderr.splitlines(): line_parts = line.strip().split() if len(line_parts) < 2: continue # GOODSIG标记代表签名合法有效 if line_parts[1] == "GOODSIG": is_valid = True # VALIDSIG行第一个参数就是完整的GPG公钥指纹 elif line_parts[1] == "VALIDSIG": gpg_fingerprint = line_parts[2] return is_valid, gpg_fingerprint # 结合你原有的遍历代码 repo_dir = "/path/to/your/repo" repo = Repo(repo_dir) fifty_first_commits = list(repo.iter_commits('master', paths="dir/in/repo/", max_count=5000)) for c in fifty_first_commits: if not c.gpgsig: continue is_valid, fingerprint = get_commit_verify_result(repo_dir, c.hexsha) print(f"提交哈希: {c.hexsha}") print(f"签名是否有效: {is_valid}") print(f"签名密钥指纹: {fingerprint}") print("-"*50)
原生Python实现方案(使用python-gnupg库)
如果不想调用外部命令,可以用第三方python-gnupg库完成验证:
- 先安装依赖:
pip install python-gnupg - 需手动提取提交的原始待签名内容(剥离gpgsig字段后的提交对象数据),再交给GPG验证
代码示例:
import gnupg from git import Repo gpg = gnupg.GPG() repo_dir = "/path/to/your/repo" repo = Repo(repo_dir) for c in repo.iter_commits('master', paths="dir/in/repo/", max_count=5000): if not c.gpgsig: continue # 提取提交的原始待签名数据 commit_data = repo.git.cat_file("commit", c.hexsha) # 剥离签名部分,拿到原始待签名内容 signed_data = "" in_signature = False for line in commit_data.splitlines(keepends=True): if line.startswith("gpgsig"): in_signature = True if in_signature: if not line.startswith(" "): in_signature = False else: continue signed_data += line # 验证签名 verify_res = gpg.verify(signed_data + c.gpgsig) print(f"提交哈希: {c.hexsha}") print(f"签名是否有效: {verify_res.valid}") print(f"签名密钥指纹: {verify_res.fingerprint}") print("-"*50)
注意事项
- 两种方案都依赖本地密钥环已经导入了对应提交的GPG公钥,未导入公钥的情况下签名会判定为无效,也无法获取到完整指纹
- 调用Git命令的方案兼容性更强,不需要处理不同Git版本提交对象的格式差异,更推荐使用
内容的提问来源于stack exchange,提问作者Joe Jasinski
相关产品推荐
相关产品推荐

