Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .github/workflows/close-spam-issues.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Auto close spam issues from new users

on:
issues:
types: [opened, reopened]

permissions:
issues: write

jobs:
close_if_new_user:
runs-on: ubuntu-latest
steps:
- name: Close issue if opened by a new user
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue
const assoc = issue.author_association || ""
const labels = (issue.labels || []).map(l => (typeof l === "string" ? l : l.name))
const exemptLabels = new Set(["allow", "do-not-close", "not-spam", "triage"])
const isExempt = labels.some(l => exemptLabels.has(l))

const newUserAssocs = new Set(["NONE", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR"])
const isNewUser = newUserAssocs.has(assoc)

if (!isNewUser || isExempt) {
core.info(`Not closing. author_association=${assoc}, exempt=${isExempt}`)
return
}
Comment on lines +18 to +30
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

This workflow will automatically close ALL issues from users with NONE, FIRST_TIMER, or FIRST_TIME_CONTRIBUTOR association, not just spam. This means legitimate first-time issue reporters will have their issues automatically closed unless they are manually exempted with a label first. Consider adding additional heuristics to identify actual spam (e.g., issue title/body patterns, length, presence of links) rather than blanket-closing all first-time issues. The current implementation may significantly harm the project's ability to receive bug reports and feature requests from new community members.

Copilot uses AI. Check for mistakes.

const message =
"Hi. This issue was auto closed because it looks like spam or low signal from a new account. " +
"If you believe this is a mistake, reply to this issue with clear details and we will review and reopen if appropriate."

await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ["spam"]
})
Comment on lines +36 to +41
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

The workflow attempts to add a "spam" label, but if this label doesn't exist in the repository, the API call will fail with a 422 error. This would prevent the subsequent comment and closing operations from executing due to the lack of error handling. Either ensure the "spam" label exists in the repository before deploying this workflow, or add error handling to gracefully continue if the label doesn't exist.

Suggested change
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ["spam"]
})
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ["spam"]
})
} catch (error) {
core.warning(`Failed to add "spam" label to issue #${issue.number}: ${error.message || error}`)
}

Copilot uses AI. Check for mistakes.

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: message
})

await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: "closed"
})
Comment on lines +36 to +55
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

The operations to label, comment, and close the issue are not atomic. If a maintainer manually adds an exempt label (like "not-spam") after the workflow starts but before it completes, the issue could still be closed despite the exemption. Consider either: (1) re-checking the labels immediately before closing, or (2) reordering operations to close first and then label (though this has its own trade-offs), or (3) using GitHub's lock API to prevent race conditions during this critical section.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +55
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

The workflow lacks error handling for the API calls. If any of the operations (addLabels, createComment, or update) fail, subsequent operations won't execute, potentially leaving the issue in an inconsistent state. For example, the issue might be labeled as spam but not closed, or closed without a comment explaining why. Consider wrapping these operations in a try-catch block to handle failures gracefully, or at minimum ensure the comment is posted before closing the issue so users understand what happened.

Suggested change
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ["spam"]
})
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: message
})
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: "closed"
})
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ["spam"]
})
} catch (error) {
core.warning(`Failed to add spam label to issue #${issue.number}: ${error}`)
}
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: message
})
} catch (error) {
core.warning(`Failed to comment on issue #${issue.number} before closing: ${error}`)
}
try {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: "closed"
})
} catch (error) {
core.warning(`Failed to close issue #${issue.number}: ${error}`)
}

Copilot uses AI. Check for mistakes.
56 changes: 56 additions & 0 deletions .github/workflows/close-spam-prs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Auto close spam PRs from new users

on:
pull_request_target:
types: [opened, reopened]

permissions:
pull-requests: write
issues: write

jobs:
close_if_new_user:
runs-on: ubuntu-latest
steps:
- name: Close PR if opened by a new user
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request
const assoc = pr.author_association || ""
const labels = (pr.labels || []).map(l => (typeof l === "string" ? l : l.name))
const exemptLabels = new Set(["allow", "do-not-close", "not-spam", "triage"])
const isExempt = labels.some(l => exemptLabels.has(l))

const newUserAssocs = new Set(["NONE", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR"])
const isNewUser = newUserAssocs.has(assoc)

if (!isNewUser || isExempt) {
core.info(`Not closing. author_association=${assoc}, exempt=${isExempt}`)
return
}
Comment on lines +19 to +31
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

This workflow will automatically close ALL pull requests from users with NONE, FIRST_TIMER, or FIRST_TIME_CONTRIBUTOR association, not just spam. This means legitimate first-time contributors will have their PRs automatically closed unless they are manually exempted with a label first. Consider adding additional heuristics to identify actual spam (e.g., PR title/body patterns, changed files, PR size) rather than blanket-closing all first-time contributions. The current implementation may significantly harm the project's ability to accept contributions from new community members.

Copilot uses AI. Check for mistakes.

const message =
"Hi. This pull request was auto closed because it looks like spam or low signal from a new account. " +
"If you believe this is a mistake, comment with what this PR changes and why it is relevant, and we will review and reopen if appropriate."

await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: ["spam"]
})
Comment on lines +37 to +42
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

The workflow attempts to add a "spam" label, but if this label doesn't exist in the repository, the API call will fail with a 422 error. This would prevent the subsequent comment and closing operations from executing due to the lack of error handling. Either ensure the "spam" label exists in the repository before deploying this workflow, or add error handling to gracefully continue if the label doesn't exist.

Suggested change
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: ["spam"]
})
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: ["spam"]
})
} catch (error) {
// If the "spam" label does not exist or labeling fails, log a warning and continue.
core.warning(`Failed to add "spam" label to PR #${pr.number}: ${error.message || error}`)
}

Copilot uses AI. Check for mistakes.

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: message
})

await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
state: "closed"
})
Comment on lines +37 to +56
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

The workflow lacks error handling for the API calls. If any of the operations (addLabels, createComment, or update) fail, subsequent operations won't execute, potentially leaving the PR in an inconsistent state. For example, the PR might be labeled as spam but not closed, or closed without a comment explaining why. Consider wrapping these operations in a try-catch block to handle failures gracefully, or at minimum ensure the comment is posted before closing the PR so users understand what happened.

Suggested change
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: ["spam"]
})
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: message
})
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
state: "closed"
})
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: ["spam"]
})
} catch (error) {
core.warning(`Failed to add spam label to PR #${pr.number}: ${error}`)
}
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: message
})
} catch (error) {
core.warning(`Failed to add spam comment to PR #${pr.number}: ${error}`)
// Do not close the PR if we couldn't explain why.
return
}
try {
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
state: "closed"
})
} catch (error) {
core.warning(`Failed to close PR #${pr.number}: ${error}`)
}

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +56
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

The operations to label, comment, and close the PR are not atomic. If a maintainer manually adds an exempt label (like "not-spam") after the workflow starts but before it completes, the PR could still be closed despite the exemption. Consider either: (1) re-checking the labels immediately before closing, or (2) reordering operations to close first and then label (though this has its own trade-offs), or (3) using GitHub's lock API to prevent race conditions during this critical section.

Copilot uses AI. Check for mistakes.
Loading