Any CI Pipeline
DriftWise is a single HTTPS endpoint. Any runner that can execute terraform show -json and POST JSON works — Jenkins, CircleCI, Buildkite, Azure Pipelines, Drone, Harness, Tekton, Argo Workflows, Bitbucket Pipelines, TeamCity, self-hosted shell scripts. No plugin, no sidecar, no agent.
The Contract
| Endpoint | POST https://app.driftwise.ai/api/v2/orgs/{ORG_ID}/analyze |
| Auth | x-api-key: dw2_... header |
| Body | {"plan_json": "<terraform show -json output, as a string>", "ci": {...}} |
| Response | {"risk_level", "narrative", "changes", "summary", "scan_run", "plan_noise"} |
| Timeout | ~120s synchronous |
plan_json is a string, not a nested objectThe API expects plan_json to be the raw Terraform JSON plan, encoded as a JSON string. Shell callers use jq -Rs . to turn a file into an escaped string. Language SDKs that serialize via JSON.stringify / json.dumps do this automatically — pass a string.
Step 1 — Produce a Plan JSON
Run this in any pipeline before the analysis step:
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
Step 2 — Call the API
curl (any shell runner)
curl -fsSL -X POST \
"https://app.driftwise.ai/api/v2/orgs/${DRIFTWISE_ORG_ID}/analyze" \
-H "x-api-key: ${DRIFTWISE_API_KEY}" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile plan plan.json \
--arg repo_owner "$REPO_OWNER" \
--arg repo_name "$REPO_NAME" \
--arg branch "$BRANCH" \
--arg sha "$COMMIT_SHA" \
'{plan_json: $plan, ci: {repo_owner: $repo_owner, repo_name: $repo_name, branch: $branch, commit_sha: $sha}}')"
-f makes curl exit non-zero on HTTP errors so the pipeline step fails. jq -n builds the JSON body safely (no brittle string concatenation).
CI Metadata
Every ci field is optional. Populate whatever your runner exposes — DriftWise uses it to link the analysis back to the source (PR comments, drill-down in the UI).
| Field | Description |
|---|---|
repo_owner | Org/user (e.g. acme-corp) |
repo_name | Repository name |
repo_url | Full URL to the repo |
pr_number | Pull/merge request number |
branch | Source branch |
commit_sha | Full commit SHA |
Runner-Specific Env Var Reference
Map your runner's built-ins to the metadata fields:
| Runner | repo_owner | repo_name | branch | commit_sha | pr_number |
|---|---|---|---|---|---|
| Jenkins | $CHANGE_AUTHOR / parse $GIT_URL | parse $GIT_URL | $BRANCH_NAME | $GIT_COMMIT | $CHANGE_ID |
| CircleCI | $CIRCLE_PROJECT_USERNAME | $CIRCLE_PROJECT_REPONAME | $CIRCLE_BRANCH | $CIRCLE_SHA1 | parse $CIRCLE_PULL_REQUEST |
| Buildkite | $BUILDKITE_ORGANIZATION_SLUG | $BUILDKITE_PIPELINE_SLUG | $BUILDKITE_BRANCH | $BUILDKITE_COMMIT | $BUILDKITE_PULL_REQUEST |
| Azure Pipelines | $(Build.Repository.Name) owner | $(Build.Repository.Name) name | $(Build.SourceBranchName) | $(Build.SourceVersion) | $(System.PullRequest.PullRequestNumber) |
| Bitbucket Pipelines | $BITBUCKET_WORKSPACE | $BITBUCKET_REPO_SLUG | $BITBUCKET_BRANCH | $BITBUCKET_COMMIT | $BITBUCKET_PR_ID |
| Drone | $DRONE_REPO_OWNER | $DRONE_REPO_NAME | $DRONE_SOURCE_BRANCH | $DRONE_COMMIT_SHA | $DRONE_PULL_REQUEST |
| Tekton / Argo | from event payload | from event payload | from event payload | from event payload | from event payload |
Secrets Handling
Store DRIFTWISE_API_KEY in your runner's secret store (Jenkins Credentials, CircleCI Contexts, Azure Key Vault, etc.). DRIFTWISE_ORG_ID is not sensitive — treat it like a project ID.
Failing the Pipeline on Risk
The examples above exit non-zero on high or critical. Adjust to your policy:
- Strict: block on
mediumand above. - Advisory only: never fail, just log the narrative for reviewers.
- Policy-driven: combine with DriftWise custom policy rules to rewrite risk on your own signals, then gate on the rewritten level.
What's Returned
The response is JSON. The fields you'll typically consume in a pipeline:
risk_level— one oflow,medium,high,critical,unknown.narrative— plain-English summary, safe to print in CI logs or post as a PR comment.scan_run.id— UUID of the recorded analysis; use to deep-link back to the DriftWise UI.plan_noise— counts of known-benign patterns vs. novel changes; useful for filtering noisy reviews.
Limits
- Request body: 5 MB. Large monorepo plans may need to be split per workspace.
- Response timeout: 120s. LLM generation dominates — slower models take longer.
- Rate limits: depend on plan. Free tier: 10 analyses/month; Team/Enterprise: unlimited.