name: Dotenv Configuration Check on: push: branches: ["**"] paths: - '.env.example' - 'scripts/focused_dotenv_linter.py' - '**/*.py' - '**/*.yml' - '**/*.yaml' - '**/*.toml' - '**/*.sh' - '**/*.bash' - '**/*.zsh' pull_request: branches: ["**"] paths: - '.env.example' - 'scripts/focused_dotenv_linter.py' - '**/*.py' - '**/*.yml' - '**/*.yaml' - '**/*.toml' - '**/*.sh' - '**/*.bash' - '**/*.zsh' jobs: dotenv-check: runs-on: ubuntu-latest name: Check .env.example Configuration Drift steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.13' cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip - name: Check .env.example drift run: | python scripts/focused_dotenv_linter.py --check --verbose - name: Generate configuration report run: | python scripts/focused_dotenv_linter.py > dotenv-report.txt - name: Upload configuration report uses: actions/upload-artifact@v4 if: always() with: name: dotenv-configuration-report path: dotenv-report.txt retention-days: 30 - name: Comment PR with configuration issues if: failure() && github.event_name == 'pull_request' uses: actions/github-script@v6 with: script: | const fs = require('fs'); try { const report = fs.readFileSync('dotenv-report.txt', 'utf8'); const comment = `## 🔍 Configuration Drift Detected The focused dotenv linter found configuration drift between \`.env.example\` and actual environment variable usage in the codebase.
Click to see full report \`\`\` ${report} \`\`\`
### 🔧 How to Fix 1. **Auto-fix missing variables:** \`\`\`bash python scripts/focused_dotenv_linter.py --fix \`\`\` 2. **Review unused variables:** - Remove variables from \`.env.example\` that are no longer used - Or add them to the linter's exclusion list if they're needed for external tools 3. **Run locally:** \`\`\`bash python scripts/focused_dotenv_linter.py --verbose \`\`\` This prevents silent configuration drift and ensures all environment variables are properly documented.`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: comment }); } catch (error) { console.log('Could not read dotenv report:', error); } dotenv-validation: runs-on: ubuntu-latest name: Validate .env.example Format needs: dotenv-check steps: - name: Checkout uses: actions/checkout@v4 - name: Validate .env.example format run: | # Check if .env.example exists and is readable if [ ! -f ".env.example" ]; then echo "❌ .env.example file not found" exit 1 fi # Check for common format issues echo "🔍 Validating .env.example format..." # Check for lines without equals signs (excluding comments and empty lines) invalid_lines=$(grep -v '^#' .env.example | grep -v '^$' | grep -v '=' | wc -l) if [ "$invalid_lines" -gt 0 ]; then echo "❌ Found $invalid_lines lines without '=' in .env.example" grep -v '^#' .env.example | grep -v '^$' | grep -v '=' | head -5 exit 1 fi # Check for variables with spaces (should be uppercase with underscores) invalid_vars=$(grep -v '^#' .env.example | grep -v '^$' | cut -d'=' -f1 | grep -E '[a-z]' | grep -v '^HTTP_PROXY$' | grep -v '^HTTPS_PROXY$' | grep -v '^NO_PROXY$' | wc -l) if [ "$invalid_vars" -gt 0 ]; then echo "⚠️ Found $invalid_vars variables with lowercase letters (should be uppercase):" grep -v '^#' .env.example | grep -v '^$' | cut -d'=' -f1 | grep -E '[a-z]' | grep -v '^HTTP_PROXY$' | grep -v '^HTTPS_PROXY$' | grep -v '^NO_PROXY$' | head -5 echo "Consider using uppercase variable names for consistency." fi # Check for duplicate variables duplicates=$(grep -v '^#' .env.example | grep -v '^$' | cut -d'=' -f1 | sort | uniq -d | wc -l) if [ "$duplicates" -gt 0 ]; then echo "❌ Found $duplicates duplicate variable names:" grep -v '^#' .env.example | grep -v '^$' | cut -d'=' -f1 | sort | uniq -d exit 1 fi echo "✅ .env.example format validation passed" dotenv-security: runs-on: ubuntu-latest name: Security Check for .env.example needs: dotenv-check steps: - name: Checkout uses: actions/checkout@v4 - name: Security check for sensitive data run: | echo "🔒 Checking .env.example for sensitive data..." # Check for potential secrets (should be placeholder values) sensitive_patterns=( "password=" "secret=" "key=" "token=" "private_key=" "api_key=" "dsn=" ) found_issues=false for pattern in "${sensitive_patterns[@]}"; do # Look for lines that might contain actual secrets (not placeholders) if grep -i "$pattern" .env.example | grep -v -E "(your-|placeholder|example|test|dummy|change-|xxx|yyy|zzz)" | grep -v -E "^#" | head -3; then echo "⚠️ Potential actual secrets found with pattern: $pattern" found_issues=true fi done # Check for common placeholder patterns placeholder_count=$(grep -c -E "(your-|placeholder|example|test|dummy|change-|xxx|yyy|zzz)" .env.example || true) echo "📊 Found $placeholder_count placeholder values (good!)" if [ "$found_issues" = true ]; then echo "❌ Please replace actual secrets with placeholder values in .env.example" echo " Use patterns like: your-secret-here, placeholder-value, change-me" exit 1 fi echo "✅ Security check passed" dotenv-summary: runs-on: ubuntu-latest name: Configuration Summary needs: [dotenv-check, dotenv-validation, dotenv-security] if: always() steps: - name: Generate summary run: | echo "# 📋 .env.example Configuration Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Check results from previous jobs if [ "${{ needs.dotenv-check.result }}" == "success" ]; then echo "✅ **Configuration Drift Check**: Passed" >> $GITHUB_STEP_SUMMARY else echo "❌ **Configuration Drift Check**: Failed" >> $GITHUB_STEP_SUMMARY fi if [ "${{ needs.dotenv-validation.result }}" == "success" ]; then echo "✅ **Format Validation**: Passed" >> $GITHUB_STEP_SUMMARY else echo "❌ **Format Validation**: Failed" >> $GITHUB_STEP_SUMMARY fi if [ "${{ needs.dotenv-security.result }}" == "success" ]; then echo "✅ **Security Check**: Passed" >> $GITHUB_STEP_SUMMARY else echo "❌ **Security Check**: Failed" >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY echo "## 📊 Configuration Statistics" >> $GITHUB_STEP_SUMMARY # Count variables in .env.example var_count=$(grep -v '^#' .env.example | grep -v '^$' | wc -l) echo "- **Variables in .env.example**: $var_count" >> $GITHUB_STEP_SUMMARY # Count sections (based on comment headers) sections=$(grep '^# ====' .env.example | wc -l) echo "- **Configuration Sections**: $sections" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "## 🔧 Maintenance" >> $GITHUB_STEP_SUMMARY echo "- **Linter**: \`python scripts/focused_dotenv_linter.py\`" >> $GITHUB_STEP_SUMMARY echo "- **Auto-fix**: \`python scripts/focused_dotenv_linter.py --fix\`" >> $GITHUB_STEP_SUMMARY echo "- **Verbose**: \`python scripts/focused_dotenv_linter.py --verbose\`" >> $GITHUB_STEP_SUMMARY