Skip to main content

PlanSeal

Cryptographic approval for saved infrastructure plans.

CI Release License

PlanSeal proves that the Terraform or OpenTofu plan being offered for execution is exactly the plan a human approved: same file, same Git revision, same provider lockfile, and same resource-action scope.

saved plan -> sanitized evidence -> owner signature -> exact-input verification -> apply

PlanSeal is local-first, has no service or account, does not manage cloud credentials, and does not persist raw plan JSON. Apply is preview-only unless the operator explicitly supplies --execute.

[!WARNING] PlanSeal is alpha software. It has not received an independent security audit. Do not treat it as the only control protecting production systems.

Why

Saved plans separate review from execution, which is useful for automation and AI-assisted operations. That separation creates a precise question:

Is this still the exact artifact I reviewed?

An approval in chat or a CI button does not, by itself, bind the approval to the plan bytes, source revision, dependency lock, and action list. PlanSeal creates and verifies that binding.

Use PlanSeal when

  • a saved Terraform or OpenTofu plan is reviewed separately from execution;
  • an owner needs to authorize exact plan bytes and a bounded action scope;
  • a local or owner-operated workflow should remain independent of a hosted approval service; or
  • automation or an AI agent prepares a plan but must not approve its own work.

Choose another control when

  • a managed platform already provides the complete plan/apply approval lifecycle you need;
  • you require multi-party approval, hardware-backed signing, remote identity, or centralized policy enforcement; or
  • you cannot protect saved plan files and the local owner key appropriately.

Quick start

Requirements: Python 3.11+, Git, and either OpenTofu or Terraform.

pipx install planseal

planseal keygen \
  --private-key ~/.config/planseal/owner-private.pem \
  --public-key ~/.config/planseal/owner-public.pem

tofu plan -out=change.tfplan

planseal inspect change.tfplan \
  --repo . \
  --lockfile .terraform.lock.hcl \
  --output evidence.json

Review the sanitized evidence, copy its digest from the inspect output, and approve only the action classes you intend:

planseal approve evidence.json \
  --private-key ~/.config/planseal/owner-private.pem \
  --allow create,update \
  --confirm sha256:REPLACE_WITH_EVIDENCE_DIGEST \
  --output certificate.json

Verify all bindings and preview the fixed apply command:

planseal verify \
  --evidence evidence.json \
  --certificate certificate.json \
  --public-key ~/.config/planseal/owner-public.pem \
  --plan change.tfplan \
  --repo . \
  --lockfile .terraform.lock.hcl

planseal apply \
  --evidence evidence.json \
  --certificate certificate.json \
  --public-key ~/.config/planseal/owner-public.pem \
  --plan change.tfplan \
  --repo . \
  --lockfile .terraform.lock.hcl

The last command is a preview. Add --execute only after reviewing its JSON output. Execution consumes the certificate nonce before starting the saved plan, so the certificate cannot be reused.

For a credential-free walkthrough, use the minimal synthetic example. To install directly from source instead, see Getting Started.

What evidence contains

{
  "actions": [
    {"actions": ["update"], "address": "module.edge.example_resource.policy"}
  ],
  "lockfile_checksum": "sha256:...",
  "plan_checksum": "sha256:...",
  "plan_id": "change.tfplan",
  "schema_version": 1,
  "source_revision_digest": "sha256:...",
  "tool": "opentofu"
}

It intentionally excludes plan values, provider configuration, state, environment variables, credentials, command output, and absolute paths. Resource addresses may still reveal naming conventions; treat evidence as operational metadata.

Security properties

  • Ed25519 signatures over canonical JSON.
  • Five-minute maximum certificate lifetime.
  • Exact plan, source revision, lockfile, and action-scope binding.
  • Explicit approval for delete and replacement actions.
  • Clean tracked Git worktree required at inspection and verification.
  • No shell invocation.
  • Preview-first execution.
  • SQLite-backed one-time certificate consumption.
  • Sanitized machine-readable errors.

Read the threat model before using PlanSeal around sensitive infrastructure.

Project status

PlanSeal v0.1 is an intentionally narrow proof of the exact-artifact approval protocol. Planned follow-up work includes encrypted OS-backed key storage, hardware-backed owner presence, remote receiver profiles, and signed receipts. Those features are not part of the current security claim.

Documentation

Start at the documentation index.

Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md, SECURITY.md, and CODE_OF_CONDUCT.md.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

planseal-0.1.2.tar.gz (32.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

planseal-0.1.2-py3-none-any.whl (16.8 kB view details)

Uploaded Python 3

File details

Details for the file planseal-0.1.2.tar.gz.

File metadata

  • Download URL: planseal-0.1.2.tar.gz
  • Upload date:
  • Size: 32.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for planseal-0.1.2.tar.gz
Algorithm Hash digest
SHA256 75575a56ff689b9d13310de2a3ab0479f1ba5034ab938d87eaafbf169b5d4e7c
MD5 5f90d748771ae685bc834e1aae3a24d3
BLAKE2b-256 8b0b8aeff5e2cfdf9a6b3ebd0cdf5a1354096617b888c4bf8d0f8fda546c6b9f

See more details on using hashes here.

Provenance

The following attestation bundles were made for planseal-0.1.2.tar.gz:

Publisher: release.yml on haithdoan/planseal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file planseal-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: planseal-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 16.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for planseal-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 57fff65b5af27f18ff5d24505cfa638ec6b915a707f6e5fbec29457a9b897e9d
MD5 58e301cdd35d11baa9fc069c065a2e13
BLAKE2b-256 5282c312ca4c525be3c4b8a0421ce3911fa64437323be676dc88c38de561d18b

See more details on using hashes here.

Provenance

The following attestation bundles were made for planseal-0.1.2-py3-none-any.whl:

Publisher: release.yml on haithdoan/planseal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page