TerraGuard — Terraform PR Reviewer Agent for Slack

Inspiration

Terraform pull requests are sneaky. A one-line diff can quietly open a security group to the entire internet, turn off deletion protection on a production database, or hand out an IAM policy with way more access than it should have and none of that jumps out when you're scrolling through a wall of +/- lines in a raw plan. In practice, reviewers end up doing one of two things: rubber-stamping PRs because actually reading the plan takes too long, or burning twenty minutes parsing output that a machine could summarize in two seconds. I wanted infrastructure review to feel as fast and natural as approving a Slack message, without losing any of the rigor a real safety review needs.

What it does

TerraGuard watches Terraform pull requests, flags anything dangerous, and lets a reviewer approve or reject them without ever leaving Slack.

When a PR touching .tf files opens, a GitHub Action runs terraform plan, converts it to JSON, and sends it over to TerraGuard. From there:

  • A deterministic risk engine scans the plan for known-dangerous patterns security groups opened to 0.0.0.0/0, database deletions, disabled deletion protection, disabled encryption, public S3 buckets, overly broad IAM policies, and large-blast-radius changes.
  • An AI summary (via Groq) turns the plan into a plain-English explanation of what's actually changing.
  • Both land in Slack as a Block Kit message with Approve, Reject, and View Full Plan buttons.
  • Clicking Reject opens a modal asking for a reason; clicking either button writes a real review back to GitHub through GitHub's MCP server posting an approval or a "request changes" review, plus a label, directly on the pull request.
  • Every decision gets logged to Postgres so there's an audit trail.

Nothing in the pipeline ever runs terraform apply TerraGuard is a review gate, not something with write access to real infrastructure. A human still merges; whatever CD pipeline you already have applies as normal.

How I built it

The backend is Java and Spring Boot, deployed on an AWS EC2 box behind Caddy for automatic HTTPS. Slack integration uses the Slack SDK for the Block Kit messages and modals, with HMAC-based signature verification on every interactivity callback. GitHub integration goes through GitHub's official MCP server — the backend speaks JSON-RPC 2.0 directly to it (tools/call for pull_request_review_write and issue_write), the same protocol an LLM agent would use, instead of hand-rolling calls against GitHub's REST API. The AI summary layer calls Groq's Llama 3.3 70B model. A GitHub Action kicks off the whole flow automatically on every pull request. Postgres handles both the audit log and tracking in-flight review decisions, with an idempotency guard so a double-click can't double-process an approval.

The one design decision I care most about: risk detection is completely separate from the AI layer. The rule engine that flags dangerous changes is pure, deterministic JSON pattern-matching no LLM involved at all. The AI's only job is writing the plain-English summary. That way, a hallucination in the summary can never hide or invent a safety issue, because the thing actually doing the safety checking is auditable and gives you the same answer every time.

Challenges I ran into

GitHub's MCP server uses the "Streamable HTTP" transport, which wraps every response as Server-Sent Events (event: message / data: {...}) even for a plain single request-response my first integration attempt assumed plain JSON and broke immediately on the literal word "event" at the start of the response. I also guessed at the MCP tool names based on what seemed like reasonable naming conventions, and guessed wrong — the real tools turned out to be pull_request_review_write and issue_write, nothing like what I expected. I only found the actual names by calling tools/list directly against the live server. Slack's signature verification was another sharp edge: trying to reconstruct the raw POST body from an already-parsed parameter to verify the HMAC signature turned out to be unreliable, since re-encoding doesn't guarantee byte-identical output to what Slack originally sent. Fixed it by grabbing the true raw request body before anything parses it.

Accomplishments I'm proud of

The full loop actually works end-to-end against real infrastructure: a real GitHub PR, a real Terraform plan (using a mock AWS provider so the demo doesn't need live cloud credentials), real risk detection, a real Slack approval flow, and a real review posted back to GitHub fully automated from PR open to Slack notification, with zero manual triggering. I'm also proud of keeping the safety-critical risk detection deterministic instead of folding everything into one LLM call that was a deliberate tradeoff between "looks more AI-native" and "is actually trustworthy for a safety tool."

What I learned

Working directly with GitHub's MCP server taught me that MCP integrations need to be checked empirically (tools/list) rather than assumed from docs or naming conventions server implementations vary more than you'd think. I also came away with a clearer sense of where AI actually belongs in a safety-critical workflow: as a communication layer, not a decision-making one. Splitting "what's dangerous" (rules) from "what does this mean in plain English" (AI) turned out to be both the better architecture and the better story to tell about responsible AI tool design.

What's next for TerraGuard

  • Cost estimation alongside risk flags, so reviewers see both safety and budget impact at a glance
  • Policy-as-code integration (OPA/Sentinel) so teams can define their own custom rules instead of relying solely on my hardcoded checks
  • Multi-cloud support — current rules are AWS-focused; Azure and GCP resource types are natural next additions
  • Slack Real-Time Search integration to let reviewers ask "have we approved something like this before?" directly in Slack, surfacing past decisions from the audit log
  • More real-world testing with actual platform engineering teams to figure out which risk patterns matter most in practice

How we built it

Challenges we ran into

Accomplishments that we're proud of

What we learned

What's next for TerraGuard

Built With

Share this project:

Updates