Skip to main content

Webhooks

Webhooks let DriftWise receive events from your VCS / CI system and post analysis results back as merge-request comments. For endpoint shapes on webhook config management, see the webhooks tag of the API reference.

info

This page covers inbound webhooks — an external system sending events to DriftWise. For outbound notifications (DriftWise alerting you when scans complete), see Scheduled Scans.

For synchronous plan analysis from your CI pipeline (GitHub Actions, GitLab CI script: steps, Atlantis run: steps), use POST /api/v2/orgs/:id/analyze with an API key — see GitHub Actions, GitLab CI, and Atlantis. The /webhooks/ endpoint described below is a separate integration path for event-driven flows: Atlantis plan events and GitLab merge-request / comment events.

Supported sources

Two webhook sources are registered at the /webhooks/ endpoint:

SourceURL segmentAuth modelSignature header
AtlantisatlantisHMAC-SHA-256 over bodyX-Atlantis-Signature (or X-Hub-Signature-256)
GitLab native webhookgitlabConstant shared secretX-Gitlab-Token

Any other :provider segment returns 404 unknown provider.

The two auth models differ:

  • Atlantis signs each request with HMAC-SHA-256 of the raw body using the webhook secret. Either header carries an sha256=<hex> value; X-Atlantis-Signature takes priority.
  • GitLab sends the shared secret verbatim in X-Gitlab-Token — exactly the behavior of GitLab's native "Secret token" field in Settings → Webhooks. DriftWise does a constant-time compare against the stored secret. This is not an HMAC; do not hash the secret before sending it.

How it works

  1. The source system POSTs an event to DriftWise.
  2. DriftWise validates the signature / token, parses the event, and returns 202 Accepted immediately.
  3. For Atlantis plan events, DriftWise runs analysis and posts a comment back to the PR via the GitHub App.
  4. For GitLab merge-request events, DriftWise observes the MR and comments via the stored API token when /driftwise commands arrive.

Comment-back requires an installed GitHub App (Atlantis path) or a stored GitLab API token (GitLab path). See each source's setup guide.

Creating a webhook config

Create webhook configs through the dashboard Settings → Webhooks page or via the API. On creation you'll get a raw_secret field in the response — save this immediately. It's shown once and required to sign inbound requests from the source.

Creation is gated to owner/admin because a viewer setting up a webhook with a known-bad secret could effectively DoS real integrations that share the org's webhook gateway.

GitLab webhook configs additionally accept an API token that DriftWise live-validates against the target GitLab instance before saving. Expired tokens, wrong-scope tokens, and tokens for unreachable instances fail at save time with a specific 400 message — no token ever lands in the DB as "active but actually broken." Tokens without an expiration date are rejected: create a Personal or Group Access Token with an explicit expiry.

Webhook URL

Your source posts events to:

https://app.driftwise.ai/webhooks/<source>/<org_id>

For example:

https://app.driftwise.ai/webhooks/atlantis/1478fe16-d292-4f0f-95fa-d249dda3d7ab

This is not a /api/v2/ endpoint — it lives outside the v2 auth middleware by design, because the source authenticates with the webhook secret, not an API key or OIDC token.

Source setup

Atlantis

Add a webhook in your Atlantis server config pointing to DriftWise:

atlantis.yaml
webhooks:
- event: plan
workspace-regex: ".*"
url: "https://app.driftwise.ai/webhooks/atlantis/<org_id>"
secret: "<raw_secret from webhook config>"

Atlantis computes an HMAC-SHA-256 of the body with the shared secret and sends it in X-Atlantis-Signature: sha256=<hex>. DriftWise validates this against every enabled atlantis config for the org and accepts if any secret matches.

See Atlantis Integration for the full workflow setup.

GitLab native webhook

In your GitLab project, open Settings → Webhooks. Add a new webhook:

  • URL: https://app.driftwise.ai/webhooks/gitlab/<org_id>
  • Secret token: paste the raw_secret returned when you created the webhook config in DriftWise (value starts with whsec_)
  • Trigger: enable Merge request events and Comments
  • Save

GitLab sends the secret token verbatim in X-Gitlab-Token on each delivery. DriftWise compares it (constant-time) against every enabled gitlab config for the org.

See GitLab CI Integration for the full setup including the optional API token for comment-back.

Updating a webhook config

The PATCH endpoint accepts {enabled, api_token} — at least one field is required (empty body returns 400, not a no-op). Token rotations re-validate against the target GitLab instance before persisting, same as on create. Failures return a 400 with an actionable message that never contains the raw token itself. api_token is only supported on gitlab configs.

Security

  • Secrets are encrypted at rest with AES-256-GCM. Only a 14-char identifier prefix (whsec_ + 8 hex chars) is stored in plaintext for lookup / display.
  • Signature validation on every inbound webhook. Atlantis: HMAC-SHA-256 over the raw body. GitLab: constant-time compare of X-Gitlab-Token against the stored secret. Both fail closed — missing headers, DB errors, decrypt failures, or zero enabled configs all reject with 401.
  • Body size cap of 5 MB at the gateway. Larger payloads are rejected with 413 before any validation work runs.
  • Replay protection — duplicate payloads (same body hash) are deduplicated to prevent double-processing.
  • Repo cross-check — when a matching webhook config has a repo_path set, the event body's repo must match it or the request is rejected with 403. Prevents a tenant member with a valid token from forging events from a different repo in the same org.
  • Async processing — webhooks return 202 immediately, so the source doesn't block on analysis.
  • provider_base_url is SSRF-validated (must be public HTTPS) before save, for GitLab configs pointing at self-hosted instances.

Endpoint reference

Webhook config CRUD is under the webhooks tag of the API reference.