Skip to main content

Webhooks

Webhooks let DriftWise receive Terraform plan events from your CI system and post analysis results back as PR comments. DriftWise supports Atlantis, GitHub Actions, and GitLab CI as webhook providers.

info

This page covers inbound webhooks — your CI system sending plan data to DriftWise. For outbound notifications (DriftWise alerting you when scans complete), see Scheduled Scans.

How It Works

  1. Your CI runs terraform plan and sends the plan JSON to DriftWise via webhook
  2. DriftWise verifies the HMAC signature, parses the plan, and runs analysis
  3. DriftWise posts a PR comment with risk scoring and narrative
  4. Returns 202 Accepted immediately — analysis runs asynchronously

Creating a Webhook Config

Via the API

curl -X POST "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs" \
-H "x-api-key: $DRIFTWISE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "atlantis",
"label": "Production Atlantis"
}'

The response includes a raw_secret field — save this immediately. It's only shown once:

{
"id": "config-uuid",
"provider": "atlantis",
"label": "Production Atlantis",
"secret_prefix": "whsec_3a2f9c8e",
"enabled": true,
"raw_secret": "whsec_3a2f9c8e7b1d4f6a..."
}

Configure this secret in your CI system as the webhook signing key.

Supported Providers

ProviderValueSignature Header
AtlantisatlantisX-Atlantis-Signature
GitHub Actionsgithub_actionsX-Hub-Signature-256
GitLab CIgitlab_ciX-Gitlab-Token

All three headers carry an sha256=<hex> HMAC value and are interchangeable at the transport layer — pick whichever your CI already produces. X-Gitlab-Token here holds the HMAC your pipeline computes, not GitLab's native constant shared-secret token. GitLab's Settings → Webhooks page uses the same header name but ships a fixed value, which doesn't pass HMAC validation; run the .gitlab-ci.yml script below from inside your pipeline instead.

Webhook URL

Point your CI system to:

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

For example:

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

Provider 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>"

See Atlantis Integration for the full workflow setup.

GitHub Actions

Add the webhook secret as a repository secret, then send plan data in your workflow:

.github/workflows/terraform.yml
- name: Send to DriftWise
run: |
terraform show -json tfplan > plan.json
BODY=$(cat plan.json)
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "${{ secrets.DW_WEBHOOK_SECRET }}" | cut -d' ' -f2)
curl -X POST "https://app.driftwise.ai/webhooks/github_actions/${{ vars.DW_ORG_ID }}" \
-H "X-Hub-Signature-256: sha256=$SIGNATURE" \
-H "Content-Type: application/json" \
-d "$BODY"

See GitHub Actions Integration for the full workflow.

GitLab CI

.gitlab-ci.yml
driftwise:
stage: analyze
script: |
terraform show -json tfplan > plan.json
BODY=$(cat plan.json)
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$DW_WEBHOOK_SECRET" | cut -d' ' -f2)
curl -X POST "https://app.driftwise.ai/webhooks/gitlab_ci/$DW_ORG_ID" \
-H "X-Gitlab-Token: sha256=$SIGNATURE" \
-H "Content-Type: application/json" \
-d "$BODY"

See GitLab CI Integration for the full workflow.

Managing Webhook Configs

List configs

curl "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs" \
-H "x-api-key: $DRIFTWISE_API_KEY"

Enable/disable a config

curl -X PATCH "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs/<config_id>" \
-H "x-api-key: $DRIFTWISE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "enabled": false }'

Delete a config

curl -X DELETE "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs/<config_id>" \
-H "x-api-key: $DRIFTWISE_API_KEY"

Security

  • Secrets are encrypted at rest with AES-256-GCM — only the whsec_ prefix is stored in plaintext for identification
  • HMAC-SHA256 signature validation on every inbound webhook — unsigned or mis-signed payloads are rejected with 401
  • Replay protection — duplicate payloads (same body hash) are deduplicated to prevent double-processing
  • Async processing — webhooks return 202 immediately, so your CI pipeline doesn't block on analysis