feat(extraction): add Terraform/OpenTofu language support with module-boundary bridging (#83, #310, #648 — carries #706) (#1173)
* feat(extraction): add Terraform and OpenTofu language support Index .tf, .tfvars, and .tofu files via the tree-sitter-terraform dialect of HCL (vendored from @tree-sitter-grammars/tree-sitter-hcl, Apache-2.0). Symbols extracted: - resource / data → class (qualified "type.name" / "data.type.name") - module → module (qualified "module.name") - variable → variable (qualified "var.name") - output → variable (qualified "output.name") - provider → namespace - locals → constant per attribute (qualified "local.key") References resolved cross-file: - var.X, local.X, module.M[.out], data.T.N[.attr], <type>.<name>[.attr] - built-ins skipped: each.*, count.*, self.*, path.*, terraform.workspace The Terraform framework resolver disambiguates same-named candidates across modules by preferring the one in the same directory as the reference site, then by closest common-ancestor path, falling back to the generic name matcher only when neither applies. Validated on two Terraform monorepos (277 and 470 .tf files): indexing runs in 1.3s and 2.4s respectively, query latency stays under 200ms, and cross-module references resolve to the correct module 100% of the time on inspected samples. 18 new extraction tests; full suite 1146/1148 green (2 pre-existing flaky skips, 0 regressions). * feat(terraform): bridge the module boundary and enforce directory scoping Builds on #706. The module declaration was a dead end: module.M.out resolved to the declaration and stopped, module inputs never reached the child module's variables, and impact could not cross the boundary — on real multi-module repos that breaks the core blast-radius question ("what breaks upstream if I change this module's variable/output"). - module blocks now wire across the boundary through :-scoped refs only the Terraform resolver understands: module.M:var.<input> → the child's variable node, module.M:output.<o> → the child's output node (emitted alongside the module.M declaration ref), and module.M:file → the local source directory's entry file (imports). Registry/git sources emit no file ref and resolve nothing — an out-of-repo module stays a visible boundary instead of a guess. - .tfvars top-level assignments reference the variable they set, walking up to the nearest ancestor directory (envs/prod.tfvars → root vars). - Resolution now enforces Terraform's real scoping: same-directory only (no cross-module fallback by common path prefix, no single-candidate anywhere-in-tree binding), and terraform refs never fall through to the generic name matcher — var.X can never legally bind outside its module directory, so the fallback could only add wrong edges. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(terraform): README language table + changelog entry + agent-eval corpus Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Javier Rodríguez Fernández <jfernandez@freepik.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
Javier Rodríguez Fernández
parent
e1a8d888e5
commit
6c24f4bddf
@@ -538,5 +538,28 @@
|
||||
"files": "~2700",
|
||||
"question": "When a cutlass device-level GEMM (cutlass::gemm::device::Gemm) is invoked, how does it reach the GPU kernel? Trace from the operator() call to the kernel entry point and its launch site."
|
||||
}
|
||||
],
|
||||
"Terraform": [
|
||||
{
|
||||
"name": "terraform-aws-vpc",
|
||||
"repo": "https://github.com/terraform-aws-modules/terraform-aws-vpc",
|
||||
"size": "Small",
|
||||
"files": "~77",
|
||||
"question": "How does the private_subnets variable shape the NAT gateway setup? Trace from the variable through the subnet and NAT gateway resources to the outputs that expose the private subnets."
|
||||
},
|
||||
{
|
||||
"name": "cloud-foundation-fabric",
|
||||
"repo": "https://github.com/GoogleCloudPlatform/cloud-foundation-fabric",
|
||||
"size": "Medium",
|
||||
"files": "~990",
|
||||
"question": "In the project module (modules/project), how does the iam variable turn into actual IAM bindings on the project, and what depends on the module's project_id output elsewhere in the repo?"
|
||||
},
|
||||
{
|
||||
"name": "terraform-aws-components",
|
||||
"repo": "https://github.com/cloudposse/terraform-aws-components",
|
||||
"size": "Large",
|
||||
"files": "~1800",
|
||||
"question": "In the eks/cluster component, how does the cluster IAM role get created and reach the EKS cluster resource, and which outputs expose cluster identity to other components?"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user