Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@vanshika921vd
Copy link

@vanshika921vd vanshika921vd commented Dec 17, 2025

Summary

Adds a GitHub Action that detects when a merged PR closes an issue with a bounty label.

Why

This is an initial step toward automating bounty payouts by identifying bounty-linked issues on PR merge.

Refs #3941

Summary by CodeRabbit

  • Chores
    • Added automated bounty detection for issues referenced in merged pull requests.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

Walkthrough

A new GitHub Actions workflow is added to detect bounty-labeled issues referenced in pull requests. When a PR closes and merges, the workflow checks the PR body for issue references, fetches each issue, and logs details if any have bounty labels containing the '$' symbol.

Changes

Cohort / File(s) Summary
GitHub Actions Workflow
​.github/workflows/detect-bounty-issue.yml
New workflow triggered on PR close/merge events that parses PR body for issue references (using close/fix keywords), fetches referenced issues via GitHub API, detects bounty labels by searching for '$' symbol, and logs detected bounty issues with their details. Uses actions/github-script@v6 for API interactions.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Verify GitHub Actions syntax and workflow trigger conditions are correct
  • Confirm GitHub API calls for fetching issues and accessing PR body are properly scoped
  • Validate the regex or parsing logic for detecting close/fix keywords and issue references
  • Check error handling for API failures or malformed issue references

Suggested labels

quality: medium

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Detect bounty issues on PR merge' clearly and specifically describes the main change: a new GitHub Actions workflow that detects bounty-labeled issues when pull requests are merged.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

👋 Hi @vanshika921vd!

This pull request needs a peer review before it can be merged. Please request a review from a team member who is not:

  • The PR author
  • DonnieBLT
  • coderabbitai
  • copilot

Once a valid peer review is submitted, this check will pass automatically. Thank you!

@github-actions github-actions bot added the needs-peer-review PR needs peer review label Dec 17, 2025
@github-actions
Copy link
Contributor

📊 Monthly Leaderboard

Hi @vanshika921vd! Here's how you rank for December 2025:

Rank User PRs Reviews Comments Total
#27 @Saptami191 1 0 0 10
#28 @vanshika921vd 1 0 0 10
#29 @Vanshikadahaliya 1 0 0 10

Leaderboard based on contributions in December 2025. Keep up the great work! 🚀

Comment on lines +9 to +44
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest

steps:
- name: Check for linked bounty issue
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
const body = pr.body || "";

const matches = body.match(/(close|closes|closed|fix|fixes|fixed)\s+#(\d+)/gi);
if (!matches) {
console.log("No linked issues found");
return;
}

for (const ref of matches) {
const issueNumber = ref.match(/#(\d+)/)[1];
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});

const hasBounty = issue.data.labels.some(
label => label.name.includes("$")
);

if (hasBounty) {
console.log(
`Bounty issue detected: #${issueNumber} | Labels: ${issue.data.labels.map(l => l.name).join(", ")}`
);
}
}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
@github-actions github-actions bot added the pre-commit: passed Pre-commit checks passed label Dec 17, 2025
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The issueNumber variable is passed as a string to the github.rest.issues.get API call, which expects an integer for the issue_number parameter, causing the call to fail.
Severity: CRITICAL | Confidence: High

🔍 Detailed Analysis

The issueNumber variable is extracted from a regex match, resulting in a string value. This string is then passed directly as the issue_number parameter to the github.rest.issues.get() API call. The GitHub REST API and its Octokit client wrapper expect this parameter to be an integer, not a string. Passing the incorrect type will cause the API call to fail, which will break the bounty detection workflow. Evidence from a similar, existing workflow shows the use of parseInt() to correctly cast the value to an integer before making the API call, confirming this is a required step.

💡 Suggested Fix

Convert the issueNumber variable to an integer before passing it to the github.rest.issues.get() API call. You can achieve this by changing line 32 to issue_number: parseInt(issueNumber). This ensures the API receives the expected data type.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: .github/workflows/detect-bounty-issue.yml#L32

Potential issue: The `issueNumber` variable is extracted from a regex match, resulting
in a string value. This string is then passed directly as the `issue_number` parameter
to the `github.rest.issues.get()` API call. The GitHub REST API and its Octokit client
wrapper expect this parameter to be an integer, not a string. Passing the incorrect type
will cause the API call to fail, which will break the bounty detection workflow.
Evidence from a similar, existing workflow shows the use of `parseInt()` to correctly
cast the value to an integer before making the API call, confirming this is a required
step.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 7655094

@github-actions github-actions bot added the tests: passed Django tests passed label Dec 17, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
.github/workflows/detect-bounty-issue.yml (2)

3-5: Consider adding branch filtering to reduce unnecessary workflow runs.

The workflow currently triggers on all PR closures regardless of the target branch. Since bounty payouts likely only matter for PRs merged to main, consider adding a branch filter.

Apply this diff to limit the workflow to the main branch:

 on:
   pull_request:
+    branches: [main]
     types: [closed]

39-43: Consider adding outputs or notifications to make bounty detection actionable.

Currently, the workflow only logs to the console, which requires manually checking workflow runs. To support automation of bounty payouts (as mentioned in the PR objectives), consider:

  1. Setting workflow outputs for downstream jobs
  2. Adding a comment to the PR or issue
  3. Creating a GitHub issue or notification
  4. Triggering a webhook or external system

Example of adding a PR comment:

               if (hasBounty) {
                 console.log(
                   `Bounty issue detected: #${issueNumber} | Labels: ${issue.data.labels.map(l => l.name).join(", ")}`
                 );
+                await github.rest.issues.createComment({
+                  owner: context.repo.owner,
+                  repo: context.repo.repo,
+                  issue_number: pr.number,
+                  body: `🎉 This PR closes bounty issue #${issueNumber}`
+                });
               }

If you add commenting, also update the permissions block to include pull-requests: write.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between cd7312d and 525f36d.

📒 Files selected for processing (1)
  • .github/workflows/detect-bounty-issue.yml (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/detect-bounty-issue.yml

14-14: the runner of "actions/github-script@v6" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 GitHub Check: CodeQL
.github/workflows/detect-bounty-issue.yml

[warning] 9-44: Workflow does not contain permissions
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run pre-commit
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
🔇 Additional comments (1)
.github/workflows/detect-bounty-issue.yml (1)

35-37: No changes needed—bounty detection using "$" is an established project convention.

The label detection logic is correct and consistent with how bounty labels are used throughout the codebase. Multiple files including website/views/issue.py and website/views/organization.py confirm that labels containing $ (e.g., $5) are the documented convention for marking bounty issues. Users are also explicitly informed via error messages about this requirement.

Likely an incorrect or invalid review comment.

Comment on lines +7 to +10
jobs:
detect-bounty:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add explicit permissions block following least-privilege principle.

The workflow does not define explicit permissions for GITHUB_TOKEN. Following security best practices, you should limit permissions to only what's required.

As per coding guidelines, apply this diff to add minimal permissions:

 jobs:
   detect-bounty:
     if: github.event.pull_request.merged == true
     runs-on: ubuntu-latest
+    permissions:
+      issues: read
+      pull-requests: read
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jobs:
detect-bounty:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
jobs:
detect-bounty:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
permissions:
issues: read
pull-requests: read
🤖 Prompt for AI Agents
.github/workflows/detect-bounty-issue.yml lines 7-10: the workflow lacks an
explicit permissions block for GITHUB_TOKEN; add a top-level permissions section
to follow least-privilege. Add a permissions block (at workflow root, above
jobs) granting only the scopes required (for example: issues: write and
contents: read) and remove any broader defaults so the workflow can
create/update issues but nothing else.

Comment on lines +21 to +25
const matches = body.match(/(close|closes|closed|fix|fixes|fixed)\s+#(\d+)/gi);
if (!matches) {
console.log("No linked issues found");
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

❓ Verification inconclusive

Script executed:

#!/bin/bash
# Find the specific file and read it
find . -name "detect-bounty-issue.yml" -o -name "*.yml" -path "*github/workflows*" | head -5

Repository: OWASP-BLT/BLT


Repository: OWASP-BLT/BLT
Exit code: 0

stdout:

./.github/workflows/add-changes-requested-label.yml
./.github/workflows/add-comment-count-label.yml
./.github/workflows/add-files-changed-label.yml
./.github/workflows/add-last-active-label.yml
./.github/workflows/add-migrations-label.yml

Script executed:

fd "detect-bounty-issue" --type f

Repository: OWASP-BLT/BLT


Repository: OWASP-BLT/BLT
Exit code: 0


Script executed:

find . -path "*workflows*" -name "*.yml" -o -path "*workflows*" -name "*.yaml" 2>/dev/null | head -10

Repository: OWASP-BLT/BLT


Repository: OWASP-BLT/BLT
Exit code: 0

stdout:

./.github/workflows/add-changes-requested-label.yml
./.github/workflows/add-comment-count-label.yml
./.github/workflows/add-files-changed-label.yml
./.github/workflows/add-last-active-label.yml
./.github/workflows/add-migrations-label.yml
./.github/workflows/assign-issues.yml
./.github/workflows/assign-new-issues-to-copilot.yml
./.github/workflows/auto-approve-dependabot.yml
./.github/workflows/auto-fix-main-precommit.yml
./.github/workflows/auto-fix-pr-precommit.yml

Script executed:

find . -name "*detect*bounty*" -o -name "*bounty*issue*" 2>/dev/null

Repository: OWASP-BLT/BLT


Repository: OWASP-BLT/BLT
Exit code: 0

stdout:

./.github/workflows/detect-bounty-issue.yml

Script executed:

grep -r "const matches = body.match" .github/workflows/ 2>/dev/null | head -5

Repository: OWASP-BLT/BLT


Repository: OWASP-BLT/BLT
Exit code: 0

stdout:

.github/workflows/detect-bounty-issue.yml:            const matches = body.match(/(close|closes|closed|fix|fixes|fixed)\s+#(\d+)/gi);

Script executed:

cat ./.github/workflows/detect-bounty-issue.yml 2>/dev/null || echo "File not found"

Repository: OWASP-BLT/BLT


Repository: OWASP-BLT/BLT
Exit code: 0

stdout:

name: Detect Bounty Issue on PR Merge

on:
  pull_request:
    types: [closed]

jobs:
  detect-bounty:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest

    steps:
      - name: Check for linked bounty issue
        uses: actions/github-script@v6
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const pr = context.payload.pull_request;
            const body = pr.body || "";

            const matches = body.match(/(close|closes|closed|fix|fixes|fixed)\s+#(\d+)/gi);
            if (!matches) {
              console.log("No linked issues found");
              return;
            }

            for (const ref of matches) {
              const issueNumber = ref.match(/#(\d+)/)[1];
              const issue = await github.rest.issues.get({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: issueNumber,
              });

              const hasBounty = issue.data.labels.some(
                label => label.name.includes("$")
              );

              if (hasBounty) {
                console.log(
                  `Bounty issue detected: #${issueNumber} | Labels: ${issue.data.labels.map(l => l.name).join(", ")}`
                );
              }
            }

Add missing GitHub closing keywords to issue reference detection.

GitHub's official closing keywords are: close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved. The current regex pattern only includes 6 of these 9 keywords and is missing "resolve", "resolves", and "resolved".

Update the regex to include all supported variants:

-            const matches = body.match(/(close|closes|closed|fix|fixes|fixed)\s+#(\d+)/gi);
+            const matches = body.match(/(close[sd]?|fix(e[sd])?|resolve[sd]?)\s*#(\d+)/gi);

This adds the missing keywords and makes whitespace optional (GitHub's linking parser is generally flexible with spacing).

🤖 Prompt for AI Agents
.github/workflows/detect-bounty-issue.yml around lines 21 to 25: the regex that
finds issue-closing keywords is missing the "resolve/resolves/resolved" variants
and doesn't allow optional whitespace before the issue number; update the
pattern to include resolve, resolves, resolved and allow an optional space (e.g.
\s* ) between the keyword and the # so it matches all GitHub closing keywords
and flexible spacing.

Comment on lines +27 to +33
for (const ref of matches) {
const issueNumber = ref.match(/#(\d+)/)[1];
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for issue API calls.

The workflow will fail if any referenced issue cannot be fetched (e.g., issue doesn't exist, API rate limit, permission issues). The workflow should handle errors gracefully and continue checking remaining issues.

Apply this diff to add error handling:

             for (const ref of matches) {
               const issueNumber = ref.match(/#(\d+)/)[1];
-              const issue = await github.rest.issues.get({
-                owner: context.repo.owner,
-                repo: context.repo.repo,
-                issue_number: issueNumber,
-              });
+              try {
+                const issue = await github.rest.issues.get({
+                  owner: context.repo.owner,
+                  repo: context.repo.repo,
+                  issue_number: issueNumber,
+                });
             
-              const hasBounty = issue.data.labels.some(
-                label => label.name.includes("$")
-              );
+                const hasBounty = issue.data.labels.some(
+                  label => label.name.includes("$")
+                );
             
-              if (hasBounty) {
-                console.log(
-                  `Bounty issue detected: #${issueNumber} | Labels: ${issue.data.labels.map(l => l.name).join(", ")}`
-                );
-              }
+                if (hasBounty) {
+                  console.log(
+                    `Bounty issue detected: #${issueNumber} | Labels: ${issue.data.labels.map(l => l.name).join(", ")}`
+                  );
+                }
+              } catch (error) {
+                console.log(`Failed to fetch issue #${issueNumber}: ${error.message}`);
+              }
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const ref of matches) {
const issueNumber = ref.match(/#(\d+)/)[1];
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
for (const ref of matches) {
const issueNumber = ref.match(/#(\d+)/)[1];
try {
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
const hasBounty = issue.data.labels.some(
label => label.name.includes("$")
);
if (hasBounty) {
console.log(
`Bounty issue detected: #${issueNumber} | Labels: ${issue.data.labels.map(l => l.name).join(", ")}`
);
}
} catch (error) {
console.log(`Failed to fetch issue #${issueNumber}: ${error.message}`);
}
}
🤖 Prompt for AI Agents
In .github/workflows/detect-bounty-issue.yml around lines 27 to 33, the call to
github.rest.issues.get assumes every referenced issue exists and will throw on
not-found, rate limits, or permission errors; wrap the API call in a try/catch,
validate the regex match before accessing group 1, and on error log a warning
(or set a flag) and continue to the next ref instead of letting the workflow
fail; ensure the rest of the loop uses a safely scoped issue variable (skip
processing when the fetch failed).

@github-project-automation github-project-automation bot moved this from Backlog to Ready in 📌 OWASP BLT Project Board Dec 17, 2025
@github-actions github-actions bot added the last-active: 0d PR last updated 0 days ago label Dec 18, 2025
@mdkaifansari04
Copy link
Contributor

@vanshika921vd resolve all the comments

@github-actions github-actions bot added last-active: 0d PR last updated 0 days ago and removed last-active: 0d PR last updated 0 days ago labels Dec 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

files-changed: 1 last-active: 0d PR last updated 0 days ago needs-peer-review PR needs peer review pre-commit: passed Pre-commit checks passed quality: medium tests: passed Django tests passed

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

2 participants