Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
9d22257
Extend the model with Kustomize kind, virtual resolved files, resolve…
whitemerch Apr 24, 2026
2305013
Add the Preprocessor API with ordered directory detection and refacto…
whitemerch Apr 24, 2026
ec45171
Add sandbox temp dirs and a kyaml BoundedFS that rejects paths outsid…
whitemerch Apr 24, 2026
1d2c470
Wire resolver diagnostics through the scanning pipeline, improve virt…
whitemerch Apr 24, 2026
b34bded
Introduce the k9-iac-enable-kustomize-resolver flag defaulting to off…
whitemerch Apr 24, 2026
41d7616
Add DefaultYAMLDetectLine as a thin wrapper around the shared path-ba…
whitemerch Apr 24, 2026
ec13e91
Split the long checkIncluded condition in datadog rule selection to s…
whitemerch Apr 24, 2026
b126212
Codex comments
whitemerch Apr 27, 2026
251b688
Codex comment: Confine Helm values files to the chart tree even witho…
whitemerch Apr 27, 2026
2636f65
Add pkg/rootfile for os.OpenRoot-scoped file reads.
whitemerch Apr 29, 2026
5cab6e4
Add Kustomize detection, stdlib-only staging primitives, and shared p…
whitemerch Apr 29, 2026
ef62010
Add Kustomize discovery, build-metadata staging, origin/transformatio…
whitemerch Apr 29, 2026
7c068ad
Add Kustomize precheck and helm chart inflation prepass with sandbox-…
whitemerch Apr 29, 2026
0a92c0f
Wire the Kustomize resolver into the scanner via a subprocess render …
whitemerch Apr 29, 2026
4a4e4b6
Add Kustomize detector with direct-source and generator/transformer l…
whitemerch Apr 29, 2026
f8854e9
Wire the Kustomize detector into engine line attribution and skip the…
whitemerch Apr 29, 2026
d349b4e
Add service-level integration tests for Kustomize line attribution.
whitemerch Apr 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions cmd/scanner/internal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"context"

"github.com/DataDog/datadog-iac-scanner/pkg/resolver/kustomize"
cli "github.com/urfave/cli/v3"
)

// internalAction holds hidden subcommands the scanner re-execs (e.g. kustomize
// render in a child the parent can kill on timeout). Hidden from --help.
var internalAction = &cli.Command{
Name: "internal",
Hidden: true,
Usage: "internal helpers used by the scanner to re-exec itself; not for direct use",
Commands: []*cli.Command{
{
Name: "kustomize-render",
Hidden: true,
Usage: "run a single kustomize build; reads a JSON request from stdin and writes a JSON response to stdout",
Action: func(ctx context.Context, c *cli.Command) error {
return kustomize.RunHelperFromStdin()
},
},
},
}
3 changes: 3 additions & 0 deletions cmd/scanner/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/DataDog/datadog-iac-scanner/pkg/resolver/kustomize"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
cli "github.com/urfave/cli/v3"
Expand All @@ -22,6 +23,7 @@ const defaultFailCode = 126
const gcPercent = 50

func main() {
kustomize.MaybeRunAsKustomizeRenderHelper()
if _, ok := os.LookupEnv("GOGC"); !ok {
debug.SetGCPercent(gcPercent)
}
Expand All @@ -32,6 +34,7 @@ func main() {
scanAction,
listPlatformsAction,
listQueriesAction,
internalAction,
},
Flags: []cli.Flag{
&cli.StringFlag{
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ require (
k8s.io/client-go v0.35.1
mvdan.cc/sh/v3 v3.12.0
sigs.k8s.io/controller-runtime v0.23.1
sigs.k8s.io/kustomize/api v0.21.1
sigs.k8s.io/kustomize/kyaml v0.21.1
)

require (
Expand Down Expand Up @@ -167,8 +169,6 @@ require (
k8s.io/component-base v0.35.1 // indirect
k8s.io/kubectl v0.35.1 // indirect
oras.land/oras-go/v2 v2.6.0 // indirect
sigs.k8s.io/kustomize/api v0.21.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
)
Expand Down
13 changes: 13 additions & 0 deletions pkg/detector/default_detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,16 @@ func (d defaultDetectLine) prepareResolvedFiles(resFiles map[string]model.Resolv
}
return resolvedFiles
}

// DefaultYAMLDetectLine is the shared YAML/JSON line detector for subpackages (e.g. kustomize).
type DefaultYAMLDetectLine struct{}

// DetectLine forwards to the default path-based YAML detector.
func (DefaultYAMLDetectLine) DetectLine(
ctx context.Context,
file *model.FileMetadata,
searchKey string,
outputLines int,
) model.VulnerabilityLines {
return defaultDetectLine{}.DetectLine(ctx, file, searchKey, outputLines)
}
108 changes: 108 additions & 0 deletions pkg/detector/kustomize/detect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package kustomize

import (
"context"
"path/filepath"
"strings"

"github.com/DataDog/datadog-iac-scanner/pkg/detector"
"github.com/DataDog/datadog-iac-scanner/pkg/model"
"github.com/DataDog/datadog-iac-scanner/pkg/rootfile"
)

// DetectKindLine maps Kustomize-rendered findings back to source lines.
type DetectKindLine struct{}

// DetectLine: direct sources use default YAML tracing; generators/transformers use kustomization lines.
func (DetectKindLine) DetectLine(
ctx context.Context,
file *model.FileMetadata,
searchKey string,
outputLines int,
) model.VulnerabilityLines {
o := file.KustomizeOrigin
if o != nil && o.OriginKind == model.KustomizeOriginDirect && o.SourceFile != "" && o.SourceRepo == "" {
if v := directSourceDetectLine(o.SourceFile, searchKey, outputLines); v.Line > 0 {
return v
}
}
if o == nil || !o.RequiresDetailedLineMapping() {
return detector.DefaultYAMLDetectLine{}.DetectLine(ctx, file, searchKey, outputLines)
}
cfg := o.GeneratorConfigFile
if cfg == "" {
return detector.DefaultYAMLDetectLine{}.DetectLine(ctx, file, searchKey, outputLines)
}
data, err := rootfile.ReadFile(filepath.Clean(cfg))
if err != nil {
return detector.DefaultYAMLDetectLine{}.DetectLine(ctx, file, searchKey, outputLines)
}
lines := strings.Split(string(data), "\n")
if v, ok := mappedLineFromKustomizeOrigin(ctx, file, o, searchKey, outputLines, lines); ok {
return v
}
return detector.DefaultYAMLDetectLine{}.DetectLine(ctx, file, searchKey, outputLines)
}

func mappedLineFromKustomizeOrigin(
ctx context.Context,
file *model.FileMetadata,
o *model.KustomizeOrigin,
searchKey string,
outputLines int,
lines []string,
) (model.VulnerabilityLines, bool) {
switch o.OriginKind {
case model.KustomizeOriginGenerator:
name := o.ResourceName
if name == "" {
name = metadataNameFromDoc(file.Document)
}
line1, p := generatorConfigLine(o, name)
return buildMappedVulnLines(line1-1, p, lines, outputLines), true
case model.KustomizeOriginTransformer:
if v := transformerPatchFileLine(ctx, o, searchKey, outputLines); v.Line > 0 {
return v, true
}
if o.OriginalSourceFile != "" && o.OriginalSourceRepo == "" {
if v := directSourceDetectLine(o.OriginalSourceFile, searchKey, outputLines); v.Line > 0 {
return v, true
}
}
line1, p := transformerLineForOrigin(o)
return buildMappedVulnLines(line1-1, p, lines, outputLines), true
default:
return model.VulnerabilityLines{}, false
}
}

func buildMappedVulnLines(lineIdx int, resolvedPath string, lines []string, outputLines int) model.VulnerabilityLines {
if lineIdx < 0 {
lineIdx = 0
}
if lineIdx >= len(lines) {
lineIdx = 0
}
return model.VulnerabilityLines{
Line: lineIdx + 1,
VulnLines: detector.GetAdjacentVulnLines(lineIdx, outputLines, lines),
LineWithVulnerability: strings.TrimSpace(lines[lineIdx]),
ResolvedFile: resolvedPath,
VulnerablilityLocation: model.ResourceLocation{
Start: model.ResourceLine{Line: lineIdx + 1, Col: 1},
End: model.ResourceLine{Line: lineIdx + 1, Col: 1},
},
}
}

func metadataNameFromDoc(doc model.Document) string {
if doc == nil {
return ""
}
m, ok := doc["metadata"].(map[string]interface{})
if !ok {
return ""
}
n, _ := m["name"].(string)
return n
}
Loading
Loading