From 0f2125817b367618c307c2903fd02ce1b117ee8d Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Wed, 31 Dec 2025 06:14:10 +0800 Subject: [PATCH] fix: enable kustomize overlays to load base configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1617. The kustomize build was failing for overlays that reference base configurations in parent directories (e.g., ../../base). This was because krusty.MakeDefaultOptions() defaults to LoadRestrictionsRootOnly, which prevents loading resources from outside the kustomize directory. Changed LoadRestrictions to LoadRestrictionsNone to allow overlays to properly resolve and merge base configurations during scanning. Added tests to verify: - Overlay directories can successfully load resources from base directories - Base directories continue to work as before - The merged configuration includes resources from both base and overlay 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 Signed-off-by: majiayu000 <1835304752@qq.com> --- core/cautils/kustomizedirectory.go | 7 +- core/cautils/kustomizedirectory_test.go | 82 +++++++++++++++++++ .../testdata/kustomize/base/deployment.yaml | 28 +++++++ .../kustomize/base/kustomization.yaml | 5 ++ .../overlays/prod/kustomization.yaml | 13 +++ 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 core/cautils/testdata/kustomize/base/deployment.yaml create mode 100644 core/cautils/testdata/kustomize/base/kustomization.yaml create mode 100644 core/cautils/testdata/kustomize/overlays/prod/kustomization.yaml diff --git a/core/cautils/kustomizedirectory.go b/core/cautils/kustomizedirectory.go index 31b449e3..0dcbfb13 100644 --- a/core/cautils/kustomizedirectory.go +++ b/core/cautils/kustomizedirectory.go @@ -9,6 +9,7 @@ import ( "github.com/kubescape/k8s-interface/workloadinterface" "github.com/kubescape/opa-utils/objectsenvelopes/localworkload" "sigs.k8s.io/kustomize/api/krusty" + "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/filesys" ) @@ -75,7 +76,11 @@ func getKustomizeDirectoryName(path string) string { func (kd *KustomizeDirectory) GetWorkloads(kustomizeDirectoryPath string) (map[string][]workloadinterface.IMetadata, []error) { fSys := filesys.MakeFsOnDisk() - kustomizer := krusty.MakeKustomizer(krusty.MakeDefaultOptions()) + // Use LoadRestrictionsNone to allow loading resources from outside the kustomize directory. + // This is necessary for overlays that reference base configurations in parent directories. + opts := krusty.MakeDefaultOptions() + opts.LoadRestrictions = types.LoadRestrictionsNone + kustomizer := krusty.MakeKustomizer(opts) resmap, err := kustomizer.Run(fSys, kustomizeDirectoryPath) if err != nil { diff --git a/core/cautils/kustomizedirectory_test.go b/core/cautils/kustomizedirectory_test.go index b569a0b5..3acb31de 100644 --- a/core/cautils/kustomizedirectory_test.go +++ b/core/cautils/kustomizedirectory_test.go @@ -4,6 +4,8 @@ import ( "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" ) func TestGetKustomizeDirectoryName(t *testing.T) { @@ -61,3 +63,83 @@ func TestGetKustomizeDirectoryName(t *testing.T) { }) } } + +func kustomizeTestdataPath() string { + o, _ := os.Getwd() + return filepath.Join(o, "testdata", "kustomize") +} + +// TestKustomizeOverlayWithBase tests that kustomize overlays can properly load +// resources from base directories. This is the main fix for issue #1617. +func TestKustomizeOverlayWithBase(t *testing.T) { + overlayPath := filepath.Join(kustomizeTestdataPath(), "overlays", "prod") + + // Verify it's detected as a kustomize directory + assert.True(t, isKustomizeDirectory(overlayPath), "overlay should be detected as kustomize directory") + + // Create kustomize directory and get workloads + kd := NewKustomizeDirectory(overlayPath) + workloads, errs := kd.GetWorkloads(overlayPath) + + // Should not have errors - this was failing before the fix because + // overlays couldn't load resources from parent base directories + assert.Empty(t, errs, "should not have errors loading overlay with base reference") + + // Should have workloads from the rendered overlay + assert.NotEmpty(t, workloads, "should have workloads from rendered kustomize overlay") + + // The overlay should have produced exactly one deployment with the merged configuration + var deploymentFound bool + for _, wls := range workloads { + for _, wl := range wls { + if wl.GetKind() == "Deployment" && wl.GetName() == "test-app" { + deploymentFound = true + + // Verify the deployment has the resource limits from the base + obj := wl.GetObject() + spec, ok := obj["spec"].(map[string]interface{}) + assert.True(t, ok, "deployment should have spec") + + template, ok := spec["template"].(map[string]interface{}) + assert.True(t, ok, "deployment should have template") + + templateSpec, ok := template["spec"].(map[string]interface{}) + assert.True(t, ok, "template should have spec") + + containers, ok := templateSpec["containers"].([]interface{}) + assert.True(t, ok, "template spec should have containers") + assert.NotEmpty(t, containers, "should have at least one container") + + container, ok := containers[0].(map[string]interface{}) + assert.True(t, ok, "container should be a map") + + resources, ok := container["resources"].(map[string]interface{}) + assert.True(t, ok, "container should have resources (from base)") + + limits, ok := resources["limits"].(map[string]interface{}) + assert.True(t, ok, "resources should have limits") + assert.Equal(t, "500m", limits["cpu"], "cpu limit should be from base") + assert.Equal(t, "256Mi", limits["memory"], "memory limit should be from base") + + // Verify overlay modifications were applied + replicas, ok := spec["replicas"].(int) + assert.True(t, ok, "replicas should be an int") + assert.Equal(t, 3, replicas, "replicas should be modified by overlay") + } + } + } + assert.True(t, deploymentFound, "deployment should be found in rendered output") +} + +// TestKustomizeBaseDirectory tests that base directories work on their own +func TestKustomizeBaseDirectory(t *testing.T) { + basePath := filepath.Join(kustomizeTestdataPath(), "base") + + assert.True(t, isKustomizeDirectory(basePath), "base should be detected as kustomize directory") + + kd := NewKustomizeDirectory(basePath) + workloads, errs := kd.GetWorkloads(basePath) + + assert.Empty(t, errs, "should not have errors loading base directory") + assert.NotEmpty(t, workloads, "should have workloads from base directory") +} diff --git a/core/cautils/testdata/kustomize/base/deployment.yaml b/core/cautils/testdata/kustomize/base/deployment.yaml new file mode 100644 index 00000000..373e861d --- /dev/null +++ b/core/cautils/testdata/kustomize/base/deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-app + labels: + app: test-app +spec: + replicas: 1 + selector: + matchLabels: + app: test-app + template: + metadata: + labels: + app: test-app + spec: + containers: + - name: test-container + image: nginx:1.19 + resources: + limits: + cpu: "500m" + memory: "256Mi" + requests: + cpu: "100m" + memory: "128Mi" + ports: + - containerPort: 80 diff --git a/core/cautils/testdata/kustomize/base/kustomization.yaml b/core/cautils/testdata/kustomize/base/kustomization.yaml new file mode 100644 index 00000000..88a04b54 --- /dev/null +++ b/core/cautils/testdata/kustomize/base/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - deployment.yaml diff --git a/core/cautils/testdata/kustomize/overlays/prod/kustomization.yaml b/core/cautils/testdata/kustomize/overlays/prod/kustomization.yaml new file mode 100644 index 00000000..611e4ae8 --- /dev/null +++ b/core/cautils/testdata/kustomize/overlays/prod/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +images: + - name: nginx + newTag: "1.21" + +replicas: + - name: test-app + count: 3