Skip to content

Commit 96fc3bb

Browse files
authored
Merge pull request 0x5t4l1n#28 from 0x5t4l1n/0x5t4l1n-patch-3
Add Discord notification for security advisories
2 parents 48715fb + bcb40a4 commit 96fc3bb

1 file changed

Lines changed: 102 additions & 0 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: Security Advisory Discord Notification
2+
3+
on:
4+
repository_advisory:
5+
types: [reported, created, published, submitted, reopened]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
notify-owners:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Ensure Discord webhook is configured
16+
id: check_secret
17+
env:
18+
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
19+
run: |
20+
if [ -z "$DISCORD_WEBHOOK" ]; then
21+
echo "::warning::Missing required secret: DISCORD_WEBHOOK. Skipping advisory notification. Add a Discord webhook URL as the DISCORD_WEBHOOK secret in your repository or organization settings."
22+
echo "skip=true" >> "$GITHUB_OUTPUT"
23+
else
24+
echo "skip=false" >> "$GITHUB_OUTPUT"
25+
fi
26+
27+
- name: Send Discord notification
28+
if: steps.check_secret.outputs.skip == 'false'
29+
env:
30+
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
31+
ADVISORY_TITLE: ${{ github.event.repository_advisory.summary }}
32+
ADVISORY_SEVERITY: ${{ github.event.repository_advisory.severity }}
33+
ADVISORY_STATE: ${{ github.event.repository_advisory.state }}
34+
ADVISORY_CVE: ${{ github.event.repository_advisory.cve_id }}
35+
ADVISORY_URL: ${{ github.event.repository_advisory.html_url }}
36+
ADVISORY_DESCRIPTION: ${{ github.event.repository_advisory.description }}
37+
ADVISORY_ACTION: ${{ github.event.action }}
38+
REPO: ${{ github.repository }}
39+
ACTOR: ${{ github.actor }}
40+
run: |
41+
# Map severity to a Discord embed colour (decimal RGB)
42+
case "${ADVISORY_SEVERITY,,}" in
43+
critical) COLOR=9831467 ;; # #960B0B dark red
44+
high) COLOR=15548997 ;; # #ED4245 red
45+
medium) COLOR=15105570 ;; # #E67E22 orange
46+
low) COLOR=16776960 ;; # #FFFF00 yellow
47+
*) COLOR=8421504 ;; # #808080 grey
48+
esac
49+
50+
# Build optional CVE field entry
51+
CVE_FIELD=""
52+
if [ -n "$ADVISORY_CVE" ]; then
53+
CVE_FIELD=$(jq -n --arg cve "$ADVISORY_CVE" \
54+
'{name: "CVE ID", value: $cve, inline: true}')
55+
CVE_FIELD=",${CVE_FIELD}"
56+
fi
57+
58+
# Truncate description to Discord's 1024-char field limit
59+
DESCRIPTION="${ADVISORY_DESCRIPTION:0:1024}"
60+
61+
PAYLOAD=$(jq -n \
62+
--arg title "🔒 Security Advisory ${ADVISORY_ACTION^} in \`${REPO}\`" \
63+
--arg footer_text "GitHub Advisory · ${REPO}" \
64+
--arg url "$ADVISORY_URL" \
65+
--arg adv_title "$ADVISORY_TITLE" \
66+
--arg severity "${ADVISORY_SEVERITY^}" \
67+
--arg state "${ADVISORY_STATE^}" \
68+
--arg actor "$ACTOR" \
69+
--arg description "$DESCRIPTION" \
70+
--argjson color "$COLOR" \
71+
'{
72+
embeds: [{
73+
title: $title,
74+
url: $url,
75+
color: $color,
76+
fields: [
77+
{name: "Title", value: $adv_title, inline: false},
78+
{name: "Severity", value: $severity, inline: true},
79+
{name: "State", value: $state, inline: true},
80+
{name: "Reported by", value: $actor, inline: true},
81+
{name: "Description", value: $description, inline: false}
82+
],
83+
footer: {text: $footer_text}
84+
}]
85+
}')
86+
87+
# Inject optional CVE field before the description field
88+
if [ -n "$CVE_FIELD" ]; then
89+
PAYLOAD=$(echo "$PAYLOAD" | jq \
90+
--argjson cve_field "$CVE_FIELD" \
91+
'.embeds[0].fields |= .[:3] + [$cve_field] + .[3:]')
92+
fi
93+
94+
RESPONSE=$(curl -sS -o /tmp/discord_response.txt -w "%{http_code}" \
95+
-X POST "$DISCORD_WEBHOOK" \
96+
-H "Content-Type: application/json" \
97+
-d "$PAYLOAD")
98+
99+
if [ "$RESPONSE" -lt 200 ] || [ "$RESPONSE" -ge 300 ]; then
100+
echo "::error::Discord webhook failed (HTTP $RESPONSE): $(cat /tmp/discord_response.txt)"
101+
exit 1
102+
fi

0 commit comments

Comments
 (0)