Summary
When a template passes a random_* value (for example random_password.x.result) into a module, the dynamic parameters form does not evaluate any module declared after it. Parameters defined in those modules silently disappear from the form, and each one is reported as Module not loaded. Did you run terraform init?. Every render also runs the evaluator's full 32 passes, so the form gets slow on large templates.
Reproduction
main.tf:
terraform {
required_providers {
coder = {
source = "coder/coder"
}
}
}
resource "random_password" "secret" {
length = 12
}
module "a_secret" {
source = "./modules/sink"
value = random_password.secret.result
}
module "b_region" {
source = "./modules/param"
}
modules/sink/main.tf:
variable "value" {
type = string
}
resource "terraform_data" "sink" {
input = var.value
}
modules/param/main.tf:
data "coder_parameter" "region" {
name = "region"
type = "string"
default = "us"
}
Rendering this with preview.Preview at the versions main pins (coder/preview c0dfdeecbd89, coder/trivy 15b949537506):
params=[]
diag: Module not loaded. Did you run `terraform init`? | Module 'module "b_region"' in file "main.tf:18,1-18" cannot be resolved. This module will be ignored.
Expected: params=[region] and no diagnostic. Replacing the module input with a plain string gives the expected result.
Cause
Two things in the coder/trivy evaluator combine:
createPresetValues (pkg/iac/terraform/presets.go) gives random_password, random_string, random_id, random_bytes, random_uuid and random_integer a new uuid.New() / rand.Int64() value on every call, and it runs on every evaluation pass. Anything outside a resource that reads one of them never settles, so evaluateSteps never sees an unchanged context and always runs maxContextIterations passes.
evaluateSubmodules (pkg/iac/scanners/terraform/parser/evaluator.go) does changed = changed || e.evaluateSubmodule(ctx, sm). Once one submodule reports a change, || short-circuits and skips every submodule after it in that pass. A submodule fed a random value reports a change on every pass, so the modules after it are never evaluated in any pass. coder/preview then flags them as not loaded.
This is not the same as coder/preview#228, where the module is evaluated and the warning is a false positive. Here the module's blocks and parameters are really missing.
On a large production template (about 60 resources and a dozen modules) this took a parameter render from about 0.35s to 3.2s, and the form showed "Module not loaded" for 11 modules.
Fix
A PR against coder/trivy follows: evaluate every submodule on each pass, and derive the random_* placeholders from the block so they are stable across passes.
Summary
When a template passes a
random_*value (for examplerandom_password.x.result) into a module, the dynamic parameters form does not evaluate any module declared after it. Parameters defined in those modules silently disappear from the form, and each one is reported asModule not loaded. Did you run terraform init?. Every render also runs the evaluator's full 32 passes, so the form gets slow on large templates.Reproduction
main.tf:modules/sink/main.tf:modules/param/main.tf:Rendering this with
preview.Previewat the versionsmainpins (coder/previewc0dfdeecbd89,coder/trivy15b949537506):Expected:
params=[region]and no diagnostic. Replacing the module input with a plain string gives the expected result.Cause
Two things in the
coder/trivyevaluator combine:createPresetValues(pkg/iac/terraform/presets.go) givesrandom_password,random_string,random_id,random_bytes,random_uuidandrandom_integera newuuid.New()/rand.Int64()value on every call, and it runs on every evaluation pass. Anything outside a resource that reads one of them never settles, soevaluateStepsnever sees an unchanged context and always runsmaxContextIterationspasses.evaluateSubmodules(pkg/iac/scanners/terraform/parser/evaluator.go) doeschanged = changed || e.evaluateSubmodule(ctx, sm). Once one submodule reports a change,||short-circuits and skips every submodule after it in that pass. A submodule fed a random value reports a change on every pass, so the modules after it are never evaluated in any pass.coder/previewthen flags them as not loaded.This is not the same as coder/preview#228, where the module is evaluated and the warning is a false positive. Here the module's blocks and parameters are really missing.
On a large production template (about 60 resources and a dozen modules) this took a parameter render from about 0.35s to 3.2s, and the form showed "Module not loaded" for 11 modules.
Fix
A PR against
coder/trivyfollows: evaluate every submodule on each pass, and derive therandom_*placeholders from the block so they are stable across passes.