You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制Git推送仅接受签名且匹配指定邮箱的提交

Git仓库限制:仅允许指定邮箱+对应GPG签名推送

问题背景

使用Git托管网站代码,已实现邮箱白名单推送限制,但扩展GPG签名验证时持续触发以下错误:

  • Commit $commit is not signed or has an invalid signature.
  • Commit $commit by $author_email is not signed or signed with an unauthorized key.

核心问题分析

  1. 服务器GPG信任缺失:git verify-commit依赖服务器导入并信任用户的GPG公钥,未导入的话会直接判定签名无效
  2. 指纹提取逻辑缺陷:原脚本的正则匹配无法精准捕获指纹,且未处理大小写差异
  3. 指纹匹配逻辑错误:16位短指纹需匹配长指纹的最后16位,原脚本直接全量对比导致不匹配

解决方案

步骤1:服务器导入并信任用户GPG公钥

要求用户导出自己的GPG公钥(执行gpg --armor --export myemail@example.dev),在服务器上执行以下操作:

# 导入用户公钥
gpg --import user_public_key.asc
# 标记为信任(避免验证时提示未信任)
gpg --edit-key 0E3DFE091F345CC152237C5502E78387B88700FE
# 输入 trust → 选择5(ultimate trust)→ 输入 save 退出

步骤2:修复后的Git钩子脚本(pre-receive)

# Allowed users and their corresponding GPG fingerprints (full 40-char or last 16-char)
declare -A ALLOWED_USERS
ALLOWED_USERS["myemail@example.dev"]="0E3DFE091F345CC152237C5502E78387B88700FE"
ALLOWED_USERS["otheremail@icontrol.dev"]="A787E5542209332D"

# Check if user is in allowed list
is_allowed_user() {
  local user_email=$1
  [[ -n "${ALLOWED_USERS[$user_email]}" ]]
}

# Verify commit signature and key authorization
is_signed_and_allowed() {
  local commit=$1
  local user_email=$2
  local allowed_fingerprint="${ALLOWED_USERS[$user_email]}"
  local extracted_fingerprint

  # Quick check for valid signature (suppress verbose output)
  if ! git verify-commit --quiet "$commit"; then
    echo "Commit $commit: unsigned or invalid/untrusted signature."
    return 1
  fi

  # Extract full 40-char fingerprint from GPG output
  extracted_fingerprint=$(git verify-commit "$commit" 2>&1 | grep -i "fingerprint:" | awk '{print $NF}' | tr -d ' ')

  if [[ -z "$extracted_fingerprint" ]]; then
    echo "Commit $commit: failed to extract GPG fingerprint."
    return 1
  fi

  # Normalize to uppercase to avoid case mismatch
  extracted_fingerprint=$(echo "$extracted_fingerprint" | tr '[:lower:]' '[:upper:]')
  allowed_fingerprint=$(echo "$allowed_fingerprint" | tr '[:lower:]' '[:upper:]')

  # Match full fingerprint or last 16 chars (for short fingerprint entries)
  if [[ "$extracted_fingerprint" != "$allowed_fingerprint" && "${extracted_fingerprint: -16}" != "$allowed_fingerprint" ]]; then
    echo "Commit $commit: unauthorized GPG key $extracted_fingerprint for user $user_email. Allowed key: $allowed_fingerprint."
    return 1
  fi

  return 0
}

# Process push requests
while read oldrev newrev refname; do
  # Skip branch deletion
  if [[ "$newrev" == "0000000000000000000000000000000000000000" ]]; then
    continue
  fi

  # Validate every new commit in the push
  for commit in $(git rev-list "$oldrev".."$newrev"); do
    author_email=$(git log -1 --format="%ae" "$commit")

    if ! is_allowed_user "$author_email"; then
      echo "Unauthorized user: $author_email"
      exit 1
    fi

    if ! is_signed_and_allowed "$commit" "$author_email"; then
      exit 1
    fi
  done
done

exit 0

关键修复说明

  • GPG信任处理:必须在服务器端导入并信任用户公钥,否则签名验证会直接失败
  • 精准指纹提取:通过grep -i "fingerprint:"定位指纹行,避免正则匹配遗漏
  • 大小写兼容:统一转换为大写,解决Windows终端复制指纹可能的大小写差异
  • 灵活指纹匹配:支持全40位指纹和16位短指纹(匹配长指纹最后16位)
  • 优化验证流程:先用--quiet快速验证签名有效性,减少冗余输出

内容的提问来源于stack exchange,提问作者Paul Williams

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:50:54