blastcheck 0.3 · format 0.1 draft · Apache-2.0

blastcheck

A Terraform plan tells you what will change. It does not tell you whether the change is safe.

blastcheck reads terraform show -json and emits an Impact Manifest: a machine-readable change-safety assertion. Free, offline, no credentials, no hosted service.


Landed here from a manifest.json?

That file was produced by this tool. It records, for every resource change in a plan, whether the change is reversible, whether anything becomes unrecoverable, whether exposure widens, and — the part that matters most — what could not be determined.

An unknown in that document is not a bug. It means the producer could not verify something, and is saying so rather than guessing. Unproven is not safe, and a consumer must never treat it as such.

Install

pip install blastcheck

terraform plan -out tfplan
terraform show -json tfplan | blastcheck > manifest.json

In a pull request:

- run: terraform show -json tfplan > plan.json

- uses: prococonsulting/blastcheck@v0
  with:
    plan: plan.json

What it reads from a plan alone

DimensionExample the plan can actually prove
reversibilityAn Azure managed disk grow is one-way. Azure cannot shrink a disk.
security_postureAn inbound rule opening 0.0.0.0/0 to 22 or 3389; a database turning on publicly_accessible; a bucket set to public-read; encryption or deletion protection switched off.
data_durabilityA delete removes the primary copy of a data-bearing resource, and recoverability is unverified rather than assumed.
state_confidencedrift_detected when Terraform's own refresh found the resource had moved. Otherwise not_verified — see below.

Every provider, in three layers

Every change in a plan is assessed. Nothing is skipped for being an unfamiliar resource type.

LayerApplies toConfidence
0 — structuralany provider ever written: action semantics, action_reason, replace_paths, drift, unreadable fieldshigh
1 — heuristicany provider, by resource-type and attribute name and value patternslow, tagged heuristic
2 — preciseresource types with an exact rule (Azure disks, VMs, NSGs, storage, SQL today)high

On a real 55-change AWS plan, with no AWS-specific code at all, the heuristic layer finds a publicly accessible unencrypted database with final snapshots disabled, a public-read bucket, and a security group open to the internet.

Those findings are graded caution, never blocking, and their evidence is tagged source: heuristic. They are leads, not determinations, and saying so is the difference between a tool people read and a tool people mute. For the same reason an open egress rule and a default route are not flagged: both are 0.0.0.0/0 by definition, and firing on them would trip on nearly every plan ever written.

Drift, without asking you for credentials

terraform plan refreshes by default: before computing a diff it reads live reality for every managed resource and records anything that moved in a top-level resource_drift array. That is a live-state observation already sitting inside an offline artifact. blastcheck did not perform the read. Terraform did. The fact is no less true for it.

A resource appearing in both resource_drift and resource_changes is the most dangerous shape this tool can find, and it is graded blocking:

azurerm_managed_disk.sql_data          severity: blocking
  state_confidence: drift_detected     (recorded 512 -> live 1024)
verdict: blocked

The plan is internally consistent. It reads as routine. It was computed against a description of that resource which had already stopped being true, and every other verdict for it was derived from the same stale state. That is the outage this exists for.

Two limits, stated rather than papered over. An empty resource_drift is ambiguous — it means either refresh found nothing or refresh did not run (-refresh=false), and the plan does not record which, so absence never earns state_matches_reality. And refresh only sees resources Terraform manages; anything created outside Terraform is not in state, so nothing refreshes it.

Why it never says safe

blastcheck is offline by design. It never queries live cloud state, so it is not entitled to certify that a change is safe — it can only report caution, blocked, or unknown. That is not a limitation being apologised for. A tool that says safe when it means I found no problem converts an absence of information into a green light and puts someone's name on it.

A false safe is catastrophic. A false unknown is annoying. The format is built around that asymmetry.

Tamper-evident

blastcheck --plan plan.json --sign > manifest.json
blastcheck --verify manifest.json

--sign attaches a digest over the manifest canonicalized with JCS (RFC 8785), so two conformant producers of the same logical document compute the same bytes. Editing a verdict after the fact breaks verification.

The format is not owned by this tool

Impact Manifest is an open specification, Apache-2.0, with no assumption of any cloud and no coupling to any implementation. blastcheck is a reference producer of it, not its owner. Other tools are expected to implement it, and the format is only worth anything if they do.

Why this exists

The plan was right. The state was wrong. — a Terraform apply that took production down on a change whose plan was three lines long and completely correct, and why every pre-apply tool would have passed it.

Contact

Bug reports and feature requests: open an issue. Questions about the format, or about implementing it in another tool: the specification repository, or email kproffitt@prococonsulting.com.

Built and maintained by Kevin Proffitt — prococonsulting.com, LinkedIn.