Skip to main content

Atlantis Integration

DriftWise integrates with Atlantis via a run step in your workflow. No plugins, no sidecars.

Setup​

Add the DriftWise step after plan in your atlantis.yaml. The analyze endpoint enqueues the job and returns 202 immediately — poll GET /llm-jobs/{job_id} until status is done (or error):

atlantis.yaml
workflows:
default:
plan:
steps:
- init
- plan
- run: |
terraform show -json $PLANFILE > /tmp/dw-plan.json
JOB_ID=$(curl -sfX POST https://api.driftwise.ai/api/v2/orgs/$ORG_ID/analyze \
-H "x-api-key: $DRIFTWISE_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"plan_json\": $(cat /tmp/dw-plan.json | jq -Rs .)}" | jq -r '.job_id')

for i in $(seq 1 36); do
BODY=$(curl -sf https://api.driftwise.ai/api/v2/orgs/$ORG_ID/llm-jobs/$JOB_ID \
-H "x-api-key: $DRIFTWISE_API_KEY")
STATUS=$(echo "$BODY" | jq -r '.status')
if [ "$STATUS" = "done" ]; then RESULT=$(echo "$BODY" | jq '.result'); break; fi
if [ "$STATUS" = "error" ]; then echo "analysis failed: $(echo "$BODY" | jq -r '.error')" >&2; exit 1; fi
sleep 5
done
[ "$STATUS" = "done" ] || { echo "timed out waiting for analysis" >&2; exit 1; }
echo "$RESULT" | jq -r '.narrative'
Why the conversion step?

Atlantis's $PLANFILE is a binary Terraform plan. The terraform show -json step converts it to JSON, then jq -Rs wraps it as an escaped JSON string inside the plan_json field that the API expects.

Environment Variables​

Set these in your Atlantis server environment:

VariableDescription
DRIFTWISE_API_KEYYour DriftWise API key (dw2_...)
ORG_IDYour DriftWise organization ID (UUID)

How It Works​

  1. Atlantis runs terraform plan as usual
  2. The run step converts the binary plan to JSON and sends it to DriftWise
  3. DriftWise enqueues the analysis and returns a job handle; the run step polls llm-jobs/{job_id} until the risk score and narrative are ready
  4. Atlantis includes the output in the plan result shown on the PR

Optional: CI Metadata​

You can pass CI context so DriftWise can link the analysis back to the PR:

- run: |
terraform show -json $PLANFILE > /tmp/dw-plan.json
JOB_ID=$(curl -sfX POST https://api.driftwise.ai/api/v2/orgs/$ORG_ID/analyze \
-H "x-api-key: $DRIFTWISE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"plan_json\": $(cat /tmp/dw-plan.json | jq -Rs .),
\"ci\": {
\"repo_owner\": \"$BASE_REPO_OWNER\",
\"repo_name\": \"$BASE_REPO_NAME\",
\"pr_number\": $PULL_NUM,
\"commit_sha\": \"$HEAD_COMMIT\",
\"branch\": \"$HEAD_BRANCH_NAME\"
}
}" | jq -r '.job_id')

for i in $(seq 1 36); do
BODY=$(curl -sf https://api.driftwise.ai/api/v2/orgs/$ORG_ID/llm-jobs/$JOB_ID \
-H "x-api-key: $DRIFTWISE_API_KEY")
STATUS=$(echo "$BODY" | jq -r '.status')
if [ "$STATUS" = "done" ]; then RESULT=$(echo "$BODY" | jq '.result'); break; fi
if [ "$STATUS" = "error" ]; then echo "analysis failed: $(echo "$BODY" | jq -r '.error')" >&2; exit 1; fi
sleep 5
done
[ "$STATUS" = "done" ] || { echo "timed out waiting for analysis" >&2; exit 1; }
echo "$RESULT" | jq -r '.narrative'