A reproducible analysis needs the same plan or state JSON bytes, Rootform release, active Dialects, and relevant options. For a plan, the same paired saved plan matters when traversals establish facts. rootform.lock fixes external selection; it does not store the embedded Dialects, which come from the binary. A saved Form offers a second path: reopen its recorded facts without the plan or state export or installed Dialects.
This walkthrough uses two copies of one project, source/ and replay/, and a private evidence/ directory. Both contain the same plan.json and plan.tfplan. Keep those input files out of Git and public artifacts: saved plans and JSON exports can contain secrets in clear text. Rootform reads them locally and does not run Terraform, contact providers, or publish sensitive values. Its reports still disclose infrastructure topology and names, so keep them internal.
-
Create an evidence directory accessible only to this workflow. Record the Rootform version and binary checksum beside it. Then analyze the source export with its saved plan:
Shellmkdir -p evidencerootform version > evidence/rootform-version.txtshasum -a 256 "$(command -v rootform)" > evidence/rootform-binary.sha256shasum -a 256 source/plan.json source/plan.tfplan > evidence/input.sha256rootform run source/plan.json --project source \--plan-file source/plan.tfplan --require-enrichment \--no-serve -o evidence/before.jsonExcerpt from analysis summary OUTPUTPlan analyzedEnrichment Saved plan paired with this plan JSON (1 module)Stage PlannedStages Recorded (reconstructed), Refreshed, Planned--require-enrichmentmakes a refused pair fail with status3instead of silently relying on plan-only evidence. The saved plan contributes configuration traversal evidence; it is not the analyzed input. On a Linux host withoutshasum, usesha256sumfor the checksum line. Keep the command flags, standard error, and Form with the exact input hashes. Terraform and OpenTofu plans gives the export procedure. -
Transfer the exact binary for the replay platform and copy the project and input files through your protected channel. An independent Rootform home proves that replay did not use shared installed content. Run the copied input and compare the Form bytes:
Shellreplay_home=$(mktemp -d)ROOTFORM_HOME="$replay_home" rootform run replay/plan.json \--project replay --plan-file replay/plan.tfplan \--require-enrichment --no-serve -o evidence/after.jsoncmp -s evidence/before.json evidence/after.jsonBoth commands return
0for this example.cmp -sestablishes byte identity; the second Rootform summary should again saySaved plan paired with this plan JSON (1 module)on itsEnrichmentline. A different input, release, selection, or saved-plan pairing result invalidates the byte comparison. A fresh home alone does not prove network isolation; run replay in the intended network-disabled environment to prove that boundary.A state JSON uses the same procedure without
--plan-fileor--require-enrichment. State input has onerecordedstage. A plan's default isplanned, and a plan with prior state may also exposerefreshed,recorded, and drift. Compare like stages when assessing architecture; byte identity is a stricter replay check. -
When the plan or state files cannot travel, use the saved Form. It contains stage facts, closures, and comparisons already established by the original run. Reopening does not reanalyze the plan:
Shellreplay_home=$(mktemp -d)ROOTFORM_HOME="$replay_home" rootform run evidence/before.json \--no-serve -o evidence/reopened.mdExcerpt from standard output OUTPUTForm loadedInput evidence/before.jsonForm Plan, saved by rootform 0.1.0-pr.117.1Enrichment Saved plan paired with this plan JSON (1 module)The Markdown file presents the saved Form. Loading needs neither the original plan nor its Dialects. It does not repair an unresolved closure or apply newer Dialect Rules; reanalysis requires the plan or state input and the intended selection. Saved Forms omit sensitive values but still reveal topology.
-
For projects with a nonempty
rootform.lock, prepare exact content before the offline run.initverifies the existing lock and may acquire missing exact OCI bytes while connected. For a disconnected environment, transfer the local source or vendor the selected content with the project. The following commands run from the project root after the reviewed lock exists:Shellrootform init . --locked --no-inputrootform vendor --offlinerootform run plan.json --plan-file plan.tfplan --require-enrichment \--locked --no-serve -o before.jsoninitleaves the lock unchanged.vendor --offlinewrites selected external Dialects and Policy Packs beneath.rootform/from verified local or installed bytes. It does not copy embedded Dialects. The final command writesbefore.jsonwith that selection. Transferrootform.lock, the applicable.rootform/families, plan pair,before.json, and the exact Rootform release. A lock file alone does not transfer external content.In the replay project, verify the vendor copy and analyze without acquisition:
Shellrootform init . --locked --offline --no-inputrootform run plan.json --plan-file plan.tfplan --require-enrichment \--locked --no-serve -o after.jsoncmp -s before.json after.jsonStatus
0fromcmpproves the locked analyses wrote identical Form bytes. If a vendor family is missing or altered, both preparation and analysis refuse it. Repair the selected family withrootform vendor dialects --offlineorrootform vendor policy-packs --offlineonly when verified source bytes are present. Otherwise prepare and vendor on the connected source environment, then transfer the complete family again. Do not remove the lock to bypass an integrity failure. Locks and vendored content gives the ownership rules. -
A saved Form is not a substitute for a separate governance decision. If selected Policies matter, evaluate each saved Form with
rootform check, preserving project selection and any--policyfilters. Savepolicy.json, the report, and the exact check status beside each Form; compare both, because a status alone hides target coverage. Check status0means every selected evaluation passed,1means a violation, and3means indeterminate or no decision. Keep SARIF and reports as internal artifacts. Understand Policy outcomes explains the evaluation counts; outputs and exit status defines the files.
If replay bytes differ, inspect the plan or state details and Dialect selection in both Forms before changing input. Troubleshooting starts with the most common pairing failure.