Skip to content

verify-commit Git Command Guide

The git verify-commit command validates GPG signatures on commits to ensure they were created by the claimed author and haven’t been tampered with. It’s crucial for maintaining the integrity and authenticity of commit history in security-conscious environments.

Terminal window
git verify-commit [--raw] [-v | --verbose] [-q | --quiet] [--keyid-format=<format>]
[--gpg-program=<gpg-program>] [--gpg-default-key=<key>]
[--gpg-home-dir=<dir>] [--gpg-ssh-allowed-signers=<file>]
[--gpg-ssh-default-key=<key>] [--gpg-ssh-program=<program>]
<commit>...
OptionDescription
--rawPrint raw GPG status output
-v, --verboseVerbose output
-q, --quietSuppress output
--keyid-format=<format>Key ID display format (short, long, etc.)
OptionDescription
--gpg-program=<program>Use custom GPG program
--gpg-default-key=<key>Default GPG key
--gpg-home-dir=<dir>GPG home directory
--gpg-ssh-allowed-signers=<file>SSH allowed signers file
--gpg-ssh-default-key=<key>Default SSH key
--gpg-ssh-program=<program>SSH signing program
ParameterDescription
<commit>Commit(s) to verify (SHA-1, branch, etc.)
Commit Signing and Verification:
├── Commit Creation: Author creates commit with content
├── GPG Signing: Commit SHA-1 signed with private key
├── Signature Storage: Signature embedded in commit object
├── Verification: Public key used to verify signature
├── Trust Validation: Key trustworthiness confirmed
└── Integrity Check: Commit content matches signed hash
GPG Commit Signature Structure:
├── Commit Data: Tree, parent, author, committer, message
├── Content Hash: SHA-1 of commit data
├── Digital Signature: Hash signed with private key
├── Public Key: Used for verification
├── Key Trust: Web of trust or keyserver validation
├── Timestamp: When signature was created
└── Validity Period: Key expiration and revocation status
Signature Verification Results:
├── GOOD: Valid signature from trusted key
├── BAD: Invalid signature or tampered content
├── EXPIRED: Key or signature has expired
├── REVOKED: Signing key has been revoked
├── UNKNOWN: Key not in keyring or untrusted
└── NO_PUBKEY: Public key not available
Terminal window
# Verify specific commit
git verify-commit abc123def456
# Verify current HEAD
git verify-commit HEAD
# Verify multiple commits
git verify-commit HEAD~3 HEAD~2 HEAD~1
Terminal window
# Verify all commits in branch
git verify-commit main
# Verify commits in range
git verify-commit main..feature-branch
# Verify recent commits
git log --oneline -10 | cut -d' ' -f1 | xargs git verify-commit
Terminal window
# Verbose verification with details
git verify-commit -v HEAD
# Raw GPG output for debugging
git verify-commit --raw HEAD
# Quiet verification (exit code only)
git verify-commit -q HEAD
Terminal window
# Verify all commits with status reporting
verify_all_commits() {
echo "Verifying all commits in repository..."
git tag | while read -r tag; do
if git verify-commit -q "$tag" 2>/dev/null; then
echo "$tag"
else
echo "$tag"
fi
done
}
# Verify commits by author
verify_author_commits() {
local author="$1"
echo "Verifying commits by $author..."
git log --author="$author" --pretty=format:%H | while read -r commit; do
if git verify-commit -q "$commit" 2>/dev/null; then
echo "$commit"
else
echo "$commit"
fi
done
}
# Usage
verify_author_commits "John Doe"
Terminal window
# Analyze signature details
analyze_signatures() {
echo "Analyzing commit signatures..."
git log --show-signature --pretty=format:"%H %G? %GS %GK" | while read -r commit status signer key; do
echo "Commit: $commit"
echo "Status: $status"
echo "Signer: $signer"
echo "Key: $key"
case "$status" in
G) echo "✓ Good signature" ;;
B) echo "✗ Bad signature" ;;
X) echo "⚠ Expired signature" ;;
Y) echo "⚠ Expired key" ;;
R) echo "✗ Revoked key" ;;
N) echo "⚠ No signature" ;;
*) echo "? Unknown status: $status" ;;
esac
echo
done
}
# Check signature freshness
check_signature_freshness() {
echo "Checking signature freshness..."
git log --show-signature --pretty=format:"%H %ct %G?" | while read -r commit timestamp status; do
current_time=$(date +%s)
signature_age=$((current_time - timestamp))
days_old=$((signature_age / 86400))
if [ "$status" = "G" ] && [ "$days_old" -gt 365 ]; then
echo "⚠ Old signature: $commit ($days_old days)"
fi
done
}
Terminal window
# Verify commits with specific key
verify_with_key() {
local key_id="$1"
echo "Verifying commits signed with key: $key_id"
git log --show-signature --pretty=format:"%H %G? %GK" | while read -r commit status key; do
if [ "$key" = "$key_id" ]; then
echo "Commit: $commit"
echo "Status: $status"
echo "Key: $key"
echo
fi
done
}
# Check key validity
check_key_validity() {
local key_id="$1"
echo "Checking validity of key: $key_id"
# Check if key exists
if gpg --list-keys "$key_id" >/dev/null 2>&1; then
echo "✓ Key exists in keyring"
# Check expiration
if gpg --list-keys --with-colons "$key_id" | grep -q "^pub:e:"; then
echo "✗ Key has expired"
else
echo "✓ Key is valid"
fi
else
echo "✗ Key not found in keyring"
fi
}
# Usage
verify_with_key "ABC123DEF456"
check_key_validity "ABC123DEF456"
Terminal window
# Configure GPG for commit signing
git config --global user.signingkey "ABC123DEF456"
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# Configure GPG program
git config --global gpg.program "gpg"
git config --global gpg.ssh.program "ssh-keygen"
# Configure key display format
git config --global verify.keyidformat "long"
# Configure SSH signing
git config --global gpg.ssh.allowedSignersFile "~/.ssh/allowed_signers"
git config --global gpg.ssh.defaultKeyCommand "ssh-add -L"
Terminal window
# Generate GPG key for commit signing
generate_gpg_key() {
echo "Generating GPG key for commit signing..."
# Generate key (interactive)
gpg --full-generate-key
# List keys
gpg --list-secret-keys --keyid-format LONG
# Export public key
echo "Export your public key:"
echo "gpg --armor --export YOUR_KEY_ID"
echo "Share with team members for commit verification"
}
# Setup SSH signing for commits
setup_ssh_signing() {
echo "Setting up SSH signing for commits..."
# Generate SSH key for signing
ssh-keygen -t ed25519 -C "git-commit-signing" -f ~/.ssh/commit_signing_key
# Configure allowed signers
echo "$(git config user.email) $(cat ~/.ssh/commit_signing_key.pub)" >> ~/.ssh/allowed_signers
# Configure Git to use SSH signing
git config --global gpg.ssh.defaultKeyCommand "ssh-add -L ~/.ssh/commit_signing_key"
git config --global gpg.format ssh
git config --global commit.gpgsign true
}
# Import team member keys
setup_team_keys() {
echo "Setting up team GPG keys for commit verification..."
# Import keys from keyserver
gpg --keyserver hkps://keys.openpgp.org --recv-keys KEY_ID_1 KEY_ID_2
# Import from files
gpg --import team-member-1.asc team-member-2.asc
# Sign imported keys (establish trust)
gpg --sign-key KEY_ID_1
gpg --sign-key KEY_ID_2
echo "Team keys imported and signed"
}
Terminal window
# Safe commit verification with error handling
safe_verify_commit() {
local commit="$1"
echo "Verifying commit: $commit"
# Check if commit exists
if ! git cat-file -e "$commit" 2>/dev/null; then
echo "Error: Commit $commit does not exist"
return 1
fi
# Attempt verification
if git verify-commit -q "$commit" 2>/dev/null; then
echo "✓ Commit signature is valid"
return 0
else
echo "✗ Commit signature verification failed"
return 1
fi
}
# Batch verification with progress
batch_verify_commits() {
local commit_count
commit_count=$(git rev-list --count HEAD)
local current=0
echo "Batch verifying $commit_count commits..."
git rev-list HEAD | while read -r commit; do
((current++))
echo -n "[$current/$commit_count] Verifying $commit... "
if safe_verify_commit "$commit" >/dev/null 2>&1; then
echo ""
else
echo ""
fi
done
echo "Batch verification complete"
}
# Usage
batch_verify_commits
Terminal window
# Verify commits in CI/CD pipelines
ci_commit_verification() {
echo "=== CI/CD Commit Verification ==="
# Verify all commits in PR
verify_pr_commits() {
echo "Verifying commits in pull request..."
# Get commits in PR (simplified - would use actual CI variables)
git log --oneline "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..${CI_COMMIT_SHA}" | while read -r line; do
commit=$(echo "$line" | cut -d' ' -f1)
message=$(echo "$line" | cut -d' ' -f2-)
echo "Verifying commit $commit: $message"
if git verify-commit -q "$commit" 2>/dev/null; then
echo "✓ Signature valid"
else
echo "✗ Signature invalid - rejecting PR"
exit 1
fi
done
echo "All commits in PR are properly signed"
}
# Setup commit signing requirement
setup_commit_signing() {
echo "Setting up commit signing requirements..."
# Configure Git to require signing
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# Setup pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Require commit signing
if [ "$(git config --bool commit.gpgsign)" = "true" ]; then
echo "Commit signing is required"
echo "Please ensure you have GPG/SSH signing configured"
else
echo "Warning: Commit signing not required"
fi
EOF
chmod +x .git/hooks/pre-commit
echo "Commit signing requirement configured"
}
# Generate signing status report
generate_signing_report() {
echo "Generating commit signing status report..."
cat > commit-signing-report.md << EOF
# Commit Signing Status Report
Generated: $(date)
Repository: $(basename "$(pwd)")
Branch: $(git branch --show-current)
## Signing Statistics
EOF
total_commits=$(git rev-list --count HEAD)
signed_commits=$(git log --show-signature | grep -c "gpg:")
unsigned_commits=$((total_commits - signed_commits))
echo "- Total commits: $total_commits" >> commit-signing-report.md
echo "- Signed commits: $signed_commits" >> commit-signing-report.md
echo "- Unsigned commits: $unsigned_commits" >> commit-signing-report.md
echo "- Signing rate: $((signed_commits * 100 / total_commits))%" >> commit-signing-report.md
cat >> commit-signing-report.md << EOF
## Recent Commit Signing Status
$(git log --oneline -10 --show-signature | while read -r line; do
if echo "$line" | grep -q "gpg:"; then
echo "- ✓ $(echo "$line" | head -1)"
else
echo "- ✗ $(echo "$line" | head -1)"
fi
done)
## Recommendations
EOF
if [ "$unsigned_commits" -gt 0 ]; then
echo "- Enable commit signing: \`git config commit.gpgsign true\`" >> commit-signing-report.md
echo "- Setup GPG key for signing" >> commit-signing-report.md
fi
echo "Commit signing report generated: commit-signing-report.md"
}
# Run CI/CD verification
verify_pr_commits
generate_signing_report
}
# Usage in CI
ci_commit_verification
Terminal window
# Audit repository for signed commits
audit_commit_signing() {
echo "=== Repository Commit Signing Audit ==="
# Analyze signing coverage
analyze_signing_coverage() {
echo "Analyzing commit signing coverage..."
declare -A signer_stats
git log --show-signature --pretty=format:"%H %ae %G?" | while read -r commit email status; do
if [ "$status" = "G" ]; then
signer_stats["$email"]=$((signer_stats["$email"] + 1))
fi
done
echo "Signing coverage by author:"
for email in "${!signer_stats[@]}"; do
echo " $email: ${signer_stats[$email]} signed commits"
done
}
# Find unsigned commits
find_unsigned_commits() {
echo "Finding unsigned commits..."
git log --pretty=format:"%H %s" | while read -r commit subject; do
if ! git verify-commit -q "$commit" 2>/dev/null; then
echo "Unsigned: $commit - $subject"
fi
done
}
# Check signing key rotation
check_key_rotation() {
echo "Checking signing key rotation..."
git log --show-signature --pretty=format:"%H %ct %GK" | while read -r commit timestamp key; do
if [ -n "$key" ]; then
echo "Commit $commit signed with key $key at $(date -d "@$timestamp")"
fi
done | sort -k4 | uniq -c | sort -nr
}
# Generate security report
generate_security_report() {
echo "Generating repository security report..."
cat > security-audit-report.md << EOF
# Repository Security Audit Report
Generated: $(date)
Repository: $(basename "$(pwd)")
## Commit Signing Analysis
EOF
total_commits=$(git rev-list --count HEAD)
signed_commits=$(git log --show-signature | grep -c "Good signature")
unsigned_commits=$((total_commits - signed_commits))
echo "### Overall Statistics" >> security-audit-report.md
echo "- Total commits: $total_commits" >> security-audit-report.md
echo "- Signed commits: $signed_commits" >> security-audit-report.md
echo "- Unsigned commits: $unsigned_commits" >> security-audit-report.md
echo "- Signing compliance: $((signed_commits * 100 / total_commits))%" >> security-audit-report.md
echo >> security-audit-report.md
echo "### Recent Unsigned Commits" >> security-audit-report.md
git log --oneline -20 | while read -r line; do
commit=$(echo "$line" | cut -d' ' -f1)
if ! git verify-commit -q "$commit" 2>/dev/null; then
echo "- $line" >> security-audit-report.md
fi
done
echo >> security-audit-report.md
echo "### Security Recommendations" >> security-audit-report.md
if [ "$unsigned_commits" -gt 0 ]; then
echo "- **HIGH**: $unsigned_commits commits are unsigned" >> security-audit-report.md
echo "- Enable mandatory commit signing" >> security-audit-report.md
echo "- Configure CI/CD to reject unsigned commits" >> security-audit-report.md
fi
echo "Security audit report generated: security-audit-report.md"
}
# Run audit
analyze_signing_coverage
echo
find_unsigned_commits
echo
check_key_rotation
echo
generate_security_report
}
# Usage
audit_commit_signing
Terminal window
# Team commit signing workflow
team_signing_workflow() {
echo "=== Team Commit Signing Workflow ==="
# Setup team signing policy
setup_team_policy() {
echo "Setting up team signing policy..."
cat > team-signing-policy.md << EOF
# Team Commit Signing Policy
## Policy Overview
All commits must be signed with a valid GPG or SSH key.
## Requirements
- Use GPG key with at least 4096-bit RSA or Ed25519
- SSH keys must be added to allowed_signers file
- Keys must be rotated annually
- Public keys must be shared with the team
## Verification
- CI/CD pipelines will reject unsigned commits
- Code reviews will check signing status
- Regular audits will verify compliance
## Setup Instructions
1. Generate GPG key: \`gpg --full-generate-key\`
2. Configure Git: \`git config commit.gpgsign true\`
3. Export public key and share with team
4. Add to allowed signers if using SSH
EOF
echo "Team signing policy created: team-signing-policy.md"
}
# Setup developer signing
setup_developer_signing() {
local developer="$1"
echo "Setting up signing for developer: $developer"
# Create developer config
mkdir -p "developer-configs/$developer"
cat > "developer-configs/$developer/signing-setup.sh" << EOF
#!/bin/bash
# Signing setup for $developer
echo "Setting up commit signing..."
# Configure Git
git config --global user.name "$developer"
git config --global user.email "$developer@company.com"
git config --global commit.gpgsign true
# Generate GPG key (interactive)
echo "Run: gpg --full-generate-key"
echo "Then configure: git config --global user.signingkey YOUR_KEY_ID"
echo "Setup complete for $developer"
EOF
chmod +x "developer-configs/$developer/signing-setup.sh"
echo "Developer signing setup created"
}
# Monitor team compliance
monitor_team_compliance() {
echo "Monitoring team signing compliance..."
# This would integrate with team management system
echo "Team members and their signing status:"
# Example team members
team_members=("alice" "bob" "charlie")
for member in "${team_members[@]}"; do
# Check recent commits by member
recent_commits=$(git log --author="$member" --oneline -5 2>/dev/null | wc -l)
if [ "$recent_commits" -gt 0 ]; then
signed_commits=$(git log --author="$member" --show-signature -5 2>/dev/null | grep -c "Good signature")
compliance=$((signed_commits * 100 / recent_commits))
echo " $member: ${compliance}% compliance ($signed_commits/$recent_commits signed)"
else
echo " $member: No recent commits"
fi
done
}
# Interactive team workflow
echo "Team Signing Workflow Options:"
echo "1. Setup team policy"
echo "2. Setup developer signing"
echo "3. Monitor team compliance"
read -p "Select option (1-3): " option
case "$option" in
1) setup_team_policy ;;
2)
read -p "Developer name: " dev
setup_developer_signing "$dev"
;;
3) monitor_team_compliance ;;
esac
}
# Usage
team_signing_workflow
Terminal window
# Diagnose signature verification problems
diagnose_signature_issues() {
echo "Diagnosing signature verification issues..."
# Test basic verification
if git verify-commit -q HEAD 2>/dev/null; then
echo "✓ Basic signature verification works"
else
echo "✗ Signature verification failed"
# Check for common issues
if ! command -v gpg >/dev/null 2>&1 && ! command -v ssh-keygen >/dev/null 2>&1; then
echo " No GPG or SSH signing tools found"
fi
# Check commit signature
if ! git show --show-signature HEAD | grep -q "gpg:"; then
echo " Commit is not signed"
fi
fi
# Check GPG keyring
if command -v gpg >/dev/null 2>&1; then
key_count=$(gpg --list-keys 2>/dev/null | grep -c "^pub")
echo "GPG keys in keyring: $key_count"
if [ "$key_count" -eq 0 ]; then
echo " No GPG keys found - import signer keys"
fi
fi
# Check SSH allowed signers
if [ -f ~/.ssh/allowed_signers ]; then
signer_count=$(wc -l < ~/.ssh/allowed_signers)
echo "SSH allowed signers: $signer_count"
else
echo "SSH allowed signers file not found"
fi
}
# Fix signature issues
fix_signature_issues() {
echo "Attempting to fix signature issues..."
# Import missing keys
echo "Attempting to import missing keys..."
# Get failed commit
failed_commit=$(git verify-commit HEAD 2>&1 | grep -o "gpg:.*key.*not.*found" | sed 's/.*key \([A-F0-9]*\).*/\1/')
if [ -n "$failed_commit" ]; then
echo "Missing key: $failed_commit"
echo "Attempting to fetch from keyserver..."
if gpg --keyserver hkps://keys.openpgp.org --recv-keys "$failed_commit" 2>/dev/null; then
echo "✓ Key imported successfully"
else
echo "✗ Could not import key"
fi
fi
# Check SSH configuration
if [ ! -f ~/.ssh/allowed_signers ]; then
echo "Creating SSH allowed signers file..."
touch ~/.ssh/allowed_signers
fi
# Test verification again
if git verify-commit -q HEAD 2>/dev/null; then
echo "✓ Signature verification now works"
else
echo "✗ Signature verification still failing"
fi
}
# Usage
diagnose_signature_issues
fix_signature_issues
Terminal window
# Troubleshoot key management problems
troubleshoot_key_management() {
echo "Troubleshooting key management issues..."
# Check key validity
check_key_status() {
local key_id="$1"
echo "Checking status of key: $key_id"
# Check if key exists
if ! gpg --list-keys "$key_id" >/dev/null 2>&1; then
echo "✗ Key not found in keyring"
return 1
fi
# Check expiration
if gpg --list-keys --with-colons "$key_id" | grep -q "^pub:e:"; then
echo "✗ Key has expired"
return 1
fi
# Check revocation
if gpg --list-keys --with-colons "$key_id" | grep -q "^pub:r:"; then
echo "✗ Key has been revoked"
return 1
fi
echo "✓ Key is valid"
return 0
}
# Find commits with invalid signatures
find_invalid_signatures() {
echo "Finding commits with invalid signatures..."
git log --oneline --all | while read -r line; do
commit=$(echo "$line" | cut -d' ' -f1)
if ! git verify-commit -q "$commit" 2>/dev/null; then
echo "Invalid signature: $line"
fi
done
}
# Update keyring
update_keyring() {
echo "Updating GPG keyring..."
# Update from keyservers
gpg --keyserver hkps://keys.openpgp.org --refresh-keys
# Update trust database
gpg --check-trustdb
echo "Keyring update complete"
}
# Interactive troubleshooting
echo "Key Management Troubleshooting:"
echo "1. Check key status"
echo "2. Find invalid signatures"
echo "3. Update keyring"
read -p "Select option (1-3): " option
case "$option" in
1)
read -p "Key ID: " key_id
check_key_status "$key_id"
;;
2) find_invalid_signatures ;;
3) update_keyring ;;
esac
}
# Usage
troubleshoot_key_management
Terminal window
# Troubleshoot configuration problems
troubleshoot_config_issues() {
echo "Troubleshooting configuration issues..."
# Check Git configuration
echo "Git signing configuration:"
git config --list | grep -E "(gpgsign|gpg|signingkey)" | while read -r config; do
echo " $config"
done
# Check if signing is enabled
if [ "$(git config --bool commit.gpgsign)" != "true" ]; then
echo "⚠ Commit signing is not enabled"
echo " Enable with: git config commit.gpgsign true"
fi
# Check signing key
signing_key=$(git config user.signingkey)
if [ -z "$signing_key" ]; then
echo "⚠ No signing key configured"
echo " Configure with: git config user.signingkey YOUR_KEY_ID"
else
echo "✓ Signing key configured: $signing_key"
fi
# Check GPG program
gpg_program=$(git config gpg.program)
if [ -n "$gpg_program" ]; then
if ! command -v "$gpg_program" >/dev/null 2>&1; then
echo "✗ Configured GPG program not found: $gpg_program"
else
echo "✓ GPG program available: $gpg_program"
fi
fi
# Check SSH signing
if [ "$(git config gpg.format)" = "ssh" ]; then
echo "SSH signing is configured"
allowed_signers=$(git config gpg.ssh.allowedSignersFile)
if [ -n "$allowed_signers" ] && [ -f "$allowed_signers" ]; then
echo "✓ SSH allowed signers file exists: $allowed_signers"
else
echo "✗ SSH allowed signers file missing or not configured"
fi
fi
}
# Fix configuration issues
fix_config_issues() {
echo "Attempting to fix configuration issues..."
# Enable commit signing
git config commit.gpgsign true
echo "✓ Enabled commit signing"
# Find and set signing key
secret_keys=$(gpg --list-secret-keys --keyid-format short | grep "^sec" | head -1 | awk '{print $2}' | cut -d'/' -f2)
if [ -n "$secret_keys" ]; then
git config user.signingkey "$secret_keys"
echo "✓ Configured signing key: $secret_keys"
else
echo "⚠ No GPG secret keys found"
echo " Generate with: gpg --full-generate-key"
fi
# Test configuration
if git verify-commit -q HEAD 2>/dev/null; then
echo "✓ Configuration is working"
else
echo "⚠ Configuration may still need adjustment"
fi
}
# Usage
troubleshoot_config_issues
fix_config_issues
#!/bin/bash
# Enterprise commit signing compliance system
enterprise_compliance() {
echo "=== Enterprise Commit Signing Compliance ==="
# Setup compliance requirements
setup_compliance_requirements() {
echo "Setting up enterprise compliance requirements..."
cat > compliance-requirements.md << EOF
# Enterprise Commit Signing Requirements
## Policy Overview
All commits to production branches must be signed with approved keys.
## Requirements
- GPG keys: RSA 4096-bit or Ed25519, valid for 2 years max
- SSH keys: Ed25519, added to organizational allowed_signers
- Key rotation: Annual mandatory rotation
- Signing requirement: All commits to main/master branches
## Approved Signers
- All employees with active GPG/SSH keys
- CI/CD systems with organizational keys
- Contractors with temporary approved keys
## Enforcement
- Pre-receive hooks reject unsigned commits
- CI/CD pipelines verify signatures
- Regular audits check compliance
- Automated reporting to security team
EOF
echo "Compliance requirements documented: compliance-requirements.md"
}
# Setup organizational key management
setup_org_key_management() {
echo "Setting up organizational key management..."
# Create key management directory
mkdir -p org-keys/{gpg,ssh,revoked}
# Setup organizational allowed signers
touch org-keys/ssh/allowed_signers
# Create key approval workflow
cat > org-keys/key-approval-process.md << EOF
# Key Approval Process
## For New Employees
1. Generate GPG/SSH key pair
2. Submit public key to IT security
3. IT verifies key meets requirements
4. Key added to organizational allowed_signers
5. Employee configures Git signing
## For Contractors
1. Generate key pair with organizational oversight
2. Submit public key for approval
3. Temporary addition to allowed_signers
4. Automatic removal after contract end
## Key Rotation
1. Annual reminder sent to all users
2. Generate new key pair
3. Submit for approval
4. Update organizational records
5. Revoke old key
EOF
echo "Organizational key management setup complete"
}
# Implement pre-receive hook for signing enforcement
setup_pre_receive_hook() {
echo "Setting up pre-receive hook for signing enforcement..."
cat > .git/hooks/pre-receive << 'EOF'
#!/bin/bash
# Enforce commit signing for protected branches
zero_commit="0000000000000000000000000000000000000000"
while read -r oldrev newrev refname; do
# Only enforce on protected branches
case "$refname" in
refs/heads/main|refs/heads/master|refs/heads/release/*)
echo "Verifying signatures for $refname..."
# Check all commits in push
for commit in $(git rev-list "$oldrev..$newrev"); do
if ! git verify-commit -q "$commit" 2>/dev/null; then
echo "ERROR: Unsigned commit detected: $commit"
echo "All commits to $refname must be signed."
echo "Please sign your commits and try again."
exit 1
fi
done
echo "✓ All commits in $refname are properly signed"
;;
*)
echo "Signature check skipped for $refname"
;;
esac
done
echo "Pre-receive hook validation complete"
EOF
chmod +x .git/hooks/pre-receive
echo "Pre-receive hook configured for signing enforcement"
}
# Generate compliance reports
generate_compliance_reports() {
echo "Generating compliance reports..."
cat > compliance-report-$(date +%Y%m%d).md << EOF
# Enterprise Compliance Report
Generated: $(date)
Period: Last 30 days
## Overall Statistics
EOF
# Calculate compliance metrics
total_commits=$(git log --since="30 days ago" --oneline | wc -l)
signed_commits=$(git log --since="30 days ago" --show-signature | grep -c "Good signature")
compliance_rate=0
if [ "$total_commits" -gt 0 ]; then
compliance_rate=$((signed_commits * 100 / total_commits))
fi
echo "- Total commits: $total_commits" >> compliance-report-$(date +%Y%m%d).md
echo "- Signed commits: $signed_commits" >> compliance-report-$(date +%Y%m%d).md
echo "- Compliance rate: ${compliance_rate}%" >> compliance-report-$(date +%Y%m%d).md
cat >> compliance-report-$(date +%Y%m%d).md << EOF
## Branch Compliance
EOF
# Check compliance by branch
for branch in main master develop; do
if git show-ref --verify "refs/heads/$branch" >/dev/null 2>&1; then
branch_commits=$(git log --oneline "$branch" --since="30 days ago" | wc -l)
branch_signed=$(git log "$branch" --since="30 days ago" --show-signature | grep -c "Good signature")
if [ "$branch_commits" -gt 0 ]; then
branch_rate=$((branch_signed * 100 / branch_commits))
echo "- $branch: ${branch_rate}% ($branch_signed/$branch_commits)" >> compliance-report-$(date +%Y%m%d).md
fi
fi
done
cat >> compliance-report-$(date +%Y%m%d).md << EOF
## Non-Compliant Commits
EOF
# List recent unsigned commits
git log --oneline --since="30 days ago" | while read -r line; do
commit=$(echo "$line" | cut -d' ' -f1)
if ! git verify-commit -q "$commit" 2>/dev/null; then
echo "- $line" >> compliance-report-$(date +%Y%m%d).md
fi
done
echo "Compliance report generated: compliance-report-$(date +%Y%m%d).md"
}
# Run enterprise compliance setup
setup_compliance_requirements
setup_org_key_management
setup_pre_receive_hook
generate_compliance_reports
echo "Enterprise compliance system setup complete!"
}
enterprise_compliance
Terminal window
# Advanced security auditing with commit verification
security_auditing() {
echo "=== Advanced Security Auditing ==="
# Audit signing key usage
audit_key_usage() {
echo "Auditing signing key usage..."
declare -A key_usage
git log --show-signature --pretty=format:"%H %ae %GK" | while read -r commit email key; do
if [ -n "$key" ]; then
key_usage["$key"]="${key_usage[$key]:-0}"
key_usage["$key"]=$((key_usage["$key"] + 1))
fi
done
echo "Signing key usage statistics:"
for key in "${!key_usage[@]}"; do
echo " $key: ${key_usage[$key]} commits"
# Check key validity
if gpg --list-keys "$key" >/dev/null 2>&1; then
echo " ✓ Key exists"
else
echo " ✗ Key not found"
fi
done
}
# Detect signature anomalies
detect_signature_anomalies() {
echo "Detecting signature anomalies..."
# Check for commits signed with expired keys
git log --show-signature --pretty=format:"%H %ct %GK" | while read -r commit timestamp key; do
if [ -n "$key" ]; then
# Check if key was valid at commit time
if gpg --list-keys --with-colons "$key" 2>/dev/null | grep -q "^pub:e:"; then
key_expiry=$(gpg --list-keys --with-colons "$key" 2>/dev/null | grep "^pub:e:" | cut -d: -f7)
if [ "$timestamp" -gt "$key_expiry" ]; then
echo "⚠ Commit $commit signed with expired key $key"
echo " Commit date: $(date -d "@$timestamp")"
echo " Key expired: $(date -d "@$key_expiry")"
fi
fi
fi
done
# Check for unusual signing patterns
echo "Checking for unusual signing patterns..."
# Find commits signed by multiple different keys
author_keys=$(git log --show-signature --pretty=format:"%ae %GK" | sort | uniq)
echo "Author-key combinations:"
echo "$author_keys" | while read -r author key; do
if [ -n "$key" ]; then
echo " $author -> $key"
fi
done
}
# Forensic commit analysis
forensic_commit_analysis() {
echo "Performing forensic commit analysis..."
# Analyze commit timing and signatures
echo "Commit timing and signature analysis:"
git log --show-signature --pretty=format:"%H %ct %ae %G?" | while read -r commit timestamp email status; do
commit_date=$(date -d "@$timestamp" "+%Y-%m-%d %H:%M:%S")
case "$status" in
"G") sig_status="✓ Good" ;;
"B") sig_status="✗ Bad" ;;
"X") sig_status="⚠ Expired sig" ;;
"Y") sig_status="⚠ Expired key" ;;
"R") sig_status="✗ Revoked key" ;;
"N") sig_status="⚠ No signature" ;;
*) sig_status="? Unknown: $status" ;;
esac
echo "$commit_date - $commit - $email - $sig_status"
done
}
# Generate security audit report
generate_security_audit() {
echo "Generating comprehensive security audit report..."
cat > security-audit-$(date +%Y%m%d).md << EOF
# Comprehensive Security Audit Report
Generated: $(date)
Repository: $(basename "$(pwd)")
Auditor: $(whoami)
## Executive Summary
This report contains a comprehensive security audit of commit signing practices.
## Key Findings
EOF
# Overall statistics
total_commits=$(git rev-list --count HEAD)
signed_commits=$(git log --show-signature | grep -c "Good signature")
unsigned_commits=$((total_commits - signed_commits))
echo "- Total commits analyzed: $total_commits" >> security-audit-$(date +%Y%m%d).md
echo "- Properly signed commits: $signed_commits" >> security-audit-$(date +%Y%m%d).md
echo "- Unsigned commits: $unsigned_commits" >> security-audit-$(date +%Y%m%d).md
echo "- Signing compliance: $((signed_commits * 100 / total_commits))%" >> security-audit-$(date +%Y%m%d).md
cat >> security-audit-$(date +%Y%m%d).md << EOF
## Detailed Findings
### Signature Status Breakdown
EOF
# Signature status breakdown
git log --show-signature --pretty=format:"%G?" | sort | uniq -c | while read -r count status; do
case "$status" in
"G") desc="Good signatures" ;;
"B") desc="Bad signatures" ;;
"X") desc="Expired signatures" ;;
"Y") desc="Expired keys" ;;
"R") desc="Revoked keys" ;;
"N") desc="No signature" ;;
*) desc="Unknown status: $status" ;;
esac
echo "- $count $desc" >> security-audit-$(date +%Y%m%d).md
done
cat >> security-audit-$(date +%Y%m%d).md << EOF
### Risk Assessment
EOF
# Risk assessment
if [ "$unsigned_commits" -gt 0 ]; then
echo "**HIGH RISK**: $unsigned_commits commits are unsigned and cannot be verified." >> security-audit-$(date +%Y%m%d).md
fi
expired_sigs=$(git log --show-signature --pretty=format:"%G?" | grep -c "X")
if [ "$expired_sigs" -gt 0 ]; then
echo "**MEDIUM RISK**: $expired_sigs commits have expired signatures." >> security-audit-$(date +%Y%m%d).md
fi
cat >> security-audit-$(date +%Y%m%d).md << EOF
### Recommendations
1. **URGENT**: Enable mandatory commit signing
2. **HIGH**: Implement CI/CD signature verification
3. **MEDIUM**: Rotate expired keys
4. **LOW**: Regular security audits
## Conclusion
Commit signing is essential for repository integrity and security.
EOF
echo "Security audit report generated: security-audit-$(date +%Y%m%d).md"
}
# Run comprehensive audit
audit_key_usage
echo
detect_signature_anomalies
echo
forensic_commit_analysis
echo
generate_security_audit
}
# Usage
security_auditing
Terminal window
# Automated compliance monitoring system
automated_compliance_monitoring() {
echo "=== Automated Compliance Monitoring ==="
# Setup monitoring infrastructure
setup_monitoring_infrastructure() {
echo "Setting up compliance monitoring infrastructure..."
# Create monitoring directories
mkdir -p compliance-monitoring/{logs,reports,alerts}
# Setup monitoring script
cat > compliance-monitoring/monitor-compliance.sh << 'EOF'
#!/bin/bash
# Automated compliance monitoring
LOG_FILE="compliance-monitoring/logs/compliance-$(date +%Y%m%d).log"
ALERT_FILE="compliance-monitoring/alerts/alerts-$(date +%Y%m%d).txt"
echo "$(date): Starting compliance check" >> "$LOG_FILE"
# Check signing compliance
total_commits=$(git rev-list --count HEAD)
signed_commits=$(git log --show-signature | grep -c "Good signature")
compliance_rate=$((signed_commits * 100 / total_commits))
echo "Compliance rate: ${compliance_rate}%" >> "$LOG_FILE"
# Alert thresholds
if [ "$compliance_rate" -lt 95 ]; then
echo "$(date): WARNING - Compliance below 95%: ${compliance_rate}%" >> "$ALERT_FILE"
fi
# Check for unsigned commits in last 24 hours
recent_unsigned=$(git log --since="24 hours ago" --oneline | while read -r line; do
commit=$(echo "$line" | cut -d' ' -f1)
if ! git verify-commit -q "$commit" 2>/dev/null; then
echo "$line"
fi
done | wc -l)
if [ "$recent_unsigned" -gt 0 ]; then
echo "$(date): ALERT - $recent_unsigned unsigned commits in last 24 hours" >> "$ALERT_FILE"
fi
echo "$(date): Compliance check complete" >> "$LOG_FILE"
EOF
chmod +x compliance-monitoring/monitor-compliance.sh
# Setup cron monitoring
(crontab -l ; echo "0 */4 * * * $(