Security Vulnerability Slack Notification #104
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 Vulnerability Slack Notification | |
| on: | |
| schedule: | |
| - cron: '0 * * * *' | |
| workflow_dispatch: | |
| jobs: | |
| check-alerts: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Check for Recent Alerts | |
| env: | |
| GH_TOKEN: ${{ secrets.DEPENDABOT_PAT }} | |
| SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} | |
| run: | | |
| # 1. Calculate time 65 minutes ago | |
| TIME_THRESHOLD=$(date -u -d '65 minutes ago' +'%Y-%m-%dT%H:%M:%SZ') | |
| echo "Checking for alerts created after: $TIME_THRESHOLD" | |
| # 2. Fetch ALL open alerts (Raw JSON) | |
| # We fetch raw data first to ensure we don't lose structure in complex filtering | |
| RAW_DATA=$(gh api "/repos/${{ github.repository }}/dependabot/alerts?state=open") | |
| # 3. Filter locally using jq | |
| # Note: If you want to force a test on OLD alerts, remove '| select(.created_at > $TIME)' below | |
| ALERTS=$(echo "$RAW_DATA" | jq --arg TIME "$TIME_THRESHOLD" \ | |
| '[ .[] | select(.created_at > $TIME) | select(.security_advisory.severity == "critical" or .security_advisory.severity == "high") ]') | |
| # 4. Check results (COMMENTED OUT FOR TESTING) | |
| # LENGTH=$(echo "$ALERTS" | jq 'length') | |
| # if [ "$LENGTH" -eq 0 ]; then | |
| # echo "No new alerts found in the last hour." | |
| # exit 0 | |
| # fi | |
| echo "New alerts detected! Debugging structure..." | |
| # --- DEBUG: Print the first alert keys to logs --- | |
| echo "Top-level keys found in first alert:" | |
| echo "$ALERTS" | jq '.[0] | keys' | |
| # ----------------------------------------------- | |
| # 5. Extract details (Using Try/Catch defaults to prevent crash) | |
| # We use // to provide fallback text if the field is null | |
| PACKAGE=$(echo "$ALERTS" | jq -r '.[0].dependency.package.name // "Unknown Package"') | |
| SEVERITY=$(echo "$ALERTS" | jq -r '.[0].security_advisory.severity // "Unknown Severity"') | |
| # Try standard html_url, fallback to url, fallback to generic string | |
| ISSUE_URL=$(echo "$ALERTS" | jq -r '.[0].html_url // .[0].url // "https://github.com"') | |
| # Prepare text | |
| REPO_NAME="${{ github.repository }}" | |
| ISSUE_TITLE="${PACKAGE} (${SEVERITY})" | |
| ISSUE_USER="Dependabot" | |
| # 6. Build Slack Message | |
| MESSAGE_TEXT=$(jq -n \ | |
| --arg repo "$REPO_NAME" \ | |
| --arg title "$ISSUE_TITLE" \ | |
| --arg user "$ISSUE_USER" \ | |
| --arg url "$ISSUE_URL" \ | |
| --arg template "*📢 New Dependabot Alert ($REPO_NAME) 📢*\n\n*Issue Title:* $ISSUE_TITLE\n*Opened By:* $ISSUE_USER\n\n*View Issue:* $ISSUE_URL" \ | |
| '$template') | |
| # 7. Build Payload & Send | |
| SLACK_PAYLOAD=$(jq -n \ | |
| --arg text "$MESSAGE_TEXT" \ | |
| '{ | |
| "channel": "#docs-devdocs-notifications", | |
| "username": "Security Vulnerability Slack Notification", | |
| "icon_emoji": ":rotating_light:", | |
| "text": $text | |
| }') | |
| curl -X POST \ | |
| -H 'Content-type: application/json' \ | |
| --data "$SLACK_PAYLOAD" \ | |
| "$SLACK_WEBHOOK_URL" |