feat. rebuild service in Go
ci / test (pull_request) Successful in 1m54s
ci / publish (pull_request) Has been skipped

Rebuild the Gitea Codex review bot from the product contract with a Go HTTP service, durable SQL queue, typed Gitea client, isolated runner, and deployment updates.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Space-Banane
2026-07-12 21:51:01 +02:00
parent fdd3819ff8
commit f19b271642
74 changed files with 2623 additions and 4819 deletions
+15
View File
@@ -0,0 +1,15 @@
# Go rebuild notes
The service was rebuilt from the product behavior rather than ported module-for-module from the previous Python implementation. The Go code keeps the durable table names and public webhook/health contracts while separating domain decisions from HTTP, SQL, Gitea, Docker, and Codex concerns.
## Deliberate differences
- There is no host-side review fallback. Runner failure is a failed attempt and is retried according to queue policy.
- Review result output is validated strictly and bounded before persistence or posting.
- The landing and 404 pages are embedded and do not load Tailwind from a third-party CDN.
- The current tested append-comment behavior is retained: each completed review posts a new comment and updates the latest `bot_comments` mapping.
- Docker execution is treated as a privileged deployment boundary. The bundled image runs the bot as root because direct Docker-socket access otherwise fails; production should replace this with a socket proxy or separate runner service, pinned images, resource limits, and least-privilege credentials.
## Migration compatibility
The Go startup migrator creates the logical `webhook_events`, `review_jobs`, `review_runs`, and `bot_comments` schema and preserves `trigger_comment_body`. Existing deployments should be backed up before switching binaries. The first Go release does not drop old columns or tables.
+36 -66
View File
@@ -1,83 +1,53 @@
# Webhook Setup (Global and Repository-Only)
# Webhook setup
This bot accepts Gitea webhook events at:
The Go service accepts signed Gitea webhooks at:
- `POST /webhook/gitea`
It only processes these event types:
It processes only `issue_comment` and `pull_request_comment` events. The handler verifies the exact raw request body with HMAC-SHA256 using `GITEA_WEBHOOK_SECRET`, enforces `ALLOWED_REPOS`, ignores bot-authored comments, and queues recognized `@codex` commands.
- `issue_comment`
- `pull_request_comment`
## Configure Gitea
It verifies `X-Gitea-Signature` using `GITEA_WEBHOOK_SECRET` (HMAC-SHA256).
1. Deploy the service at a URL reachable by Gitea, for example `https://bot.example.com/webhook/gitea`.
2. Set the same random secret in Gitea and `GITEA_WEBHOOK_SECRET`.
3. Configure either an instance/global webhook or one repository webhook per target repository.
4. Use JSON content type and enable only Issue comment and Pull request comment events.
5. Add every allowed `owner/repository` to `ALLOWED_REPOS`.
6. Test the webhook from Gitea, then check `GET /healthz`.
## Prerequisites
`WEBHOOK_MODE=global` or `WEBHOOK_MODE=repo` is a deployment label; webhook provisioning remains an administrator responsibility.
1. Bot is reachable from Gitea (example: `https://bot.example.com/webhook/gitea`).
2. `GITEA_WEBHOOK_SECRET` is set in your bot `.env`.
3. `ALLOWED_REPOS` includes repositories you want to allow (example: `team/repo-a,team/repo-b`).
## Environment
## Option A: Global Webhook (single webhook, recommended)
Required values are `GITEA_BASE_URL`, `GITEA_TOKEN`, `GITEA_BOT_USERNAME`, `GITEA_WEBHOOK_SECRET`, `ALLOWED_REPOS`, and either `DATABASE_URL` or the `DB_*` values. API-key Codex mode also requires `OPENAI_API_KEY`.
Use this when you want one webhook configuration for many repositories.
1. In Gitea, open site administration webhook settings (instance-level/global webhooks).
2. Add a new webhook of type `Gitea` (JSON payload).
3. Set:
- `Payload URL`: `https://bot.example.com/webhook/gitea`
- `HTTP Method`: `POST`
- `Secret`: same value as `GITEA_WEBHOOK_SECRET`
- `Content Type`: `application/json`
4. Enable only these events:
- `Issue comment`
- `Pull request comment`
5. Save and use the webhook test/ping action.
6. Set `WEBHOOK_MODE=global` in bot env (informational, for deployment clarity).
Notes:
- The bot still enforces `ALLOWED_REPOS`; non-allowlisted repos are ignored.
- A global webhook is usually easiest to operate at scale.
## Option B: Repository-Only Webhook (per repository)
Use this when you want explicit repo-by-repo control.
1. Open the repository in Gitea.
2. Go to repository `Settings` -> `Webhooks`.
3. Add a new `Gitea` webhook.
4. Set:
- `Payload URL`: `https://bot.example.com/webhook/gitea`
- `HTTP Method`: `POST`
- `Secret`: same value as `GITEA_WEBHOOK_SECRET`
- `Content Type`: `application/json`
5. Enable only:
- `Issue comment`
- `Pull request comment`
6. Save and test.
7. Repeat for each repository.
8. Set `WEBHOOK_MODE=repo` in bot env.
Important:
- This bot has one configured secret (`GITEA_WEBHOOK_SECRET`) per bot instance.
- If multiple repo webhooks use different secrets, signature verification will fail for repos not matching the configured secret.
## Minimal `.env` snippet
The recommended local development database is SQLite:
```dotenv
GITEA_WEBHOOK_SECRET=replace-with-random-secret
ALLOWED_REPOS=team/repo-a,team/repo-b
WEBHOOK_MODE=global
DATABASE_URL=sqlite://./gitea-codex.db
```
For repo-only mode, use `WEBHOOK_MODE=repo`.
Production deployments should use MariaDB and a token with only the Gitea permissions needed to read pull requests/files and create comments. Keep the runner image pinned to a reviewed digest and treat review execution as untrusted code execution.
## Validation Checklist
## Command examples
1. `GET /healthz` returns `{"status":"ok"}`.
2. Webhook deliveries from Gitea return HTTP `200` (or bot returns accepted/ignored JSON, not `401`).
3. `401 invalid signature` means webhook secret mismatch.
4. `{"accepted": false, "reason": "repo not allowed"}` means update `ALLOWED_REPOS`.
5. A PR comment with `@codex review` on an allowlisted repo queues a job.
```text
@codex review
@codex review security
@codex review performance --full
@codex review tests
@codex rerun
@codex explain
@codex ignore
@codex help
```
Commands must begin the comment. Inline mentions in ordinary discussion text are intentionally ignored for compatibility. `@codex fix` is not supported.
## Security notes
- Invalid signatures return HTTP 401.
- Fork pull requests are skipped unless `ALLOW_UNTRUSTED_FORKS=true`.
- The bot launches review containers through the host Docker API; secure the Docker socket and runner host accordingly.
- The review container receives credentials required by the configured Codex/Gitea workflow. Use least-privilege credentials, restrict network access, and do not use unpinned images in production.
- Health detail endpoints expose bounded job metadata. Put them behind an internal network or reverse-proxy authentication if repository names and review errors are sensitive.