docs: Translate deployment strategy to Chinese and link in README #40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Security - Check for Private Keys | |
| on: | |
| pull_request: | |
| branches: [ main, master, develop ] | |
| push: | |
| branches: [ main, master, develop ] | |
| jobs: | |
| check-secrets: | |
| runs-on: ubuntu-latest | |
| name: Scan for Private Keys and Secrets | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for private keys and sensitive data | |
| run: | | |
| #!/bin/bash | |
| set -e | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' | |
| # 排除的目录 (新增 singleton-paymaster 和 deprecated) | |
| EXCLUDED_DIRS="node_modules|\.git|\.netlify|\.svelte-kit|build|dist|\.next|contracts/broadcast|contracts/cache|contracts/lib|test-results|playwright-report|\.auth|vendor|cache|out|singleton-paymaster|deprecated" | |
| # 扫描的文件扩展名 | |
| SCAN_EXTENSIONS="\.(ts|tsx|js|jsx|svelte|sol|md|json|env|example|toml|yaml|yml)$" | |
| echo -e "${BLUE}🔒 GitHub Actions: Scanning repository for private keys...${NC}\n" | |
| # 获取所有文件(排除特定目录) | |
| FILES_TO_SCAN=$(find . -type f | grep -E "$SCAN_EXTENSIONS" | grep -v -E "$EXCLUDED_DIRS" || true) | |
| if [ -z "$FILES_TO_SCAN" ]; then | |
| echo -e "${GREEN}✅ No files to scan${NC}" | |
| exit 0 | |
| fi | |
| FILE_COUNT=$(echo "$FILES_TO_SCAN" | wc -l | tr -d ' ') | |
| echo -e "${BLUE}📋 Scanning ${FILE_COUNT} file(s) for secrets...${NC}\n" | |
| # 检测模式 | |
| # 1. Ethereum private key (more specific to avoid common hashes) | |
| # We look for common key-like assignments or standalone 64-char hex in sensitive files | |
| ETHEREUM_KEY_PATTERN='(key|secret|pk|private).{0,10}0x[a-fA-F0-9]{64}' | |
| # 2. PEM format private keys | |
| PEM_PATTERN='BEGIN.*PRIVATE KEY' | |
| # 3. AWS access key | |
| AWS_ACCESS_PATTERN='AKIA[0-9A-Z]{16}' | |
| # 4. AWS secret key | |
| AWS_SECRET_PATTERN='aws_secret_access_key[[:space:]]*=[[:space:]]*[a-zA-Z0-9/+]{40}' | |
| # 5. Private key with actual hex value | |
| PRIVATE_KEY_WITH_VALUE_PATTERN='private[_-]key[[:space:]]*[:=][[:space:]]*0x[a-fA-F0-9]{32,}' | |
| # 6. OpenAI API keys (sk-... or sk-proj-...) | |
| OPENAI_KEY_PATTERN='sk-[a-zA-Z0-9]{48,}' | |
| OPENAI_PROJ_KEY_PATTERN='sk-proj-[a-zA-Z0-9_-]{48,}' | |
| # 7. Google AI (Gemini) API keys (AIza...) | |
| GOOGLE_AI_KEY_PATTERN='AIza[a-zA-Z0-9_-]{35,}' | |
| # 8. Anthropic (Claude) API keys (sk-ant-...) | |
| ANTHROPIC_KEY_PATTERN='sk-ant-[a-zA-Z0-9_-]{95,}' | |
| # 9. GitHub Personal Access Tokens (ghp_..., gho_..., ghs_...) | |
| GITHUB_PAT_PATTERN='gh[pousr]_[a-zA-Z0-9]{36,}' | |
| # 10. Stripe API keys (sk_live_..., sk_test_...) | |
| STRIPE_KEY_PATTERN='sk_(live|test)_[a-zA-Z0-9]{24,}' | |
| # 11. Generic API keys | |
| API_KEY_PATTERN='api[_-]key[[:space:]]*[:=][[:space:]]*[\"\\x27][a-zA-Z0-9]{32,}[\"\\x27]' | |
| FOUND_SECRETS=0 | |
| TOTAL_FINDINGS=0 | |
| for FILE in $FILES_TO_SCAN; do | |
| if [ ! -f "$FILE" ]; then | |
| continue | |
| fi | |
| FINDINGS="" | |
| # Check Ethereum keys | |
| if grep -nE "$ETHEREUM_KEY_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| FINDINGS="${FINDINGS} [CRITICAL] Ethereum Private Key (256-bit hex)\n" | |
| FINDINGS="${FINDINGS}$(grep -nE "$ETHEREUM_KEY_PATTERN" "$FILE" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| # Check PEM keys | |
| if grep -nE "$PEM_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| FINDINGS="${FINDINGS} [CRITICAL] PEM Private Key\n" | |
| FINDINGS="${FINDINGS}$(grep -nE "$PEM_PATTERN" "$FILE" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| # Check AWS access keys | |
| if grep -nE "$AWS_ACCESS_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| FINDINGS="${FINDINGS} [CRITICAL] AWS Access Key\n" | |
| FINDINGS="${FINDINGS}$(grep -nE "$AWS_ACCESS_PATTERN" "$FILE" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| # Check AWS secret keys | |
| if grep -nE "$AWS_SECRET_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| FINDINGS="${FINDINGS} [CRITICAL] AWS Secret Key\n" | |
| FINDINGS="${FINDINGS}$(grep -nE "$AWS_SECRET_PATTERN" "$FILE" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| # Check private keys with values | |
| if grep -nEi "$PRIVATE_KEY_WITH_VALUE_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| PRIVATE_KEY_LINES=$(grep -nEi "$PRIVATE_KEY_WITH_VALUE_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$PRIVATE_KEY_LINES" ]; then | |
| FINDINGS="${FINDINGS} [CRITICAL] Private Key with Hex Value\n" | |
| FINDINGS="${FINDINGS}$(echo "$PRIVATE_KEY_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| # Check OpenAI API keys | |
| if grep -nE "$OPENAI_KEY_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| OPENAI_LINES=$(grep -nE "$OPENAI_KEY_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$OPENAI_LINES" ]; then | |
| FINDINGS="${FINDINGS} [CRITICAL] OpenAI API Key\n" | |
| FINDINGS="${FINDINGS}$(echo "$OPENAI_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| if grep -nE "$OPENAI_PROJ_KEY_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| OPENAI_PROJ_LINES=$(grep -nE "$OPENAI_PROJ_KEY_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$OPENAI_PROJ_LINES" ]; then | |
| FINDINGS="${FINDINGS} [CRITICAL] OpenAI Project API Key\n" | |
| FINDINGS="${FINDINGS}$(echo "$OPENAI_PROJ_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| # Check Google AI (Gemini) API keys | |
| if grep -nE "$GOOGLE_AI_KEY_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| GOOGLE_LINES=$(grep -nE "$GOOGLE_AI_KEY_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$GOOGLE_LINES" ]; then | |
| FINDINGS="${FINDINGS} [CRITICAL] Google AI (Gemini) API Key\n" | |
| FINDINGS="${FINDINGS}$(echo "$GOOGLE_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| # Check Anthropic (Claude) API keys | |
| if grep -nE "$ANTHROPIC_KEY_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| ANTHROPIC_LINES=$(grep -nE "$ANTHROPIC_KEY_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$ANTHROPIC_LINES" ]; then | |
| FINDINGS="${FINDINGS} [CRITICAL] Anthropic (Claude) API Key\n" | |
| FINDINGS="${FINDINGS}$(echo "$ANTHROPIC_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| # Check GitHub tokens | |
| if grep -nE "$GITHUB_PAT_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| GITHUB_LINES=$(grep -nE "$GITHUB_PAT_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$GITHUB_LINES" ]; then | |
| FINDINGS="${FINDINGS} [CRITICAL] GitHub Personal Access Token\n" | |
| FINDINGS="${FINDINGS}$(echo "$GITHUB_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| # Check Stripe API keys | |
| if grep -nE "$STRIPE_KEY_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| STRIPE_LINES=$(grep -nE "$STRIPE_KEY_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$STRIPE_LINES" ]; then | |
| FINDINGS="${FINDINGS} [CRITICAL] Stripe API Key\n" | |
| FINDINGS="${FINDINGS}$(echo "$STRIPE_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| # Check API keys | |
| if grep -nEi "$API_KEY_PATTERN" "$FILE" > /dev/null 2>&1; then | |
| API_KEY_LINES=$(grep -nEi "$API_KEY_PATTERN" "$FILE" | grep -v "^[[:space:]]*#" | grep -v "^[[:space:]]*//") | |
| if [ -n "$API_KEY_LINES" ]; then | |
| FINDINGS="${FINDINGS} [WARNING] Possible API Key\n" | |
| FINDINGS="${FINDINGS}$(echo "$API_KEY_LINES" | head -3 | sed 's/^/ /')\n" | |
| FOUND_SECRETS=1 | |
| TOTAL_FINDINGS=$((TOTAL_FINDINGS + 1)) | |
| fi | |
| fi | |
| if [ -n "$FINDINGS" ]; then | |
| echo -e "${RED}❌ ${FILE}:${NC}" | |
| echo -e "$FINDINGS" | |
| fi | |
| done | |
| if [ $FOUND_SECRETS -eq 1 ]; then | |
| echo -e "${RED}========================================${NC}" | |
| echo -e "${RED}🚨 SECURITY ALERT: ${TOTAL_FINDINGS} secret(s) detected!${NC}\n" | |
| echo -e "${YELLOW}⚠️ Do NOT merge this code!${NC}\n" | |
| echo -e "Actions required:" | |
| echo -e " 1. ${YELLOW}Remove${NC} all private keys and secrets from the code" | |
| echo -e " 2. Use ${BLUE}.env${NC} files for sensitive data (add to ${BLUE}.gitignore${NC})" | |
| echo -e " 3. Rotate any exposed credentials immediately" | |
| echo -e " 4. Review git history for leaked secrets" | |
| echo -e " 5. Consider using tools like ${BLUE}git-secrets${NC} or ${BLUE}truffleHog${NC}\n" | |
| echo -e "${RED}========================================${NC}\n" | |
| # 设置 GitHub Actions 注解 | |
| echo "::error::Private keys or secrets detected in the codebase. Please remove them before merging." | |
| exit 1 | |
| fi | |
| echo -e "${GREEN}========================================${NC}" | |
| echo -e "${GREEN}✅ No private keys detected${NC}" | |
| echo -e "${GREEN}✅ Security check passed!${NC}" | |
| echo -e "${GREEN}========================================${NC}\n" | |
| exit 0 | |
| - name: Comment on PR (if secrets found) | |
| if: failure() && github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: '🚨 **Security Alert**: Private keys or secrets detected in this PR!\n\n' + | |
| '⚠️ Please remove all sensitive data before merging.\n\n' + | |
| 'Check the Actions log for details about what was found.' | |
| }) |