document api endpoints and webhooks
This commit is contained in:
601
docs/api.md
Normal file
601
docs/api.md
Normal file
@@ -0,0 +1,601 @@
|
||||
# API Reference
|
||||
|
||||
Arbiter provides a REST API for managing reviews, monitoring metrics, and receiving
|
||||
webhook events from GitHub and GitLab.
|
||||
|
||||
## Interactive Documentation
|
||||
|
||||
The API provides auto-generated interactive documentation:
|
||||
|
||||
- **Swagger UI:** `http://localhost:8000/docs`
|
||||
- **ReDoc:** `http://localhost:8000/redoc`
|
||||
- **OpenAPI Schema:** `http://localhost:8000/openapi.json`
|
||||
|
||||
## Base URL
|
||||
|
||||
All API endpoints are relative to the base URL:
|
||||
|
||||
```
|
||||
http://localhost:8000
|
||||
```
|
||||
|
||||
In production, use your configured domain with HTTPS.
|
||||
|
||||
## Authentication
|
||||
|
||||
### Webhook Authentication
|
||||
|
||||
Webhooks use signature/token verification:
|
||||
|
||||
**GitHub:**
|
||||
- Header: `X-Hub-Signature-256`
|
||||
- Format: `sha256=<hmac_hex_digest>`
|
||||
- Algorithm: HMAC-SHA256 using `ARBITER_GITHUB_WEBHOOK_SECRET`
|
||||
|
||||
**GitLab:**
|
||||
- Header: `X-GitLab-Token`
|
||||
- Format: Plain token string
|
||||
- Verification: Constant-time comparison with `ARBITER_GITLAB_WEBHOOK_TOKEN`
|
||||
|
||||
### API Authentication
|
||||
|
||||
The REST API currently does not require authentication. For production deployments,
|
||||
place it behind a reverse proxy with authentication or configure network-level access
|
||||
controls.
|
||||
|
||||
## REST Endpoints
|
||||
|
||||
### Reviews
|
||||
|
||||
#### List Reviews
|
||||
|
||||
```http
|
||||
GET /api/reviews
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `page` | integer | 1 | Page number (1-indexed) |
|
||||
| `page_size` | integer | 20 | Items per page (1-100) |
|
||||
| `repository` | string | - | Filter by repository name |
|
||||
| `status` | string | - | Filter by status (pending, processing, completed, failed) |
|
||||
| `verdict` | string | - | Filter by verdict (approve, request_changes, comment) |
|
||||
| `author` | string | - | Filter by PR author |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "abc123",
|
||||
"repository": "owner/repo",
|
||||
"pr_number": 42,
|
||||
"pr_title": "Add new feature",
|
||||
"author": "username",
|
||||
"status": "completed",
|
||||
"verdict": "request_changes",
|
||||
"verdict_confidence": 0.92,
|
||||
"finding_count": 5,
|
||||
"critical_count": 1,
|
||||
"high_count": 2,
|
||||
"total_cost_usd": 0.12,
|
||||
"created_at": "2025-06-04T10:00:00Z",
|
||||
"completed_at": "2025-06-04T10:02:30Z"
|
||||
}
|
||||
],
|
||||
"total": 150,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"pages": 8
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Review Detail
|
||||
|
||||
```http
|
||||
GET /api/reviews/{review_id}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "abc123",
|
||||
"repository": "owner/repo",
|
||||
"pr_number": 42,
|
||||
"pr_title": "Add new feature",
|
||||
"base_sha": "abc1234",
|
||||
"head_sha": "def5678",
|
||||
"author": "username",
|
||||
"is_draft": false,
|
||||
"status": "completed",
|
||||
"verdict": "request_changes",
|
||||
"verdict_confidence": 0.92,
|
||||
"verdict_reasoning": "Critical security issue requires resolution",
|
||||
"total_tokens": 15000,
|
||||
"total_cost_usd": 0.12,
|
||||
"tokens_by_agent": {"security": 5000, "style": 5000, "complexity": 5000},
|
||||
"cost_by_agent": {"security": 0.04, "style": 0.04, "complexity": 0.04},
|
||||
"created_at": "2025-06-04T10:00:00Z",
|
||||
"started_at": "2025-06-04T10:00:05Z",
|
||||
"completed_at": "2025-06-04T10:02:30Z",
|
||||
"error_message": null,
|
||||
"findings": [
|
||||
{
|
||||
"id": "finding-1",
|
||||
"agent": "security",
|
||||
"file": "src/auth.py",
|
||||
"line_start": 42,
|
||||
"line_end": 45,
|
||||
"severity": "critical",
|
||||
"confidence": 0.95,
|
||||
"title": "SQL Injection Vulnerability",
|
||||
"description": "User input is passed directly to SQL query",
|
||||
"reasoning": "String interpolation in SQL queries allows injection",
|
||||
"suggestion": "Use parameterized queries",
|
||||
"references": ["https://owasp.org/..."],
|
||||
"prompt_version": "security-v1.0"
|
||||
}
|
||||
],
|
||||
"conflicts": [
|
||||
{
|
||||
"id": "conflict-1",
|
||||
"finding_ids": ["finding-2", "finding-3"],
|
||||
"nature": "opposing_recommendation",
|
||||
"description": "Style suggests splitting function, complexity wants to keep it",
|
||||
"severity_weight": 0.5,
|
||||
"resolution": "Keep function together for readability",
|
||||
"winning_finding_id": "finding-3"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Deliberation Log
|
||||
|
||||
```http
|
||||
GET /api/reviews/{review_id}/deliberation
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"review_id": "abc123",
|
||||
"steps": [
|
||||
{
|
||||
"id": "step-1",
|
||||
"step_type": "agent_start",
|
||||
"timestamp": "2025-06-04T10:00:10Z",
|
||||
"description": "Security agent started review",
|
||||
"details": {"agent": "security"},
|
||||
"sequence": 1
|
||||
},
|
||||
{
|
||||
"id": "step-2",
|
||||
"step_type": "finding_added",
|
||||
"timestamp": "2025-06-04T10:00:45Z",
|
||||
"description": "Security agent found SQL injection",
|
||||
"details": {"finding_id": "finding-1", "severity": "critical"},
|
||||
"sequence": 2
|
||||
},
|
||||
{
|
||||
"id": "step-3",
|
||||
"step_type": "conflict_detected",
|
||||
"timestamp": "2025-06-04T10:01:30Z",
|
||||
"description": "Detected conflict between style and complexity",
|
||||
"details": {"conflict_id": "conflict-1"},
|
||||
"sequence": 3
|
||||
},
|
||||
{
|
||||
"id": "step-4",
|
||||
"step_type": "verdict_determined",
|
||||
"timestamp": "2025-06-04T10:02:00Z",
|
||||
"description": "Final verdict: request_changes",
|
||||
"details": {"verdict": "request_changes", "confidence": 0.92},
|
||||
"sequence": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Trigger Manual Review
|
||||
|
||||
```http
|
||||
POST /api/reviews
|
||||
```
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"repository": "owner/repo",
|
||||
"pr_number": 42,
|
||||
"base_sha": "abc1234",
|
||||
"head_sha": "def5678",
|
||||
"pr_title": "Add new feature",
|
||||
"author": "username",
|
||||
"is_draft": false,
|
||||
"policy_name": "default",
|
||||
"diff_content": "diff --git a/file.py b/file.py\n..."
|
||||
}
|
||||
```
|
||||
|
||||
**Response (202 Accepted):**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "queued",
|
||||
"job_id": "job-abc123",
|
||||
"review_id": null,
|
||||
"message": "Review queued with job ID job-abc123"
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Metrics
|
||||
|
||||
```http
|
||||
GET /api/reviews/metrics
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"total_reviews": 500,
|
||||
"completed_reviews": 485,
|
||||
"average_cost_usd": 0.15,
|
||||
"verdict_counts": {
|
||||
"approve": 300,
|
||||
"request_changes": 150,
|
||||
"comment": 35
|
||||
},
|
||||
"severity_counts": {
|
||||
"critical": 50,
|
||||
"high": 200,
|
||||
"medium": 500,
|
||||
"low": 1000,
|
||||
"info": 300
|
||||
},
|
||||
"reviews_by_day": [
|
||||
{"date": "2025-06-01", "count": 15},
|
||||
{"date": "2025-06-02", "count": 22},
|
||||
{"date": "2025-06-03", "count": 18}
|
||||
],
|
||||
"cost_by_agent": {
|
||||
"security": 25.50,
|
||||
"style": 20.00,
|
||||
"complexity": 22.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Conversations
|
||||
|
||||
#### List Conversations
|
||||
|
||||
```http
|
||||
GET /api/conversations
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `page` | integer | 1 | Page number |
|
||||
| `page_size` | integer | 20 | Items per page |
|
||||
| `repository` | string | - | Filter by repository |
|
||||
| `review_id` | string | - | Filter by review ID |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "conv-123",
|
||||
"review_id": "abc123",
|
||||
"platform": "github",
|
||||
"repository": "owner/repo",
|
||||
"pr_number": 42,
|
||||
"message_count": 4,
|
||||
"total_tokens": 2000,
|
||||
"total_cost_usd": 0.02,
|
||||
"started_at": "2025-06-04T11:00:00Z",
|
||||
"last_activity": "2025-06-04T11:15:00Z"
|
||||
}
|
||||
],
|
||||
"total": 25,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"pages": 2
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Conversation Detail
|
||||
|
||||
```http
|
||||
GET /api/conversations/{conversation_id}
|
||||
```
|
||||
|
||||
#### Get Conversation for Review
|
||||
|
||||
```http
|
||||
GET /api/conversations/review/{review_id}
|
||||
```
|
||||
|
||||
Returns `null` if no conversation exists for the review.
|
||||
|
||||
### Health Endpoints
|
||||
|
||||
#### Basic Health Check
|
||||
|
||||
```http
|
||||
GET /health
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"version": "0.5.0"
|
||||
}
|
||||
```
|
||||
|
||||
#### Readiness Check
|
||||
|
||||
```http
|
||||
GET /health/ready
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ready",
|
||||
"components": {
|
||||
"database": {"status": "healthy"},
|
||||
"redis": {"status": "healthy"},
|
||||
"worker": {"status": "healthy", "queue_size": 3}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Liveness Probe
|
||||
|
||||
```http
|
||||
GET /health/live
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "alive"
|
||||
}
|
||||
```
|
||||
|
||||
#### Prometheus Metrics
|
||||
|
||||
```http
|
||||
GET /metrics
|
||||
```
|
||||
|
||||
Returns Prometheus-formatted metrics.
|
||||
|
||||
## Webhook Endpoints
|
||||
|
||||
### GitHub Webhook
|
||||
|
||||
```http
|
||||
POST /webhooks/github
|
||||
```
|
||||
|
||||
**Headers:**
|
||||
|
||||
| Header | Description |
|
||||
|--------|-------------|
|
||||
| `X-Hub-Signature-256` | HMAC-SHA256 signature |
|
||||
| `X-GitHub-Event` | Event type (pull_request, issue_comment) |
|
||||
|
||||
**Supported Events:**
|
||||
|
||||
- `pull_request` — PR opened, synchronized, or reopened
|
||||
- `issue_comment` — Comment created on PR (for follow-up questions)
|
||||
|
||||
#### Pull Request Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "opened",
|
||||
"pull_request": {
|
||||
"number": 42,
|
||||
"title": "Add new feature",
|
||||
"draft": false,
|
||||
"base": {"sha": "abc1234"},
|
||||
"head": {"sha": "def5678"},
|
||||
"user": {"login": "username"}
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "owner/repo"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Issue Comment Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "created",
|
||||
"issue": {
|
||||
"number": 42,
|
||||
"pull_request": {}
|
||||
},
|
||||
"comment": {
|
||||
"id": 123456,
|
||||
"body": "Can you explain the SQL injection warning?",
|
||||
"user": {"login": "username"}
|
||||
},
|
||||
"repository": {
|
||||
"full_name": "owner/repo"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Responses:**
|
||||
|
||||
```json
|
||||
{"status": "queued", "job_id": "abc123", "repository": "owner/repo", "pr_number": 42}
|
||||
```
|
||||
|
||||
```json
|
||||
{"status": "ignored", "reason": "Event type 'push' not processed"}
|
||||
```
|
||||
|
||||
```json
|
||||
{"status": "duplicate", "reason": "Review already queued for this commit"}
|
||||
```
|
||||
|
||||
### GitLab Webhook
|
||||
|
||||
```http
|
||||
POST /webhooks/gitlab
|
||||
```
|
||||
|
||||
**Headers:**
|
||||
|
||||
| Header | Description |
|
||||
|--------|-------------|
|
||||
| `X-GitLab-Token` | Verification token |
|
||||
|
||||
**Supported Events:**
|
||||
|
||||
- `merge_request` — MR opened, reopened, or updated
|
||||
- `note` — Comment (note) on MR (for follow-up questions)
|
||||
|
||||
#### Merge Request Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"object_kind": "merge_request",
|
||||
"object_attributes": {
|
||||
"iid": 42,
|
||||
"title": "Add new feature",
|
||||
"action": "open",
|
||||
"target_branch": "main",
|
||||
"work_in_progress": false,
|
||||
"last_commit": {"id": "def5678"}
|
||||
},
|
||||
"project": {
|
||||
"path_with_namespace": "owner/repo"
|
||||
},
|
||||
"user": {
|
||||
"username": "username"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Note Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"object_kind": "note",
|
||||
"object_attributes": {
|
||||
"id": 123456,
|
||||
"note": "Can you explain this warning?",
|
||||
"noteable_type": "MergeRequest"
|
||||
},
|
||||
"merge_request": {
|
||||
"iid": 42
|
||||
},
|
||||
"project": {
|
||||
"path_with_namespace": "owner/repo"
|
||||
},
|
||||
"user": {
|
||||
"username": "username"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
All endpoints return standard HTTP error codes with JSON error details:
|
||||
|
||||
### 400 Bad Request
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Missing required fields"
|
||||
}
|
||||
```
|
||||
|
||||
### 401 Unauthorized
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Invalid signature"
|
||||
}
|
||||
```
|
||||
|
||||
### 404 Not Found
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Review abc123 not found"
|
||||
}
|
||||
```
|
||||
|
||||
### 422 Validation Error
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": ["body", "pr_number"],
|
||||
"msg": "value is not a valid integer",
|
||||
"type": "type_error.integer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 500 Internal Server Error
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Internal server error"
|
||||
}
|
||||
```
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
The API applies rate limiting per client IP:
|
||||
|
||||
- Default: 60 requests per minute
|
||||
- Configurable via `ARBITER_API_RATE_LIMIT_PER_MINUTE`
|
||||
|
||||
Rate limit headers are included in responses:
|
||||
|
||||
```
|
||||
X-RateLimit-Limit: 60
|
||||
X-RateLimit-Remaining: 55
|
||||
X-RateLimit-Reset: 1707048120
|
||||
```
|
||||
|
||||
## CORS
|
||||
|
||||
Cross-Origin Resource Sharing is configured via `ARBITER_CORS_ORIGINS`:
|
||||
|
||||
```bash
|
||||
ARBITER_CORS_ORIGINS=["http://localhost:3000","https://dashboard.example.com"]
|
||||
```
|
||||
|
||||
The API allows:
|
||||
- Specified origins
|
||||
- All standard headers
|
||||
- Credentials
|
||||
- GET, POST, PUT, DELETE methods
|
||||
Reference in New Issue
Block a user