fix: refactor methods to reduce cyclomatic complexity #251
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 Scan | |
| on: | |
| push: | |
| branches: [ master, develop ] | |
| pull_request: | |
| branches: [ master, develop ] | |
| # TODO: Reativar quando em produção | |
| # schedule: | |
| # # Run weekly on Monday at 9am UTC | |
| # - cron: '0 9 * * 1' | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| brakeman: | |
| name: Brakeman Security Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1 | |
| with: | |
| ruby-version: 3.4.5 | |
| bundler-cache: true | |
| - name: Install Brakeman | |
| run: gem install brakeman | |
| - name: Run Brakeman | |
| run: | | |
| brakeman --rails7 \ | |
| --format json \ | |
| --output brakeman-report.json \ | |
| --no-exit-on-warn \ | |
| --no-exit-on-error | |
| - name: Parse Results | |
| id: parse | |
| run: | | |
| WARNINGS=$(jq '.warnings | length' brakeman-report.json) | |
| HIGH=$(jq '[.warnings[] | select(.confidence == "High")] | length' brakeman-report.json) | |
| echo "warnings=$WARNINGS" >> $GITHUB_OUTPUT | |
| echo "high=$HIGH" >> $GITHUB_OUTPUT | |
| - name: Upload Report | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: brakeman-report | |
| path: brakeman-report.json | |
| - name: Comment PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6 | |
| with: | |
| script: | | |
| const warnings = '${{ steps.parse.outputs.warnings }}'; | |
| const high = '${{ steps.parse.outputs.high }}'; | |
| const body = `## 🔒 Brakeman Security Scan | |
| - Total warnings: ${warnings} | |
| - High confidence: ${high} | |
| ${high > 0 ? '⚠️ High confidence issues found! Please review.' : '✅ No high confidence issues found.'} | |
| `; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); | |
| - name: Fail on High Confidence Issues | |
| if: steps.parse.outputs.high > 0 | |
| run: | | |
| echo "::error::Found ${{ steps.parse.outputs.high }} high confidence security issues!" | |
| exit 1 | |
| dependency-check: | |
| name: Dependency Vulnerability Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1 | |
| with: | |
| ruby-version: 3.4.5 | |
| bundler-cache: true | |
| - name: Install Bundle Audit | |
| run: gem install bundler-audit | |
| - name: Update Vulnerability Database | |
| run: bundle-audit update | |
| - name: Run Bundle Audit | |
| id: audit | |
| run: | | |
| bundle-audit check --output bundle-audit.txt || echo "vulnerabilities=true" >> $GITHUB_OUTPUT | |
| cat bundle-audit.txt | |
| - name: Upload Report | |
| if: always() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: bundle-audit-report | |
| path: bundle-audit.txt | |
| - name: Comment PR | |
| if: github.event_name == 'pull_request' && always() | |
| uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const report = fs.readFileSync('bundle-audit.txt', 'utf8'); | |
| const hasVulns = report.includes('Vulnerabilities found'); | |
| const body = `## 📦 Dependency Security Check | |
| ${hasVulns ? '⚠️ Vulnerabilities found in dependencies!' : '✅ No known vulnerabilities found.'} | |
| <details> | |
| <summary>View Report</summary> | |
| \`\`\` | |
| ${report} | |
| \`\`\` | |
| </details> | |
| `; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); | |
| - name: Fail on Vulnerabilities | |
| if: steps.audit.outputs.vulnerabilities == 'true' | |
| run: | | |
| echo "::error::Vulnerable dependencies found!" | |
| exit 1 | |
| semgrep: | |
| name: Semgrep Static Analysis | |
| runs-on: ubuntu-latest | |
| container: | |
| image: returntocorp/semgrep | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Run Semgrep | |
| run: | | |
| semgrep scan \ | |
| --config=auto \ | |
| --json \ | |
| --output=semgrep-report.json \ | |
| --exclude 'scripts/' \ | |
| --exclude 'load_tests/' \ | |
| --exclude 'security_tests/' \ | |
| --exclude 'vendor/' \ | |
| --verbose \ | |
| || true | |
| echo "::group::Semgrep Report Preview" | |
| cat semgrep-report.json | head -c 5000 | |
| echo "" | |
| echo "::endgroup::" | |
| - name: Parse Results | |
| id: parse | |
| run: | | |
| # Count total results | |
| TOTAL=$(jq '.results | length' semgrep-report.json) | |
| # Count actual ERROR severity issues (not warnings) | |
| ERRORS=$(jq '.results | map(select(.extra.severity == "ERROR")) | length' semgrep-report.json) | |
| WARNINGS=$(jq '.results | map(select(.extra.severity == "WARNING")) | length' semgrep-report.json) | |
| # Count HIGH confidence security issues (excluding audit rules) | |
| CRITICAL=$(jq '.results | map(select(.extra.metadata.confidence == "HIGH" and (.extra.metadata.subcategory // "vuln") != "audit")) | length' semgrep-report.json) | |
| echo "errors=$ERRORS" >> $GITHUB_OUTPUT | |
| echo "warnings=$WARNINGS" >> $GITHUB_OUTPUT | |
| echo "critical=$CRITICAL" >> $GITHUB_OUTPUT | |
| echo "::notice::Semgrep Analysis Complete" | |
| echo "::notice:: - Total findings: $TOTAL" | |
| echo "::notice:: - ERROR severity: $ERRORS" | |
| echo "::notice:: - WARNING severity: $WARNINGS" | |
| echo "::notice:: - HIGH confidence (non-audit): $CRITICAL" | |
| # Show details of ERROR severity issues if any | |
| if [ "$ERRORS" -gt 0 ]; then | |
| echo "::group::ERROR Severity Issues" | |
| jq -r '.results[] | select(.extra.severity == "ERROR") | " - \(.path):\(.start.line) - \(.check_id)"' semgrep-report.json | |
| echo "::endgroup::" | |
| fi | |
| - name: Upload Report | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: semgrep-report | |
| path: semgrep-report.json | |
| - name: Comment PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6 | |
| with: | |
| script: | | |
| const errors = '${{ steps.parse.outputs.errors }}'; | |
| const warnings = '${{ steps.parse.outputs.warnings }}'; | |
| const critical = '${{ steps.parse.outputs.critical }}'; | |
| const body = `## 🔍 Semgrep Static Analysis | |
| - **Errors**: ${errors} | |
| - **Critical Issues**: ${critical} | |
| - **Warnings**: ${warnings} | |
| ${errors > 0 ? '❌ Security errors found! Please fix.' : critical > 0 ? '⚠️ High confidence security issues found. Please review.' : warnings > 0 ? '⚠️ Warnings found (non-blocking).' : '✅ No issues found.'} | |
| `; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); | |
| - name: Fail on Critical Errors | |
| if: steps.parse.outputs.errors > 0 | |
| run: | | |
| echo "::error::Semgrep found ${{ steps.parse.outputs.errors }} security errors with ERROR severity!" | |
| echo "::error::Review the semgrep-report.json artifact for details" | |
| exit 1 | |
| secret-scan: | |
| name: Secret Detection | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: TruffleHog Secret Scan | |
| uses: trufflesecurity/trufflehog@6961f2bace57ab32b23b3ba40f8f420f6bc7e004 # main | |
| with: | |
| path: ./ | |
| extra_args: --only-verified | |
| security-summary: | |
| name: Security Summary | |
| runs-on: ubuntu-latest | |
| needs: [brakeman, dependency-check, semgrep] | |
| if: always() | |
| steps: | |
| - name: Check Results | |
| run: | | |
| echo "Brakeman: ${{ needs.brakeman.result }}" | |
| echo "Dependency Check: ${{ needs.dependency-check.result }}" | |
| echo "Semgrep: ${{ needs.semgrep.result }}" | |
| - name: Post Summary | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6 | |
| with: | |
| script: | | |
| const brakeman = '${{ needs.brakeman.result }}'; | |
| const deps = '${{ needs.dependency-check.result }}'; | |
| const semgrep = '${{ needs.semgrep.result }}'; | |
| const status = (result) => { | |
| switch(result) { | |
| case 'success': return '✅'; | |
| case 'failure': return '❌'; | |
| default: return '⚠️'; | |
| } | |
| }; | |
| const body = `## 🔐 Security Scan Summary | |
| | Check | Status | | |
| |-------|--------| | |
| | Brakeman | ${status(brakeman)} ${brakeman} | | |
| | Dependencies | ${status(deps)} ${deps} | | |
| | Semgrep | ${status(semgrep)} ${semgrep} | | |
| ${brakeman === 'success' && deps === 'success' && semgrep === 'success' | |
| ? '✅ All security checks passed!' | |
| : '⚠️ Some security checks failed. Please review the details above.'} | |
| `; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body | |
| }); |