This file contains 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 Alerts Review | |
on: | |
push: | |
paths: | |
- "**/*.sol" | |
- ".github/workflows/securityAlertsReview.yml" | |
issue_comment: | |
types: | |
- created | |
- edited | |
pull_request: | |
types: | |
- ready_for_review | |
workflow_dispatch: | |
jobs: | |
check-security-alerts: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Fetch PR Number | |
id: fetch_pr | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
PR_NUMBER=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ | |
"https://api.github.com/repos/${{ github.repository }}/pulls?state=open" | jq -r '.[0].number') | |
if [[ -z "$PR_NUMBER" || "$PR_NUMBER" == "null" ]]; then | |
echo "No open PR found, skipping check." | |
exit 0 | |
fi | |
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV | |
echo "PR number: $PR_NUMBER" | |
- name: Fetch Security Alerts for PR | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
echo "Fetching security alerts for PR #${PR_NUMBER}..." | |
ALERTS=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ | |
"https://api.github.com/repos/${{ github.repository }}/code-scanning/alerts?pr=${PR_NUMBER}") | |
echo "Raw API Response: $ALERTS" | |
UNRESOLVED_ALERTS=$(echo "$ALERTS" | jq -c '[.[] | select(.state == "open")]' || echo "[]") | |
DISMISSED_WITH_COMMENTS=$(echo "$ALERTS" | jq -c '[.[] | select(.state == "dismissed" and (.dismissed_comment != null and .dismissed_comment != ""))]' || echo "[]") | |
DISMISSED_WITHOUT_COMMENTS=$(echo "$ALERTS" | jq -c '[.[] | select(.state == "dismissed" and (.dismissed_comment == null or .dismissed_comment == ""))]' || echo "[]") | |
UNRESOLVED_COUNT=$(echo "$UNRESOLVED_ALERTS" | jq -r 'length') | |
DISMISSED_WITH_COMMENTS_COUNT=$(echo "$DISMISSED_WITH_COMMENTS" | jq -r 'length') | |
DISMISSED_WITHOUT_COMMENTS_COUNT=$(echo "$DISMISSED_WITHOUT_COMMENTS" | jq -r 'length') | |
echo "UNRESOLVED_COUNT=$UNRESOLVED_COUNT" >> $GITHUB_ENV | |
echo "DISMISSED_WITH_COMMENTS_COUNT=$DISMISSED_WITH_COMMENTS_COUNT" >> $GITHUB_ENV | |
echo "DISMISSED_WITHOUT_COMMENTS_COUNT=$DISMISSED_WITHOUT_COMMENTS_COUNT" >> $GITHUB_ENV | |
# (Optional: Add a step here to set EXISTING_COMMENT_ID if updating an existing comment) | |
- name: Post or Update PR Comment | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
COMMENT_BODY=$'### π€ GitHub Action: Security Alerts Review π\n' | |
# Unresolved Alerts | |
if [[ "$UNRESOLVED_COUNT" -gt 0 ]]; then | |
COMMENT_BODY+=$'\n## π¨ Unresolved Security Alerts\n' | |
COMMENT_BODY+=$'These **must be resolved** before merging:\n\n' | |
while IFS= read -r row; do | |
ALERT_URL=$(echo "$row" | jq -r '.html_url') | |
ALERT_FILE=$(echo "$row" | jq -r '.most_recent_instance.location.path') | |
ALERT_DESCRIPTION=$(echo "$row" | jq -r '.most_recent_instance.message.text') | |
COMMENT_BODY+=$'π΄ **[View Alert]('"$ALERT_URL"')**\n' | |
COMMENT_BODY+=$'π **File:** `'"$ALERT_FILE"'`\n' | |
COMMENT_BODY+=$'π‘ **Issue:** '"$ALERT_DESCRIPTION"$'\n\n' | |
done < <(echo "$UNRESOLVED_ALERTS" | jq -c '.[]') | |
COMMENT_BODY+=$'β οΈ **Please resolve these alerts before merging.**\n\n' | |
fi | |
# Dismissed Alerts With Comments (including DISMISS_REASON) | |
if [[ "$DISMISSED_WITH_COMMENTS_COUNT" -gt 0 ]]; then | |
COMMENT_BODY+=$'\n## β Dismissed Alerts with Explanations\n' | |
COMMENT_BODY+=$'The following alerts were dismissed with valid reasons:\n\n' | |
while IFS= read -r row; do | |
ALERT_URL=$(echo "$row" | jq -r '.html_url') | |
ALERT_FILE=$(echo "$row" | jq -r '.most_recent_instance.location.path') | |
ALERT_DESCRIPTION=$(echo "$row" | jq -r '.most_recent_instance.message.text') | |
DISMISS_REASON=$(echo "$row" | jq -r '.dismissed_reason') | |
DISMISS_COMMENT=$(echo "$row" | jq -r '.dismissed_comment') | |
# Capitalize the first letter of the dismissal reason | |
FORMATTED_DISMISS_REASON=$(echo "$DISMISS_REASON" | awk '{print toupper(substr($0,1,1)) substr($0,2)}') | |
COMMENT_BODY+=$'π’ **[View Alert]('"$ALERT_URL"')**\n' | |
COMMENT_BODY+=$'π **File:** `'"$ALERT_FILE"'`\n' | |
COMMENT_BODY+=$'π‘ **Issue:** '"$ALERT_DESCRIPTION"$'\n' | |
COMMENT_BODY+=$'βοΈ **Dismissal Reason:** `'${FORMATTED_DISMISS_REASON}'`\n' | |
COMMENT_BODY+=$'π¬ **Comment:** "'"$DISMISS_COMMENT"'"'\n\n' | |
done < <(echo "$DISMISSED_WITH_COMMENTS" | jq -c '.[]') | |
COMMENT_BODY+=$'β **These alerts were reviewed and dismissed correctly.**\n\n' | |
fi | |
# Dismissed Alerts Without Comments | |
if [[ "$DISMISSED_WITHOUT_COMMENTS_COUNT" -gt 0 ]]; then | |
COMMENT_BODY+=$'\n## β οΈ Dismissed Alerts Without Comments\n' | |
COMMENT_BODY+=$'The following alerts were dismissed without explanations:\n\n' | |
while IFS= read -r row; do | |
ALERT_URL=$(echo "$row" | jq -r '.html_url') | |
ALERT_FILE=$(echo "$row" | jq -r '.most_recent_instance.location.path') | |
ALERT_DESCRIPTION=$(echo "$row" | jq -r '.most_recent_instance.message.text') | |
COMMENT_BODY+=$'β οΈ **[View Alert]('"$ALERT_URL"')**\n' | |
COMMENT_BODY+=$'π **File:** `'"$ALERT_FILE"'`\n' | |
COMMENT_BODY+=$'π‘ **Issue:** '"$ALERT_DESCRIPTION"$'\n\n' | |
done < <(echo "$DISMISSED_WITHOUT_COMMENTS" | jq -c '.[]') | |
COMMENT_BODY+=$'β οΈ **Please provide a dismissal reason for these alerts.**\n\n' | |
fi | |
echo "COMMENT_BODY:" | |
echo "$COMMENT_BODY" | |
# Build JSON payload so that newlines are preserved. | |
COMMENT_BODY_JSON=$(jq -n --arg body "$COMMENT_BODY" '{body: $body}') | |
echo "COMMENT_BODY_JSON:" | |
echo "$COMMENT_BODY_JSON" | |
# Determine API URL (update if EXISTING_COMMENT_ID is set) | |
if [[ -n "$EXISTING_COMMENT_ID" ]]; then | |
API_URL="https://api.github.com/repos/${{ github.repository }}/issues/comments/${EXISTING_COMMENT_ID}" | |
else | |
API_URL="https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" | |
fi | |
echo "Using API URL: $API_URL" | |
# Post or update the PR comment using the JSON payload | |
HTTP_RESPONSE=$(curl -s -o response.json -w "%{http_code}" -X POST \ | |
-H "Authorization: token ${GITHUB_TOKEN}" -H "Content-Type: application/json" \ | |
--data "$COMMENT_BODY_JSON" \ | |
"$API_URL") | |
echo "HTTP_RESPONSE: $HTTP_RESPONSE" | |
cat response.json | |
if [[ "$HTTP_RESPONSE" -ne 200 && "$HTTP_RESPONSE" -ne 201 ]]; then | |
echo "β Error: Failed to update PR comment. HTTP Status: $HTTP_RESPONSE" | |
exit 1 | |
fi |