Deterministic infrastructure risk analysis engine for Terraform plans
Project description
PreApply
Deterministic Terraform plan risk analyzer โ know your blast radius before you apply.
The Problem
You've been there. It's deployment day. You run terraform plan. The output is 800 lines long. You scan it. It looks fine. You apply.
Then your load balancer goes down. Three dependent services follow. Your phone explodes with alerts.
PreApply solves this by analyzing your Terraform plan before you apply it โ giving you a clear, deterministic risk assessment you can trust.
What You Get
$ preapply analyze plan.json
+===============================================================+
| [!] HIGH RISK - SENIOR ENGINEER APPROVAL REQUIRED |
+===============================================================+
Risk Score: 96.34 / 250+ (HIGH tier)
Required Action: Obtain approval before applying
WHY THIS IS HIGH:
* Sensitive deletion: aws_db_instance.production
* Security exposure: ingress open to 0.0.0.0/0 (Port 22)
RECOMMENDED ACTIONS:
1. REVIEW DATABASE DELETION - Verify backup before proceeding
2. ADDRESS SECURITY EXPOSURE - Restrict to known IP ranges
3. GET APPROVALS - SENIOR_ENGINEER or TECH_LEAD sign-off required
Key Features
- ๐ฅ Blast Radius Analysis โ Calculate exactly which resources are affected
- ๐ Multi-Dimensional Risk Scoring โ 0-250+ score across data loss, security, infrastructure, and cost
- โก Interaction Detection โ Detects when multiple risks combine into catastrophic scenarios
- ๐ Policy Enforcement โ Block hazardous plans in CI/CD (exit codes: 0=pass, 2=block, 3=approval)
- ๐ฏ 100% Deterministic โ Same plan = same score, every time
- ๐ค Optional Local AI โ Plain-language explanations (runs offline, no data leaves your machine)
Why Deterministic?
Most infrastructure tools try to use AI for risk detection. We don't.
AI-based risk detection is unreliable for infrastructure decisions because:
Non-deterministic (same plan can get different scores) Hard to audit or explain to stakeholders Can "hallucinate" risks or miss real ones Requires external API calls (privacy concern) PreApply's approach:
Core analysis is 100% deterministic AI is optional and advisory only (never changes risk score) Every decision is traceable and explainable Works fully offline
Installation
# Basic installation
pip install preapply
# With optional AI advisor
pip install 'preapply[ai]'
AI support requires Ollama installed and running locally.
Quick Start
# Generate plan
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
# Analyze
preapply analyze plan.json
# Enforce in CI
preapply policy check plan.json --policy-file policy.yaml
Try it now (no Terraform required):
preapply analyze samples/low_risk.json
CI/CD Integration
GitHub Actions
- name: Install PreApply
run: pip install preapply
- name: Generate Plan
run: |
terraform init
terraform plan -out=tfplan
terraform show -json tfplan > plan.json
- name: Risk Analysis & Policy Check
run: |
preapply analyze plan.json
preapply policy check plan.json --policy-file policy.yaml
Exit codes: 0 = pass, 2 = blocked, 3 = approval required
Why Deterministic?
AI-based risk detection is unreliable for infrastructure:
- Non-deterministic (same plan = different scores)
- Hard to audit or explain
- Can hallucinate risks or miss real ones
PreApply's approach:
- 100% deterministic mathematical model
- AI is optional and advisory only (never affects risk score)
- Every decision is traceable and explainable
- Works fully offline
How It Works
PreApply uses a multi-dimensional risk model:
- Data Loss โ RDS/S3 deletions, protection removal
- Security โ Public exposures (0.0.0.0/0), sensitive ports (SSH/RDP)
- Infrastructure โ Shared resources, critical infra (VPC, ALB)
- Cost โ High-cost creations, instance scaling
Interaction Multipliers detect when risks amplify each other:
- Database deletion + security exposure = 1.65ร multiplier
- 3+ dimensions elevated = "perfect storm" bonus
6-Tier Risk Levels:
- LOW โ AUTO_APPROVE
- MEDIUM โ REQUIRE_PEER_REVIEW
- HIGH โ REQUIRE_APPROVAL (senior engineer)
- HIGH-SEVERE โ REQUIRE_APPROVAL (senior + architect)
- CRITICAL โ SOFT_BLOCK (VP or director)
- CRITICAL-CATASTROPHIC โ HARD_BLOCK (VP + incident review)
Command Reference
# Analyze a plan
preapply analyze plan.json [--json] [--ascii]
# Policy check (CI/CD)
preapply policy check plan.json --policy-file policy.yaml
# Get explanations
preapply explain analysis.json [resource_id]
# Ask AI (optional, requires Ollama)
preapply ask ai "What's the worst case?" analysis.json
Output Format
PreApply outputs structured JSON with:
{
"version": "1.0.4",
"risk_level": "HIGH",
"risk_level_detailed": "HIGH",
"blast_radius_score": 96.34,
"risk_action": "REQUIRE_APPROVAL",
"approval_required": "SENIOR_ENGINEER or TECH_LEAD",
"risk_breakdown": {
"primary_dimension": "data",
"dimensions": {
"data": 75.5,
"security": 60.0,
"infrastructure": 0.0,
"cost": 0.0
},
"interaction_multiplier": 1.35
},
"sensitive_deletions": [...],
"security_exposures": [...],
"recommendations": [...]
}
Architecture
PreApply processes Terraform plans through five layers:
Terraform Plan JSON
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Ingest Layer โ Loads and normalizes plan JSON
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Graph Layer โ Builds dependency relationships
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Analysis Layer โ Calculates blast radius + risk scores
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โContract Layer โ Versioned CoreOutput schema
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โPresentation โ Human-readable or JSON output
โโโโโโโโโโโโโโโโโโโ
AI Advisor
The AI advisor is a read-only helper powered by Ollama (local AI).
โ Can:
- Help you understand the plan file
- Answer questions about the analysis
- Provide plain-language context about risk factors
โ Cannot:
- Modify anything
- Change risk scores or levels
- Affect policy decisions
Why local AI? Your Terraform plans contain sensitive infrastructure details. PreApply's AI never sends data to external APIs. Everything stays on your machine.
FAQ
Does this replace Terraform's plan review?
No. It augments it by calculating blast radius and risk scores you can't see in raw output.
Will this slow down CI/CD?
No. Analysis takes <2 seconds for plans with 100+ resources.
Can I customize the scoring?
Yes. See src/preapply/config/defaults.yaml for weights and thresholds.
Development
git clone https://github.com/akileshthuniki/PreApply.git
cd PreApply/Core
pip install -e ".[dev]"
# Validate
preapply analyze samples/low_risk.json
# Format & lint
black src/
ruff check src/
Contributing
Contributions welcome! Open an issue before submitting large PRs.
Help wanted:
- Additional Terraform resource handlers
- More CI/CD examples
- Documentation improvements
License
Apache License 2.0
Author
Built by Akilesh Thuniki โ DevOps Engineer specializing in infrastructure safety.
PreApply โ Because "it looked fine in the plan" isn't good enough.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file preapply-1.0.4.tar.gz.
File metadata
- Download URL: preapply-1.0.4.tar.gz
- Upload date:
- Size: 66.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ff82d763501508fec0024c3b16dfe4421406e46c7564e1950d1bcd1aec44b47
|
|
| MD5 |
b977d3ac086c06b14d170ffdb2cf609f
|
|
| BLAKE2b-256 |
17d05d23a55ce9af891751f7cc7a9011ba4cfc415a468e4cd6443e2614530ffa
|
File details
Details for the file preapply-1.0.4-py3-none-any.whl.
File metadata
- Download URL: preapply-1.0.4-py3-none-any.whl
- Upload date:
- Size: 83.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7744bfc3fe4329057bda1a9f960693b24a0b5872a17921f497f49a4e91d3fb2e
|
|
| MD5 |
fe4cde09c02a1b5ad29115cf745f9e93
|
|
| BLAKE2b-256 |
5c16500fb47d5454ee18fae11706b9c99a1f4d1d9b02b81bea3c1f9d2fc42254
|