Skip to content

Resolve Terraform plan line numbers from searchKey#215

Merged
whitemerch merged 3 commits into
mainfrom
chakib.hamie/searchkey_tfplan_line_detection
Jun 29, 2026
Merged

Resolve Terraform plan line numbers from searchKey#215
whitemerch merged 3 commits into
mainfrom
chakib.hamie/searchkey_tfplan_line_detection

Conversation

@whitemerch

@whitemerch whitemerch commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Motivation

Terraform plan JSON is remapped under a top-level resource key, so line detection cannot rely on text matching for attribute-level findings. Rules today duplicate location hints via a searchLine field alongside searchKey. This change lets plan files resolve lines from searchKey alone so rules can drop searchLine for attribute-level paths.

Changes

File kind

Introduce KindTerraformPlan and set it when the JSON parser recognizes Terraform plan content, so plan files are routed to the correct line-detection path.

Line detection

For KindTerraformPlan, convert bracket-style searchKey values (e.g. aws_s3_bucket[b].acl) into a structural path under resource.<type>.<name>.<attr> and resolve the line via the existing gjson _dd_lines lookup. Attribute-level keys are resolved structurally; resource-only keys (no attribute segment) still fall back to text matching so existing expected lines are preserved.

Tests

Add unit tests for path conversion and an integration test that parses a minimal plan and asserts the resolved line.

Author Checklist

  • I have reviewed my own PR.
  • I have added or updated relevant unit tests where necessary. If no tests are added, I've explained why.
  • All new and existing tests pass.
  • I have tested my changes on staging (if applicable).
  • I have updated any relevant documentation (if applicable).

QA Instruction

  1. go test ./pkg/detector/... ./pkg/parser/...
  2. go test ./...
  3. Point the default-rules repo at this branch (go mod edit -replace github.com/DataDog/datadog-iac-scanner=../datadog-iac-scanner) and run ./tool.sh test.
  4. Remove searchLine from a Terraform rule with a plan JSON fixture (e.g. terraform-alicloud-rds-instance-address-publicly-accessible) and confirm plan line numbers still match expected results.

Blast Radius

Datadog IaC Scanner line detection for Terraform plan JSON files. No change to .tf HCL detection, CloudFormation, Kubernetes, or other JSON/YAML formats.

Additional Notes

This PR does not read the rego searchLine field. The engine still honors searchLine when rules provide it (searchLineCalculator in vulnerability_builder.go); follow-up work in the default-rules repo can remove those fields once this ships. Resource-only searchKey values on plans continue to use text matching rather than structural lookup.

I submit this contribution under the Apache-2.0 license.

@datadog-official

datadog-official Bot commented Jun 26, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 68.42%
Overall Coverage: 49.47% (-0.17%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 76706bb | Docs | Datadog PR Page | Give us feedback!

@whitemerch
whitemerch force-pushed the chakib.hamie/searchkey_tfplan_line_detection branch from 7c7ee11 to 8a8e323 Compare June 26, 2026 13:32
@whitemerch
whitemerch marked this pull request as ready for review June 26, 2026 13:37
@whitemerch
whitemerch requested a review from a team as a code owner June 26, 2026 13:37
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@whitemerch
whitemerch force-pushed the chakib.hamie/searchkey_tfplan_line_detection branch from 8a8e323 to a552f98 Compare June 26, 2026 14:04
@whitemerch
whitemerch force-pushed the chakib.hamie/searchkey_tfplan_line_detection branch from a552f98 to 5b879c5 Compare June 26, 2026 14:26

@ChouraquiBen ChouraquiBen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments but the core of the idea is good!

Comment thread pkg/detector/default_detect.go Outdated
Comment thread pkg/detector/default_detect.go
Comment thread pkg/detector/default_detect.go Outdated
Comment thread pkg/parser/parser.go
}

kind := c.Parsers.GetKind()
if ck, ok := c.Parsers.(contentKindParser); ok {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: This is stylish as it allows not to create many changes in the parsers but it creates an abstraction that is used by only one parser. Are there any other parsers that could benefit from it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t see another parser with the same “same extension, different semantic kind” case today, but it could be possible in the future yes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, let's leave it as is then

@whitemerch
whitemerch force-pushed the chakib.hamie/searchkey_tfplan_line_detection branch from 5b879c5 to d6b6d8b Compare June 29, 2026 09:31
@whitemerch
whitemerch force-pushed the chakib.hamie/searchkey_tfplan_line_detection branch from d6b6d8b to e3d3f44 Compare June 29, 2026 09:32

@ChouraquiBen ChouraquiBen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two comments, one is about performance and can imo be overlooked, the other one is a bit more important 🙏
Thanks for the time you're taking to tackle my comments

Comment thread pkg/parser/json/parser.go Outdated
// KindForContent overrides the static kind for Terraform plan JSON so line
// detection can resolve plan resources structurally instead of by text match.
func (p *Parser) KindForContent(content []byte) (model.FileKind, bool) {
if contentIsTerraformPlan(content) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: this function calls parseTFPlan and raises the total number of parseTFPlan usage to 3 per TFPlan. There should be 1 or 2 TFPlan scanned per repo but this is to be noticed

Comment thread pkg/detector/default_detect.go
// structured gjson lookup (precise, handles array indices and numeric map keys). On
// failure it strips numerics and returns the remainder for the text-matcher fallback.
// Returns (nil, nil) when no numeric segment is present.
func handleArrayIndex(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Here, the array index is being read but in [1], the bracket values have been taken away. Is the behaviour broken or am I missing the place where they are being populated back?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not broken, the values are restored in extractStructuralPath. GetBracketValues captures [name] as a pair ["[name]", "name"] in extractedString. The sanitization loop replaces the full bracket expression [name] with {{0}} so the dot-split works cleanly. Then extractStructuralPath replaces {{0}} back with ext[1] = "name" (the value without brackets) before passing the path to GetLineBySearchLine. gjson expects plain dotted keys, not bracket notation, so stripping [] while preserving the value is intentional

Comment thread pkg/parser/json/parser.go
// co-presence is a reliable signal. Used by KindForContent and StringifyContent
// where a full parseTFPlan call would be redundant (Parse already does it).
func looksLikeTerraformPlan(content []byte) bool {
return bytes.Contains(content, []byte(`"format_version"`)) &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

big

@ChouraquiBen ChouraquiBen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ChouraquiBen

Copy link
Copy Markdown
Contributor

Thanks for going through all the comments 🙏

@whitemerch
whitemerch merged commit a03ed50 into main Jun 29, 2026
19 checks passed
@whitemerch
whitemerch deleted the chakib.hamie/searchkey_tfplan_line_detection branch June 29, 2026 11:42
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.

2 participants