|
| 1 | +# Gitea Webhook Integration Setup and Testing Guide |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The Topcoder Review API includes a secure Gitea webhook integration that receives webhook events from Gitea repositories, validates them using HMAC-SHA256 signature verification, and stores them in the database for audit and future processing. |
| 6 | + |
| 7 | +## Table of Contents |
| 8 | + |
| 9 | +1. [Quick Start](#quick-start) |
| 10 | +2. [Environment Setup](#environment-setup) |
| 11 | +3. [Gitea Repository Configuration](#Gitea-repository-configuration) |
| 12 | +4. [Local Development Setup](#local-development-setup) |
| 13 | +5. [Testing the Integration](#testing-the-integration) |
| 14 | +6. [API Endpoint Reference](#api-endpoint-reference) |
| 15 | +7. [Database Schema](#database-schema) |
| 16 | +8. [Security Considerations](#security-considerations) |
| 17 | +9. [Troubleshooting](#troubleshooting) |
| 18 | +10. [Monitoring and Maintenance](#monitoring-and-maintenance) |
| 19 | + |
| 20 | +## Quick Start |
| 21 | + |
| 22 | +For immediate setup, follow these steps: |
| 23 | + |
| 24 | +1. Generate a secure webhook secret |
| 25 | +2. Configure environment variables |
| 26 | +3. Set up Gitea webhook in repository settings |
| 27 | +4. Test with a sample event |
| 28 | + |
| 29 | +## Environment Setup |
| 30 | + |
| 31 | +### Required Environment Variables |
| 32 | + |
| 33 | +Add the following environment variable to your application configuration: |
| 34 | + |
| 35 | +```bash |
| 36 | +# .env file |
| 37 | +GITEA_WEBHOOK_SECRET=your_generated_secret_here |
| 38 | +``` |
| 39 | + |
| 40 | +### Generate Webhook Secret |
| 41 | + |
| 42 | +**Using OpenSSL:** |
| 43 | + |
| 44 | +```bash |
| 45 | +openssl rand -hex 32 |
| 46 | +``` |
| 47 | + |
| 48 | +**Example Output:** |
| 49 | + |
| 50 | +``` |
| 51 | +a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456 |
| 52 | +``` |
| 53 | + |
| 54 | +⚠️ **Important:** Store this secret securely and use the same value in both your application environment and Gitea webhook configuration. |
| 55 | + |
| 56 | +### Database Setup |
| 57 | + |
| 58 | +The webhook integration requires the `gitWebhookLog` table. If not already created, run the database migration: |
| 59 | + |
| 60 | +```bash |
| 61 | +npx prisma migrate dev |
| 62 | +``` |
| 63 | + |
| 64 | +## Gitea Repository Configuration |
| 65 | + |
| 66 | +### Step 1: Access Repository Settings |
| 67 | + |
| 68 | +1. Navigate to your Gitea repository |
| 69 | +2. Click on the **Settings** tab (requires admin permissions) |
| 70 | +3. In the left sidebar, click **Webhooks** |
| 71 | +4. Click **Add webhook** |
| 72 | + |
| 73 | +### Step 2: Configure Webhook Settings |
| 74 | + |
| 75 | +#### Payload URL |
| 76 | + |
| 77 | +**Production/Staging Environment:** |
| 78 | + |
| 79 | +``` |
| 80 | +https://your-api-domain.com/v6/review/webhooks/gitea |
| 81 | +``` |
| 82 | + |
| 83 | +**Development Environment:** |
| 84 | + |
| 85 | +``` |
| 86 | +https://your-dev-domain.com/webhooks/gitea |
| 87 | +``` |
| 88 | + |
| 89 | +Note: The `/v6/review` prefix is only added in production when `NODE_ENV=production`. |
| 90 | + |
| 91 | +#### Content Type |
| 92 | + |
| 93 | +- Select `application/json` |
| 94 | + |
| 95 | +#### Secret |
| 96 | + |
| 97 | +- Enter the webhook secret you generated earlier |
| 98 | +- This must exactly match your `GITEA_WEBHOOK_SECRET` environment variable |
| 99 | + |
| 100 | +#### SSL Verification |
| 101 | + |
| 102 | +- Keep **Enable SSL verification** checked (recommended for production) |
| 103 | +- For development with proper HTTPS setup, this should remain enabled |
| 104 | + |
| 105 | +### Step 3: Select Events |
| 106 | + |
| 107 | +Choose one of the following options: |
| 108 | + |
| 109 | +**Option A: Send Everything (Recommended for Testing)** |
| 110 | + |
| 111 | +- Select "Send me everything" to receive all Gitea event types |
| 112 | + |
| 113 | +**Option B: Select Individual Events** |
| 114 | +Common events for development workflows: |
| 115 | + |
| 116 | +- **Pushes** - Code pushes to repository |
| 117 | +- **Pull requests** - PR creation, updates, merges |
| 118 | +- **Issues** - Issue creation, updates, comments |
| 119 | +- **Issue comments** - Comments on issues and PRs |
| 120 | +- **Releases** - Release creation and updates |
| 121 | +- **Create** - Branch or tag creation |
| 122 | +- **Delete** - Branch or tag deletion |
| 123 | + |
| 124 | +### Step 4: Activate and Create |
| 125 | + |
| 126 | +1. Ensure **Active** checkbox is checked |
| 127 | +2. Click **Add webhook** |
| 128 | +3. Gitea will automatically send a `ping` event to test the webhook |
| 129 | + |
| 130 | +## Local Development Setup |
| 131 | + |
| 132 | +Since Gitea webhooks require a publicly accessible URL, local development requires exposing your local server to the internet. |
| 133 | + |
| 134 | +**Install ngrok:** |
| 135 | + |
| 136 | +```bash |
| 137 | +npm install -g ngrok |
| 138 | +``` |
| 139 | + |
| 140 | +**Setup process:** |
| 141 | + |
| 142 | +```bash |
| 143 | +# 1. Start your local API server |
| 144 | +pnpm run start:dev |
| 145 | + |
| 146 | +# 2. In another terminal, expose your local server |
| 147 | +ngrok http 3000 |
| 148 | + |
| 149 | +# 3. Copy the HTTPS URL from ngrok output |
| 150 | +# Example: https://abc123.ngrok.io |
| 151 | + |
| 152 | +# 4. Use this URL in Gitea webhook settings |
| 153 | +# https://abc123.ngrok.io/webhooks/gitea |
| 154 | +``` |
| 155 | + |
| 156 | +## Testing the Integration |
| 157 | + |
| 158 | +### Manual Testing |
| 159 | + |
| 160 | +#### 1. Verify Initial Setup |
| 161 | + |
| 162 | +After creating the webhook, Gitea automatically sends a `ping` event: |
| 163 | + |
| 164 | +1. Go to your repository's webhook settings |
| 165 | +2. Click on your webhook |
| 166 | +3. Check **Recent Deliveries** section |
| 167 | +4. Look for the `ping` event with status 200 OK |
| 168 | + |
| 169 | +#### 2. Trigger Test Events |
| 170 | + |
| 171 | +**Create a Push Event:** |
| 172 | + |
| 173 | +```bash |
| 174 | +# Make a small change |
| 175 | +echo "webhook test" >> test-webhook.txt |
| 176 | +git add test-webhook.txt |
| 177 | +git commit -m "Test webhook integration" |
| 178 | +git push origin main |
| 179 | +``` |
| 180 | + |
| 181 | +**Create an Issue:** |
| 182 | + |
| 183 | +1. Go to your repository on Gitea |
| 184 | +2. Click **Issues** tab |
| 185 | +3. Click **New issue** |
| 186 | +4. Create a test issue |
| 187 | + |
| 188 | +**Create a Pull Request:** |
| 189 | + |
| 190 | +1. Create a new branch: `git checkout -b test-webhook` |
| 191 | +2. Make changes and commit |
| 192 | +3. Push branch: `git push origin test-webhook` |
| 193 | +4. Open pull request on Gitea |
| 194 | + |
| 195 | +### Testing with curl |
| 196 | + |
| 197 | +You can test the webhook endpoint directly using curl with proper signature generation: |
| 198 | + |
| 199 | +```bash |
| 200 | +#!/bin/bash |
| 201 | + |
| 202 | +# Configuration |
| 203 | +WEBHOOK_URL="http://localhost:3000/webhooks/gitea" # Adjust for your environment |
| 204 | +WEBHOOK_SECRET="your_webhook_secret_here" |
| 205 | +PAYLOAD='{"test": "data", "repository": {"name": "test-repo"}}' |
| 206 | +DELIVERY_ID="test-delivery-$(date +%s)" |
| 207 | +EVENT_TYPE="push" |
| 208 | + |
| 209 | +# Generate signature |
| 210 | +SIGNATURE="sha256=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | sed 's/^.* //')" |
| 211 | + |
| 212 | +# Send test webhook |
| 213 | +curl -X POST "$WEBHOOK_URL" \ |
| 214 | + -H "Content-Type: application/json" \ |
| 215 | + -H "X-Gitea-Event: $EVENT_TYPE" \ |
| 216 | + -H "X-Gitea-Delivery: $DELIVERY_ID" \ |
| 217 | + -H "X-Hub-Signature-256: $SIGNATURE" \ |
| 218 | + -d "$PAYLOAD" |
| 219 | +``` |
| 220 | + |
| 221 | +## API Endpoint Reference |
| 222 | + |
| 223 | +### Webhook Endpoint |
| 224 | + |
| 225 | +**URL:** `POST /webhooks/gitea` (development) or `POST /v6/review/webhooks/gitea` (production) |
| 226 | + |
| 227 | +**Required Headers:** |
| 228 | + |
| 229 | +- `Content-Type: application/json` |
| 230 | +- `X-Gitea-Event: {event_type}` - Gitea event type (push, pull_request, etc.) |
| 231 | +- `X-Gitea-Delivery: {delivery_id}` - Unique delivery identifier from Gitea |
| 232 | +- `X-Hub-Signature-256: sha256={signature}` - HMAC-SHA256 signature for verification |
| 233 | + |
| 234 | +**Request Body:** |
| 235 | + |
| 236 | +- Gitea webhook payload (varies by event type) |
| 237 | + |
| 238 | +**Response Codes:** |
| 239 | + |
| 240 | +- `200 OK` - Webhook processed successfully |
| 241 | +- `400 Bad Request` - Missing required headers or invalid payload |
| 242 | +- `403 Forbidden` - Invalid signature verification |
| 243 | +- `500 Internal Server Error` - Processing error or configuration issue |
| 244 | + |
| 245 | +**Success Response:** |
| 246 | + |
| 247 | +```json |
| 248 | +{ |
| 249 | + "success": true, |
| 250 | + "message": "Webhook processed successfully" |
| 251 | +} |
| 252 | +``` |
| 253 | + |
| 254 | +**Error Response:** |
| 255 | + |
| 256 | +```json |
| 257 | +{ |
| 258 | + "statusCode": 403, |
| 259 | + "message": "Invalid signature", |
| 260 | + "error": "Forbidden", |
| 261 | + "timestamp": "2024-01-01T00:00:00.000Z", |
| 262 | + "path": "/webhooks/gitea" |
| 263 | +} |
| 264 | +``` |
| 265 | + |
| 266 | +## Database Schema |
| 267 | + |
| 268 | +Webhook events are stored in the `gitWebhookLog` table: |
| 269 | + |
| 270 | +```sql |
| 271 | +CREATE TABLE "gitWebhookLog" ( |
| 272 | + "id" VARCHAR(14) NOT NULL DEFAULT nanoid(), |
| 273 | + "eventId" TEXT NOT NULL, |
| 274 | + "event" TEXT NOT NULL, |
| 275 | + "eventPayload" JSONB NOT NULL, |
| 276 | + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, |
| 277 | + |
| 278 | + CONSTRAINT "gitWebhookLog_pkey" PRIMARY KEY ("id") |
| 279 | +); |
| 280 | + |
| 281 | +-- Indexes for efficient querying |
| 282 | +CREATE INDEX "gitWebhookLog_eventId_idx" ON "gitWebhookLog"("eventId"); |
| 283 | +CREATE INDEX "gitWebhookLog_event_idx" ON "gitWebhookLog"("event"); |
| 284 | +CREATE INDEX "gitWebhookLog_createdAt_idx" ON "gitWebhookLog"("createdAt"); |
| 285 | +``` |
| 286 | + |
| 287 | +### Query Examples |
| 288 | + |
| 289 | +**View recent webhook events:** |
| 290 | + |
| 291 | +```sql |
| 292 | +SELECT |
| 293 | + id, |
| 294 | + "eventId", |
| 295 | + event, |
| 296 | + "createdAt" |
| 297 | +FROM "gitWebhookLog" |
| 298 | +ORDER BY "createdAt" DESC |
| 299 | +LIMIT 10; |
| 300 | +``` |
| 301 | + |
| 302 | +**Filter by event type:** |
| 303 | + |
| 304 | +```sql |
| 305 | +SELECT * FROM "gitWebhookLog" |
| 306 | +WHERE event = 'push' |
| 307 | +ORDER BY "createdAt" DESC; |
| 308 | +``` |
| 309 | + |
| 310 | +**View specific webhook payload:** |
| 311 | + |
| 312 | +```sql |
| 313 | +SELECT |
| 314 | + event, |
| 315 | + "eventPayload" |
| 316 | +FROM "gitWebhookLog" |
| 317 | +WHERE "eventId" = 'your-delivery-id'; |
| 318 | +``` |
| 319 | + |
| 320 | +## Security Considerations |
| 321 | + |
| 322 | +### Signature Verification |
| 323 | + |
| 324 | +The webhook implementation uses Gitea's recommended security practices: |
| 325 | + |
| 326 | +1. **HMAC-SHA256 Signature:** All incoming webhooks are verified using HMAC-SHA256 |
| 327 | +2. **Timing-Safe Comparison:** Uses `crypto.timingSafeEqual()` to prevent timing attacks |
| 328 | +3. **Secret Protection:** Webhook secrets are stored as environment variables |
| 329 | +4. **Header Validation:** Validates all required Gitea headers |
| 330 | + |
| 331 | +### Best Practices |
| 332 | + |
| 333 | +1. **Use HTTPS:** Always use HTTPS URLs for production webhooks |
| 334 | +2. **Rotate Secrets:** Periodically rotate webhook secrets |
| 335 | +3. **Monitor Access:** Regularly review webhook delivery logs |
| 336 | +4. **Limit Events:** Only subscribe to events you actually need |
| 337 | +5. **Access Control:** Restrict webhook configuration to repository administrators |
| 338 | + |
| 339 | +### Environment Security |
| 340 | + |
| 341 | +- Store `GITEA_WEBHOOK_SECRET` securely using your deployment platform's secret management |
| 342 | +- Never commit secrets to version control |
| 343 | +- Use different secrets for different environments |
| 344 | +- Implement proper secret rotation procedures |
| 345 | + |
| 346 | +### Log Analysis |
| 347 | + |
| 348 | +Key log messages to monitor: |
| 349 | + |
| 350 | +``` |
| 351 | +# Successful webhook processing |
| 352 | +[WebhookController] Successfully processed Gitea webhook |
| 353 | +
|
| 354 | +# Signature validation failures |
| 355 | +[GiteaSignatureGuard] Invalid webhook signature for delivery |
| 356 | +
|
| 357 | +# Configuration errors |
| 358 | +[GiteaSignatureGuard] Gitea_WEBHOOK_SECRET environment variable is not configured |
| 359 | +``` |
0 commit comments