Last active
March 26, 2026 14:43
-
-
Save homanp/083184bfc57140af4ce443dfa5804b42 to your computer and use it in GitHub Desktop.
Commit Security Scan
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: PR Security Scan | |
| on: | |
| pull_request_target: | |
| types: [opened, reopened, synchronize, ready_for_review] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| scan: | |
| name: Scan PR | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| concurrency: | |
| group: brin-pr-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Scan PR with Brin | |
| id: scan | |
| shell: bash | |
| env: | |
| REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| set -euo pipefail | |
| RESPONSE=$(curl -sfL --max-time 300 \ | |
| "https://api.brin.sh/pr/${REPO}/${PR_NUMBER}?details=true&mode=full&tolerance=conservative" \ | |
| || echo '{}') | |
| SCORE=$(jq -r '.score // empty' <<<"$RESPONSE") | |
| VERDICT=$(jq -r '.verdict // "unknown"' <<<"$RESPONSE") | |
| PENDING=$(jq -r '.pending_deep_scan // false' <<<"$RESPONSE") | |
| if [ -z "$SCORE" ] || [ "$PENDING" = "true" ]; then | |
| echo "status=inconclusive" >> "$GITHUB_OUTPUT" | |
| echo "should_fail=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "score=${SCORE}" >> "$GITHUB_OUTPUT" | |
| echo "verdict=${VERDICT}" >> "$GITHUB_OUTPUT" | |
| if [ "$VERDICT" = "dangerous" ] || [ "$SCORE" -lt 30 ]; then | |
| echo "status=blocking" >> "$GITHUB_OUTPUT" | |
| echo "should_fail=true" >> "$GITHUB_OUTPUT" | |
| elif [ "$VERDICT" = "suspicious" ]; then | |
| echo "status=review" >> "$GITHUB_OUTPUT" | |
| echo "should_fail=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "status=clean" >> "$GITHUB_OUTPUT" | |
| echo "should_fail=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| THREATS=$(jq -r '(.threats // [])[] | "- \(.type): \(.detail)"' <<<"$RESPONSE") | |
| { | |
| echo "threats<<BRIN_EOF" | |
| echo "$THREATS" | |
| echo "BRIN_EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Comment on flagged PR | |
| if: steps.scan.outputs.status == 'blocking' || steps.scan.outputs.status == 'review' | |
| uses: actions/github-script@v7 | |
| env: | |
| SCORE: ${{ steps.scan.outputs.score }} | |
| VERDICT: ${{ steps.scan.outputs.verdict }} | |
| STATUS: ${{ steps.scan.outputs.status }} | |
| THREATS: ${{ steps.scan.outputs.threats }} | |
| with: | |
| script: | | |
| const marker = "<!-- brin-pr-scan -->"; | |
| const { owner, repo } = context.repo; | |
| const issue_number = context.payload.pull_request.number; | |
| const headline = process.env.STATUS === "blocking" | |
| ? "This PR has findings that should block merge." | |
| : "This PR has findings that should be reviewed."; | |
| let body = `${marker}\n### Brin PR Security Scan\n\n`; | |
| body += `${headline}\n\n`; | |
| body += `- **Score:** ${process.env.SCORE}/100\n`; | |
| body += `- **Verdict:** ${process.env.VERDICT}\n\n`; | |
| if (process.env.THREATS) { | |
| body += `**Findings:**\n${process.env.THREATS}\n\n`; | |
| } | |
| body += `<sub>Analyzed by [Brin](https://brin.sh)</sub>`; | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner, repo, issue_number, per_page: 100, | |
| }); | |
| const existing = comments.find((c) => 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: Delete old comment when clean | |
| if: steps.scan.outputs.status == 'clean' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const marker = "<!-- brin-pr-scan -->"; | |
| const { owner, repo } = context.repo; | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner, repo, | |
| issue_number: context.payload.pull_request.number, | |
| per_page: 100, | |
| }); | |
| const existing = comments.find((c) => c.body?.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.deleteComment({ owner, repo, comment_id: existing.id }); | |
| } | |
| - name: Fail if blocking | |
| if: steps.scan.outputs.should_fail == 'true' | |
| run: | | |
| echo "::error::Brin flagged this PR as dangerous or scoring below 30" | |
| exit 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment