A self-hosted GitHub App that requires unknown issue and pull request authors to verify with GitHub OAuth and CAPTCHA before maintainers prioritize their contributions.
Slop Block helps maintainers reduce GitHub issue spam, pull request spam, bot-created issues, AI-generated PR slop, and low-quality drive-by contributions.
Unknown contributors are labeled until they complete GitHub Human Auth with GitHub OAuth and CAPTCHA.
- CAPTCHA for GitHub issues
- CAPTCHA for GitHub pull requests
- GitHub issue spam filtering
- GitHub PR spam filtering
- GitHub OAuth human verification
- Cloudflare Turnstile for GitHub contributors
- Labeling unverified GitHub contributors
- Blocking AI-generated issue and pull request slop
- Adds a
needs-human-verificationlabel to issues and pull requests from unknown authors. - Posts a verification link.
- Requires GitHub OAuth so the verifier controls the GitHub account that opened the issue or PR.
- Requires CAPTCHA through Cloudflare Turnstile, hCaptcha, or reCAPTCHA.
- Adds
human-verifiedafter successful verification. - Lets maintainers allowlist trusted contributors.
Open source maintainers are generous, not infinite. When every repo becomes a magnet for low-effort AI sludge, fake reports, and suspicious PRs, real contributors get buried and maintainers lose momentum.
This project adds a lightweight verification gate for unknown authors:
- GitHub sends an issue or PR event to the app.
- The app checks the repository policy and allowlist.
- Unknown contributors are routed through GitHub OAuth plus CAPTCHA.
- Verified humans can proceed; trusted users can be allowlisted for smoother future contributions.
- Self-hostable stack — Rust/Axum API, Next.js dashboard, and PostgreSQL via Docker Compose.
- GitHub App webhook receiver — validates
X-Hub-Signature-256before processing GitHub events. - GitHub OAuth verification — confirms the person completing verification controls the relevant GitHub account.
- CAPTCHA support — Cloudflare Turnstile, hCaptcha, and reCAPTCHA configuration support, with an explicit local-dev bypass.
- Maintainer dashboard — GitHub-login-protected UI for installed projects, policies, CAPTCHA/OAuth settings, labels, comments, and allowlists.
- Repository-level policies — enable/disable verification and tune requirements per repository.
- Trusted contributor allowlists — let known-good humans skip the hoop-jumping.
- Admin controls — browser sessions for maintainers plus optional legacy bearer-token access for automation.
- PostgreSQL-backed state — migrations run on API startup.
- Health checks —
/healthzfor process health and/readyzfor database readiness. - No project-owned hosted dependency — you run the app and database yourself; GitHub and your CAPTCHA provider stay in your accounts.
GitHub webhooks ──> Rust API ──> PostgreSQL
GitHub OAuth ─────┘ ▲
CAPTCHA provider ───────┘
Next.js dashboard ──> Rust API
apps/apireceives GitHub webhooks, handles OAuth callbacks, validates CAPTCHA tokens, stores verification state, and exposes policy/admin APIs.apps/webprovides contributor verification pages and a maintainer dashboard.crates/*contains shared Rust libraries for GitHub, CAPTCHA, policy, database, jobs, and common types.migrationscontains SQL schema migrations.docscontains operator guides for setup, configuration, security, and self-hosting.
For the Docker Compose path:
- Docker and Docker Compose
- A GitHub App
- PostgreSQL, supplied by Compose by default
- A CAPTCHA provider account/key for production
- Public HTTPS URLs for production webhook and OAuth callback traffic
For local development checks:
- Rust toolchain from
rust-toolchain.toml - Node.js/pnpm
cp .env.example .envEdit .env and fill in at least:
POSTGRES_PASSWORD/DATABASE_URLGITHUB_APP_IDGITHUB_PRIVATE_KEYGITHUB_WEBHOOK_SECRETGITHUB_OAUTH_CLIENT_IDGITHUB_OAUTH_CLIENT_SECRETADMIN_GITHUB_LOGINSADMIN_SESSION_SECRETSECRETS_ENCRYPTION_KEY- CAPTCHA secrets/site keys for the provider you use
Generate useful local secrets:
openssl rand -base64 32 # good for SECRETS_ENCRYPTION_KEY
openssl rand -hex 32 # good for ADMIN_SESSION_SECRET or webhook-style secretsStart everything:
docker compose up --build -dCheck the API and dashboard:
curl http://localhost:8080/healthz
curl http://localhost:8080/readyz
open http://localhost:3000Compose starts:
postgreswith a persistent volumeapion${API_PORT:-8080}webon${WEB_PORT:-3000}
Create a GitHub App in GitHub → Settings → Developer settings → GitHub Apps.
Recommended values:
- Homepage URL:
WEB_BASE_URL, for examplehttps://auth.example.com - Callback URL:
API_BASE_URL/api/github/oauth/callback - Webhook URL:
API_BASE_URL/api/github/webhook - Webhook secret: a long random value matching
GITHUB_WEBHOOK_SECRET
Minimum permissions for the current app:
| Permission | Access | Why |
|---|---|---|
| Metadata | Read-only | Required by GitHub Apps |
| Issues | Read and write | Read issue context and post/update verification guidance |
| Pull requests | Read and write | Read PR context and post/update verification guidance |
| Contents | Read-only | Read repository metadata without code write access |
Subscribe to these events:
issuesissue_commentpull_requestpull_request_review_comment
After creating the app, copy its App ID, private key, OAuth client ID, and OAuth client secret into .env. Install the app only on repositories where you want verification.
See docs/github-app-setup.md for the detailed walkthrough.
Before pointing real repositories at it:
- Use HTTPS for
WEB_BASE_URL,API_BASE_URL, andNEXT_PUBLIC_API_BASE_URL. - Set
COOKIE_SECURE=true. - Set
CORS_ALLOWED_ORIGINSto your exact dashboard origin. - Set
ADMIN_GITHUB_LOGINSto the maintainer GitHub accounts allowed into the dashboard. - Keep PostgreSQL private.
- Inject secrets through your deployment platform rather than committing
.env. - Never enable
TURNSTILE_DEV_BYPASS=trueon a public deployment. - Back up PostgreSQL and test restores.
More detail lives in:
Install JavaScript dependencies:
pnpm installInstall repository git hooks once per clone:
./scripts/install-git-hooks.shThe tracked hooks mirror CI to reduce broken pushes:
pre-commit:cargo fmt --all --checkandpnpm --filter web lintpre-push: Rust formatting, compilation, clippy, tests, web lint/build, anddocker compose config
Run checks manually:
cargo fmt --all --check
cargo check --workspace --all-targets
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
pnpm --filter web lint
pnpm --filter web build
docker compose config >/tmp/github-human-auth-compose.ymlRun the API locally:
cargo run -p apiRun the web app locally:
pnpm --filter web devFor local CAPTCHA-free testing, set:
COOKIE_SECURE=false
TURNSTILE_DEV_BYPASS=trueThe API intentionally rejects that bypass when secure-cookie production posture is enabled.
docker compose ps
docker compose logs -f api
docker compose logs -f web
docker compose up --build -d
docker compose downapps/api Rust/Axum API service
apps/web Next.js dashboard and verification UI
crates/ Shared Rust crates
migrations/ SQL migrations
docker/ Container build assets
docs/ Operator documentation
GitHub Human Auth is built to reduce the slop tax: fewer mystery accounts, fewer bot-shaped chores, fewer “please review my 4,000-line vibe PR” moments. Real contributors still get a path in. Maintainers get a calmer queue. Everyone gets to keep a little more sanity.