fix: enable kustomize overlays to load base configurations

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 <noreply@anthropic.com>
Signed-off-by: majiayu000 <1835304752@qq.com>
This commit is contained in:
majiayu000
2025-12-31 06:14:10 +08:00
parent 1225540590
commit 0f2125817b
5 changed files with 134 additions and 1 deletions

View File

@@ -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 {

View File

@@ -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")
}

View File

@@ -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

View File

@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml

View File

@@ -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