Skip to content

Commit 186d8ed

Browse files
fix: kustomize components + monorepos
With #21674 the ability to ignore Kustomize component directories if they do not exist got introduced. This generally works fine, but the `securejoin` check is a bit too strict - we want to ensure that no-one can break out of the repo, but the current implementation doesn't allow for breaking outside the kustomization folder. This breaks the usage of this feature when using it for a monorepo. This PR loosens the check to allow for traversals up to the repo root. We use the new `os.Root` functionality to ensure that users can't break outside the repo. Path traversals are still relative from the kustomize repo. Signed-off-by: Blake Pettersson <[email protected]>
1 parent 2ae9f43 commit 186d8ed

7 files changed

Lines changed: 119 additions & 5 deletions

File tree

util/kustomize/kustomize.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ import (
2424
executil "github.com/argoproj/argo-cd/v3/util/exec"
2525
"github.com/argoproj/argo-cd/v3/util/git"
2626
"github.com/argoproj/argo-cd/v3/util/proxy"
27-
28-
securejoin "github.com/cyphar/filepath-securejoin"
2927
)
3028

3129
// Image represents a Docker image in the format NAME[:TAG].
@@ -346,12 +344,18 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp
346344
foundComponents := opts.Components
347345
if opts.IgnoreMissingComponents {
348346
foundComponents = make([]string, 0)
347+
root, err := os.OpenRoot(k.repoRoot)
348+
if err != nil {
349+
return nil, nil, nil, fmt.Errorf("failed to open the repo folder: %w", err)
350+
}
351+
349352
for _, c := range opts.Components {
350-
resolvedPath, err := securejoin.SecureJoin(k.path, c)
353+
resolvedPath, err := filepath.Rel(k.repoRoot, filepath.Join(k.path, c))
351354
if err != nil {
352-
return nil, nil, nil, fmt.Errorf("Kustomize components path failed: %w", err)
355+
log.Debugf("failed to relativize path: %s", err)
356+
continue
353357
}
354-
_, err = os.Stat(resolvedPath)
358+
_, err = root.Stat(resolvedPath)
355359
if err != nil {
356360
log.Debugf("%s component directory does not exist", resolvedPath)
357361
continue

util/kustomize/kustomize_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const (
2525
kustomization6 = "kustomization_yaml_components"
2626
kustomization7 = "label_without_selector"
2727
kustomization8 = "kustomization_yaml_patches_empty"
28+
kustomization9 = "kustomization_yaml_components_monorepo"
2829
)
2930

3031
func testDataDir(tb testing.TB, testData string) (string, error) {
@@ -512,6 +513,31 @@ func TestKustomizeBuildComponents(t *testing.T) {
512513
assert.Equal(t, int64(3), replicas)
513514
}
514515

516+
func TestKustomizeBuildComponentsMonoRepo(t *testing.T) {
517+
rootPath, err := testDataDir(t, kustomization9)
518+
require.NoError(t, err)
519+
appPath := path.Join(rootPath, "envs/inseng-pdx-egert-sandbox/namespaces/inst-system/apps/hello-world")
520+
kustomize := NewKustomizeApp(rootPath, appPath, git.NopCreds{}, "", "", "", "")
521+
kustomizeSource := v1alpha1.ApplicationSourceKustomize{
522+
Components: []string{"../../../../../../kustomize/components/all"},
523+
IgnoreMissingComponents: true,
524+
}
525+
objs, _, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil)
526+
require.NoError(t, err)
527+
obj := objs[2]
528+
require.Equal(t, "hello-world-kustomize", obj.GetName())
529+
require.Equal(t, map[string]string{
530+
"app.kubernetes.io/name": "hello-world-kustomize",
531+
"app.kubernetes.io/owner": "fire-team",
532+
}, obj.GetLabels())
533+
replicas, ok, err := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "tolerations")
534+
require.NoError(t, err)
535+
require.True(t, ok)
536+
require.Equal(t, 1, len(replicas))
537+
require.Equal(t, "my-special-toleration", replicas[0].(map[string]any)["key"])
538+
require.Equal(t, "Exists", replicas[0].(map[string]any)["operator"])
539+
}
540+
515541
func TestKustomizeBuildPatches(t *testing.T) {
516542
appPath, err := testDataDir(t, kustomization5)
517543
require.NoError(t, err)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: hello-world
5+
labels:
6+
app.kubernetes.io/name: hello-world
7+
spec:
8+
replicas: 1
9+
selector:
10+
matchLabels:
11+
app.kubernetes.io/name: hello-world
12+
template:
13+
metadata:
14+
labels:
15+
app.kubernetes.io/name: hello-world
16+
spec:
17+
serviceAccountName: hello-world
18+
containers:
19+
- name: hello-world
20+
image: "nginx:1.16.0"
21+
imagePullPolicy: IfNotPresent
22+
ports:
23+
- name: http
24+
containerPort: 80
25+
protocol: TCP
26+
livenessProbe:
27+
httpGet:
28+
path: /
29+
port: http
30+
readinessProbe:
31+
httpGet:
32+
path: /
33+
port: http
34+
tolerations: []
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
apiVersion: kustomize.config.k8s.io/v1beta1
3+
kind: Kustomization
4+
5+
resources:
6+
- deployment.yaml
7+
- service.yaml
8+
- serviceaccount.yaml
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
apiVersion: v1
3+
kind: Service
4+
metadata:
5+
name: hello-world
6+
labels:
7+
app.kubernetes.io/name: hello-world
8+
spec:
9+
type: ClusterIP
10+
ports:
11+
- port: 80
12+
targetPort: http
13+
protocol: TCP
14+
name: http
15+
selector:
16+
app.kubernetes.io/name: hello-world
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: hello-world
6+
labels:
7+
app.kubernetes.io/name: hello-world
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
apiVersion: kustomize.config.k8s.io/v1alpha1
3+
kind: Component
4+
5+
labels:
6+
- pairs:
7+
app.kubernetes.io/owner: fire-team
8+
includeSelectors: false
9+
includeTemplates: false
10+
11+
patches:
12+
- target:
13+
kind: Deployment
14+
patch: |-
15+
- op: add
16+
path: /spec/template/spec/tolerations/-
17+
value:
18+
key: my-special-toleration
19+
operator: Exists

0 commit comments

Comments
 (0)