Skip to content

fix(autodetect): stop dropping nested non-Terraform projects - #28

Closed
liamcervante wants to merge 1 commit into
mainfrom
fix/autodetect-nested-non-terraform-projects
Closed

liamcervante wants to merge 1 commit into
mainfrom
fix/autodetect-nested-non-terraform-projects

Conversation

@liamcervante

Copy link
Copy Markdown
Contributor

Problem

The final filter in filterProjects dropped any non-Terraform project that had a project ancestor:

if (!project.IsTerragrunt() && !project.IsTerraform()) && project.IsInsideProject() {
    continue
}

Nesting is the normal, correct layout for several formats — a Kustomize app directory holds base/ and overlays/ subdirectories that are themselves kustomization directories — so this discarded projects that should have been detected.

The effect is worst in a GitOps repository that keeps a controller manifest in its root (an Argo CD Application, say) pointing at the manifests held elsewhere in the tree. That manifest carries top-level apiVersion + kind, so the root directory is a Kubernetes project in its own right. Every project in the repository then has a project ancestor, so all of them are dropped and the repository collapses to . — which ParseDirToTree reads non-recursively, yielding nothing. A repository of ~1800 Kustomize directories reports one project and zero resources.

Fix

The comment above that filter describes something much narrower than the condition implements: "remove cfn projects that lie within a tf/tg project". That case is real — a CloudFormation template inside a Terraform project is usually deployed by that Terraform via aws_cloudformation_stack, so emitting it standalone represents one deployment twice. So check for it specifically:

if project.IsCloudFormation() && project.IsInsideTerraformProject() {
    continue
}

Where a parent genuinely owns its nested directories, the parent's IdentifyEnvironments answer already claims them (claimedDirs in expandProjects), which suppresses them precisely instead of by proximity. That mechanism is two-pass and order-independent, so it does this job without help from the proximity filter.

IsInsideProject had no other callers and is replaced by the narrower IsInsideTerraformProject.

Blast radius

Beyond Kubernetes, the blanket condition was also dropping nested ARM and Cisco Stacks projects for the same wrong reason. Those now nest too. Repositories with such layouts will gain projects they should have had, so it is worth a look at runner golden output before this ships.

Testing

generate_nesting_with_plugins_test.go drives real files on disk through config.Generate with the released parser plugins, so identification and environment expansion are exercised end to end rather than mocked:

  • Nested Kubernetes projects — a root controller manifest plus a Kustomize app with base/ and overlays/dev/, and a directory of controller manifests. Asserts three projects: the root, app-dev at app/overlays/dev with app/base/** as a dependency path, and wrappers. Note app/base and app/overlays/dev are correctly absent, suppressed by the app's claimed directories.
  • CloudFormation inside Terraform — still suppressed, while the same template outside a Terraform project is still a project.

Against the old condition the first test reports expected 3 projects, got 1, reproducing the production failure exactly — verified by reinstating it, so the test is not vacuous. infracost-parser-kubernetes is added to the downloaded test plugins.

Full suite passes.

Notes

  • No existing test covered this behaviour, which is how it survived.
  • No parser change is needed. Every directory in such a repository is correctly identified today, including the controller-manifest directories that carry no costed resources — they are legitimate Kubernetes project directories and should be emitted as such.

The final filter in filterProjects dropped any non-Terraform project that had
a project ancestor. Nesting is the normal, correct layout for several formats -
a Kustomize app directory holds base/ and overlays/ subdirectories that are
themselves kustomization directories - so this discarded projects that should
have been detected.

The effect is worst in a GitOps repository that keeps a controller manifest in
its root, pointing at the manifests held elsewhere in the tree. That root
directory is a Kubernetes project in its own right, so every project in the
repository has a project ancestor and all of them are dropped, collapsing the
repository to its root - which is read non-recursively and yields nothing.

The filter's documented purpose is narrower than its condition: a
CloudFormation template inside a Terraform project is usually deployed by that
Terraform via aws_cloudformation_stack, so emitting it standalone represents
one deployment twice. Check for that case specifically. Where a parent
genuinely owns its nested directories, the parent's IdentifyEnvironments answer
already claims them, which suppresses them precisely rather than by proximity.

This also restores nesting for ARM and Cisco Stacks projects, which the blanket
condition dropped for the same reason.

IsInsideProject had no other callers and is replaced by the narrower
IsInsideTerraformProject.
@liamcervante
liamcervante requested review from a team and liamg August 17, 2026 10:28
@liamcervante
liamcervante marked this pull request as ready for review August 17, 2026 10:34
@liamcervante

Copy link
Copy Markdown
Contributor Author

#29 does this but better

@liamcervante
liamcervante deleted the fix/autodetect-nested-non-terraform-projects branch August 17, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant