Merge pull request #29 from 0x5t4l1n/copilot/check-discord-functionality #4
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: Security Advisory Discord Notification | ||
| on: | ||
| push: | ||
| branches: | ||
| - '**' | ||
| issues: | ||
| types: [opened, reopened] | ||
| 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 }} | ||
| REPO: ${{ github.repository }} | ||
| ACTOR: ${{ github.actor }} | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| EVENT_PATH: ${{ github.event_path }} | ||
| run: | | ||
| if [ "$EVENT_NAME" = "repository_advisory" ]; then | ||
| ADVISORY_TITLE=$(jq -r '.repository_advisory.summary // "Security advisory"' "$EVENT_PATH") | ||
| ADVISORY_SEVERITY=$(jq -r '.repository_advisory.severity // "unknown"' "$EVENT_PATH") | ||
| ADVISORY_STATE=$(jq -r '.repository_advisory.state // "unknown"' "$EVENT_PATH") | ||
| ADVISORY_CVE=$(jq -r '.repository_advisory.cve_id // empty' "$EVENT_PATH") | ||
| ADVISORY_URL=$(jq -r '.repository_advisory.html_url // "https://github.com/'"$REPO"'"' "$EVENT_PATH") | ||
| ADVISORY_DESCRIPTION=$(jq -r '.repository_advisory.description // "No description provided."' "$EVENT_PATH") | ||
| ADVISORY_ACTION=$(jq -r '.action // "updated"' "$EVENT_PATH") | ||
| 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 | ||
| 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" \ | ||
| --arg cve "$ADVISORY_CVE" \ | ||
| --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} | ||
| ] + | ||
| (if $cve != "" then [{name: "CVE ID", value: $cve, inline: true}] else [] end) + | ||
| [{name: "Description", value: $description, inline: false}] | ||
| ), | ||
| footer: {text: $footer_text} | ||
| }] | ||
| }') | ||
| elif [ "$EVENT_NAME" = "push" ]; then | ||
| COMMIT_MESSAGE=$(jq -r '.head_commit.message // "No commit message provided."' "$EVENT_PATH") | ||
| COMMIT_URL=$(jq -r '.head_commit.url // .compare // "https://github.com/'"$REPO"'"' "$EVENT_PATH") | ||
| COMMIT_SHA=$(jq -r '.head_commit.id // .after // ""' "$EVENT_PATH" | cut -c1-7) | ||
| BRANCH_NAME=$(jq -r '.ref // ""' "$EVENT_PATH" | sed 's|refs/heads/||') | ||
| PUSHER_NAME=$(jq -r '.pusher.name // "unknown"' "$EVENT_PATH") | ||
| PAYLOAD=$(jq -n \ | ||
| --arg title "馃摝 New Commit in \`${REPO}\`" \ | ||
| --arg footer_text "GitHub Push 路 ${REPO}" \ | ||
| --arg url "$COMMIT_URL" \ | ||
| --arg commit "${COMMIT_MESSAGE:0:1024}" \ | ||
| --arg sha "$COMMIT_SHA" \ | ||
| --arg branch "$BRANCH_NAME" \ | ||
| --arg pusher "$PUSHER_NAME" \ | ||
| '{ | ||
| embeds: [{ | ||
| title: $title, | ||
| url: $url, | ||
| color: 3447003, | ||
| fields: [ | ||
| {name: "Commit", value: $commit, inline: false}, | ||
| {name: "SHA", value: $sha, inline: true}, | ||
| {name: "Branch", value: $branch, inline: true}, | ||
| {name: "Pushed by", value: $pusher, inline: true} | ||
| ], | ||
| footer: {text: $footer_text} | ||
| }] | ||
| }') | ||
| elif [ "$EVENT_NAME" = "issues" ]; then | ||
| ISSUE_TITLE=$(jq -r '.issue.title // "Untitled issue"' "$EVENT_PATH") | ||
| ISSUE_URL=$(jq -r '.issue.html_url // "https://github.com/'"$REPO"'/issues"' "$EVENT_PATH") | ||
| ISSUE_NUMBER=$(jq -r '.issue.number // ""' "$EVENT_PATH") | ||
| ISSUE_BODY=$(jq -r '.issue.body // "No description provided."' "$EVENT_PATH") | ||
| ISSUE_STATE=$(jq -r '.issue.state // "open"' "$EVENT_PATH") | ||
| ISSUE_ACTION=$(jq -r '.action // "opened"' "$EVENT_PATH") | ||
| PAYLOAD=$(jq -n \ | ||
| --arg title "馃悰 Issue ${ISSUE_ACTION^} in \`${REPO}\`" \ | ||
| --arg footer_text "GitHub Issues 路 ${REPO}" \ | ||
| --arg url "$ISSUE_URL" \ | ||
| --arg issue_title "$ISSUE_TITLE" \ | ||
| --arg issue_number "$ISSUE_NUMBER" \ | ||
| --arg issue_state "${ISSUE_STATE^}" \ | ||
| --arg reporter "$ACTOR" \ | ||
| --arg description "${ISSUE_BODY:0:1024}" \ | ||
| '{ | ||
| embeds: [{ | ||
| title: $title, | ||
| url: $url, | ||
| color: 15844367, | ||
| fields: [ | ||
| {name: "Issue", value: "#" + $issue_number + " 路 " + $issue_title, inline: false}, | ||
| {name: "State", value: $issue_state, inline: true}, | ||
| {name: "Raised by", value: $reporter, inline: true}, | ||
| {name: "Description", value: $description, inline: false} | ||
| ], | ||
| footer: {text: $footer_text} | ||
| }] | ||
| }') | ||
| else | ||
| echo "Skipping unsupported event: $EVENT_NAME" | ||
| exit 0 | ||
| 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 | ||