@@ -11,11 +11,17 @@ jobs:
1111 scan :
1212 name : Scan for secrets
1313 runs-on : ubuntu-latest
14+ env :
15+ SMTP_URL : ${{ secrets.SMTP_URL }}
16+ SMTP_PORT : ${{ secrets.SMTP_PORT || '25' }}
17+ SMTP_EMAIL : ${{ secrets.SMTP_EMAIL }}
18+ SMTP_PASSWORD : ${{ secrets.SMTP_PASSWORD }}
1419 steps :
1520 - name : Checkout repository
1621 uses : actions/checkout@v4
1722 with :
1823 fetch-depth : 1
24+ ref : ${{ github.event.pull_request.head.sha || github.sha }}
1925
2026 - name : Run Betterleaks
2127 id : betterleaks
4147 path : betterleaks-report.json
4248 if-no-files-found : ignore
4349
50+ - name : Build Betterleaks email summary
51+ id : leak_summary
52+ if : steps.betterleaks.outcome == 'failure'
53+ shell : bash
54+ run : |
55+ if [[ -s betterleaks-report.json ]]; then
56+ jq -r '
57+ def one_line:
58+ tostring
59+ | gsub("[\r\n]+"; " ")
60+ | if length > 240 then .[0:240] + "..." else . end;
61+
62+ .[:20][]
63+ | "- " + (.RuleID // "unknown-rule")
64+ + " at " + (.File // "unknown-file")
65+ + ":" + ((.StartLine // 0) | tostring)
66+ + "\n match: " + ((.Match // .Secret // "REDACTED") | one_line)
67+ ' betterleaks-report.json > betterleaks-email-summary.txt
68+
69+ count="$(jq 'length' betterleaks-report.json)"
70+ if (( count > 20 )); then
71+ {
72+ echo ""
73+ echo "... and $((count - 20)) more finding(s). Download the artifact for full details."
74+ } >> betterleaks-email-summary.txt
75+ fi
76+ else
77+ echo "No JSON report was generated. Download the workflow logs for details." > betterleaks-email-summary.txt
78+ fi
79+
80+ {
81+ echo "text<<BETTERLEAKS_SUMMARY"
82+ cat betterleaks-email-summary.txt
83+ echo "BETTERLEAKS_SUMMARY"
84+ } >> "$GITHUB_OUTPUT"
85+
86+ - name : Resolve committer email
87+ id : committer
88+ if : steps.betterleaks.outcome == 'failure'
89+ shell : bash
90+ run : |
91+ committer_email="$(git log -1 --format='%ce')"
92+ author_email="$(git log -1 --format='%ae')"
93+ email="$committer_email"
94+ if [[ -z "$email" || "$email" == *"noreply.github.com"* ]]; then
95+ email="$author_email"
96+ fi
97+ if [[ "$email" =~ ^[^[:space:]@]+@[^[:space:]@]+\.[^[:space:]@]+$ && "$email" != *"noreply.github.com"* ]]; then
98+ echo "email=$email" >> "$GITHUB_OUTPUT"
99+ else
100+ echo "No deliverable committer email found; skipping Betterleaks email notification."
101+ echo "email=" >> "$GITHUB_OUTPUT"
102+ fi
103+
104+ - name : Email committer on Betterleaks failure
105+ if : steps.betterleaks.outcome == 'failure' && steps.committer.outputs.email != '' && env.SMTP_URL != '' && env.SMTP_EMAIL != ''
106+ uses : dawidd6/action-send-mail@v18
107+ with :
108+ server_address : ${{ env.SMTP_URL }}
109+ server_port : ${{ env.SMTP_PORT }}
110+ secure : ${{ env.SMTP_PORT == '465' }}
111+ username : ${{ env.SMTP_EMAIL }}
112+ password : ${{ env.SMTP_PASSWORD }}
113+ from : ${{ env.SMTP_EMAIL }}
114+ to : ${{ steps.committer.outputs.email }}
115+ subject : " [Betterleaks] Secret scan failed in ${{ github.repository }}"
116+ body : |
117+ Betterleaks detected one or more potential secrets.
118+
119+ Repository: ${{ github.repository }}
120+ Branch: ${{ github.ref_name }}
121+ Commit: ${{ github.sha }}
122+ Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
123+
124+ Findings:
125+ ${{ steps.leak_summary.outputs.text }}
126+
127+ Download the betterleaks-report artifact from the workflow run for details.
128+
44129 - name : Fail if Betterleaks found leaks
45130 if : steps.betterleaks.outcome == 'failure'
46131 run : |
0 commit comments