Security Checks #114
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 Checks | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| schedule: | |
| # Run security checks weekly on Monday at 00:00 UTC | |
| - cron: '0 0 * * 1' | |
| permissions: | |
| contents: read | |
| security-events: write | |
| jobs: | |
| secret-scanning: | |
| name: Secret Scanning | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for initial commit (Push) | |
| if: github.event_name == 'push' | |
| id: check_initial | |
| run: | | |
| if [ "${{ github.event.before }}" = "0000000000000000000000000000000000000000" ]; then | |
| echo "is_initial=true" >> $GITHUB_OUTPUT | |
| FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD) | |
| echo "first_commit=$FIRST_COMMIT" >> $GITHUB_OUTPUT | |
| else | |
| echo "is_initial=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: TruffleHog OSS (Push - Initial Commit) | |
| if: github.event_name == 'push' && steps.check_initial.outputs.is_initial == 'true' | |
| uses: trufflesecurity/trufflehog@main | |
| with: | |
| path: ./ | |
| base: ${{ steps.check_initial.outputs.first_commit }} | |
| head: ${{ github.sha }} | |
| extra_args: --only-verified | |
| - name: TruffleHog OSS (Push - Regular) | |
| if: github.event_name == 'push' && steps.check_initial.outputs.is_initial == 'false' | |
| uses: trufflesecurity/trufflehog@main | |
| with: | |
| path: ./ | |
| base: ${{ github.event.before }} | |
| head: ${{ github.sha }} | |
| extra_args: --only-verified | |
| - name: TruffleHog OSS (Pull Request) | |
| if: github.event_name == 'pull_request' | |
| uses: trufflesecurity/trufflehog@main | |
| with: | |
| path: ./ | |
| base: ${{ github.event.pull_request.base.sha }} | |
| head: ${{ github.event.pull_request.head.sha }} | |
| extra_args: --only-verified | |
| - name: TruffleHog OSS (Scheduled) | |
| if: github.event_name == 'schedule' | |
| uses: trufflesecurity/trufflehog@main | |
| with: | |
| path: ./ | |
| extra_args: --only-verified | |
| license-check: | |
| name: License Compliance | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up JDK 21 | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: '21' | |
| distribution: 'temurin' | |
| cache: gradle | |
| - name: Validate Gradle wrapper | |
| uses: gradle/actions/wrapper-validation@v5 | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v5 | |
| with: | |
| gradle-home-cache-cleanup: true | |
| - name: Check license headers with Spotless | |
| run: | | |
| echo "Checking for Apache License headers using Spotless..." | |
| ./gradlew spotlessCheck --no-daemon | |
| if [ $? -eq 0 ]; then | |
| echo "✅ All Java files have proper license headers and formatting" | |
| else | |
| echo "❌ Spotless check failed!" | |
| echo "" | |
| echo "Some files are missing license headers or need formatting." | |
| echo "To fix, run locally:" | |
| echo " ./gradlew spotlessApply" | |
| echo "Then commit and push the changes." | |
| exit 1 | |
| fi | |
| - name: Verify required files exist | |
| run: | | |
| echo "Checking for required legal files..." | |
| required_files=( | |
| "LICENSE" | |
| "NOTICE" | |
| "SECURITY.md" | |
| "CODE_OF_CONDUCT.md" | |
| "CONTRIBUTING.md" | |
| ) | |
| missing=0 | |
| for file in "${required_files[@]}"; do | |
| if [ ! -f "$file" ]; then | |
| echo "❌ Missing required file: $file" | |
| missing=$((missing + 1)) | |
| else | |
| echo "✅ Found: $file" | |
| fi | |
| done | |
| if [ $missing -gt 0 ]; then | |
| echo "⚠️ Missing $missing required file(s)" | |
| exit 1 | |
| fi | |
| sensitive-data-check: | |
| name: Sensitive Data Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Check for accidentally committed secrets | |
| run: | | |
| echo "Checking for sensitive files that should not be committed..." | |
| sensitive_patterns=( | |
| "config.json" | |
| "service-account.json" | |
| "*.key" | |
| "*.pem" | |
| "*.p12" | |
| ".env" | |
| "id_rsa" | |
| "id_dsa" | |
| "*.ppk" | |
| "database.properties" | |
| "oauth-secrets.json" | |
| "client_secret*.json" | |
| ) | |
| found_sensitive=0 | |
| for pattern in "${sensitive_patterns[@]}"; do | |
| files=$(find . -name "$pattern" -not -path "*/build/*" -not -path "*/.gradle/*" 2>/dev/null || true) | |
| if [ -n "$files" ]; then | |
| echo "⚠️ Found potentially sensitive file(s) matching pattern: $pattern" | |
| echo "$files" | |
| found_sensitive=1 | |
| fi | |
| done | |
| if [ $found_sensitive -eq 1 ]; then | |
| echo "" | |
| echo "❌ Sensitive files detected in repository!" | |
| echo "These files should be in .gitignore and removed from git history" | |
| echo "If these files were committed, they should be removed and credentials rotated" | |
| exit 1 | |
| else | |
| echo "✅ No sensitive files detected in repository" | |
| fi | |
| - name: Check for hardcoded secrets in code | |
| run: | | |
| echo "Checking for potential hardcoded secrets..." | |
| # Search for common secret patterns | |
| secrets_found=0 | |
| # Discord bot tokens | |
| if grep -r "discord.*token.*=.*[\"'][A-Za-z0-9._-]\{50,\}[\"']" --include="*.java" --exclude-dir="build" . ; then | |
| echo "⚠️ Possible Discord token found in code" | |
| secrets_found=1 | |
| fi | |
| # Database passwords | |
| if grep -r "password.*=.*[\"'][^\"']\{8,\}[\"']" --include="*.java" --include="*.properties" --exclude-dir="build" . | grep -v "example" | grep -v "your_password"; then | |
| echo "⚠️ Possible hardcoded password found" | |
| secrets_found=1 | |
| fi | |
| # API keys | |
| if grep -r "api[_-]key.*=.*[\"'][A-Za-z0-9]\{20,\}[\"']" --include="*.java" --exclude-dir="build" . ; then | |
| echo "⚠️ Possible API key found in code" | |
| secrets_found=1 | |
| fi | |
| if [ $secrets_found -eq 1 ]; then | |
| echo "" | |
| echo "❌ Potential secrets detected in code!" | |
| echo "Please use environment variables or config files (that are gitignored)" | |
| exit 1 | |
| else | |
| echo "✅ No obvious hardcoded secrets detected" | |
| fi | |
| security-summary: | |
| name: Security Summary | |
| runs-on: ubuntu-latest | |
| needs: [secret-scanning, license-check, sensitive-data-check] | |
| if: always() | |
| steps: | |
| - name: Check results | |
| run: | | |
| echo "🔒 Security scan completed" | |
| echo "" | |
| echo "Results:" | |
| echo "- Secret Scanning: ${{ needs.secret-scanning.result }}" | |
| echo "- License Compliance: ${{ needs.license-check.result }}" | |
| echo "- Sensitive Data Check: ${{ needs.sensitive-data-check.result }}" | |
| echo "" | |
| if [ "${{ needs.secret-scanning.result }}" == "failure" ] || \ | |
| [ "${{ needs.license-check.result }}" == "failure" ] || \ | |
| [ "${{ needs.sensitive-data-check.result }}" == "failure" ]; then | |
| echo "❌ Security checks failed! Please review and fix issues." | |
| exit 1 | |
| else | |
| echo "✅ All critical security checks passed!" | |
| fi | |
| echo "" | |
| echo "ℹ️ Note: Dependency security is handled by GitHub's Dependabot and Dependency Review Action" | |