Read the module diff before changing your source
force_destroy = var.force_destroy
object_lock_enabled = var.object_lock_enabled
tags = var.tags
+
+ lifecycle {
+ prevent_destroy = true
+ ignore_changes = [tags, tags_all]
+ }
}This is the code change returned by the public preview for two rules on
terraform-aws-modules/s3-bucket 5.15.4. You can read it without an account,
without configuring AWS, and before changing a module source in your stack.
The capture reports 2 rules applied, 3 resources affected and 1 file changed. Those numbers tell you to look at the diff. They do not tell you whether every bucket gets destruction protection, or whether every submodule was inspected.
Ask for the exact module version and rules
curl -sS "https://registry.compliance.tf/api/v1/modules/terraform-aws-modules/s3-bucket/aws/5.15.4/rules/preview?rules=lifecycle_prevent_destroy_data,lifecycle_ignore_tags" \
| jq '{summary, outcomes, files}'lifecycle_prevent_destroy_data requests protection for supported data resources.
lifecycle_ignore_tags requests lifecycle handling for tag changes. Keeping the
version pinned makes the target of this request explicit.
The response contains summary, per-rule outcomes, and unified diffs in
files. To explore the recorded response without a network call:
git clone https://github.com/antonbabenko/compliance.tf-demo
cd compliance.tf-demo/scenarios/02-free-preview
jq '{summary, outcomes, files}' expected/preview.jsonThat response was captured on 2026-10-07.
The directory bucket gets a different block
The ordinary aws_s3_bucket gets the block at the top of this page. The
aws_s3_directory_bucket gets:
tags = var.tags
+
+ lifecycle {
+ ignore_changes = [tags]
+ }
}There is no prevent_destroy in that added block. An applied-rule count would
not reveal that distinction. Review the actual resource types and settings
before translating "rules applied" into a statement about protection.
The settings also represent different choices. prevent_destroy rejects
Terraform plans that destroy or replace a protected resource while its
configuration is present. It does not survive removal of that configuration,
and it does not prevent deletion through the AWS console.
ignore_changes assigns update ownership elsewhere. Terraform can configure the
listed attributes at creation, but will not reconcile their later changes.
That can be appropriate when another system manages tags. It also means that
unwanted tag changes will not be repaired by Terraform. The
Terraform lifecycle reference
describes both behaviors; this demo captures the inserted code, not a deployed
test of those behaviors.
Five omitted submodules matter more than a success flag
Inspect summary.scope_coverage and summary.submodules_omitted:
jq '.summary | {scope_coverage, submodules_omitted}' expected/preview.jsonFor this response, scope is module_root_only. The omitted paths are
modules/account-public-access, modules/notification, modules/object,
modules/table-bucket and modules/vectors. Success means the request succeeded
within that stated scope, not that the entire package was rewritten.
Refused requests tell you where the public route stops
The same capture set includes five deliberate refusals:
| Request | HTTP | Code |
|---|---|---|
&framework=soc2 | 400 | PREVIEW_PARAM_NOT_ACCEPTED |
&disable=s3_bucket_logging_enabled | 400 | PREVIEW_PARAM_NOT_ACCEPTED |
Version latest instead of 5.15.4 | 400 | PREVIEW_VERSION_NOT_PINNED |
&ruleset=production | 403 | PREVIEW_TIER_REQUIRED |
No rules= parameter | 400 | RULE_SYNTAX |
Run make refusals from the scenario directory to read each recorded error and
its remediation field. The public route accepts operational-rule requests for
allowlisted, pinned modules. These errors are not evidence that the same
parameters are unavailable on authenticated routes.
An error response and an empty successful diff are different results. For an
example of the latter, see the not_configured rule in the
lifecycle walkthrough.
Previewing and downloading are separate steps
make demo replays the recorded summary and diff. make live makes a fresh
preview call. Neither target installs the rewritten module or runs a plan.
Downloading from a framework host needs
registry authentication.
Live preview calls are rate limited; the scripts space requests 11 seconds apart and retry HTTP 429 responses. Replays make no network calls. The Rules Playground offers another way to inspect the diff.
If you are evaluating a rule, read its diff, outcome and scope together. Then review an authenticated download and a plan for your own inputs before treating that code change as a tested infrastructure change.