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}..." | |
# Fetch security alerts via GitHub API | |
ALERTS=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ | |
"https://api.github.com/repos/${{ github.repository }}/code-scanning/alerts?pr=${PR_NUMBER}") | |
# Log raw API response for debugging | |
echo "Raw API Response:" | |
echo "$ALERTS" | |
# Ensure valid JSON parsing; default to empty array if parsing fails | |
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') | |
# Output for debugging | |
echo "UNRESOLVED_ALERTS: $UNRESOLVED_ALERTS" | |
echo "DISMISSED_WITH_COMMENTS: $DISMISSED_WITH_COMMENTS" | |
echo "DISMISSED_WITHOUT_COMMENTS: $DISMISSED_WITHOUT_COMMENTS" | |
echo "UNRESOLVED_COUNT: $UNRESOLVED_COUNT" | |
echo "DISMISSED_WITH_COMMENTS_COUNT: $DISMISSED_WITH_COMMENTS_COUNT" | |
echo "DISMISSED_WITHOUT_COMMENTS_COUNT: $DISMISSED_WITHOUT_COMMENTS_COUNT" | |
# Save them properly in the environment as single-line JSON | |
echo "UNRESOLVED_ALERTS=$UNRESOLVED_ALERTS" >> $GITHUB_ENV | |
echo "DISMISSED_WITH_COMMENTS=$DISMISSED_WITH_COMMENTS" >> $GITHUB_ENV | |
echo "DISMISSED_WITHOUT_COMMENTS=$DISMISSED_WITHOUT_COMMENTS" >> $GITHUB_ENV | |
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 | |
- name: Find Existing PR Comment | |
id: find_comment | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
echo "Searching for existing PR comment..." | |
COMMENT_ID=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ | |
"https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" | jq -r \ | |
'.[] | select(.body | startswith("### π€ GitHub Action: Security Alerts Review")) | .id') | |
if [[ -n "$COMMENT_ID" && "$COMMENT_ID" != "null" ]]; then | |
echo "EXISTING_COMMENT_ID=$COMMENT_ID" >> $GITHUB_ENV | |
fi | |
echo "Found comment ID: $COMMENT_ID" | |
- name: Post or Update PR Comment | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
COMMENT_BODY="### π€ GitHub Action: Security Alerts Review π\n" | |
# Add 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 | |
# Add Dismissed Alerts With Comments | |
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 | |
# Add 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 | |
# Convert COMMENT_BODY to a properly formatted JSON string | |
COMMENT_BODY_JSON=$(echo "$COMMENT_BODY" | jq -Rs .) | |
# Update existing comment if found | |
if [[ -n "$EXISTING_COMMENT_ID" ]]; then | |
echo "Updating existing comment ID: $EXISTING_COMMENT_ID" | |
curl -s -X PATCH -H "Authorization: token ${GITHUB_TOKEN}" -H "Content-Type: application/json" \ | |
-d "{\"body\": $COMMENT_BODY_JSON}" \ | |
"https://api.github.com/repos/${{ github.repository }}/issues/comments/${EXISTING_COMMENT_ID}" | |
else | |
echo "Posting new comment to PR..." | |
curl -s -X POST -H "Authorization: token ${GITHUB_TOKEN}" -H "Content-Type: application/json" \ | |
-d "{\"body\": $COMMENT_BODY_JSON}" \ | |
"https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" | |
fi | |
- name: Check if Action Should Fail | |
run: | | |
echo "π Checking if the workflow should fail based on security alerts..." | |
echo "UNRESOLVED_COUNT" | |
echo $UNRESOLVED_COUNT | |
echo "DISMISSED_COUNT" | |
echo $DISMISSED_COUNT | |
# If there are unresolved alerts | |
if [[ "$UNRESOLVED_COUNT" -gt 0 ]]; then | |
echo "β ERROR: $UNRESOLVED_COUNT unresolved security alerts found!" | |
echo "β οΈ These alerts must be resolved before merging." | |
exit 1 # Fail the workflow | |
fi | |
# If there are dismissed alerts without comments | |
if [[ "$DISMISSED_COUNT" -gt 0 ]]; then | |
echo "β ERROR: $DISMISSED_COUNT security alerts were dismissed without comments!" | |
echo "β οΈ Please provide a dismissal reason for these alerts." | |
exit 1 # Fail the workflow | |
fi | |
echo "β No security issues found. The workflow will pass successfully." |