Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Atlantis with Overmind CLI
FROM ghcr.io/runatlantis/atlantis:latest

# Switch to root to install
USER root

# Install Overmind CLI from GitHub releases
RUN curl -fsSL https://github.com/overmindtech/cli/releases/download/v1.11.1/overmind_cli_Linux_x86_64.tar.gz -o /tmp/overmind.tar.gz && \
tar -xzf /tmp/overmind.tar.gz -C /usr/local/bin && \
rm /tmp/overmind.tar.gz && \
chmod +x /usr/local/bin/overmind

# Verify installation
RUN overmind --version

# Switch back to atlantis user
USER atlantis
119 changes: 89 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This integration adds automated blast radius analysis and complete lifecycle tra

- Atlantis server (self-hosted or cloud)
- Overmind account ([sign up](https://app.overmind.tech))
- Overmind CLI installed on Atlantis server
- Terraform 0.12 or later

### Setup
Expand All @@ -30,10 +31,6 @@ This integration adds automated blast radius analysis and complete lifecycle tra
```bash
# Copy atlantis.yaml to your repository root
cp atlantis.yaml /path/to/your/repo/

# Copy the integration script
cp scripts/overmind-integration.sh /path/to/your/repo/scripts/
chmod +x /path/to/your/repo/scripts/overmind-integration.sh
```

3. **Set the environment variable** on your Atlantis server:
Expand All @@ -56,11 +53,22 @@ Test the integration locally before deploying:
# Set your API key
export OVM_API_KEY="your-overmind-api-key"

# Run the quick test
# Quick test - just submits a plan
./quick-test.sh

# Full lifecycle test - simulates complete Atlantis workflow
./full-lifecycle-test.sh
```

This will create a Terraform plan and submit it to Overmind for analysis.
The **quick test** creates a Terraform plan and submits it to Overmind.

The **full lifecycle test** simulates the complete Atlantis workflow:
1. `terraform init` + `terraform plan`
2. `overmind submit-plan` - creates change
3. `overmind start-change` - marks as running
4. `terraform apply` - applies changes
5. `overmind end-change` - marks as complete
6. `overmind get-change` - retrieves summary

## How It Works

Expand All @@ -75,7 +83,7 @@ Atlantis executes Terraform plan
Plan submitted to Overmind (submit-plan)
Change ID saved for apply phase
Change URL returned, UUID extracted and saved
Risk analysis available in Overmind dashboard
Expand All @@ -94,10 +102,12 @@ The integration provides full lifecycle tracking of infrastructure changes:

**Plan Phase:**
1. Executes `terraform plan`
2. Converts plan to JSON format
3. Submits to Overmind via `submit-plan`
4. Saves the Change ID to `.overmind-change-id` file
5. Links to PR and adds repository tags
2. Converts plan to JSON file (CLI requires a file, not stdin)
3. Submits JSON file to Overmind via `submit-plan`
4. Captures the change URL from stdout (e.g., `https://app.overmind.tech/changes/{uuid}/blast-radius`)
5. Extracts the UUID and saves it to `.overmind-change-id` file
6. Tags the change with repository and workspace info
7. Cleans up temporary JSON file

**Apply Phase:**
1. Reads saved Change ID from `.overmind-change-id`
Expand All @@ -107,6 +117,8 @@ The integration provides full lifecycle tracking of infrastructure changes:
5. Retrieves final change summary
6. Cleans up temporary files

> **Note:** The CLI outputs the change URL to stdout. It does not automatically post comments to PRs - view analysis in the Overmind dashboard or check Atlantis logs for the change URL.

## Configuration

### Repository-Specific Setup
Expand All @@ -123,31 +135,43 @@ workflows:
- init
- plan
- run: |
# Submit plan and save Change ID
terraform show -json $PLANFILE | \
overmind changes submit-plan - \
# Convert plan to JSON (CLI requires a file, not stdin)
terraform show -json $PLANFILE > .overmind-plan.json

# Submit and capture the change URL from output
CHANGE_URL=$(overmind changes submit-plan .overmind-plan.json \
--ticket-link "$PULL_REQUEST_URL" \
--tags "atlantis=true,repo=$BASE_REPO_NAME" \
--format json > .overmind-response.json
2>&1 | grep -oE 'https://[^ ]+' | head -1)

rm -f .overmind-plan.json

CHANGE_ID=$(cat .overmind-response.json | grep -o '"uuid":"[^"]*"' | head -1 | cut -d'"' -f4)
echo "$CHANGE_ID" > .overmind-change-id
# Extract UUID from the URL (format: .../changes/{uuid}/blast-radius)
CHANGE_ID=$(echo "$CHANGE_URL" | grep -oE '[0-9a-f-]{36}')

if [ -n "$CHANGE_ID" ]; then
echo "$CHANGE_ID" > .overmind-change-id
echo "View at: $CHANGE_URL"
fi

apply:
steps:
- run: |
# Mark change as starting
CHANGE_ID=$(cat .overmind-change-id)
overmind changes start-change --uuid "$CHANGE_ID"
if [ -f .overmind-change-id ]; then
CHANGE_ID=$(cat .overmind-change-id)
overmind changes start-change --uuid "$CHANGE_ID" || true
fi
- apply
- run: |
# Mark change as complete
CHANGE_ID=$(cat .overmind-change-id)
overmind changes end-change --uuid "$CHANGE_ID"
overmind changes get-change --uuid "$CHANGE_ID" --format markdown
if [ -f .overmind-change-id ]; then
CHANGE_ID=$(cat .overmind-change-id)
overmind changes end-change --uuid "$CHANGE_ID" || true
overmind changes get-change --uuid "$CHANGE_ID" --format markdown || true
rm -f .overmind-change-id
fi
```

The workflow saves the Change ID during `plan` to a file (`.overmind-change-id`), which is then used during `apply` to track the complete lifecycle.
The workflow saves the plan to a JSON file (required by the CLI), submits it, captures the change URL from the output, and extracts the UUID for the apply phase.

**Fallback Hook (for repositories without custom workflows):**

Expand All @@ -158,9 +182,10 @@ repos:
- run: |
# Simple post-plan submission for basic integration
if [ "$COMMAND_NAME" = "plan" ]; then
terraform show -json "$PLANFILE" | \
overmind changes submit-plan - \
terraform show -json "$PLANFILE" > .overmind-plan.json
overmind changes submit-plan .overmind-plan.json \
--ticket-link "$PULL_REQUEST_URL"
rm -f .overmind-plan.json
fi
```

Expand All @@ -177,6 +202,25 @@ repos:

Place `scripts/overmind-integration.sh` on your Atlantis server and reference it in your server configuration.

## Valid CLI Flags

### `submit-plan` Command

| Flag | Description |
|------|-------------|
| `--ticket-link` | URL to the associated ticket/PR |
| `--tags` | Comma-separated key=value pairs (e.g., `repo=myrepo,env=prod`) |
| `--title` | Title for the change |
| `--description` | Description of the change |
| `--blast-radius-link-depth` | Depth for blast radius link analysis |
| `--blast-radius-max-items` | Maximum items in blast radius |
| `--blast-radius-max-time` | Maximum time for blast radius calculation |

> **Note:**
> - `--format` and `--labels` flags are **not available** on `submit-plan`
> - The CLI requires a **file path** (not stdin) - piping with `-` is not supported
> - The change URL is printed to stdout on its own line

## Features

- **Complete Lifecycle Tracking** - Track changes from plan → apply → completion
Expand Down Expand Up @@ -211,6 +255,7 @@ These variables are automatically provided by Atlantis:
- `BASE_REPO_OWNER` - Repository owner
- `PULL_NUM` - Pull request number
- `WORKSPACE` - Terraform workspace name
- `COMMAND_NAME` - The Atlantis command being run (plan, apply, etc.)

## Targeted Plans

Expand Down Expand Up @@ -253,9 +298,9 @@ overmind --version

### No Analysis Appearing

The integration submits plans to Overmind but doesn't post comments to PRs by default. View analysis at:
The CLI outputs the change URL to stdout but doesn't automatically post comments to PRs. View analysis at:
- [Overmind Dashboard](https://app.overmind.tech)
- Use the change link from Atlantis logs
- Check Atlantis logs for the change URL

### Apply Fails with "Change ID not found"

Expand All @@ -269,6 +314,19 @@ This occurs when the `.overmind-change-id` file is missing:

**Prevention:** Ensure you're using the same workspace for plan and apply

### Could Not Extract Change ID

If you see "Could not extract Change ID from URL":

**Check:**
- The `submit-plan` command completed successfully
- The URL format matches expected pattern (contains a UUID)

**Common Issues:**
- Network connectivity to Overmind API
- Invalid API key
- Empty plan (no changes)

### Change Not Marked as Complete

If `end-change` fails:
Expand Down Expand Up @@ -310,7 +368,8 @@ See `docker-compose.yml` for configuration details.
| `atlantis-server.yaml` | Example server-side configuration |
| `scripts/overmind-integration.sh` | Reusable integration hook script |
| `docker-compose.yml` | Docker setup for local testing |
| `quick-test.sh` | Local testing script |
| `quick-test.sh` | Quick plan submission test |
| `full-lifecycle-test.sh` | Full lifecycle test (plan → apply with all Overmind steps) |
| `main.tf` | Example Terraform configuration |

## Security Considerations
Expand Down
40 changes: 28 additions & 12 deletions atlantis-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repos:
post_workflow_hooks:
- run: |
# Only run for successful plans
if [ "$ATLANTIS_PLAN_EXIT_CODE" != "0" ]; then
if [ "${ATLANTIS_PLAN_EXIT_CODE:-0}" != "0" ]; then
echo "Plan failed, skipping Overmind analysis"
exit 0
fi
Expand All @@ -25,20 +25,36 @@ repos:
exit 0
fi

# Convert plan to JSON
terraform show -json $PLANFILE > tfplan.json

# Build tags
TAGS="atlantis=true,repo=$REPO_NAME,workspace=$WORKSPACE"
if [ ! -z "$ATLANTIS_TERRAFORM_TARGET" ]; then
TAGS="atlantis=true,repo=${BASE_REPO_NAME:-$REPO_NAME},workspace=${WORKSPACE:-default}"
if [ -n "$ATLANTIS_TERRAFORM_TARGET" ]; then
TAGS="$TAGS,target=$ATLANTIS_TERRAFORM_TARGET"
fi

# Submit to Overmind
overmind changes submit-plan tfplan.json \
# Convert plan to JSON (CLI requires a file, not stdin)
terraform show -json "$PLANFILE" > .overmind-plan.json

# Submit to Overmind and capture output
OUTPUT=$(overmind changes submit-plan .overmind-plan.json \
--ticket-link "$PULL_REQUEST_URL" \
--tags "$TAGS"
--tags "$TAGS" \
2>&1)

# Clean up temp file
rm -f .overmind-plan.json

# Post results
overmind changes get-change --format markdown | \
gh pr comment $PULL_NUM --body-file -
# Extract the clean URL (CLI prints it on its own line)
CHANGE_URL=$(echo "$OUTPUT" | grep '^https://' | tail -1)

if [ -n "$CHANGE_URL" ]; then
echo "✅ Plan submitted to Overmind"
echo "View at: $CHANGE_URL"

# Extract UUID for lifecycle tracking
CHANGE_ID=$(echo "$CHANGE_URL" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
if [ -n "$CHANGE_ID" ]; then
echo "$CHANGE_ID" > .overmind-change-id
fi
else
echo "⚠️ Warning: Overmind submission may have failed"
fi
Loading