Fix: Update comment moderation logic (#38451)

# Fix: Update comment moderation logic

Inspired by #38450 to help fix/complete the moderation script,
this updates the moderation script to:

- Add language detection for non-English comments
- Implement profanity filtering
- Check for off-topic content
- Improve forbidden link detection
- Add owner exemption logic
- Enhance error handling and logging
- Add a message indicating why the comment was deleted.

*To configure the moderation lists:*

- Go to repository Settings > Secrets > Actions
- Add `MODERATION_PROFANITY` secret containing a JSON array of terms
- Add `MODERATION_OFFTOPIC` secret containing a JSON array of phrases
- Example format for each: `["term1","term2","term3"]`

Resources for priming the PROFANITY and OFFTOPIC lists:
- https://www.cs.cmu.edu/~biglou/resources/ (first link)
- https://github.com/OOPSpam/spam-words/blob/main/spam-words-EN.txt

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
This commit is contained in:
MDW 2026-06-10 21:15:32 +02:00 committed by GitHub
parent 0874c86165
commit 29b60cd552
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -4,7 +4,6 @@ name: Moderation Bot
on:
issue_comment:
types: [created, edited]
pull_request_review_comment:
types: [created, edited]
@ -15,45 +14,63 @@ permissions:
jobs:
moderate:
runs-on: ubuntu-latest
steps:
- name: Install franc
run: npm install franc
- name: Moderate comments
uses: actions/github-script@v9
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const franc = require('franc')
const comment = context.payload.comment.body || ''
const lower = comment.toLowerCase()
// Détection YouTube Music
const forbiddenPatterns = [
'music.youtube.com',
'youtu.be',
'youtube.com/watch'
]
const hasYoutubeMusic = forbiddenPatterns.some(p => lower.includes(p))
const profanityList = JSON.parse(process.env.PROFANITY_LIST || '[]')
const offTopicKeywords = JSON.parse(process.env.OFFTOPIC_LIST || '[]')
const comment = context.payload.comment.body || ''
const commentAuthor = context.payload.comment.user.login
const repoOwner = context.repo.owner
const isOwner = commentAuthor === repoOwner
const isForbidden = forbiddenPatterns.some(p => comment.toLowerCase().includes(p))
const isProfane = profanityList.some(word => new RegExp(`\\b${word}\\b`, 'i').test(comment))
const isOffTopic = offTopicKeywords.some(kw => comment.toLowerCase().includes(kw.toLowerCase()))
// Détection langue
let isEnglish = true
try {
const franc = require('franc')
const lang = franc(comment)
isEnglish = lang === 'eng'
isEnglish = lang && lang.startsWith('eng')
} catch (e) {
console.log('Language detection failed:', e)
}
console.log('Detected language:', isEnglish ? 'english' : 'not english')
if ((isForbidden || isProfane || isOffTopic || !isEnglish) && !isOwner) {
try {
const issueNumber = context.payload.issue?.number || context.payload.pull_request?.number
const reason = !isEnglish ? 'non-English comment' :
isForbidden ? 'forbidden link' :
isProfane ? 'profanity' : 'off-topic content'
if (hasYoutubeMusic) {
console.log('Deleting comment...')
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: `Comment auto removed: ${reason} violates repository guidelines.`
})
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id
})
} catch (error) {
console.error('Moderation error:', error)
throw error
}
}