Merge pull request #1 from EdgarPsda/v0.2.0-changes #15
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: ["main"] | |
| pull_request: | |
| permissions: | |
| contents: read | |
| issues: write | |
| pull-requests: write | |
| jobs: | |
| security: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Prepare artifacts directory | |
| run: mkdir -p artifacts/security | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.21" | |
| - name: Install dependencies | |
| run: go mod download | |
| - name: Run Semgrep | |
| uses: returntocorp/semgrep-action@v1 | |
| with: | |
| config: "p/ci" | |
| - name: Run Gitleaks | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Run Trivy FS Scan | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: fs | |
| format: json | |
| output: artifacts/security/trivy-fs.json | |
| severity: HIGH,CRITICAL | |
| - name: Generate security summary (JSON) | |
| if: always() | |
| run: | | |
| echo "Generating security summary..." | |
| mkdir -p artifacts/security | |
| # Gitleaks: count total findings (supports array or {findings:[...]}) | |
| if [ -f artifacts/security/gitleaks-report.json ]; then | |
| GITLEAKS_COUNT=$(jq 'if type=="array" then length else (.findings | length // 0) end' artifacts/security/gitleaks-report.json) | |
| else | |
| GITLEAKS_COUNT=0 | |
| fi | |
| # Trivy: group vulnerabilities by severity (CRITICAL/HIGH/etc.) | |
| if [ -f artifacts/security/trivy-fs.json ]; then | |
| TRIVY_SUMMARY=$(jq ' | |
| ( [ .Results[].Vulnerabilities[]? | .Severity ] | |
| | group_by(.) | |
| | map({ (.[0]): length }) | |
| | add | |
| ) // {}' artifacts/security/trivy-fs.json) | |
| else | |
| TRIVY_SUMMARY='{}' | |
| fi | |
| jq -n \ | |
| --argjson gitleaks_count "$GITLEAKS_COUNT" \ | |
| --argjson trivy "$TRIVY_SUMMARY" \ | |
| '{ gitleaks: { total: $gitleaks_count }, trivy: $trivy }' \ | |
| > artifacts/security/summary.json | |
| echo "Summary written to artifacts/security/summary.json" | |
| - name: Post security summary as PR comment | |
| if: always() && github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const fs = require('fs'); | |
| const path = 'artifacts/security/summary.json'; | |
| const marker = '<!-- devsecops-kit-security-summary -->'; | |
| let summary; | |
| try { | |
| const raw = fs.readFileSync(path, 'utf8'); | |
| summary = JSON.parse(raw); | |
| } catch (err) { | |
| core.warning(`Could not read ${path}: ${err}`); | |
| summary = null; | |
| } | |
| let body = `${marker}\n`; | |
| body += '### 🔐 DevSecOps Kit Security Summary\n\n'; | |
| if (!summary) { | |
| body += '_No summary.json available. Check workflow logs._\n'; | |
| } else { | |
| const gitleaksTotal = summary?.gitleaks?.total ?? 0; | |
| const trivy = summary?.trivy || {}; | |
| body += `- **Gitleaks:** ${gitleaksTotal} leak(s)\n`; | |
| const severities = Object.keys(trivy); | |
| if (severities.length > 0) { | |
| body += '- **Trivy vulnerabilities:**\n'; | |
| for (const sev of severities.sort()) { | |
| body += ` - ${sev}: ${trivy[sev]}\n`; | |
| } | |
| } else { | |
| body += '- **Trivy vulnerabilities:** none counted in summary\n'; | |
| } | |
| const hasBlocking = | |
| gitleaksTotal > 0 || | |
| (trivy.CRITICAL ?? 0) > 0 || | |
| (trivy.HIGH ?? 0) > 0; | |
| body += '\n'; | |
| body += hasBlocking | |
| ? '🚨 _Status: Potential blocking issues detected._\n' | |
| : '✅ _Status: No blocking issues detected (HIGH/CRITICAL)._ \n'; | |
| } | |
| const { owner, repo } = context.repo; | |
| const issue_number = context.issue.number; | |
| const comments = await github.rest.issues.listComments({ | |
| owner, | |
| repo, | |
| issue_number, | |
| }); | |
| const existing = comments.data.find(c => c.body && c.body.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner, | |
| repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number, | |
| body, | |
| }); | |
| } | |
| - name: Upload security artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: security-reports | |
| path: artifacts/security/ |