From db06fcc22cdbdec26a96fee15c16c0f46da4d689 Mon Sep 17 00:00:00 2001 From: qinhui <> Date: Mon, 12 May 2025 18:44:39 +0800 Subject: [PATCH] Add commit message scanning script --- .git-hooks/check-commit-message.sh | 22 ++++ .git-hooks/install-hooks.sh | 163 +++++++++++++++++++++++++++++ .git-hooks/post-commit | 27 +++++ .git-hooks/pre-commit | 25 +++++ .githooks/pre-commit | 38 ------- .gitleaks.toml | 142 +++++++++++++++++++++++++ .pre-commit-config.yaml | 15 +++ HOOKS-GUIDE.md | 75 +++++++++++++ 8 files changed, 469 insertions(+), 38 deletions(-) create mode 100755 .git-hooks/check-commit-message.sh create mode 100755 .git-hooks/install-hooks.sh create mode 100755 .git-hooks/post-commit create mode 100755 .git-hooks/pre-commit delete mode 100755 .githooks/pre-commit create mode 100644 .gitleaks.toml create mode 100644 .pre-commit-config.yaml create mode 100644 HOOKS-GUIDE.md diff --git a/.git-hooks/check-commit-message.sh b/.git-hooks/check-commit-message.sh new file mode 100755 index 000000000..8d0f57a6d --- /dev/null +++ b/.git-hooks/check-commit-message.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +commit_msg_file=$1 +commit_msg=$(cat "$commit_msg_file") + + +if perl -e ' + binmode(STDIN, ":utf8"); + $/ = undef; + $text = <>; + if ($text =~ /[\x{4e00}-\x{9fff}]/) { + exit(1); + } else { + exit(0); + }' < "$commit_msg_file" +then + exit 0 +else + echo "Error: Commit message contains Chinese characters." + echo "Please use English only in commit messages." + exit 1 +fi \ No newline at end of file diff --git a/.git-hooks/install-hooks.sh b/.git-hooks/install-hooks.sh new file mode 100755 index 000000000..5c63f9e92 --- /dev/null +++ b/.git-hooks/install-hooks.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +# Functions for colored text output +print_green() { + echo -e "\033[0;32m$1\033[0m" +} + +print_yellow() { + echo -e "\033[0;33m$1\033[0m" +} + +print_red() { + echo -e "\033[0;31m$1\033[0m" +} + +# Function to add executable permissions +ensure_executable() { + if [ -f "$1" ] && [ ! -x "$1" ]; then + chmod +x "$1" + print_green "Added executable permission to $1" + fi +} + +# Ensure script runs from project root directory +if [ ! -d ".git" ]; then + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + cd "$(dirname "$SCRIPT_DIR")" || { print_red "Cannot find project root directory"; exit 1; } + + if [ ! -d ".git" ]; then + print_red "Please run this script from the project root directory" + exit 1 + fi +fi + +# Check if pre-commit is installed +if ! command -v pre-commit &> /dev/null; then + print_yellow "pre-commit not found, attempting to install..." + if command -v pip3 &> /dev/null; then + pip3 install pre-commit + elif command -v pip &> /dev/null; then + pip install pre-commit + else + print_red "pip not found, please install Python and pip first, then run this script again" + exit 1 + fi + + if [ $? -ne 0 ]; then + print_red "Failed to install pre-commit, please install manually: pip install pre-commit" + exit 1 + fi + print_green "pre-commit installed successfully!" +else + print_green "pre-commit is already installed!" +fi + +# Check if gitleaks is installed +if ! command -v gitleaks &> /dev/null; then + print_yellow "gitleaks not found, please install it..." + print_yellow "Installation guide: https://github.com/gitleaks/gitleaks#installing" + + # Attempt automatic installation (based on OS) + if [[ "$OSTYPE" == "darwin"* ]]; then + print_yellow "Detected macOS, attempting to install gitleaks via Homebrew..." + if command -v brew &> /dev/null; then + brew install gitleaks + if [ $? -eq 0 ]; then + print_green "gitleaks installed successfully!" + else + print_red "Cannot automatically install gitleaks, please install manually" + exit 1 + fi + else + print_red "Homebrew not found, please install Homebrew or install gitleaks manually" + exit 1 + fi + else + print_red "Please install gitleaks manually and try again" + exit 1 + fi +fi + +# Check required files and directories +if [ ! -d ".git-hooks" ]; then + print_red "Cannot find .git-hooks directory, please ensure you're in the correct project" + exit 1 +fi + +if [ ! -f ".gitleaks.toml" ]; then + print_red "Cannot find .gitleaks.toml configuration file, please ensure it exists" + exit 1 +fi + +if [ ! -f ".git-hooks/check-commit-message.sh" ]; then + print_red "Cannot find .git-hooks/check-commit-message.sh file, please ensure it exists" + exit 1 +fi + +# Ensure all scripts have executable permissions +print_yellow "Granting executable permissions to hook scripts..." +ensure_executable ".git-hooks/check-commit-message.sh" +ensure_executable ".git-hooks/post-commit" +ensure_executable ".git-hooks/pre-commit" + +# Install pre-commit hook +print_yellow "Installing pre-commit hook..." +pre-commit install +if [ $? -ne 0 ]; then + print_red "Failed to install pre-commit hook!" + exit 1 +fi +print_green "pre-commit hook installed successfully!" + +# Install commit-msg hook +print_yellow "Installing commit-msg hook..." +pre-commit install --hook-type commit-msg +if [ $? -ne 0 ]; then + print_red "Failed to install commit-msg hook!" + exit 1 +fi +print_green "pre-commit commit-msg hook installed successfully!" + +# Copy and set up custom hooks +print_yellow "Setting up custom hooks..." +# Copy commit-msg hook +cp .git-hooks/check-commit-message.sh .git/hooks/commit-msg +chmod +x .git/hooks/commit-msg + +# Copy post-commit hook (if exists) +if [ -f ".git-hooks/post-commit" ]; then + cp .git-hooks/post-commit .git/hooks/post-commit + chmod +x .git/hooks/post-commit +fi + +# Copy pre-commit hook (if exists) +if [ -f ".git-hooks/pre-commit" ]; then + # Backup pre-commit hook + if [ -f ".git/hooks/pre-commit" ]; then + cp .git/hooks/pre-commit .git/hooks/pre-commit.bak + fi + + cp .git-hooks/pre-commit .git/hooks/pre-commit.custom + chmod +x .git/hooks/pre-commit.custom + + # Add custom pre-commit to existing hook chain + if [ -f ".git/hooks/pre-commit" ]; then + HOOK_CONTENT=$(cat .git/hooks/pre-commit) + if ! grep -q "pre-commit.custom" .git/hooks/pre-commit; then + echo -e "\n# Run custom pre-commit hook\n.git/hooks/pre-commit.custom || exit 1" >> .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit + fi + else + echo -e "#!/bin/bash\n\n# Run custom pre-commit hook\n.git/hooks/pre-commit.custom" > .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit + fi +fi + +pre-commit clean && pre-commit install && pre-commit install --hook-type commit-msg + +print_green "================================================================" +print_green "🎉 Git hooks setup complete! Your repository now has:" +print_green " - Sensitive information leak detection using gitleaks" +print_green " - Chinese character detection in commit messages" +print_green "================================================================" diff --git a/.git-hooks/post-commit b/.git-hooks/post-commit new file mode 100755 index 000000000..74ae8b053 --- /dev/null +++ b/.git-hooks/post-commit @@ -0,0 +1,27 @@ +#!/bin/bash + +# Check if required hooks are installed +if [ ! -f ".git/hooks/commit-msg" ] || [ ! -x ".git/hooks/commit-msg" ]; then + echo "============================================================" + echo "Note: Git hooks for checking Chinese characters in commit messages are not installed." + echo "Please run the following commands to install:" + echo "" + echo " 1. Install pre-commit:" + echo " pip install pre-commit" + echo "" + echo " 2. Install pre-commit hook:" + echo " pre-commit install" + echo "" + echo " 3. Install commit-msg hook:" + echo " pre-commit install --hook-type commit-msg" + echo " cp .git-hooks/check-commit-message.sh .git/hooks/commit-msg" + echo " chmod +x .git/hooks/commit-msg" + echo "" + echo "These hooks will help detect sensitive information leaks and Chinese characters in commit messages." + echo "============================================================" +fi + +# Ensure the hook itself is executable +if [ -f ".git-hooks/check-commit-message.sh" ] && [ ! -x ".git-hooks/check-commit-message.sh" ]; then + chmod +x .git-hooks/check-commit-message.sh +fi \ No newline at end of file diff --git a/.git-hooks/pre-commit b/.git-hooks/pre-commit new file mode 100755 index 000000000..57221d159 --- /dev/null +++ b/.git-hooks/pre-commit @@ -0,0 +1,25 @@ +#!/bin/bash + +# Check if gitleaks is configured +if ! command -v gitleaks &> /dev/null; then + echo "============================================================" + echo "Gitleaks not detected. This is a required tool to prevent sensitive information leaks." + echo "Please install gitleaks first: https://github.com/gitleaks/gitleaks#installing" + echo "After installation, run: ./.git-hooks/install-hooks.sh" + echo "============================================================" + exit 1 +fi + +# Check for sensitive information +if [ -f ".gitleaks.toml" ]; then + gitleaks detect --source . --config .gitleaks.toml + if [ $? -ne 0 ]; then + echo "Gitleaks detected sensitive information. Commit rejected." + echo "Please review the output above and remove sensitive information." + exit 1 + fi +else + echo "No .gitleaks.toml configuration file found, skipping sensitive information check." +fi + +exit 0 \ No newline at end of file diff --git a/.githooks/pre-commit b/.githooks/pre-commit deleted file mode 100755 index d662cda96..000000000 --- a/.githooks/pre-commit +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=$(git hash-object -t tree /dev/null) -fi - -SCRIPT_DIR=$(dirname "$0") -SCRIPT_ABS_PATH=`cd "$SCRIPT_DIR"; pwd` - - -ANDROID_DIFF_FILES=`git diff --cached --name-only --diff-filter=ACM -- '*' | grep 'Android'` -if [[ "$ANDROID_DIFF_FILES" != "" ]] -then - cd Android/APIExample - echo "precommit >> current paht = $(pwd), diff files = $ANDROID_DIFF_FILES" - ./gradlew -Dorg.gradle.project.commit_diff_files="$ANDROID_DIFF_FILES" checkstyle detekt - if [ $? -eq 0 ]; then - echo "precommit >> checkstyle detekt OK." - else - echo "precommit >> checkstyle detekt Failed." - exit 1 - fi -else - echo "precommit >> No changing android files." -fi - - diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 000000000..46489f554 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,142 @@ +title = "gitleaks config" + +# Gitleaks rules are defined by regular expressions and entropy ranges. +# Some secrets have unique signatures which make detecting those secrets easy. +# Examples of those secrets would be GitLab Personal Access Tokens, AWS keys, and GitHub Access Tokens. +# All these examples have defined prefixes like `glpat`, `AKIA`, `ghp_`, etc. +# +# Other secrets might just be a hash which means we need to write more complex rules to verify +# that what we are matching is a secret. +# +# Here is an example of a semi-generic secret +# +# discord_client_secret = "8dyfuiRyq=vVc3RRr_edRk-fK__JItpZ" +# +# We can write a regular expression to capture the variable name (identifier), +# the assignment symbol (like '=' or ':='), and finally the actual secret. +# The structure of a rule to match this example secret is below: +# +# Beginning string +# quotation +# │ End string quotation +# │ │ +# ▼ ▼ +# (?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9=_\-]{32})['\"] +# +# ▲ ▲ ▲ +# │ │ │ +# │ │ │ +# identifier assignment symbol +# Secret +# + +[extend] +useDefault = true + +[[rules]] +id = "chinese-characters" +description = "Detecting Chinese characters" +regex = '''[\p{Han}]+''' +tags = ["chinese"] + +[[rules]] +id = "chinese-comments" +description = "Detect Chinese comments" +regex = '''(//|#|/\*|\*).*[\p{Han}]+''' +tags = ["chinese", "comments"] + +[[rules]] +id = "agora-app-id-pattern" +description = "Agora App ID Pattern" +regex = '''(?i)(AGORA_APP_ID|AG_APP_ID|static\s+let\s+AppId:\s+String|static\s+let\s+AG_APP_ID:\s+String)(\s*=\s*)(?:['"]?([0-9a-zA-Z]{1,32})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "agora-app-certificate-pattern" +description = "Agora App Certificate Pattern" +regex = '''(?i)(AGORA_APP_CERTIFICATE|AG_APP_CERTIFICATE|static\s+let\s+Certificate:\s+String\?|static\s+let\s+AG_APP_CERTIFICATE:\s+String)(\s*=\s*)(?:['"]?([0-9a-zA-Z]{1,32})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "basic-auth-key" +description = "Basic Auth Key" +regex = '''(?i)(BASIC_AUTH_KEY|static\s+let\s+BASIC_AUTH_KEY:\s+String)(\s*=\s*)(?:['"]?([0-9a-zA-Z\-_=]{1,64})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "basic-auth-secret" +description = "Basic Auth Secret" +regex = '''(?i)(BASIC_AUTH_SECRET|static\s+let\s+BASIC_AUTH_SECRET:\s+String)(\s*=\s*)(?:['"]?([0-9a-zA-Z\-_=]{1,64})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "llm-api-key" +description = "LLM API Key" +regex = '''(?i)(LLM_API_KEY|static\s+let\s+LLM_API_KEY:\s+String)(\s*=\s*)(?:['"]?([a-zA-Z0-9\-_]{1,100})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "llm-url-with-key" +description = "LLM URL with API Key" +regex = '''(?i)(LLM_URL|static\s+let\s+LLM_URL:\s+String)(\s*=\s*)['"]?(https?:\/\/[^\s'"]+?(?:api_key|apikey|token|secret|password|key)=[^\s'"&]+)['"]?''' +secretGroup = 3 + +[[rules]] +id = "tts-key-pattern" +description = "TTS API Key in Parameters" +regex = '''(?i)(TTS_PARAMS|static\s+let\s+TTS_PARAMS)(\s*=\s*)(?:['"]?.*["']key["']:\s*["']([a-zA-Z0-9\-_]{1,64})["'].*['"]?)''' +secretGroup = 3 + +[[rules]] +id = "im-app-key-pattern" +description = "IM App Key Pattern" +regex = '''(?i)(IM_APP_KEY|static\s+var\s+IMAppKey:\s+String\?)(\s*=\s*)(?:['"]?([0-9a-zA-Z#]{1,64})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "im-client-id-pattern" +description = "IM Client ID Pattern" +regex = '''(?i)(IM_APP_CLIENT_ID|static\s+var\s+IMClientId:\s+String\?)(\s*=\s*)(?:['"]?([0-9a-zA-Z]{1,64})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "im-client-secret-pattern" +description = "IM Client Secret Pattern" +regex = '''(?i)(IM_APP_CLIENT_SECRET|static\s+var\s+IMClientSecret:\s+String\?)(\s*=\s*)(?:['"]?([0-9a-zA-Z\-_=]{1,64})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "restful-api-key-pattern" +description = "Restful API Key Pattern" +regex = '''(?i)(RESTFUL_API_KEY|static\s+let\s+RestfulApiKey:\s+String\?)(\s*=\s*)(?:['"]?([0-9a-zA-Z\-_=]{1,64})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "restful-api-secret-pattern" +description = "Restful API Secret Pattern" +regex = '''(?i)(RESTFUL_API_SECRET|static\s+let\s+RestfulApiSecret:\s+String\?)(\s*=\s*)(?:['"]?([0-9a-zA-Z\-_=]{1,64})['"]?)''' +secretGroup = 3 + +[[rules]] +id = "openai-api-key" +description = "OpenAI API Key Pattern" +regex = '''(?i)sk-(live|test|proj)-[0-9a-zA-Z]{24,48}''' + +[allowlist] +description = "global allow lists" +regexes = ['''219-09-9999''', '''078-05-1120''', '''(9[0-9]{2}|666)-\d{2}-\d{4}'''] +paths = [ + '''gitleaks.toml''', + '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', + '''(go.mod|go.sum)$''', + '''iOS/.*\.strings''', + '''iOS/.*\.lproj/.*''', + '''iOS/Scenes/ConvoAI/.*''', + '''.*\.strings$''', + '''.*\.strings''', + '''.*\/zh-Hans\.lproj\/.*''', + '''.*\/zh-Hant\.lproj\/.*''', + '''.*\/zh\.lproj\/.*''', + '''iOS/Pods/.*''', + '''README\.md''' +] \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..b06a5f51f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.24.2 + hooks: + - id: gitleaks + args: ["--config=.gitleaks.toml"] + + - repo: local + hooks: + - id: check-commit-message + name: Check commit message for Chinese characters + description: Ensures commit messages do not contain Chinese characters + entry: .git-hooks/check-commit-message.sh + language: script + stages: [commit-msg] diff --git a/HOOKS-GUIDE.md b/HOOKS-GUIDE.md new file mode 100644 index 000000000..a0a79aba3 --- /dev/null +++ b/HOOKS-GUIDE.md @@ -0,0 +1,75 @@ +# Git Hook Installation Guide + +This project uses Git hooks to prevent sensitive information leaks and check commit messages. After cloning the code for the first time, please follow these steps to install the hooks: + +## One-click installation + +Execute the following command to install all necessary Git hooks with one click: + +```bash +./.git-hooks/install-hooks.sh +``` + +## Hook Features + +After installation, the following features will be enabled: + +1. **Sensitive Information Detection** (Based on Gitleaks) + +- Detect sensitive information such as API keys and tokens in the code + +- Block code submissions containing sensitive information + +2. **Commit Message Inspection** + +- Detect and block commit messages containing Chinese characters + +- Ensure commit messages use only English +## Manual Installation + +If the automatic installation fails, you can manually follow these steps: + +1. Install pre-commit: + +```bash + +pip install pre-commit + +``` + +2. Install the pre-commit hook: + +```bash + +pre-commit install + +``` + +3. Install the commit-msg hook: + ```bash + pre-commit install --hook-type commit-msg + cp .git-hooks/check-commit-message.sh .git/hooks/commit-msg + chmod +x .git/hooks/commit-msg + ``` + +## Frequently Asked Questions + +**Q: How to temporarily skip hook checks?** + +A: In special cases, you can use the `--no-verify` parameter to skip checks: + +```bash + +git commit -m "Your commit message" --no-verify + +``` + +However, use this parameter with caution to avoid leaking sensitive information. + +**Q: How to allow Chinese content in specific files?** + +A: Modify the `allowlist` section in the `.gitleaks.toml` file and add the corresponding file paths. + +**Q: Getting a "Chinese characters detected" prompt when committing?** + +A: Commit messages must not contain Chinese characters. Please write commit messages in English only. \ No newline at end of file