From cd376620b526c43403d2e4e2f2dae7e5c995d191 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Wed, 15 Apr 2026 14:56:57 -0400 Subject: [PATCH 1/4] ci: add Slack PR notification workflow Sends alerts to Slack channel on PR open, close, merge, reopen, and review events. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/slack-pr-notifications.yml | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/slack-pr-notifications.yml diff --git a/.github/workflows/slack-pr-notifications.yml b/.github/workflows/slack-pr-notifications.yml new file mode 100644 index 0000000..8015e74 --- /dev/null +++ b/.github/workflows/slack-pr-notifications.yml @@ -0,0 +1,63 @@ +name: Slack PR Notifications + +on: + pull_request: + types: [opened, closed, reopened] + branches: ["main"] + pull_request_review: + types: [submitted] + +jobs: + notify: + runs-on: ubuntu-latest + steps: + - name: Set notification details + id: details + run: | + if [[ "${{ github.event_name }}" == "pull_request_review" ]]; then + STATE="${{ github.event.review.state }}" + TITLE="PR Review: ${STATE} - ${{ github.event.pull_request.title }}" + COLOR=$([[ "$STATE" == "approved" ]] && echo "good" || echo "warning") + BODY="${{ github.event.review.user.login }} ${STATE} the PR" + else + ACTION="${{ github.event.action }}" + TITLE="PR ${ACTION^}: ${{ github.event.pull_request.title }}" + if [[ "$ACTION" == "closed" && "${{ github.event.pull_request.merged }}" == "true" ]]; then + TITLE="PR Merged: ${{ github.event.pull_request.title }}" + COLOR="good" + elif [[ "$ACTION" == "opened" ]]; then + COLOR="#1a73e8" + elif [[ "$ACTION" == "reopened" ]]; then + COLOR="warning" + else + COLOR="danger" + fi + BODY="${{ github.event.pull_request.user.login }} ${ACTION} the PR" + fi + + echo "title=${TITLE}" >> $GITHUB_OUTPUT + echo "color=${COLOR}" >> $GITHUB_OUTPUT + echo "body=${BODY}" >> $GITHUB_OUTPUT + + - name: Send Slack notification + uses: slackapi/slack-github-action@v2.1.0 + with: + webhook: ${{ secrets.SLACK_WEBHOOK_URL }} + webhook-type: incoming-webhook + payload: | + { + "attachments": [ + { + "color": "${{ steps.details.outputs.color }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*${{ steps.details.outputs.title }}*\n${{ steps.details.outputs.body }}\n*Repo:* `${{ github.repository }}`\n*Branch:* `${{ github.event.pull_request.head.ref }}` -> `${{ github.event.pull_request.base.ref }}`\n<${{ github.event.pull_request.html_url }}|View Pull Request>" + } + } + ] + } + ] + } From 72d785aa25dea2335540895012e3d7292018f456 Mon Sep 17 00:00:00 2001 From: sfulmer <59585501+stevefulme1@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:14:31 -0400 Subject: [PATCH 2/4] Potential fix for pull request finding 'CodeQL / Code injection' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/slack-pr-notifications.yml | 26 +++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/workflows/slack-pr-notifications.yml b/.github/workflows/slack-pr-notifications.yml index 8015e74..764cb62 100644 --- a/.github/workflows/slack-pr-notifications.yml +++ b/.github/workflows/slack-pr-notifications.yml @@ -13,17 +13,25 @@ jobs: steps: - name: Set notification details id: details + env: + EVENT_NAME: ${{ github.event_name }} + REVIEW_STATE: ${{ github.event.review.state }} + PR_TITLE: ${{ github.event.pull_request.title }} + REVIEW_USER_LOGIN: ${{ github.event.review.user.login }} + EVENT_ACTION: ${{ github.event.action }} + PR_MERGED: ${{ github.event.pull_request.merged }} + PR_USER_LOGIN: ${{ github.event.pull_request.user.login }} run: | - if [[ "${{ github.event_name }}" == "pull_request_review" ]]; then - STATE="${{ github.event.review.state }}" - TITLE="PR Review: ${STATE} - ${{ github.event.pull_request.title }}" + if [[ "$EVENT_NAME" == "pull_request_review" ]]; then + STATE="$REVIEW_STATE" + TITLE="PR Review: ${STATE} - ${PR_TITLE}" COLOR=$([[ "$STATE" == "approved" ]] && echo "good" || echo "warning") - BODY="${{ github.event.review.user.login }} ${STATE} the PR" + BODY="${REVIEW_USER_LOGIN} ${STATE} the PR" else - ACTION="${{ github.event.action }}" - TITLE="PR ${ACTION^}: ${{ github.event.pull_request.title }}" - if [[ "$ACTION" == "closed" && "${{ github.event.pull_request.merged }}" == "true" ]]; then - TITLE="PR Merged: ${{ github.event.pull_request.title }}" + ACTION="$EVENT_ACTION" + TITLE="PR ${ACTION^}: ${PR_TITLE}" + if [[ "$ACTION" == "closed" && "$PR_MERGED" == "true" ]]; then + TITLE="PR Merged: ${PR_TITLE}" COLOR="good" elif [[ "$ACTION" == "opened" ]]; then COLOR="#1a73e8" @@ -32,7 +40,7 @@ jobs: else COLOR="danger" fi - BODY="${{ github.event.pull_request.user.login }} ${ACTION} the PR" + BODY="${PR_USER_LOGIN} ${ACTION} the PR" fi echo "title=${TITLE}" >> $GITHUB_OUTPUT From b4e1fb2fdb905eb2ecf228c027afb569ce1aa622 Mon Sep 17 00:00:00 2001 From: sfulmer <59585501+stevefulme1@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:14:52 -0400 Subject: [PATCH 3/4] Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/slack-pr-notifications.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/slack-pr-notifications.yml b/.github/workflows/slack-pr-notifications.yml index 764cb62..18b6a91 100644 --- a/.github/workflows/slack-pr-notifications.yml +++ b/.github/workflows/slack-pr-notifications.yml @@ -7,6 +7,8 @@ on: pull_request_review: types: [submitted] +permissions: {} + jobs: notify: runs-on: ubuntu-latest From b1c57ec594e05eace8d166c9c584c577ea86d151 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Sat, 2 May 2026 10:29:43 -0400 Subject: [PATCH 4/4] security: fix JSON injection and pin Slack action to SHA - Move all attacker-controlled values (PR title, branch name, user) into env vars instead of direct ${{ }} interpolation in JSON payload - Use jq to build JSON payload safely, preventing injection via crafted PR titles or branch names containing quotes - Pin slackapi/slack-github-action to commit SHA (v2.1.0) --- .github/workflows/slack-pr-notifications.yml | 39 +++++++++----------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/.github/workflows/slack-pr-notifications.yml b/.github/workflows/slack-pr-notifications.yml index 18b6a91..ad25ba8 100644 --- a/.github/workflows/slack-pr-notifications.yml +++ b/.github/workflows/slack-pr-notifications.yml @@ -23,6 +23,10 @@ jobs: EVENT_ACTION: ${{ github.event.action }} PR_MERGED: ${{ github.event.pull_request.merged }} PR_USER_LOGIN: ${{ github.event.pull_request.user.login }} + PR_HEAD_REF: ${{ github.event.pull_request.head.ref }} + PR_BASE_REF: ${{ github.event.pull_request.base.ref }} + PR_URL: ${{ github.event.pull_request.html_url }} + REPO_NAME: ${{ github.repository }} run: | if [[ "$EVENT_NAME" == "pull_request_review" ]]; then STATE="$REVIEW_STATE" @@ -45,29 +49,22 @@ jobs: BODY="${PR_USER_LOGIN} ${ACTION} the PR" fi - echo "title=${TITLE}" >> $GITHUB_OUTPUT - echo "color=${COLOR}" >> $GITHUB_OUTPUT - echo "body=${BODY}" >> $GITHUB_OUTPUT + # Build the Slack message text safely + MSG="*${TITLE}*\n${BODY}\n*Repo:* \`${REPO_NAME}\`\n*Branch:* \`${PR_HEAD_REF}\` -> \`${PR_BASE_REF}\`\n<${PR_URL}|View Pull Request>" + + # Use JSON-safe encoding via jq to prevent injection + { + echo "payload<> "$GITHUB_OUTPUT" - name: Send Slack notification - uses: slackapi/slack-github-action@v2.1.0 + uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52 # v2.1.0 with: webhook: ${{ secrets.SLACK_WEBHOOK_URL }} webhook-type: incoming-webhook - payload: | - { - "attachments": [ - { - "color": "${{ steps.details.outputs.color }}", - "blocks": [ - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "*${{ steps.details.outputs.title }}*\n${{ steps.details.outputs.body }}\n*Repo:* `${{ github.repository }}`\n*Branch:* `${{ github.event.pull_request.head.ref }}` -> `${{ github.event.pull_request.base.ref }}`\n<${{ github.event.pull_request.html_url }}|View Pull Request>" - } - } - ] - } - ] - } + payload: ${{ steps.details.outputs.payload }}