Webhook Sources
Overview
Webhook sources let you ingest change events from external tools — GitLab, GitHub, and ArgoCD — into the Proxima Console change events timeline. These events appear alongside agent-detected file changes on the Events Timeline, enabling root cause correlation across your delivery pipeline:
merge → deploy → config change → metric spike
Each webhook source is registered with a unique token-based URL. When the external tool sends a webhook, Proxima normalizes the payload into a structured change event and stores it in the change_events table.
Architecture
Key design decisions:
- Token-based URL authentication — each webhook source gets a unique token embedded in the URL. Tokens are SHA-256 hashed for storage; the plaintext is shown once at creation.
- Source-specific normalization — each source type has a dedicated normalizer that extracts structured metadata (git info, CI/CD status, deploy details) into typed JSONB.
- Same
change_eventstable — webhook events coexist with agent-detected file changes, enabling unified timeline queries. - Optional host mapping — map source-specific keys (e.g.,
repo:org/apporapp:frontend) to host UUIDs for host-level correlation.
Supported Sources
GitLab
Handles the following GitLab webhook event types:
| GitLab Hook | Event Type | Severity | Description |
|---|---|---|---|
| Push Hook | push | info | Code pushed to a branch |
| Tag Push Hook | tag | info | Tag created or pushed |
| Merge Request Hook (merged) | merge_request | info | Merge request merged |
| Pipeline Hook (success) | pipeline_completed | info | Pipeline finished successfully |
| Pipeline Hook (failed) | pipeline_failed | warning | Pipeline failed |
| Job Hook | pipeline_completed / pipeline_failed | info / warning | Individual job completed |
Non-merged merge requests and other event types (Note Hook, Issue Hook, etc.) are silently ignored with a 200 OK response.
Authentication: GitLab sends the secret in the X-Gitlab-Token header. A secret is required: Proxima decrypts the stored secret (via Vault Transit) and compares it to the header value with a constant-time comparison. A source with no secret configured has every delivery rejected (404).
GitHub
Handles the following GitHub webhook event types:
| GitHub Event | Event Type | Severity | Description |
|---|---|---|---|
push | push | info | Code pushed to a branch |
pull_request (merged) | pull_request | info | Pull request merged |
release (published) | release | info | Release published |
workflow_run (success) | workflow_completed | info | Workflow run completed |
workflow_run (failure) | workflow_failed | warning | Workflow run failed |
check_suite (success) | workflow_completed | info | Check suite passed |
check_suite (failure) | workflow_failed | warning | Check suite failed |
Non-merged PRs, draft releases, and non-completed workflow runs are silently ignored.
Authentication: GitHub uses HMAC-SHA256 signatures via the X-Hub-Signature-256 header. A secret is required: Proxima validates the signature against the full request body. A source with no secret configured has every delivery rejected (404).
ArgoCD
Handles ArgoCD notification webhook payloads:
| ArgoCD Event | Event Type | Severity | Description |
|---|---|---|---|
sync | sync | info | Application synced successfully |
health-degraded | health_degraded | warning | Application health degraded |
sync-failed | sync_failed | critical | Sync operation failed |
| (empty/unknown) | sync | info | Defaults to sync event |
Authentication: ArgoCD sends the secret in the X-Argocd-Token header. A secret is required: Proxima compares it to the stored secret with a constant-time comparison. A source with no secret configured has every delivery rejected (404).
ArgoCD notifications require explicit template configuration. There is no default webhook payload format. See ArgoCD Setup below for the required notification template.
Event Normalization
Each webhook payload is normalized into structured metadata stored as JSONB in the details column:
Git Events (push, merge_request, tag, release)
| Field | Description |
|---|---|
event_type | The normalized event type |
repo | Repository full name (e.g., org/repo) |
branch | Target branch |
commit_sha | Head commit SHA |
author | Commit or merge author |
message | Commit message (first line) |
url | Link to the commit/MR/PR |
CI/CD Events (pipeline, workflow_run, check_suite)
| Field | Description |
|---|---|
event_type | The normalized event type |
pipeline_name | Pipeline or workflow name |
status | Conclusion status (success, failure, etc.) |
branch | Source branch |
commit_sha | Head commit SHA |
duration_seconds | Pipeline duration in seconds |
url | Link to the pipeline/workflow run |
Deploy Events (ArgoCD sync)
| Field | Description |
|---|---|
event_type | The normalized event type |
app_name | ArgoCD application name |
namespace | Target Kubernetes namespace |
image | First container image from the summary |
status | Sync/health status |
revision | Git revision |
All metadata types also include a raw field containing the original webhook payload for debugging.
Setup
1. Register a Webhook Source
Navigate to Admin → Webhook Sources and click Create. Provide:
| Field | Required | Description |
|---|---|---|
| Name | Yes | Display name (e.g., "Production GitLab") |
| Source Type | Yes | gitlab, github, or argocd |
| Client | Yes | Client this webhook belongs to |
| Environment | No | Scopes events to an environment |
| Secret | Yes | Shared secret for signature validation |
| Host Mapping | No | JSON mapping of source keys to host UUIDs |
After creation, the webhook URL and token are displayed once. Copy them immediately.
A secret is required for every webhook source. Proxima fails closed: a source with no secret configured has all deliveries rejected with 404 Not Found, regardless of a valid URL token. Always configure both the URL token and the matching secret in the external tool.
The plaintext token is shown only at creation time. If you lose it, use the Rotate action to generate a new token (the old one is immediately invalidated).
2. Configure the External Tool
GitLab
- Go to your GitLab project → Settings → Webhooks
- Set the URL to the webhook URL from step 1
- Set the Secret token to the secret you configured for the source (required)
- Select the event triggers you want: Push events, Tag push events, Merge request events, Pipeline events, Job events
- Click Add webhook
GitHub
- Go to your GitHub repository → Settings → Webhooks → Add webhook
- Set the Payload URL to the webhook URL from step 1
- Set Content type to
application/json - Set the Secret to the secret you configured for the source (required)
- Select individual events: Pushes, Pull requests, Releases, Workflow runs, Check suites
- Click Add webhook
ArgoCD
ArgoCD requires a notification template to be configured. Add the following to your ArgoCD notification configuration:
1. Add the webhook service (argocd-notifications-cm ConfigMap):
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
service.webhook.proxima: |
url: https://your-console.example.com/api/v1/webhooks/argocd/<TOKEN>
headers:
- name: X-Argocd-Token
value: <YOUR_SECRET>
2. Add notification templates:
template.proxima-sync: |
webhook:
proxima:
method: POST
body: |
{
"app": {{toJson .app}},
"type": "{{.type}}",
"message": "{{.message}}"
}
template.proxima-health-degraded: |
webhook:
proxima:
method: POST
body: |
{
"app": {{toJson .app}},
"type": "health-degraded",
"message": "Application {{.app.metadata.name}} health degraded"
}
3. Add triggers:
trigger.on-sync-succeeded: |
- when: app.status.operationState.phase in ['Succeeded']
send: [proxima-sync]
trigger.on-health-degraded: |
- when: app.status.health.status == 'Degraded'
send: [proxima-health-degraded]
trigger.on-sync-failed: |
- when: app.status.operationState.phase in ['Error', 'Failed']
send: [proxima-sync]
4. Annotate your ArgoCD Application:
metadata:
annotations:
notifications.argoproj.io/subscribe.on-sync-succeeded.proxima: ""
notifications.argoproj.io/subscribe.on-health-degraded.proxima: ""
notifications.argoproj.io/subscribe.on-sync-failed.proxima: ""
3. Host Mapping (Optional)
Host mapping lets you associate webhook events with specific monitored hosts. The mapping is a JSON object where keys are source-specific identifiers and values are host UUIDs:
{
"repo:org/frontend": "550e8400-e29b-41d4-a716-446655440001",
"app:backend-api": "550e8400-e29b-41d4-a716-446655440002"
}
Key format by source type:
| Source | Key Format | Example |
|---|---|---|
| GitLab | repo:<path_with_namespace> | repo:myorg/myapp |
| GitHub | repo:<full_name> | repo:myorg/myapp |
| ArgoCD | app:<app_name> | app:frontend |
When a webhook event matches a key, the resulting change event is linked to the corresponding host, making it visible on that host's timeline.
RBAC
Webhook source management requires the following permissions:
| Permission | Required For |
|---|---|
webhooks:read | List and view webhook sources |
webhooks:write | Create, update, and rotate webhook sources |
webhooks:delete | Delete webhook sources |
The webhook receiver endpoints (/api/v1/webhooks/{source}/{token}) are public — they authenticate via the token in the URL rather than JWT/API key.
Management API
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /api/v1/webhook-sources | webhooks:read | List webhook sources (paginated) |
| POST | /api/v1/webhook-sources | webhooks:write | Create webhook source (returns token once) |
| GET | /api/v1/webhook-sources/{id} | webhooks:read | Get webhook source |
| PUT | /api/v1/webhook-sources/{id} | webhooks:write | Update webhook source |
| DELETE | /api/v1/webhook-sources/{id} | webhooks:delete | Delete webhook source |
| POST | /api/v1/webhook-sources/{id}/rotate | webhooks:write | Rotate token (invalidates old one) |
Webhook Receiver Endpoints
These endpoints receive webhook payloads from external tools. No JWT or API key is required — authentication is via the token in the URL.
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/webhooks/gitlab/{token} | Receive GitLab webhook |
| POST | /api/v1/webhooks/github/{token} | Receive GitHub webhook |
| POST | /api/v1/webhooks/argocd/{token} | Receive ArgoCD webhook |
Request body limit: the request body is read up to a 1 MB limit; any bytes beyond 1 MB are truncated. A truncated payload that no longer parses is rejected with 400 Bad Request.
Events Timeline
Webhook events appear on the Events Timeline alongside agent-detected file changes. Each event type has a distinct icon and color:
| Source | Icon | Color |
|---|---|---|
| GitLab / GitHub (push, merge, tag) | Git branch | Blue |
| CI/CD (pipeline, workflow) | Play circle | Cyan |
| ArgoCD (deploy) | Rocket | Orange |
Click on any event to expand its details panel, which shows the normalized metadata and a link to the original event in the source tool.
Troubleshooting
Webhook not received
- Verify the webhook source is enabled in Admin → Webhook Sources
- Check the token hasn't been rotated (the URL would have changed)
- Verify network connectivity from the source tool to the Proxima Console backend
- Check backend logs for rejected requests:
./scripts/obs.sh logs 'webhook' 15m
Signature validation failed
- GitLab: Ensure the
X-Gitlab-Tokenheader value matches the secret configured in the webhook source - GitHub: Ensure the webhook secret in GitHub settings matches exactly. GitHub uses HMAC-SHA256 to sign the full request body
- ArgoCD: Ensure the
X-Argocd-Tokenheader in the notification template matches the configured secret
Events not appearing on timeline
- Check that the
sourcefilter on the timeline includes the webhook source type - If using host mapping, verify the mapping key matches the source's identifier format
- Events without host mapping appear on the environment-level timeline but not on individual host timelines