## Summary
PR #22785 merged with a Cursor attribution (05afc49e) even though the
`check-blocked-contributors` job ran and passed. The PR's commits were
clean, but the description ended with Cursor's attribution footer, which
starts with "Made with" followed by a markdown link to cursor.com, while
the script only matched the "Generated with" wording. Since the repo
squash-merges, the PR description became the merged commit message,
carrying the footer (plus the co-author trailer GitHub appends at squash
time) into main's history.
This broadens the signature pattern in
`scripts/check-blocked-contributors.ts` to also cover the "Made"/"Built"
wordings.
Note: this description intentionally avoids quoting the banned strings
verbatim, since the check scans it too (and it would become the squash
commit message).
## Test plan
Verified the new pattern against:
- The exact footer from the PR #22785 description - now caught
- The co-author trailer from the merged squash commit - caught by
existing patterns
- The "Generated with" and "Built with" wordings, with and without the
"Agent" suffix in the link label - caught
- Negative cases: prose mentioning the word cursor and a plain markdown
link to cursor.com - not flagged
## What
Extends the **Blocked Contributors Check** beyond commits so it also
scans a PR's:
- **Description** (PR body)
- **Conversation comments**
- **Inline review comments**
- **Review summaries**
## Why
The check already fails a PR when a commit is attributed to a known bot
(via author/committer/email and `Co-Authored-By` trailers). But
bot-generated content also leaks into PR prose — descriptions and
comments carry attribution footers like `🤖 Generated with Claude Code`
that the commit-only scan never saw.
## How
- **Commits** keep matching on bot *identity* (`IDENTITY_PATTERNS`:
`@anthropic.com`, `cursoragent@cursor.com`, `copilot-swe-agent[bot]`).
- **Prose surfaces** are matched only on `SIGNATURE_PATTERNS` — the
verbatim auto-generated attribution footers (`Generated with Claude
Code`, `Co-Authored-By: Claude`, Cursor equivalents). This is
deliberately tight: contributors legitimately discuss Claude/Cursor in
comments, so a bare product-name mention must **not** trip the check.
Verified that "I used Claude Code to draft this but rewrote it", "works
great in Cursor", and human `Co-Authored-By` lines all stay clean while
real footers flag.
- The workflow now also triggers on `issue_comment`,
`pull_request_review` and `pull_request_review_comment` (plus PR
`edited`), so bot prose added *between* commit pushes is still caught.
`issue_comment` is guarded to PRs only, and `PR_NUMBER` resolves from
either event.
- Each prose violation reports the surface kind and a clickable URL.
## Notes
`SIGNATURE_PATTERNS` are conservative by design and won't catch a footer
someone reworded by hand. Widening them is a follow-up if we decide to
trade some false positives for broader coverage.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22547?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## What
Adds a CI check (`Blocked Contributors Check`) that runs on every PR and
**fails** if any commit is attributed to a known bot — via the commit
author, committer, or a `Co-Authored-By:` trailer.
Goal: keep automated agents (Claude, Cursor, Copilot, …) out of Twenty's
contributor history.
## How
- On `pull_request` (`opened`, `synchronize`, `reopened`) it fetches all
PR commits via the GitHub API and matches author/committer name+email
and the full commit message (for trailers) against an editable
blocklist.
- Patterns target **bot identities** (emails / `[bot]` handles), **not**
bare first names — so a human contributor named "Claude" is *not*
flagged.
- On failure it emits `::error::` annotations naming the offending SHA +
what matched, plus remediation guidance (rebase with `--reset-author`,
strip trailers, force-push).
Current blocklist:
```
noreply@anthropic.com
@anthropic.com
cursoragent@cursor.com
copilot-swe-agent[bot]
```
Add a line to block another bot — no logic changes needed.
## Notes
- This workflow only *reports* a failed status. To actually block
merges, add **Blocked Contributors Check** as a required status check in
branch-protection rules for `main` (repo Settings → Branches).
- `@anthropic.com` also blocks any Anthropic-domain identity; narrow to
just `noreply@anthropic.com` if real Anthropic employees may contribute
under their work email.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21926?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->