Inverted TargetContains check in backend_apply emits false warnings and misses partial target overrides
Terraform Version
Terraform v1.17.0-dev / main (commit c571b6ac82)
Terraform Configuration Files
terraform {
required_providers {
null = {
source = "hashicorp/null"
}
}
}
resource "null_resource" "a" {}
resource "null_resource" "b" {}
Debug Output
N/A (Behavior is observable directly in CLI standard output and reproducible via unit test)
Expected Behavior
When applying a saved plan that contains multiple targeted resources (e.g. both null_resource.a and null_resource.b), passing -target=null_resource.a to apply cannot narrow down or filter the already-computed changes in the plan file.
Terraform should warn the user that the plan file contains additional targets (null_resource.b) that will still be applied despite the -target=null_resource.a flag.
Actual Behavior
Terraform runs completely silently with zero warnings and applies both resources:
null_resource.a: Creating...
null_resource.b: Creating...
null_resource.a: Creation complete after 0s [id=6482619472648123912]
null_resource.b: Creation complete after 0s [id=3194827501928472911]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
The user is given no indication that their -target flag was disregarded and that null_resource.b was applied.
Steps to Reproduce
Create a plan with two targets: terraform plan -target=null_resource.a -target=null_resource.b -out=test.tfplan
Attempt to apply only one of the targets using the saved plan: terraform apply -target=null_resource.a test.tfplan
Observe that both null_resource.a and null_resource.b are applied, and no warning diagnostic is emitted.
Additional Context
This relates to the recent changes added in PR #38698 (commit c571b6ac82) in internal/backend/local/backend_apply.go:
if len(op.Targets) != 0 {
// Do target flags all match targets in the plan?
for _, target := range op.Targets {
found := false
for _, planTarget := range plan.TargetAddrs {
if target.TargetContains(planTarget) {
found = true
break
}
}
if !found {
// emit warning
}
}
}
Two separate logic problems exist in this block:
- Inverted containment check:
target.TargetContains(planTarget)checks if the CLI target contains the plan target, rather than whether the plan target covers the CLI target.
- If a plan targeted
module.fooand the user runsapply -target=module.foo.null_resource.bar,module.foo.null_resource.bar.TargetContains(module.foo)returns false. This emits a false-positive warning saying the resource does not match a target in the plan file, even though it was included undermodule.foo. - If a plan targeted
module.foo.null_resource.barand the user runsapply -target=module.foo, it returns true and emits no warning.
- Subset / re-targeting blind spot:
The check only verifies that each CLI target is found in
plan.TargetAddrs. Ifplan.TargetAddrscontains[A, B]and the user passes-target=A,AmatchesA, sofoundis true and no warning is generated. However,Bwill still be applied without warning.
References
- #38670 (Original issue)
- #38698 (PR adding plan option warnings on apply)
- Commit c571b6ac82
Generative AI / LLM assisted development?
No (Code inspection and reproduction verified locally).
Source: hashicorp/terraform