Last active
March 10, 2026 15:25
-
-
Save homanp/258bc8be96ef7abb74f2a6c1392a1890 to your computer and use it in GitHub Desktop.
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: Contributor Trust Check | |
| on: | |
| pull_request_target: | |
| types: [opened, reopened, synchronize] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| jobs: | |
| check: | |
| name: Scan PR author | |
| runs-on: ubuntu-24.04 | |
| concurrency: | |
| group: brin-check-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Query Brin API | |
| id: brin | |
| run: | | |
| AUTHOR="${{ github.event.pull_request.user.login }}" | |
| RESPONSE=$(curl -sf "https://api.brin.sh/contributor/${AUTHOR}?details=true&mode=full" || echo '{}') | |
| echo "response<<BRIN_EOF" >> "$GITHUB_OUTPUT" | |
| echo "$RESPONSE" >> "$GITHUB_OUTPUT" | |
| echo "BRIN_EOF" >> "$GITHUB_OUTPUT" | |
| - name: Apply label and comment | |
| uses: actions/github-script@v7 | |
| env: | |
| BRIN_RESPONSE: ${{ steps.brin.outputs.response }} | |
| with: | |
| script: | | |
| const marker = "<!-- brin-check -->"; | |
| const pr = context.payload.pull_request; | |
| let data; | |
| try { | |
| data = JSON.parse(process.env.BRIN_RESPONSE); | |
| } catch { | |
| core.warning("Failed to parse Brin API response"); | |
| return; | |
| } | |
| if (!data.score && data.score !== 0) { | |
| core.warning("Brin API returned no score"); | |
| return; | |
| } | |
| const score = data.score; | |
| const verdict = data.verdict ?? "unknown"; | |
| const confidence = data.confidence ?? "unknown"; | |
| const isSafe = verdict === "safe"; | |
| const labels = [ | |
| { name: "contributor:verified", color: "0969da", description: "Contributor passed trust analysis." }, | |
| { name: "contributor:flagged", color: "e16f24", description: "Contributor flagged for review by trust analysis." }, | |
| ]; | |
| for (const label of labels) { | |
| try { | |
| const { data: existing } = await github.rest.issues.getLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: label.name, | |
| }); | |
| if (existing.color !== label.color || (existing.description ?? "") !== label.description) { | |
| await github.rest.issues.updateLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: label.name, | |
| color: label.color, | |
| description: label.description, | |
| }); | |
| } | |
| } catch (error) { | |
| if (error.status !== 404) throw error; | |
| await github.rest.issues.createLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: label.name, | |
| color: label.color, | |
| description: label.description, | |
| }); | |
| } | |
| } | |
| const nextLabel = isSafe ? "contributor:verified" : "contributor:flagged"; | |
| const labelNames = labels.map((l) => l.name); | |
| const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| }); | |
| const preserved = currentLabels | |
| .map((l) => l.name) | |
| .filter((name) => !labelNames.includes(name)); | |
| await github.rest.issues.setLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| labels: [...preserved, nextLabel], | |
| }); | |
| core.info(`PR #${pr.number}: ${verdict} -> ${nextLabel}`); | |
| if (isSafe) { | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| per_page: 100, | |
| }); | |
| const existing = comments.find((c) => c.body?.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.deleteComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| }); | |
| } | |
| return; | |
| } | |
| const sub = data.sub_scores ?? {}; | |
| const fmt = (v) => (v != null ? String(Math.round(v)) : "\u2014"); | |
| const verdictEmoji = { | |
| caution: "\u26A0\uFE0F", | |
| suspicious: "\u26D4", | |
| dangerous: "\uD83D\uDEA8", | |
| }[verdict] ?? "\u2753"; | |
| let body = `${marker}\n`; | |
| body += `### ${verdictEmoji} Contributor Trust Check \u2014 Review Recommended\n\n`; | |
| body += `This contributor's profile shows patterns that may warrant additional review. `; | |
| body += `This is based on their GitHub activity, not the contents of this PR.\n\n`; | |
| body += `**[${data.name}](https://github.com/${data.name})** \u00b7 Score: **${score}**/100\n\n`; | |
| if (data.threats && data.threats.length > 0) { | |
| body += `#### Why was this flagged?\n\n`; | |
| body += `| Signal | Severity | Detail |\n|--------|----------|--------|\n`; | |
| for (const t of data.threats) { | |
| body += `| ${t.type} | ${t.severity} | ${t.detail} |\n`; | |
| } | |
| body += `\n`; | |
| } | |
| body += `<details>\n<summary>Dimension breakdown</summary>\n\n`; | |
| body += `| Dimension | Score | What it measures |\n|-----------|-------|------------------|\n`; | |
| body += `| Identity | ${fmt(sub.identity)} | Account age, contribution history, GPG keys, org memberships |\n`; | |
| body += `| Behavior | ${fmt(sub.behavior)} | PR patterns, unsolicited contribution ratio, activity cadence |\n`; | |
| body += `| Content | ${fmt(sub.content)} | PR body substance, issue linkage, contribution quality |\n`; | |
| body += `| Graph | ${fmt(sub.graph)} | Cross-repo trust, co-contributor relationships |\n\n`; | |
| body += `</details>\n\n`; | |
| body += `<sub>Analyzed by [Brin](https://brin.sh) \u00b7 [Full profile](${data.url}?details=true)</sub>\n`; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| per_page: 100, | |
| }); | |
| const existingComment = comments.find((c) => c.body?.includes(marker)); | |
| if (existingComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existingComment.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| body, | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment