mirror of
https://github.com/th30d4y/OpenLearnX.git
synced 2026-05-26 19:26:33 +00:00
Replace SMTP email with Discord webhook for advisory notifications
Agent-Logs-Url: https://github.com/th30d4y/OpenLearnX/sessions/c1dfb007-d13e-4526-b2aa-1abb3365dd5a Co-authored-by: 0x5t4l1n <161853795+0x5t4l1n@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
a642d16f89
commit
6213bc68f7
@@ -0,0 +1,102 @@
|
|||||||
|
name: Security Advisory Discord Notification
|
||||||
|
|
||||||
|
on:
|
||||||
|
repository_advisory:
|
||||||
|
types: [reported, created, published, submitted, reopened]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
notify-owners:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Ensure Discord webhook is configured
|
||||||
|
id: check_secret
|
||||||
|
env:
|
||||||
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
run: |
|
||||||
|
if [ -z "$DISCORD_WEBHOOK" ]; then
|
||||||
|
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."
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Send Discord notification
|
||||||
|
if: steps.check_secret.outputs.skip == 'false'
|
||||||
|
env:
|
||||||
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
ADVISORY_TITLE: ${{ github.event.repository_advisory.summary }}
|
||||||
|
ADVISORY_SEVERITY: ${{ github.event.repository_advisory.severity }}
|
||||||
|
ADVISORY_STATE: ${{ github.event.repository_advisory.state }}
|
||||||
|
ADVISORY_CVE: ${{ github.event.repository_advisory.cve_id }}
|
||||||
|
ADVISORY_URL: ${{ github.event.repository_advisory.html_url }}
|
||||||
|
ADVISORY_DESCRIPTION: ${{ github.event.repository_advisory.description }}
|
||||||
|
ADVISORY_ACTION: ${{ github.event.action }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
ACTOR: ${{ github.actor }}
|
||||||
|
run: |
|
||||||
|
# Map severity to a Discord embed colour (decimal RGB)
|
||||||
|
case "${ADVISORY_SEVERITY,,}" in
|
||||||
|
critical) COLOR=9831467 ;; # #960B0B dark red
|
||||||
|
high) COLOR=15548997 ;; # #ED4245 red
|
||||||
|
medium) COLOR=15105570 ;; # #E67E22 orange
|
||||||
|
low) COLOR=16776960 ;; # #FFFF00 yellow
|
||||||
|
*) COLOR=8421504 ;; # #808080 grey
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Build optional CVE field entry
|
||||||
|
CVE_FIELD=""
|
||||||
|
if [ -n "$ADVISORY_CVE" ]; then
|
||||||
|
CVE_FIELD=$(jq -n --arg cve "$ADVISORY_CVE" \
|
||||||
|
'{name: "CVE ID", value: $cve, inline: true}')
|
||||||
|
CVE_FIELD=",${CVE_FIELD}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Truncate description to Discord's 1024-char field limit
|
||||||
|
DESCRIPTION="${ADVISORY_DESCRIPTION:0:1024}"
|
||||||
|
|
||||||
|
PAYLOAD=$(jq -n \
|
||||||
|
--arg title "🔒 Security Advisory ${ADVISORY_ACTION^} in \`${REPO}\`" \
|
||||||
|
--arg footer_text "GitHub Advisory · ${REPO}" \
|
||||||
|
--arg url "$ADVISORY_URL" \
|
||||||
|
--arg adv_title "$ADVISORY_TITLE" \
|
||||||
|
--arg severity "${ADVISORY_SEVERITY^}" \
|
||||||
|
--arg state "${ADVISORY_STATE^}" \
|
||||||
|
--arg actor "$ACTOR" \
|
||||||
|
--arg description "$DESCRIPTION" \
|
||||||
|
--argjson color "$COLOR" \
|
||||||
|
'{
|
||||||
|
embeds: [{
|
||||||
|
title: $title,
|
||||||
|
url: $url,
|
||||||
|
color: $color,
|
||||||
|
fields: [
|
||||||
|
{name: "Title", value: $adv_title, inline: false},
|
||||||
|
{name: "Severity", value: $severity, inline: true},
|
||||||
|
{name: "State", value: $state, inline: true},
|
||||||
|
{name: "Reported by", value: $actor, inline: true},
|
||||||
|
{name: "Description", value: $description, inline: false}
|
||||||
|
],
|
||||||
|
footer: {text: $footer_text}
|
||||||
|
}]
|
||||||
|
}')
|
||||||
|
|
||||||
|
# Inject optional CVE field before the description field
|
||||||
|
if [ -n "$CVE_FIELD" ]; then
|
||||||
|
PAYLOAD=$(echo "$PAYLOAD" | jq \
|
||||||
|
--argjson cve_field "$CVE_FIELD" \
|
||||||
|
'.embeds[0].fields |= .[:3] + [$cve_field] + .[3:]')
|
||||||
|
fi
|
||||||
|
|
||||||
|
RESPONSE=$(curl -sS -o /tmp/discord_response.txt -w "%{http_code}" \
|
||||||
|
-X POST "$DISCORD_WEBHOOK" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$PAYLOAD")
|
||||||
|
|
||||||
|
if [ "$RESPONSE" -lt 200 ] || [ "$RESPONSE" -ge 300 ]; then
|
||||||
|
echo "::error::Discord webhook failed (HTTP $RESPONSE): $(cat /tmp/discord_response.txt)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
name: Security Advisory Email Notification
|
|
||||||
|
|
||||||
on:
|
|
||||||
repository_advisory:
|
|
||||||
types: [reported, created, published, submitted, reopened]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
notify-owners:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Ensure SMTP secrets are configured
|
|
||||||
id: check_secrets
|
|
||||||
env:
|
|
||||||
MAIL_SERVER: ${{ secrets.ADVISORY_MAIL_SERVER }}
|
|
||||||
MAIL_USERNAME: ${{ secrets.ADVISORY_MAIL_USERNAME }}
|
|
||||||
MAIL_PASSWORD: ${{ secrets.ADVISORY_MAIL_PASSWORD }}
|
|
||||||
MAIL_TO: ${{ secrets.ADVISORY_MAIL_TO }}
|
|
||||||
run: |
|
|
||||||
missing=()
|
|
||||||
[ -z "$MAIL_SERVER" ] && missing+=("ADVISORY_MAIL_SERVER")
|
|
||||||
[ -z "$MAIL_USERNAME" ] && missing+=("ADVISORY_MAIL_USERNAME")
|
|
||||||
[ -z "$MAIL_PASSWORD" ] && missing+=("ADVISORY_MAIL_PASSWORD")
|
|
||||||
[ -z "$MAIL_TO" ] && missing+=("ADVISORY_MAIL_TO")
|
|
||||||
|
|
||||||
if [ ${#missing[@]} -gt 0 ]; then
|
|
||||||
echo "::warning::Missing required secrets: ${missing[*]}. Skipping advisory email notification. Configure these secrets in your repository or organization settings."
|
|
||||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build email body
|
|
||||||
if: steps.check_secrets.outputs.skip == 'false'
|
|
||||||
id: build_body
|
|
||||||
env:
|
|
||||||
ADVISORY_TITLE: ${{ github.event.repository_advisory.summary }}
|
|
||||||
ADVISORY_SEVERITY: ${{ github.event.repository_advisory.severity }}
|
|
||||||
ADVISORY_STATE: ${{ github.event.repository_advisory.state }}
|
|
||||||
ADVISORY_CVE: ${{ github.event.repository_advisory.cve_id }}
|
|
||||||
ADVISORY_URL: ${{ github.event.repository_advisory.html_url }}
|
|
||||||
ADVISORY_DESCRIPTION: ${{ github.event.repository_advisory.description }}
|
|
||||||
ADVISORY_ACTION: ${{ github.event.action }}
|
|
||||||
REPO: ${{ github.repository }}
|
|
||||||
ACTOR: ${{ github.actor }}
|
|
||||||
run: |
|
|
||||||
CVE_LINE=""
|
|
||||||
if [ -n "$ADVISORY_CVE" ]; then
|
|
||||||
CVE_LINE="CVE ID : $ADVISORY_CVE"$'\n'
|
|
||||||
fi
|
|
||||||
|
|
||||||
BODY="A security advisory has been ${ADVISORY_ACTION} on the repository ${REPO}.
|
|
||||||
|
|
||||||
Repository : https://github.com/${REPO}
|
|
||||||
Action : ${ADVISORY_ACTION}
|
|
||||||
Title : ${ADVISORY_TITLE}
|
|
||||||
Severity : ${ADVISORY_SEVERITY}
|
|
||||||
State : ${ADVISORY_STATE}
|
|
||||||
${CVE_LINE}Advisory : ${ADVISORY_URL}
|
|
||||||
Reported by: ${ACTOR}
|
|
||||||
|
|
||||||
--- Description ---
|
|
||||||
${ADVISORY_DESCRIPTION}
|
|
||||||
|
|
||||||
---
|
|
||||||
This notification was sent automatically by GitHub Actions.
|
|
||||||
Repository: https://github.com/${REPO}
|
|
||||||
"
|
|
||||||
|
|
||||||
# Write to file to avoid multiline env issues
|
|
||||||
printf '%s' "$BODY" > /tmp/advisory_body.txt
|
|
||||||
echo "body_file=/tmp/advisory_body.txt" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Send email to org owners
|
|
||||||
if: steps.check_secrets.outputs.skip == 'false'
|
|
||||||
# dawidd6/action-send-mail v3.12.0 — pinned to exact commit for supply-chain security.
|
|
||||||
# Verify: https://github.com/dawidd6/action-send-mail/commit/2cea9617b09d83a84e7015b8b4c893f01b028020
|
|
||||||
uses: dawidd6/action-send-mail@2cea9617b09d83a84e7015b8b4c893f01b028020
|
|
||||||
with:
|
|
||||||
server_address: ${{ secrets.ADVISORY_MAIL_SERVER }}
|
|
||||||
# ADVISORY_MAIL_PORT defaults to 465 (SMTPS / implicit TLS).
|
|
||||||
# Set the secret to 587 and secure to false if your SMTP server requires STARTTLS instead.
|
|
||||||
server_port: ${{ secrets.ADVISORY_MAIL_PORT || 465 }}
|
|
||||||
secure: ${{ secrets.ADVISORY_MAIL_SECURE || true }}
|
|
||||||
username: ${{ secrets.ADVISORY_MAIL_USERNAME }}
|
|
||||||
password: ${{ secrets.ADVISORY_MAIL_PASSWORD }}
|
|
||||||
subject: "[Security Advisory] [${{ github.event.repository_advisory.severity }}] ${{ github.event.repository_advisory.summary }} — ${{ github.repository }}"
|
|
||||||
to: ${{ secrets.ADVISORY_MAIL_TO }}
|
|
||||||
from: "GitHub Advisory Bot <${{ secrets.ADVISORY_MAIL_USERNAME }}>"
|
|
||||||
body: file:///tmp/advisory_body.txt
|
|
||||||
Reference in New Issue
Block a user