- Python 99.4%
- Dockerfile 0.6%
| forgejo_janitor | ||
| tests | ||
| .gitignore | ||
| config.example.toml | ||
| docker-compose.example.yml | ||
| Dockerfile | ||
| pyproject.toml | ||
| README.md | ||
Forgejo Janitor
Automated, conservative cleanup for Forgejo SEO spam accounts.
The janitor scores recently registered users, or users with recent repository/issue/comment activity, using profile, repository, issue, comment, and SSH-key signals. It is dry-run by default and never deletes accounts. Executed actions are limited to:
sanitize_profile: clear profilefull_name,website,location, anddescription.restrict_user: setis_restricted = true.prohibit_login: setprohibit_login = truefor high-confidence spam only.quarantine_repo: make a spam repository private, archive it, and clear repo metadata.redact_issue: replace spam issue title/body and close/lock the issue.redact_comment: replace spam comment body.
It intentionally does not print raw email addresses. Reports include only email domains.
Members of protected organizations are never scored or acted on. The default protected org is pleroma.
Quick Start
python -m venv .venv
. .venv/bin/activate
pip install -e '.[test]'
pytest
Run a dry scan:
DATABASE_URL='postgresql://forgejo:password@db:5432/forgejo' \
forgejo-janitor scan --config config.example.toml --output summary
Run with optional bare repository scanning:
DATABASE_URL='postgresql://forgejo:password@db:5432/forgejo' \
forgejo-janitor scan \
--config config.example.toml \
--repo-root /data/git/repositories \
--output jsonl
Apply planned actions:
DATABASE_URL='postgresql://forgejo:password@db:5432/forgejo' \
forgejo-janitor run \
--config config.example.toml \
--repo-root /data/git/repositories \
--max-actions 100 \
--execute
Monitor recent repo/issue/comment activity continuously:
DATABASE_URL='postgresql://forgejo:password@db:5432/forgejo' \
forgejo-janitor monitor \
--config config.example.toml \
--repo-root /data/git/repositories \
--activity-minutes 5 \
--interval 60 \
--max-actions 100 \
--execute
Omit --execute to keep monitor mode in dry-run mode.
Email Notifications
Pass --notify-email to send an email when actions are planned or applied. Recipients default to active Forgejo admins from the database unless JANITOR_EMAIL_TO is set.
export JANITOR_SMTP_HOST=mail.example
export JANITOR_SMTP_PORT=587
export JANITOR_SMTP_USERNAME=janitor@example
export JANITOR_SMTP_PASSWORD=secret
export JANITOR_EMAIL_FROM=janitor@example
export JANITOR_EMAIL_TO=admin1@example,admin2@example
Set JANITOR_SMTP_STARTTLS=false to disable STARTTLS.
Omit --execute to keep run in dry-run mode.
Docker
Build locally:
docker build -t forgejo-janitor:latest .
Dry-run with Docker:
docker run --rm \
--network forgejo_default \
-e DATABASE_URL='postgresql://forgejo:password@db:5432/forgejo' \
-v /opt/forgejo/volumes/forgejo/git/repositories:/data/git/repositories:ro \
-v ./config.example.toml:/config/janitor.toml:ro \
forgejo-janitor:latest scan --config /config/janitor.toml --repo-root /data/git/repositories
Use docker-compose.example.yml as a starting point for a monitor deployment.
Policy
Thresholds and heuristics live in config.example.toml. The default policy is tuned to remove SEO backlink value first and reserve login prohibition/content redaction for high-confidence issue/repository/comment spam.
Known-good automation should be allowlisted by username or email domain. The example allowlists pleroma-ci and pleroma.social.
Organization members that must never be touched should be listed under allowlist.protected_orgs. The example protects all members of the pleroma organization.
Development
pytest
python -m forgejo_janitor.cli scan --help